@rebasepro/app 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +1 -1
  2. package/dist/RlsSimulatorPanel-DOfmVgM3.js +403 -0
  3. package/dist/RlsSimulatorPanel-DOfmVgM3.js.map +1 -0
  4. package/dist/collections/form-layout.d.ts +30 -27
  5. package/dist/components/LanguageToggle.d.ts +9 -0
  6. package/dist/components/LoginView/index.d.ts +7 -0
  7. package/dist/components/index.d.ts +1 -0
  8. package/dist/components/studio/RlsSimulatorBar.d.ts +39 -0
  9. package/dist/components/studio/RlsSimulatorPanel.d.ts +29 -0
  10. package/dist/contexts/RlsSimulationContext.d.ts +47 -0
  11. package/dist/contexts/index.d.ts +1 -0
  12. package/dist/core/effective_role_state.d.ts +9 -0
  13. package/dist/{de-BMgOgwue.js → de-3yzzpuZj.js} +175 -1
  14. package/dist/de-3yzzpuZj.js.map +1 -0
  15. package/dist/debug.js +96 -46
  16. package/dist/{es-DSOOSgPW.js → es-mnyTaRkK.js} +175 -1
  17. package/dist/es-mnyTaRkK.js.map +1 -0
  18. package/dist/{fr-CnXidmZf.js → fr-nJHADzlI.js} +175 -1
  19. package/dist/fr-nJHADzlI.js.map +1 -0
  20. package/dist/{hi-lTvNsFMr.js → hi-B9_iunnL.js} +175 -1
  21. package/dist/hi-B9_iunnL.js.map +1 -0
  22. package/dist/hooks/useBuildEffectiveRoleController.d.ts +9 -3
  23. package/dist/hooks/usePermissions.d.ts +4 -0
  24. package/dist/hooks/useUnsavedChangesDialog.d.ts +7 -1
  25. package/dist/i18n/RebaseI18nProvider.d.ts +11 -0
  26. package/dist/index.es.js +2814 -2555
  27. package/dist/index.es.js.map +1 -1
  28. package/dist/{it-BoT_vBlx.js → it-DoEtz-OK.js} +175 -1
  29. package/dist/it-DoEtz-OK.js.map +1 -0
  30. package/dist/{pt-D9mSchbY.js → pt-DT26AmBU.js} +175 -1
  31. package/dist/pt-DT26AmBU.js.map +1 -0
  32. package/package.json +7 -7
  33. package/dist/de-BMgOgwue.js.map +0 -1
  34. package/dist/es-DSOOSgPW.js.map +0 -1
  35. package/dist/fr-CnXidmZf.js.map +0 -1
  36. package/dist/hi-lTvNsFMr.js.map +0 -1
  37. package/dist/it-BoT_vBlx.js.map +0 -1
  38. package/dist/pt-D9mSchbY.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","names":[],"sources":["../src/core/PluginProviderStack.tsx","../src/core/PluginLifecycleManager.tsx","../src/core/deprecated_plugin_keys.ts","../src/contexts/SnackbarProvider.tsx","../src/contexts/ModeController.tsx","../src/contexts/AdminModeController.tsx","../src/contexts/EffectiveRoleController.tsx","../src/contexts/AuthControllerContext.tsx","../src/contexts/DataDriverContext.tsx","../src/contexts/DataSourcesContext.tsx","../src/contexts/RebaseDataContext.tsx","../src/contexts/AnalyticsContext.tsx","../src/contexts/StorageSourceContext.tsx","../src/contexts/StorageSourcesContext.tsx","../src/contexts/UserConfigurationPersistenceContext.tsx","../src/contexts/DialogsProvider.tsx","../src/contexts/RebaseClientInstanceContext.tsx","../src/contexts/CustomizationControllerContext.tsx","../src/contexts/ComponentOverrideContext.tsx","../src/contexts/CollectionScopeContext.tsx","../src/contexts/CollectionResolverContext.tsx","../src/hooks/data/useData.tsx","../src/components/SchemaDriftBanner.tsx","../src/hooks/data/collectionQuery.ts","../src/collections/summary-property.ts","../src/util/previews.ts","../src/util/realtime.ts","../src/hooks/data/useStableFilterValues.ts","../src/hooks/data/useCollection.tsx","../src/hooks/data/collectionWindow.ts","../src/hooks/useAuthController.tsx","../src/hooks/useRebaseClient.tsx","../src/hooks/useStorageSource.tsx","../src/hooks/useSnackbarController.tsx","../src/hooks/useUserConfigurationPersistence.tsx","../src/hooks/useDialogsController.tsx","../src/hooks/useCustomizationController.tsx","../src/hooks/useAnalyticsController.tsx","../src/hooks/useEffectiveRoleController.tsx","../src/contexts/DatabaseAdminContext.tsx","../src/hooks/useRebaseContext.tsx","../src/hooks/data/useFetch.tsx","../src/hooks/data/useBatchedFetch.tsx","../src/hooks/data/useRelationSelector.tsx","../src/hooks/data/save.ts","../src/hooks/data/delete.ts","../src/hooks/useNavigationBlocker.tsx","../src/hooks/useUnsavedChangesDialog.tsx","../src/components/common/useScrollRestoration.tsx","../src/util/entity_cache.ts","../src/collections/entity-display-cache.ts","../src/auth/session_caches.ts","../src/hooks/useAuthSubscription.ts","../src/hooks/useAdminModeController.tsx","../src/util/local_storage.ts","../src/hooks/useBuildAdminModeController.tsx","../src/hooks/useBuildEffectiveRoleController.tsx","../src/hooks/useModeController.tsx","../src/hooks/useClipboard.tsx","../src/hooks/useLargeLayout.tsx","../src/hooks/useCollapsedGroups.ts","../src/hooks/useBrowserTitleAndIcon.tsx","../src/hooks/useSlot.tsx","../src/hooks/useBuildLocalConfigurationPersistence.tsx","../src/hooks/useBuildModeController.tsx","../src/hooks/useRebaseRegistry.tsx","../src/hooks/usePermissions.ts","../src/hooks/ApiConfigContext.tsx","../src/hooks/useTranslation.ts","../src/hooks/useNavigationGroupLabel.ts","../src/hooks/useResolvedComponent.tsx","../src/hooks/useComponentOverride.tsx","../src/components/ErrorTooltip.tsx","../src/components/ErrorView.tsx","../src/components/common/useDebouncedData.ts","../src/collections/property-path.ts","../src/collections/property_presentation.ts","../src/components/common/useColumnsIds.tsx","../src/hooks/data/useDataOrder.ts","../src/components/common/useDataTableController.tsx","../src/components/common/table_height.tsx","../src/components/NotFoundPage.tsx","../src/components/ConfirmationDialog.tsx","../src/components/RebaseLogo.tsx","../src/components/AIIcon.tsx","../src/components/email-change-message.ts","../src/components/UserSettingsView.tsx","../src/components/LanguageToggle.tsx","../src/components/UserSelectPopover.tsx","../src/components/UserDisplay.tsx","../src/components/LoginView/oauth-redirect-flow.ts","../src/components/LoginView/auth-error-message.ts","../src/components/LoginView/email-link.ts","../src/components/LoginView/mfa-required.ts","../src/components/LoginView/LoginView.tsx","../src/components/RebaseAuth.tsx","../src/components/ConnectionLostBanner.tsx","../src/locales/en.ts","../src/i18n/RebaseI18nProvider.tsx","../src/core/Rebase.tsx","../src/core/RebaseRouter.tsx","../src/core/RebaseRoutes.tsx","../src/auth/useRebaseAuthController.ts","../src/auth/api.ts","../src/util/icon_list.ts","../src/util/icons.tsx","../src/util/createFormexStub.tsx","../src/util/useStorageUploadController.tsx","../src/util/enums.ts","../src/util/constants.ts","../src/internal/common.tsx","../src/internal/useRestoreScroll.tsx","../src/components/UnsavedChangesDialog.tsx","../src/hooks/useStudioBridge.tsx","../src/hooks/useBridgeRegistration.tsx","../src/collections/collection_view_config.ts","../src/collections/entity-display.ts","../src/collections/entity_image_preview.ts","../src/collections/filter-operator-resolution.ts","../src/collections/form-layout.ts","../src/collections/navigation_utils.ts","../src/collections/navigation_from_path.ts","../src/collections/parent_references_from_path.ts","../src/collections/title-property.ts"],"sourcesContent":["import type { RebasePlugin } from \"@rebasepro/cms-types\";\nimport React from \"react\";\n;\n\n/**\n * Wraps children with all provider components from plugins that match the given scope.\n *\n * Replaces the 3 copy-pasted `plugins.forEach(plugin => { if (plugin.form?.provider) ... })` patterns\n * in Rebase.tsx, EditViewBinding.tsx, and PopupFormField.tsx.\n *\n * @param plugins - Array of plugins to extract providers from.\n * @param scope - `\"root\"` or `\"form\"` — which providers to apply.\n * @param scopeProps - Additional props passed to each provider component.\n * @param children - The content to wrap.\n *\n * @group Core\n */\nexport function PluginProviderStack({\n plugins,\n scope,\n scopeProps,\n children\n}: {\n plugins: RebasePlugin[];\n scope: \"root\" | \"form\";\n scopeProps?: Record<string, unknown>;\n children: React.ReactNode;\n}) {\n const providers = plugins.flatMap(p => p.providers ?? [])\n .filter(p => p.scope === scope);\n\n return providers.reduceRight<React.ReactNode>(\n (acc, provider) => (\n <provider.Component {...provider.props} {...scopeProps}>\n {acc}\n </provider.Component>\n ),\n children\n );\n}\n","\nimport { useEffect, useRef } from \"react\";\nimport type { RebasePlugin, RebaseContext } from \"@rebasepro/cms-types\";\n\n/**\n * Render-less component that manages plugin lifecycle hooks.\n *\n * - Calls `lifecycle.onMount(context)` once, the first time auth is ready.\n * - Calls `lifecycle.onAuthStateChange(user)` on every change of user after\n * that — `null` on sign-out, the new user on the next sign-in.\n * - Calls `lifecycle.onUnmount()` when the Rebase tree unmounts.\n *\n * Mounted for as long as there are plugins, signed in or not. It used to be\n * mounted only while a user was signed in, so a sign-out unmounted it and the\n * next sign-in mounted a fresh one — `onAuthStateChange` could never see the\n * user change, and never fired.\n *\n * Mount this component inside the Rebase tree, below PluginProviderStack,\n * so that the RebaseContext is fully available.\n *\n * @internal\n */\nexport function PluginLifecycleManager({\n plugins,\n context,\n authReady\n}: {\n plugins: RebasePlugin[];\n context: RebaseContext;\n /** Signed in, or sign-in skipped: what `onMount` waits for. */\n authReady: boolean;\n}) {\n const mountedRef = useRef(false);\n const prevUidRef = useRef<string | null>(null);\n const currentUser = context.authController?.user ?? null;\n\n // ── Mount ────────────────────────────────────────────────────────\n useEffect(() => {\n if (!authReady || mountedRef.current) return;\n mountedRef.current = true;\n prevUidRef.current = currentUser?.uid ?? null;\n\n for (const plugin of plugins) {\n if (plugin.lifecycle?.onMount) {\n try {\n const result = plugin.lifecycle.onMount(context);\n if (result instanceof Promise) {\n result.catch((err) =>\n console.error(`[Rebase] Plugin \"${plugin.key}\" onMount error:`, err)\n );\n }\n } catch (err) {\n console.error(`[Rebase] Plugin \"${plugin.key}\" onMount error:`, err);\n }\n }\n }\n // Once: later changes of user are `onAuthStateChange`'s.\n }, [authReady]);\n\n // ── Unmount ──────────────────────────────────────────────────────\n useEffect(() => {\n return () => {\n if (!mountedRef.current) return;\n mountedRef.current = false;\n for (const plugin of plugins) {\n if (plugin.lifecycle?.onUnmount) {\n try {\n plugin.lifecycle.onUnmount();\n } catch (err) {\n console.error(`[Rebase] Plugin \"${plugin.key}\" onUnmount error:`, err);\n }\n }\n }\n };\n // Only on unmount — plugins array identity should be stable\n }, []);\n\n // ── Auth state change ────────────────────────────────────────────\n useEffect(() => {\n // Before `onMount` there is nobody to tell.\n if (!mountedRef.current) return;\n\n // Only fire when the user identity actually changes\n const currUid = currentUser?.uid ?? null;\n if (prevUidRef.current === currUid) return;\n prevUidRef.current = currUid;\n\n for (const plugin of plugins) {\n if (plugin.lifecycle?.onAuthStateChange) {\n try {\n plugin.lifecycle.onAuthStateChange(currentUser);\n } catch (err) {\n console.error(\n `[Rebase] Plugin \"${plugin.key}\" onAuthStateChange error:`,\n err\n );\n }\n }\n }\n }, [currentUser, plugins]);\n\n return null;\n}\n","import type { RebasePlugin } from \"@rebasepro/cms-types\";\nimport { warnDeprecated } from \"@rebasepro/common\";\n\n/**\n * Warn, once per plugin and key, about plugin keys that are declared on\n * `RebasePlugin` but that nothing has ever called.\n *\n * A plugin that set one of these did nothing and said nothing about it. The\n * types mark them deprecated; this names them at runtime too, which also\n * reaches a plugin written in JavaScript.\n */\nexport function warnDeprecatedPluginKeys(plugins: readonly RebasePlugin[]): void {\n for (const plugin of plugins) {\n if (plugin.hooks?.modifyCollectionAsync !== undefined) {\n warnDeprecated(\n `plugin:${plugin.key}:hooks.modifyCollectionAsync`,\n `Plugin \"${plugin.key}\" sets \\`hooks.modifyCollectionAsync\\`, which is deprecated: ` +\n \"nothing has ever called it. Remove it: fetch what the change needs before rendering \" +\n \"`<Rebase>`, then build the plugin from that data and apply it in `hooks.modifyCollection`.\"\n );\n }\n if (plugin.lifecycle?.onCollectionChange !== undefined) {\n warnDeprecated(\n `plugin:${plugin.key}:lifecycle.onCollectionChange`,\n `Plugin \"${plugin.key}\" sets \\`lifecycle.onCollectionChange\\`, which is deprecated: ` +\n \"nothing has ever called it. Remove it and subscribe to the rows yourself instead — \" +\n \"`context.data.collection(slug).listen(...)` from `lifecycle.onMount`, unsubscribing in \" +\n \"`lifecycle.onUnmount`.\"\n );\n }\n }\n}\n","\"use client\";\n\nimport React, { PropsWithChildren } from \"react\";\nimport { SnackbarProvider as NotistackSnackbarProvider } from \"notistack\";\n\nexport const SnackbarProvider: React.FC<PropsWithChildren> = ({ children }) => {\n\n return (\n <NotistackSnackbarProvider maxSnack={3}\n preventDuplicate={true}\n autoHideDuration={3500}>\n {children}\n </NotistackSnackbarProvider>\n );\n};\n","import React from \"react\";\nimport type { ModeController } from \"../hooks/useModeController\";\n\nconst DEFAULT_MODE_STATE: ModeController = {\n mode: \"light\",\n setMode: (mode: \"light\" | \"dark\" | \"system\") => {\n }\n};\nexport const ModeControllerContext = React.createContext<ModeController>(DEFAULT_MODE_STATE);\n\nexport const ModeControllerProvider = ModeControllerContext.Provider;\n","import React from \"react\";\nimport type { AdminModeController } from \"../hooks/useAdminModeController\";\n\nconst DEFAULT_ADMIN_MODE_STATE: AdminModeController = {\n mode: \"cms\",\n setMode: (mode: \"cms\" | \"studio\") => {\n }\n};\nexport const AdminModeControllerContext = React.createContext<AdminModeController>(DEFAULT_ADMIN_MODE_STATE);\n\nexport const AdminModeControllerProvider = AdminModeControllerContext.Provider;\n","import type { EffectiveRoleController } from \"@rebasepro/types\";\nimport React from \"react\";\n;\n\nconst DEFAULT_EFFECTIVE_ROLE_STATE: EffectiveRoleController = {\n effectiveRole: null,\n setEffectiveRole: (_role: string | null) => {\n }\n};\nexport const EffectiveRoleControllerContext = React.createContext<EffectiveRoleController>(DEFAULT_EFFECTIVE_ROLE_STATE);\n\nexport const EffectiveRoleControllerProvider = EffectiveRoleControllerContext.Provider;\n","import React from \"react\";\nimport { AuthController } from \"@rebasepro/cms-types\";\n\n/** `null` outside `<Rebase>` — see {@link RebaseDataContext}. */\nexport const AuthControllerContext = React.createContext<AuthController<any, any> | null>(null);\n","import React from \"react\";\nimport { DataDriver } from \"@rebasepro/types\";\n\nexport const DataDriverContext = React.createContext<DataDriver>({} as DataDriver);\n","import React from \"react\";\nimport { DataSourceDefinition, RebaseData } from \"@rebasepro/types\";\n\n/**\n * The data-source configuration provided to `<Rebase>`: the declared\n * definitions plus the built {@link RebaseData} instances for direct/custom\n * transports.\n *\n * The actual path-based routing is assembled by the navigation layer (which\n * has the collection registry) via `resolveDataSource` + `buildRoutedRebaseData`\n * and re-provided through `RebaseDataContext`.\n *\n * @internal\n */\nexport interface DataSourcesContextValue {\n /** All declared data sources, keyed by data-source key. */\n registry: Record<string, DataSourceDefinition>;\n /**\n * Built {@link RebaseData} for direct/custom data sources, keyed by\n * data-source key. Server-mediated sources are absent (they ride the\n * default client).\n */\n sources: Record<string, RebaseData>;\n}\n\nconst EMPTY: DataSourcesContextValue = { registry: {}, sources: {} };\n\n/** @internal */\nexport const DataSourcesContext = React.createContext<DataSourcesContextValue>(EMPTY);\n\n/**\n * Access the data-source configuration provided to `<Rebase>` via the\n * `dataSources` prop.\n * @internal\n */\nexport const useDataSources = (): DataSourcesContextValue => React.useContext(DataSourcesContext);\n","import React from \"react\";\nimport { RebaseData } from \"@rebasepro/types\";\n\n/**\n * `null` outside `<Rebase>`, so {@link useData} can say so.\n *\n * The default used to be `{} as RebaseData` — a lie the type system agreed\n * with. A hook called outside the tree handed back an empty object, and the\n * first thing anyone does with it is `data.collection(\"posts\")`, which fails as\n * \"data.collection is not a function\" somewhere in a component's render. That\n * names neither the hook nor the missing provider.\n */\nexport const RebaseDataContext = React.createContext<RebaseData | null>(null);\n","import React from \"react\";\nimport { AnalyticsController } from \"@rebasepro/cms-types\";\n\nexport const AnalyticsContext = React.createContext<AnalyticsController>({} as AnalyticsController);\n","import React from \"react\";\nimport { StorageSource } from \"@rebasepro/types\";\n\n/**\n * Three states, and they mean different things:\n *\n * - `null` — outside `<Rebase>`.\n * - `undefined` — inside it, but the project configured no storage. `<Rebase>`\n * already warns about this on the console.\n * - a source — the resolved default storage.\n *\n * See {@link RebaseDataContext} for why the default is not `{}`.\n */\nexport const StorageSourceContext = React.createContext<StorageSource | null | undefined>(null);\n","import React from \"react\";\nimport type { StorageSource, StorageSourceDefinition, StorageSourceRegistry } from \"@rebasepro/types\";\n\n/**\n * The storage-source configuration provided to `<Rebase>`: the declared\n * definitions and the built {@link StorageSource} instances, wrapped in a\n * {@link StorageSourceRegistry} for fast key-based lookup.\n *\n * Mirrors the {@link DataSourcesContext} pattern used for databases.\n *\n * @internal\n */\nexport interface StorageSourcesContextValue {\n /** All declared storage sources, keyed by storage-source key. */\n registry: Record<string, StorageSourceDefinition>;\n /** Built {@link StorageSource} for direct sources, keyed by key. */\n sources: Record<string, StorageSource>;\n /**\n * A server-routed source for a key not (yet) in `sources` — requests carry\n * `?storageId=<key>`, so the server serves it or refuses naming it, rather\n * than the panel guessing the default. Absent without a client.\n */\n createSource?: (key: string) => StorageSource;\n}\n\nconst EMPTY: StorageSourcesContextValue = { registry: {}, sources: {} };\n\n/** @internal */\nexport const StorageSourcesContext = React.createContext<StorageSourcesContextValue>(EMPTY);\n\n/**\n * Access the storage-source configuration provided to `<Rebase>` via the\n * `storageSources` prop.\n * @internal\n */\nexport const useStorageSources = (): StorageSourcesContextValue => React.useContext(StorageSourcesContext);\n","import React from \"react\";\nimport { UserConfigurationPersistence } from \"@rebasepro/cms-types\";\n\nexport const UserConfigurationPersistenceContext = React.createContext<UserConfigurationPersistence | undefined>(undefined);\n","import type { DialogControllerEntryProps, DialogsController } from \"@rebasepro/cms-types\";\nimport React, { PropsWithChildren, useCallback, useRef, useState, useMemo } from \"react\";\n;\n\n/** `null` outside `<Rebase>` — see `RebaseDataContext`. */\nexport const DialogsControllerContext = React.createContext<DialogsController | null>(null);\n\nexport const DialogsProvider: React.FC<PropsWithChildren> = ({ children }) => {\n\n const [dialogEntries, setDialogEntries] = useState<DialogControllerEntryProps[]>([]);\n const dialogEntriesRef = useRef<DialogControllerEntryProps[]>(dialogEntries);\n\n const updateDialogEntries = (newPanels: DialogControllerEntryProps<any>[]) => {\n dialogEntriesRef.current = newPanels;\n setDialogEntries(newPanels);\n };\n\n const close = useCallback(() => {\n\n if (dialogEntries.length === 0)\n return;\n\n const updatedPanels = [...dialogEntriesRef.current.slice(0, -1)];\n updateDialogEntries(updatedPanels);\n\n }, [dialogEntries]);\n\n const open = useCallback(<T extends object = object>(dialogEntry: DialogControllerEntryProps<T>) => {\n\n const updatedPanels = [...dialogEntriesRef.current, dialogEntry];\n updateDialogEntries(updatedPanels);\n\n return {\n closeDialog: () => {\n const updatedPanels = dialogEntriesRef.current.filter(e => e.key !== dialogEntry.key);\n updateDialogEntries(updatedPanels);\n }\n }\n }, [dialogEntries]);\n\n const dialogsController = useMemo(() => ({\n open,\n close\n }), [open, close]);\n\n return (\n <DialogsControllerContext.Provider value={dialogsController}>\n {children}\n {dialogEntries.map((entry, i) => <entry.Component\n key={`dialog_${i}`}\n open={true}\n closeDialog={close}\n {...entry.props}\n />)}\n </DialogsControllerContext.Provider>\n );\n};\n","import React from \"react\";\n\n/**\n * Context that exposes the full RebaseClient instance.\n * Used by the JS Editor to give developer scripts access to `client.data`, `client.auth`, etc.\n */\nexport const RebaseClientInstanceContext = React.createContext<any>(undefined);\n","import type { CustomizationController } from \"@rebasepro/cms-types\";\nimport React from \"react\";\n\n/** `null` outside `<Rebase>` — see {@link RebaseDataContext}. */\nexport const CustomizationControllerContext = React.createContext<CustomizationController | null>(null);\n","import React, { createContext, useContext, useMemo } from \"react\";\nimport type { ComponentOverrideMap } from \"@rebasepro/cms-types\";\n\n/** Stable empty reference to avoid re-creating context values on every render. */\nconst EMPTY_OVERRIDES: ComponentOverrideMap = {};\n\n/**\n * Internal state for the component override resolution chain.\n * Holds both global overrides (set on `<Rebase>`) and collection-scoped\n * overrides (set on individual collections).\n *\n * Resolution priority: collection > global > default.\n *\n * @internal\n */\ninterface ComponentOverrideState {\n globalOverrides: ComponentOverrideMap;\n collectionOverrides: ComponentOverrideMap;\n}\n\nexport const ComponentOverrideContext = createContext<ComponentOverrideState>({\n globalOverrides: EMPTY_OVERRIDES,\n collectionOverrides: EMPTY_OVERRIDES\n});\n\n/**\n * Provider set at the `<Rebase>` root level to supply global component overrides.\n *\n * @internal — Used by the Rebase component. End users set overrides via\n * the `components` prop on `<Rebase>`.\n */\nexport function GlobalComponentOverrideProvider({\n overrides,\n children\n}: {\n overrides?: ComponentOverrideMap;\n children: React.ReactNode;\n}) {\n const value = useMemo<ComponentOverrideState>(() => ({\n globalOverrides: overrides ?? EMPTY_OVERRIDES,\n collectionOverrides: EMPTY_OVERRIDES\n }), [overrides]);\n\n return (\n <ComponentOverrideContext.Provider value={value}>\n {children}\n </ComponentOverrideContext.Provider>\n );\n}\n\n/**\n * Provider set at the collection level to layer collection-scoped overrides\n * on top of global overrides.\n *\n * When a collection defines `components`, this provider is mounted\n * around the collection's view subtree. Components within the subtree\n * will resolve overrides in order: collection → global → default.\n *\n * @internal — Used by DataCollectionView when a collection has\n * `components` defined.\n */\nexport function CollectionComponentOverrideProvider({\n overrides,\n children\n}: {\n overrides?: ComponentOverrideMap;\n children: React.ReactNode;\n}) {\n const parent = useContext(ComponentOverrideContext);\n\n const value = useMemo<ComponentOverrideState>(() => ({\n globalOverrides: parent.globalOverrides,\n collectionOverrides: overrides ?? EMPTY_OVERRIDES\n }), [parent.globalOverrides, overrides]);\n\n return (\n <ComponentOverrideContext.Provider value={value}>\n {children}\n </ComponentOverrideContext.Provider>\n );\n}\n","import React, { createContext, useContext } from \"react\";\n\nimport { CollectionComponentOverrideProvider } from \"./ComponentOverrideContext\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\n/**\n * Carries the collection a UI subtree is currently bound to.\n *\n * Mounted by every collection binding (main collection views, entity\n * edit/detail views, side panels, reference-selection dialogs, import\n * previews) via {@link CollectionScopeProvider}. Leaf components read it with\n * {@link useCollectionScope} to derive collection-dependent behavior — e.g.\n * filter fields resolve the engine's supported operators from\n * `collection.engine` — without every intermediate component threading\n * collection props.\n *\n * @internal\n */\nexport const CollectionScopeContext = createContext<AdminCollection | undefined>(undefined);\n\n/**\n * Read the collection the current subtree is bound to, or `undefined` when\n * rendered outside any collection scope (e.g. a fully standalone table).\n *\n * @group Hooks\n */\nexport function useCollectionScope(): AdminCollection | undefined {\n return useContext(CollectionScopeContext);\n}\n\n/**\n * Scopes a UI subtree to a collection.\n *\n * Provides two things at once:\n * 1. The collection itself — readable via {@link useCollectionScope} —\n * so leaf components (filter fields, previews, …) can derive\n * collection-dependent behavior such as engine capabilities.\n * 2. The collection's component overrides (`collection.components`),\n * by mounting {@link CollectionComponentOverrideProvider}.\n *\n * Mount this wherever a subtree is bound to a specific collection. If you\n * build a custom view around `SelectableTable` / `CollectionTableBinding`,\n * wrap it in this provider to get engine-aware filters and collection-scoped\n * component overrides for free:\n *\n * ```tsx\n * <CollectionScopeProvider collection={myCollection}>\n * <CollectionTableBinding ... />\n * </CollectionScopeProvider>\n * ```\n *\n * @group Components\n */\nexport function CollectionScopeProvider({\n collection,\n children\n}: {\n collection: AdminCollection<any> | undefined;\n children: React.ReactNode;\n}) {\n return (\n <CollectionScopeContext.Provider value={collection as AdminCollection | undefined}>\n <CollectionComponentOverrideProvider overrides={collection?.components}>\n {children}\n </CollectionComponentOverrideProvider>\n </CollectionScopeContext.Provider>\n );\n}\n","import React from \"react\";\n\n/**\n * Look up a collection's config by slug.\n */\nexport type CollectionResolver = (slug: string) => { properties?: Record<string, unknown> } | undefined;\n\n/**\n * Translate the path a collection is addressed by into the path its driver\n * stores it under — `fs_diagnosis` into `diagnosis`, for a Firestore collection\n * that declares `path: \"diagnosis\"`. See `EntityDataOptions.resolveDataPath`.\n */\nexport type DataPathResolver = (path: string) => string | undefined;\n\n/**\n * Lets the layer that owns the collections hand a resolver *up* to the data\n * layer, which needs a collection's primary keys to give its rows an address.\n *\n * The inversion is forced by the composition: `<Rebase client>` builds the data\n * layer, and `<RebaseCMS collections>` sits inside it — so the collections are\n * not in scope where the data is created, and `Rebase` cannot take them as a\n * prop without giving every headless BaaS app a collections argument it has no\n * use for.\n *\n * The same layer knows where each collection is stored, so it hands up the\n * data-path translation alongside: a direct driver has to be given a\n * collection's declared `path`, and only the registry knows it.\n *\n * Registration is a ref write, so it is safe to call during render — and it has\n * to be. The views that fetch rows are *below* the registrar, and child effects\n * run before parent effects, so registering in an effect would bind after the\n * first page of rows had already been converted.\n *\n * Several layers may own collections at once — the CMS navigation, and each\n * standalone `CollectionsProvider` on a page — so each registers under its own\n * `owner` (`\"default\"` when omitted). A lookup asks every owner and takes the\n * first that knows the collection. Registering nothing (`undefined` for both)\n * removes that owner's registration.\n */\nexport type CollectionResolverRegistration = (\n resolver: CollectionResolver | undefined,\n resolveDataPath?: DataPathResolver,\n owner?: string\n) => void;\n\nexport const CollectionResolverRegistrationContext =\n React.createContext<CollectionResolverRegistration>(() => undefined);\n","import { useContext } from \"react\";\nimport { RebaseData } from \"@rebasepro/types\";\nimport { RebaseDataContext } from \"../../contexts/RebaseDataContext\";\n\n/**\n * Use this hook to access the unified data API.\n *\n * ```ts\n * const data = useData();\n * const { data: products } = await data.products.find({ where: { status: [\"==\", \"published\"] } });\n * await data.products.create({ name: \"Camera\", price: 299 });\n * ```\n *\n * @group Hooks and utilities\n */\nexport const useData = (): RebaseData => {\n const data = useContext(RebaseDataContext);\n if (!data) throw new Error(\"useData must be used inside <Rebase>\");\n return data;\n};\n","import React, { createContext, useCallback, useContext, useMemo, useState } from \"react\";\nimport { Alert, Typography } from \"@rebasepro/ui\";\n\n// ── Schema Drift Context ────────────────────────────────────────────────\n\ninterface SchemaDriftContextValue {\n /** Report a schema drift error (call from any data-loading hook). */\n reportSchemaDrift: (message: string) => void;\n /** The most recent schema drift message, or null. */\n schemaDriftMessage: string | null;\n /** Dismiss the banner for this session. */\n dismiss: () => void;\n}\n\nconst SchemaDriftContext = createContext<SchemaDriftContextValue>({\n reportSchemaDrift: () => {},\n schemaDriftMessage: null,\n dismiss: () => {}\n});\n\nexport function useSchemaDriftContext(): SchemaDriftContextValue {\n return useContext(SchemaDriftContext);\n}\n\n/**\n * Detects schema drift from an error object.\n * Checks both the error code (from `RebaseApiError`) and the message\n * for schema drift indicators.\n */\nexport function isSchemaDriftError(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n // RebaseApiError from the SDK has a `code` property\n if (\"code\" in error && (error as { code?: string }).code === \"SCHEMA_DRIFT\") {\n return true;\n }\n // Fallback: check the message for the telltale phrase\n if (error instanceof Error && error.message.includes(\"Schema drift:\")) {\n return true;\n }\n return false;\n}\n\n// ── Provider ─────────────────────────────────────────────────────────────\n\nexport function SchemaDriftProvider({ children }: { children: React.ReactNode }) {\n const [schemaDriftMessage, setSchemaDriftMessage] = useState<string | null>(null);\n const [dismissed, setDismissed] = useState(false);\n\n const reportSchemaDrift = useCallback((message: string) => {\n setSchemaDriftMessage(prev => prev ?? message);\n }, []);\n\n const dismiss = useCallback(() => {\n setDismissed(true);\n }, []);\n\n const value = useMemo<SchemaDriftContextValue>(() => ({\n reportSchemaDrift,\n schemaDriftMessage: dismissed ? null : schemaDriftMessage,\n dismiss\n }), [reportSchemaDrift, schemaDriftMessage, dismissed, dismiss]);\n\n return (\n <SchemaDriftContext.Provider value={value}>\n {children}\n </SchemaDriftContext.Provider>\n );\n}\n\n// ── Banner Component ─────────────────────────────────────────────────────\n\nexport interface SchemaDriftBannerProps {\n className?: string;\n}\n\n/**\n * Persistent banner shown when a schema drift error is detected.\n */\nexport function SchemaDriftBanner({ className }: SchemaDriftBannerProps) {\n const { schemaDriftMessage, dismiss } = useSchemaDriftContext();\n\n if (!schemaDriftMessage) return null;\n\n return (\n <Alert\n color=\"warning\"\n size=\"small\"\n onDismiss={dismiss}\n className={className}\n >\n <div className=\"flex flex-col gap-1\">\n <Typography variant=\"label\" className=\"text-amber-800 dark:text-amber-200\">\n Schema drift detected\n </Typography>\n <Typography variant=\"body2\" className=\"text-amber-700 dark:text-amber-300\">\n {schemaDriftMessage}\n </Typography>\n </div>\n </Alert>\n );\n}\n","import type { FindParams, FilterValues, LogicalCondition, OrderBySpec } from \"@rebasepro/types\";\n\n/**\n * The one place a collection read's parameters are assembled.\n *\n * ## Why this exists\n *\n * Four call sites used to build this object by hand — `useCollection` and\n * `useDataTableController`, each in both their `listen` and `find` branches.\n * Every one of them listed the fields it forwarded, so adding an option to\n * `FindParams` meant remembering four places, and forgetting one failed\n * silently: the option simply never reached the server, and the feature it\n * enabled looked broken for reasons nowhere near the code that dropped it.\n *\n * That is not hypothetical. `searchExplain` was added to three of the four and\n * the miss was found by intercepting a WebSocket frame, because nothing else\n * could see it.\n *\n * A field added here reaches every read. `toFindParams` returns `FindParams`\n * itself, so the compiler checks the shape rather than a hand-copied list.\n */\nexport interface CollectionQueryInput<M extends Record<string, unknown>> {\n where?: FilterValues<Extract<keyof M, string>>;\n logical?: LogicalCondition;\n /**\n * Loosened from `FindParams[\"orderBy\"]` on purpose: callers hold the sort\n * as plain `[string, direction]` pairs read off user config or a URL, where\n * the columns are not statically known. Narrowing it here would push a cast\n * onto every call site, which is the kind of friction that sends people back\n * to hand-building the object this exists to replace.\n */\n orderBy?: OrderBySpec;\n limit?: number;\n offset?: number;\n page?: number;\n searchString?: string;\n include?: string[];\n}\n\n/**\n * Build the parameters for one collection read.\n *\n * Derived options live here rather than at the call sites, so they cannot\n * disagree: `searchExplain` rides along exactly when there is a search string\n * to explain, which is also the only time it costs anything.\n */\nexport function toFindParams<M extends Record<string, unknown>>(\n input: CollectionQueryInput<M>\n): FindParams<M> {\n const { searchString, limit, ...rest } = input;\n return {\n ...rest,\n ...resolveLimit(limit),\n ...(searchString ? { searchString, searchExplain: true } : {})\n } as FindParams<M>;\n}\n\n/**\n * Keep a meaningless `limit` inside the browser.\n *\n * The API refuses a `limit` below 1 — rightly: a window nobody can be served is\n * better refused than quietly widened. But a client that computes one has a bug\n * *here*, and forwarding it turns that bug into a 400 the user reads as the\n * server being broken. That is exactly how a restored, empty scroll entry\n * presented: an `Invalid limit: 0` error where the table should have been.\n *\n * Only the meaningless end is guarded. An absent limit is a supported request —\n * every ingress defaults it (`resolveClientListLimit`), so dropping one cannot\n * produce an unbounded read — whereas a limit *above* the ceiling states an\n * intent, and silently trimming it would hand back a page the caller cannot\n * tell apart from the whole collection. That one still travels, and is still\n * refused where the ceiling lives.\n */\nfunction resolveLimit(limit: number | undefined): { limit?: number } {\n if (limit === undefined) return {};\n if (Number.isInteger(limit) && limit >= 1) return { limit };\n console.warn(`Ignoring an unusable \\`limit\\` of ${limit} — a page size must be a whole number of at least 1. ` +\n \"Reading with the server's default page size instead.\");\n return {};\n}\n","import type { Property } from \"@rebasepro/types\";\n\n/**\n * Whether a property can stand in for a record in *one line*.\n *\n * Preview surfaces — the reference card, a list row, a board card — have a\n * single line per property and no way to grow. That is a constraint on the\n * *value*, not on the property's importance: a Markdown biography is the most\n * interesting column on an author, and it is still the wrong thing to paste\n * into a 44px card. Ranking it here means the picker can skip it without\n * anyone having to configure their way out of a broken card.\n *\n * Kept beside {@link getTitlePropertyCandidates} because the two answer\n * neighbouring questions — \"what is this record called\" and \"what else can be\n * said about it in a line\" — from the same property schema.\n *\n * @group Collections\n */\nexport const SUMMARY_RANK = {\n /**\n * No single-line form exists. A map renders as a key/value table and an\n * array of maps as a stack of them; there is no first line to take.\n */\n UNUSABLE: 0,\n /**\n * Readable in one line, but only as an excerpt — the property holds a\n * document, and the line is its opening. Worth showing when nothing better\n * is available, never in preference to a value that fits whole.\n */\n EXCERPT: 1,\n /** Short and self-contained: the line *is* the value. */\n DIRECT: 2\n} as const;\n\n/** One of the three summary ranks. */\nexport type SummaryRank = typeof SUMMARY_RANK[keyof typeof SUMMARY_RANK];\n\n/**\n * File-storage backed content (single image, array of images, generic upload…).\n * Preview surfaces give these their own image slot, so they are never also a\n * text line.\n *\n * @group Collections\n */\nexport function isStorageProperty(property: Property | undefined): boolean {\n if (!property) return false;\n if (property.type === \"string\" && (property.storage || property.admin?.urlPreview === \"image\")) return true;\n if (property.type === \"array\" && property.of && !Array.isArray(property.of)) {\n const inner = property.of;\n if (inner.type === \"string\" && (inner.storage || inner.admin?.urlPreview === \"image\")) return true;\n }\n return false;\n}\n\n/**\n * True when the property holds free text long enough to be a document rather\n * than a value — Markdown, or an explicitly multi-line string.\n *\n * @group Collections\n */\nexport function isLongTextProperty(property: Property | undefined): boolean {\n if (!property || property.type !== \"string\") return false;\n return Boolean(property.admin?.markdown || property.admin?.multiline);\n}\n\n/**\n * How well a property reads as one line of a preview. See {@link SUMMARY_RANK}.\n *\n * Decided from the property *schema* only: no values are consulted, so the\n * answer is stable for a collection and can be memoised per collection rather\n * than per row.\n *\n * @group Collections\n */\nexport function rankSummaryProperty(property: Property | undefined): SummaryRank {\n if (!property) return SUMMARY_RANK.UNUSABLE;\n\n // Rendered by the image slot, not as text.\n if (isStorageProperty(property)) return SUMMARY_RANK.UNUSABLE;\n\n // A map is a table of its own, whether it declares its properties (a row\n // per sub-property) or not (a key/value dump). Neither has a first line.\n if (property.type === \"map\") return SUMMARY_RANK.UNUSABLE;\n\n if (property.type === \"array\") {\n // A tuple: several properties side by side, so there is nothing single\n // about the line it would produce.\n if (Array.isArray(property.of)) return SUMMARY_RANK.UNUSABLE;\n if (!property.of) return property.oneOf ? SUMMARY_RANK.UNUSABLE : SUMMARY_RANK.DIRECT;\n // Arrays of block-shaped things inherit the block shape.\n const innerRank = rankSummaryProperty(property.of);\n if (innerRank === SUMMARY_RANK.UNUSABLE) return SUMMARY_RANK.UNUSABLE;\n // An array of documents is a stack of excerpts — worse than one\n // excerpt, and never what a card should lead with.\n if (innerRank === SUMMARY_RANK.EXCERPT) return SUMMARY_RANK.UNUSABLE;\n // Short values render as a run of chips, which fits a line.\n return SUMMARY_RANK.DIRECT;\n }\n\n if (isLongTextProperty(property)) return SUMMARY_RANK.EXCERPT;\n\n // Numbers, dates, booleans, enums, plain strings, and single references or\n // relations (which collapse to one linked line) all fit as they are.\n return SUMMARY_RANK.DIRECT;\n}\n\n/**\n * True when the property has any single-line form at all.\n *\n * @group Collections\n */\nexport function canSummariseProperty(property: Property | undefined): boolean {\n return rankSummaryProperty(property) !== SUMMARY_RANK.UNUSABLE;\n}\n","import type { Property } from \"@rebasepro/types\";\nimport type { PropertyConfig, AdminCollection } from \"@rebasepro/cms-types\";\nimport { AuthController } from \"@rebasepro/cms-types\";\nimport { isPropertyBuilder, resolveCollectionRelations } from \"@rebasepro/common\";\nimport { getTitlePropertyKey } from \"@rebasepro/app\";\nimport { SUMMARY_RANK, isStorageProperty, rankSummaryProperty } from \"../collections/summary-property\";\n\nfunction isReferenceProperty(property: Property) {\n if (!property) return null;\n if (property.type === \"reference\") return true;\n if (property.type === \"array\") {\n if (Array.isArray(property.of)) return false;\n else return property.of?.type === \"reference\";\n }\n return false;\n}\n\nfunction isRelationProperty(property: Property) {\n if (!property) return null;\n if (property.type === \"relation\") return true;\n if (property.type === \"array\") {\n if (Array.isArray(property.of)) return false;\n else return property.of?.type === \"relation\";\n }\n return false;\n}\n\nfunction isHiddenProperty(property: Property | undefined): boolean {\n if (!property) return false;\n return Boolean(property.admin?.hideFromCollection);\n}\n\n/**\n * The properties a preview surface should render for a record, best first.\n *\n * Three things decide the answer, in this order:\n *\n * 1. `previewProperties` — passed in, or declared on the collection. A stated\n * list is returned verbatim, ranking and limit included: a developer who\n * asks for the Markdown biography gets the Markdown biography.\n * 2. Whether the value has a one-line form at all. A map renders as a\n * key/value table and a Markdown field as a document; neither fits a card\n * line, so they never take a slot from a value that does. See\n * {@link rankSummaryProperty}.\n * 3. `propertiesOrder`, which breaks ties.\n *\n * The middle step is the one that is easy to get wrong by leaving out.\n * `propertiesOrder` states the *column* order of a collection table — it is\n * not a statement that the first three columns summarise a record, and reading\n * it as one is how a card ends up rendering somebody's entire biography.\n */\nexport function getEntityPreviewKeys(\n authController: AuthController,\n targetCollection: AdminCollection<any>,\n fields: Record<string, PropertyConfig>,\n previewProperties?: string[],\n limit = 3) {\n const allProperties = Object.keys(targetCollection.properties);\n let listProperties = previewProperties?.filter(p => allProperties.includes(p as string));\n if (!listProperties && targetCollection.previewProperties) {\n listProperties = targetCollection.previewProperties?.filter(p => allProperties.includes(p as string));\n }\n if (listProperties && listProperties.length > 0) {\n return listProperties;\n }\n\n // Relations read as a link to somewhere else rather than as a value here,\n // so they are left to the dedicated relation chips — unless the collection\n // ordered its properties explicitly, which puts them back in play.\n const hasExplicitOrder = !!(targetCollection.propertiesOrder as string[] | undefined);\n const order = (targetCollection.propertiesOrder as string[]) || allProperties;\n\n const direct: string[] = [];\n const excerpt: string[] = [];\n\n for (const key of order) {\n const property = targetCollection.properties[key];\n if (!property || isPropertyBuilder(property)) continue;\n if (key === \"id\" || (\"isId\" in property && Boolean((property as { isId?: boolean }).isId))) continue;\n if (isReferenceProperty(property)) continue;\n if (!hasExplicitOrder && isRelationProperty(property)) continue;\n if (isHiddenProperty(property)) continue;\n if (isStorageProperty(property as Property)) continue;\n\n const rank = rankSummaryProperty(property as Property);\n if (rank === SUMMARY_RANK.UNUSABLE) continue;\n (rank === SUMMARY_RANK.EXCERPT ? excerpt : direct).push(key);\n\n // Every remaining slot can already be filled by a value that fits\n // whole, so nothing below can change the answer.\n if (direct.length >= limit) break;\n }\n\n // A long-text field is a poor summary but a fine last resort: better an\n // opening line than a card with nothing under the title.\n return [...direct, ...excerpt].slice(0, limit);\n}\n\n// Returned as-is rather than rebuilt per call, so the result is referentially\n// stable and safe to use as a hook dependency.\nconst INCLUDE_ALL_RELATIONS: string[] = [\"*\"];\n\n/**\n * Include lists handed out, interned by content.\n *\n * Key: the relation names, joined. A list is a pure function of its names, so\n * nothing ever invalidates an entry; the map holds one per distinct set of\n * names a session reads — one per collection shape, a handful in all. It is\n * what keeps the result referentially stable when a caller builds its\n * collection object afresh on every render: `useRelationSelector` lists the\n * include as an effect dependency, and a new array per render was a new read\n * per render.\n */\nconst INTERNED_INCLUDES = new Map<string, string[]>();\n\n/**\n * The `include` a collection view's read sends, so a relation cell renders from\n * the row it arrived with instead of fetching once per cell.\n *\n * It names the relations a **property** of the collection declares — the ones\n * a table column, a list or card chip, a picker option or a board card can\n * render, because the view model only maps relation data onto property keys\n * (`toViewModelValues`). It used to be `[\"*\"]`, which the server reads as\n * every relation the collection declares, one hop. That included the\n * relations declared only in `relations: []` for a record's tabs: no property\n * names them and no list surface shows them, yet every read embedded all of\n * their rows for every parent on the page — a `companies` table with one\n * `owner` column and a `hasMany activities` tab read 50 × 2,000 activity rows a\n * page, and again on every realtime re-read of the rows held.\n *\n * What a property renders is unchanged: each name here is exactly what `*`\n * loaded for that property, uncapped. Both transports read `include` — the\n * REST list and the realtime subscription run the same include loader on the\n * server.\n *\n * Only names the collection resolves as relations are sent: the server answers\n * an unknown one with a 400 `UNKNOWN_RELATION`. A collection whose relations\n * cannot be resolved here (a target that does not load in the browser) falls\n * back to `*` and lets the server decide, as before.\n */\nexport function getRelationIncludeParams(collection: AdminCollection<any>): string[] | undefined {\n const properties = collection.properties;\n if (!properties) return undefined;\n\n let relationNames: string[];\n try {\n relationNames = Object.keys(resolveCollectionRelations(collection));\n } catch (_e) {\n const hasRelations = Object.values(properties).some(property =>\n property && !isPropertyBuilder(property) &&\n (isRelationProperty(property as Property) || isReferenceProperty(property as Property)));\n return hasRelations ? INCLUDE_ALL_RELATIONS : undefined;\n }\n\n const names = relationNames.filter(name =>\n Object.prototype.hasOwnProperty.call(properties, name) && Boolean(properties[name]));\n if (names.length === 0) return undefined;\n\n const key = names.join(\"\\u0000\");\n const interned = INTERNED_INCLUDES.get(key);\n if (interned) return interned;\n INTERNED_INCLUDES.set(key, names);\n return names;\n}\n\n/**\n * The property that fills the title slot for a collection. Ranking lives in\n * `@rebasepro/common`, shared with the admin package so both agree on what an\n * entity is called.\n */\nexport function getEntityTitlePropertyKey<M extends Record<string, any>>(collection: AdminCollection<M>, propertyConfigs: Record<string, PropertyConfig>): string | undefined {\n return getTitlePropertyKey(collection as AdminCollection<Record<string, unknown>>);\n}\n\n","/**\n * Whether an error is the realtime client saying the connection is down —\n * not that the data is gone.\n *\n * Once the socket has been down for longer than a blip, the SDK tells every\n * live subscription `CONNECTION_LOST` through its `onError`, once, and keeps\n * the subscription: when the socket is back it is re-subscribed and its next\n * update carries what changed meanwhile. A view that already shows data should\n * keep showing it (the admin's connection banner says it may be stale) rather\n * than replace it with an error — for an open record that would unmount the\n * form and everything typed into it.\n *\n * Read by `code` rather than `instanceof RebaseApiError`: two copies of\n * `@rebasepro/types` in one tree disagree about the class, never about the code.\n *\n * @group Hooks and utilities\n */\nexport function isConnectionLostError(error: unknown): boolean {\n return typeof error === \"object\"\n && error !== null\n && \"code\" in error\n && error.code === \"CONNECTION_LOST\";\n}\n","import { useRef } from \"react\";\nimport { deepEqual } from \"fast-equals\";\n\n/**\n * The same filter object for as long as its contents stay the same.\n *\n * Callers write filters inline — the hooks guide does — so every render hands\n * a data hook a new object. Used as an effect dependency by identity, that\n * re-subscribed on every render, and every delivery rendered again: a\n * subscribe loop against the server for as long as the component was mounted.\n */\nexport function useStableFilterValues<T>(filterValues: T): T {\n const ref = useRef(filterValues);\n if (!deepEqual(ref.current, filterValues)) {\n ref.current = filterValues;\n }\n return ref.current;\n}\n","\nimport { useEffect, useState, useMemo } from \"react\";\nimport { Entity, FilterValues, User } from \"@rebasepro/types\";\nimport { useData } from \"./useData\";\nimport { isSchemaDriftError, useSchemaDriftContext } from \"../../components/SchemaDriftBanner\";\nimport { toFindParams } from \"./collectionQuery\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\nimport { isConnectionLostError } from \"../../util/realtime\";\nimport { useStableFilterValues } from \"./useStableFilterValues\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n/**\n * @group Hooks and utilities\n */\nexport interface CollectionProps<M extends Record<string, any>> {\n\n /**\n * Absolute collection path\n */\n path: string;\n\n /**\n * collection of the entity displayed by this collection\n */\n collection: AdminCollection<M>\n\n /**\n * Number of entities to fetch\n */\n itemCount?: number;\n\n /**\n * Number of items to skip\n */\n offset?: number;\n\n /**\n * Page number (1-indexed), alternative to offset\n */\n page?: number;\n\n /**\n * Filter the fetched data by the property\n */\n filterValues?: FilterValues<Extract<keyof M, string>>;\n\n /**\n * Sort the results by\n */\n sortBy?: [Extract<keyof M, string>, \"asc\" | \"desc\"];\n\n /**\n * Search string\n */\n searchString?: string;\n}\n\n/**\n * @group Hooks and utilities\n */\nexport interface CollectionResult<M extends Record<string, any>> {\n data: Entity<M>[];\n dataLoading: boolean;\n noMoreToLoad: boolean;\n dataLoadingError?: Error;\n totalCount?: number;\n}\n\n/**\n * This hook is used to fetch collections using a given collection\n * @param path\n * @param collection\n * @param filterValues\n * @param sortBy\n * @param itemCount\n * @param offset\n * @param page\n * @param searchString\n * @group Hooks and utilities\n */\nexport function useCollection<M extends Record<string, any>, USER extends User>(\n {\n path,\n collection,\n filterValues,\n sortBy,\n itemCount,\n offset,\n page,\n searchString\n }: CollectionProps<M>): CollectionResult<M> {\n const dataClient = useData();\n const { reportSchemaDrift } = useSchemaDriftContext();\n\n const sortByProperty = sortBy ? sortBy[0] : undefined;\n const currentSort = sortBy ? sortBy[1] : undefined;\n // Map to PostgREST format for orderBy\n const orderByParams: [string, \"asc\" | \"desc\"] | undefined = sortBy ? [String(sortBy[0]), sortBy[1]] : undefined;\n\n // filterValues is already FilterValues — pass directly. Held by content,\n // not identity: callers write it inline.\n const whereParams = useStableFilterValues(\n filterValues && Object.keys(filterValues).length > 0 ? filterValues : undefined);\n\n const [data, setData] = useState<Entity<M>[]>([]);\n\n const [dataLoading, setDataLoading] = useState<boolean>(false);\n const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();\n const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);\n const [totalCount, setTotalCount] = useState<number | undefined>();\n\n useEffect(() => {\n\n setDataLoading(true);\n\n // Whether this subscription has put rows on screen.\n let showingData = false;\n\n const onEntitiesUpdate = async (res: { data: Entity<M>[], meta: { hasMore: boolean; total?: number } }) => {\n showingData = true;\n const entities = res.data;\n setDataLoading(false);\n setDataLoadingError(undefined);\n // The rows as they came. A row a push did not change arrives as\n // the object it was last time (the socket and the admin boundary\n // both keep it), and a copy of every row of every frame told\n // every consumer memoised on its rows that all of them changed.\n setData(entities);\n setNoMoreToLoad(!res.meta.hasMore);\n setTotalCount(res.meta.total);\n };\n\n const onError = (error: Error) => {\n // The connection is down, not the collection: keep the rows. The\n // subscription is kept too, and its next update replaces them.\n if (showingData && isConnectionLostError(error)) return;\n console.error(\"ERROR\", error);\n setDataLoading(false);\n setData([]);\n setDataLoadingError(error);\n setTotalCount(undefined);\n // Report schema drift to the global banner context\n if (isSchemaDriftError(error)) {\n reportSchemaDrift(error.message);\n }\n };\n\n const accessor = dataClient.collection(path);\n\n // Eagerly include relations to avoid N+1 fetches.\n const includeParams = getRelationIncludeParams(collection);\n\n if (accessor.listen) {\n // Assembled in one place — see `toFindParams`.\n return accessor.listen(\n toFindParams({ where: whereParams, limit: itemCount, offset, page,\n orderBy: orderByParams, searchString, include: includeParams }),\n (res) => onEntitiesUpdate({ data: res.data as Entity<M>[],\nmeta: res.meta }), onError);\n } else {\n // The one-shot fallback, taken whenever the client has no socket.\n // `listen` above cancels on cleanup, and every dependency of this\n // effect — the search string, the filters, the sort, the page —\n // changes while a request is in flight. A promise cannot be\n // unsubscribed, so the cleanup has to disown its result instead:\n // without this, whichever response arrives last wins, and responses\n // do not arrive in request order. Typing into search would settle\n // on the results for whichever query the server happened to finish\n // last.\n let cancelled = false;\n accessor.find(\n toFindParams({ where: whereParams, limit: itemCount, offset, page,\n orderBy: orderByParams, searchString, include: includeParams }))\n .then((res) => {\n if (cancelled) return;\n onEntitiesUpdate({ data: res.data as Entity<M>[],\nmeta: res.meta });\n })\n .catch((e) => {\n if (cancelled) return;\n onError(e);\n });\n return () => {\n cancelled = true;\n };\n }\n }, [path, itemCount, offset, page, currentSort, sortByProperty, whereParams, searchString, dataClient, collection]);\n\n return useMemo(() => ({\n data,\n dataLoading,\n dataLoadingError,\n noMoreToLoad,\n totalCount\n }), [data, dataLoading, dataLoadingError, noMoreToLoad, totalCount]);\n\n}\n","import { MAX_LIST_LIMIT } from \"@rebasepro/types\";\nimport type { CollectionAccessor, Entity, FindParams } from \"@rebasepro/types\";\n\nimport { isConnectionLostError } from \"../../util/realtime\";\n\n/**\n * The part of a read that says *which* rows, without saying how many or from\n * where. The window adds `limit` and `offset` itself, page by page.\n */\nexport type CollectionWindowQuery<M extends Record<string, unknown>> =\n Omit<FindParams<M>, \"limit\" | \"offset\" | \"page\" | \"after\">;\n\n/**\n * What a {@link CollectionWindow} reports on every change.\n */\nexport interface CollectionWindowState<M extends Record<string, unknown> = Record<string, unknown>> {\n /**\n * The rows in the window, in order, without duplicates.\n *\n * `undefined` until the window first covers what it was opened for — the\n * first page, or every row a restored scroll position had on screen — so a\n * view that is still showing its previous rows keeps them instead of\n * flashing a partial list.\n */\n rows: Entity<M>[] | undefined;\n /**\n * The same rows by position, with `undefined` where a row exists but has\n * not been read — the rows above a scroll position the window was\n * restored to ({@link CollectionWindowOptions.seed}), until the view\n * scrolls to them. Absent when nothing is missing, which is always the\n * case for a window no view reports a range to: `rows` is then complete\n * from the first row.\n */\n sparse?: (Entity<M> | undefined)[];\n /** Rows not yet on screen are being read: the first page, or the next one. */\n loading: boolean;\n error: Error | undefined;\n /** A page came back short, so there is nothing past `rows`. */\n complete: boolean;\n}\n\nexport interface CollectionWindowOptions<M extends Record<string, unknown>> {\n accessor: Pick<CollectionAccessor<M>, \"find\" | \"listen\">;\n query: CollectionWindowQuery<M>;\n /** Rows in the first page, which is the one kept live. */\n pageSize: number;\n /** How many rows the window should hold. `Infinity` reads them all. */\n target: number;\n /** Subscribe to the first page when the accessor can. Defaults to `true`. */\n live?: boolean;\n /**\n * Applied to every page as it arrives, before it is merged — the panel's\n * own `afterRead`, for instance.\n */\n process?: (rows: Entity<M>[]) => Promise<Entity<M>[]> | Entity<M>[];\n /**\n * When the subscription fails, read the first page once instead of\n * reporting the failure (which is only reported if that read fails too).\n */\n fallbackToFind?: boolean;\n /**\n * Read the first page once if the subscription has not answered by then.\n * The subscription still wins whenever it does answer.\n */\n firstPaintTimeoutMs?: number;\n /**\n * The quiet time kept between the end of one re-read of the rows past the\n * first page and the start of the next. Defaults to\n * {@link REREAD_INTERVAL_MS}. A push after a quiet spell is re-read at\n * once; pushes inside this window fold into one re-read at its end.\n */\n rereadIntervalMs?: number;\n /**\n * Rows already known, from a view this window replaces (a scroll position\n * kept while a record was open full screen): `rows` sit at `offset` and\n * on. They are shown at once and read again only when a view reports\n * them in range ({@link CollectionWindow.setVisibleRange}); the rows\n * between the first page and `offset` are not read until a view scrolls\n * to them. `target` should cover them.\n */\n seed?: { offset: number; rows: Entity<M>[] };\n onChange: (state: CollectionWindowState<M>) => void;\n}\n\n/**\n * A row held past the first page, and the version of the collection it was\n * read at. The version moves on with every push that says the collection\n * changed, so a row read before the last push is stale.\n */\ntype Slot<M extends Record<string, unknown>> = { row: Entity<M>; version: number };\n\n/**\n * The quiet time between two re-reads of the rows held past the first page.\n *\n * The server pushes at most once per ~300 ms of quiet per subscription, and at\n * least once a second under a steady stream of writes; each push used to start\n * a re-read of every held row past the first page as soon as the last one\n * ended, so a table scrolled to 10,000 rows ran ten 1,000-row reads back to\n * back for as long as the writes went on. This keeps the duty cycle bounded:\n * at most one re-read per re-read time plus this.\n */\nexport const REREAD_INTERVAL_MS = 2_000;\n\n/**\n * A scrolled collection view's rows, read one page at a time.\n *\n * ## Why this exists\n *\n * The table, list, card and board views used to grow a single read: the next\n * page was the same query with `limit` raised by a page, so page *k* re-read\n * the *k − 1* pages before it, and the read that reached row 1,001 asked for a\n * `limit` the API refuses (`MAX_LIST_LIMIT`). Every row past 1,000 was out of\n * reach, behind a developer error. The board clamped at the ceiling instead,\n * and its columns then said they were finished while their own header counted\n * thousands more.\n *\n * ## How it reads\n *\n * - The **first page** is a subscription when the accessor can listen, else a\n * one-shot read. It is the only live query the window holds.\n * - Every **later page** is a one-shot read by `offset`, of only the rows past\n * the ones already held, never more than `MAX_LIST_LIMIT` at a time. Offset\n * rather than the keyset cursor because it is the one paging every sort a\n * view offers can express — a relevance-ordered search has no cursor — and\n * because the server breaks ties on the id, so pages neither repeat nor skip\n * rows under a sort with duplicates.\n * - **Realtime.** The server re-runs a subscription on every write to its\n * collection, so each push after the first says \"something changed\", and\n * every row held past the first page is stale from then on. Which of them\n * are read again depends on whether a view says what it shows:\n * - A view that reports the rows it draws ({@link setVisibleRange}) has the\n * rows on screen read again, plus a page either side — one read, however\n * far it was scrolled. Rows further out stay stale and are read when they\n * come within half a page of the screen, before they are on it.\n * - Without a report, every row held is read again, in reads of at most\n * `MAX_LIST_LIMIT`, and replaced in one step — the only way a view that\n * cannot say what it shows never shows a stale row.\n * Either way a push after a quiet spell is re-read at once; pushes that\n * arrive while a re-read runs, or within `rereadIntervalMs` of the last one\n * ending, fold into one re-read at the end of that interval — at once if the\n * view asks for more rows or scrolls to rows not read since. The first page\n * itself is applied the moment it is pushed, as always.\n *\n * Rows are de-duplicated by id, keeping the copy read last: an insert or a\n * delete above shifts every offset by one, so between a push and the re-read\n * of the rows it moved, a row can sit in two places — on the first page and in\n * the stale row below it, or in the rows just re-read and the stale ones next\n * to them.\n *\n * A window can hold **gaps**: a restored scroll position ({@link\n * CollectionWindowOptions.seed}) shows the rows that were on screen without\n * reading every row above them. A gap is read when a view scrolls to it; a\n * window no view reports a range to reads its gaps at once and shows nothing\n * until they are filled, as it would have read them all before.\n */\nexport class CollectionWindow<M extends Record<string, unknown>> {\n\n private readonly accessor: CollectionWindowOptions<M>[\"accessor\"];\n private readonly query: CollectionWindowQuery<M>;\n private readonly pageSize: number;\n private readonly options: CollectionWindowOptions<M>;\n /** Rows the window must hold before it first shows any. */\n private readonly holdUntil: number;\n\n private target: number;\n private head: Entity<M>[] | undefined;\n /** The first page came back full, so there may be more past it. */\n private headFull = false;\n /**\n * Rows past the first page: `slots[i]` is the row at offset\n * `pageSize + i`, `undefined` where it has not been read (a gap).\n */\n private slots: (Slot<M> | undefined)[] = [];\n /** The last read reaching the end of the held rows came back short. */\n private tailEnded = false;\n /** Moves on with every push after the first: rows read before it are stale. */\n private version = 0;\n /**\n * The offsets a view says it draws, end exclusive. `undefined` until one\n * says so, and again when it goes: every held row is then kept current.\n */\n private range: { start: number; end: number } | undefined;\n /** The view moved to rows not read since: read them without waiting. */\n private rangeMoved = false;\n /** Offset of each row (or gap) of the last state reported, by position. */\n private emittedOffsets: number[] | undefined;\n private pumping = false;\n private pumpQueued = false;\n private loadingMore = false;\n private headError: Error | undefined;\n private tailError: Error | undefined;\n private settled = false;\n private disposed = false;\n private headSequence = 0;\n private liveAnswered = false;\n private unsubscribe: (() => void) | undefined;\n private firstPaintTimer: ReturnType<typeof setTimeout> | undefined;\n /** When the last re-read of the rows past the first page finished. */\n private lastRereadEndedAt: number | undefined;\n /** A re-read waiting out {@link REREAD_INTERVAL_MS}. */\n private rereadTimer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(options: CollectionWindowOptions<M>) {\n this.options = options;\n this.accessor = options.accessor;\n this.query = options.query;\n // A page the API would refuse is not a page; the ceiling is the page.\n this.pageSize = Math.max(1, Math.min(Math.floor(options.pageSize), MAX_LIST_LIMIT));\n this.target = normalizeTarget(options.target);\n // A restored scroll position asks for as many rows as it had on screen,\n // and showing the first page of them first would throw that position\n // away. \"Everything\" is the exception: the first page shows at once and\n // the rest follow.\n this.holdUntil = Number.isFinite(this.target) ? this.target : this.pageSize;\n const seed = options.seed;\n if (seed && seed.rows.length > 0) {\n // Read at no version the collection has had: stale from the start.\n const start = Math.max(0, Math.floor(seed.offset) - this.pageSize);\n const skip = Math.max(0, this.pageSize - Math.floor(seed.offset));\n const rows = seed.rows.slice(skip);\n this.slots = Array.from({ length: start + rows.length },\n (_, i) => i < start ? undefined : { row: rows[i - start], version: -1 });\n }\n }\n\n start(): void {\n if (this.disposed) return;\n const live = this.options.live !== false && Boolean(this.accessor.listen);\n if (!live) {\n this.readHeadOnce(true);\n return;\n }\n this.unsubscribe = this.accessor.listen!(\n { ...this.query, limit: this.pageSize },\n (response) => {\n this.liveAnswered = true;\n void this.receiveHead(response.data);\n },\n (error) => this.receiveLiveError(error)\n );\n const timeout = this.options.firstPaintTimeoutMs;\n if (timeout !== undefined) {\n this.firstPaintTimer = setTimeout(() => {\n if (this.disposed || this.liveAnswered || this.head !== undefined) return;\n this.readHeadOnce(false);\n }, timeout);\n }\n }\n\n /** Hold this many rows. Fewer than are held drops the rows past it. */\n setTarget(target: number): void {\n if (this.disposed) return;\n const next = normalizeTarget(target);\n if (next === this.target) return;\n this.target = next;\n const keep = Math.max(0, next - this.pageSize);\n if (this.slots.length > keep) {\n this.slots = this.slots.slice(0, keep);\n this.tailEnded = false;\n }\n // Asking for more is also how a view retries a page that failed.\n this.tailError = undefined;\n this.emit();\n void this.pump();\n }\n\n /**\n * The rows a view draws, by position in the last `rows` (or `sparse`) it\n * was given, end exclusive; `undefined` when it stops drawing them. Rows\n * near the range are kept current and gaps near it are read; see the\n * class comment.\n */\n setVisibleRange(range: { start: number; end: number } | undefined): void {\n if (this.disposed) return;\n const next = range ? this.toOffsets(range) : undefined;\n if (next === undefined && this.range === undefined) return;\n if (next && this.range && next.start === this.range.start && next.end === this.range.end) return;\n this.range = next;\n this.rangeMoved = true;\n // Not at once: a view handing over to another reports `undefined`\n // and then the new range in the same breath, and reading for the\n // moment in between would read every held row.\n this.schedulePump();\n }\n\n /**\n * What to keep of this window to show it again later: the rows read\n * around the range a view last reported — or, with none reported, every\n * row from the first — the offset of the first of them, and how many\n * rows the window holds in all. See {@link CollectionWindowOptions.seed}.\n */\n snapshot(): { offset: number; rows: Entity<M>[]; held: number } {\n const held = this.head === undefined ? 0 : this.head.length + this.slots.length;\n if (!this.range) return { offset: 0, rows: this.rows().rows, held };\n const margin = this.pageSize;\n const from = Math.max(0, this.range.start - margin);\n const to = this.range.end + margin;\n const rows: Entity<M>[] = [];\n let offset: number | undefined;\n if (from < this.pageSize && this.head) {\n for (let i = from; i < Math.min(to, this.head.length); i++) rows.push(this.head[i]);\n offset = from;\n }\n for (let i = Math.max(0, from - this.pageSize); i < Math.min(this.slots.length, to - this.pageSize); i++) {\n const slot = this.slots[i];\n if (!slot) {\n // A gap ends the run: the rows kept are one block.\n if (rows.length > 0) break;\n continue;\n }\n if (offset === undefined) offset = this.pageSize + i;\n rows.push(slot.row);\n }\n return { offset: offset ?? 0, rows, held };\n }\n\n dispose(): void {\n this.disposed = true;\n if (this.firstPaintTimer !== undefined) clearTimeout(this.firstPaintTimer);\n if (this.rereadTimer !== undefined) clearTimeout(this.rereadTimer);\n this.rereadTimer = undefined;\n this.unsubscribe?.();\n this.unsubscribe = undefined;\n }\n\n private readHeadOnce(reportFailure: boolean, liveError?: Error): void {\n let request: Promise<{ data: Entity<M>[] }>;\n try {\n request = Promise.resolve(this.accessor.find(this.oneShot(this.pageSize)));\n } catch (error) {\n request = Promise.reject(error);\n }\n request\n .then((response) => {\n // The subscription answered while this was in flight: it wins.\n if (this.disposed || (!reportFailure && this.liveAnswered && !liveError)) return;\n return this.receiveHead(response.data);\n })\n .catch((error: unknown) => {\n if (this.disposed || !reportFailure) return;\n this.headError = liveError ?? toError(error);\n this.emit();\n });\n }\n\n private receiveLiveError(error: Error): void {\n if (this.disposed) return;\n // The socket is down, not the data: the SDK keeps the subscription and\n // its first push after the reconnect carries what changed meanwhile.\n // Rows already on screen stay there (the connection banner says they\n // may be stale) instead of turning into an error, as `useCollection`\n // and `useFetch` already do.\n if (this.head !== undefined && isConnectionLostError(error)) return;\n if (this.options.fallbackToFind) {\n this.readHeadOnce(true, error);\n return;\n }\n this.headError = error;\n this.emit();\n }\n\n private async receiveHead(rows: Entity<M>[] | undefined): Promise<void> {\n const sequence = ++this.headSequence;\n const raw = rows ?? [];\n let processed: Entity<M>[];\n try {\n processed = await this.process(raw);\n } catch (error) {\n if (this.disposed || sequence !== this.headSequence) return;\n this.headError = toError(error);\n this.emit();\n return;\n }\n // A newer push overtook this one while it was being processed.\n if (this.disposed || sequence !== this.headSequence) return;\n const first = this.head === undefined;\n this.head = processed;\n this.headFull = raw.length >= this.pageSize;\n this.headError = undefined;\n if (!this.headFull) {\n // The whole set fits in the first page: nothing is held past it.\n this.slots = [];\n this.tailEnded = false;\n } else if (!first) {\n this.version++;\n this.tailError = undefined;\n }\n this.emit();\n await this.pump();\n }\n\n /** Rows still wanted past the ones held. */\n private wanted(): number {\n if (this.head === undefined || !this.headFull || this.tailEnded || this.tailError) return 0;\n return Math.max(0, this.target - this.pageSize - this.slots.length);\n }\n\n private needsRead(index: number): boolean {\n const slot = this.slots[index];\n return slot === undefined || slot.version < this.version;\n }\n\n /**\n * The held rows to read again now, by slot, or `undefined` if none.\n *\n * With a range: the stale rows and gaps within a page of it, once any of\n * them is within half a page — so scrolling into stale rows reads a\n * stretch of them ahead of the screen rather than one row per frame.\n * Without: every stale row and gap, as one span.\n */\n private nextRefresh(): { start: number; end: number; urgent: boolean } | undefined {\n if (!this.headFull || this.slots.length === 0 || this.tailError) return undefined;\n let readFrom = 0;\n let readTo = this.slots.length;\n if (this.range) {\n const margin = this.pageSize;\n const half = Math.ceil(margin / 2);\n const triggerFrom = Math.max(0, this.range.start - half - this.pageSize);\n const triggerTo = Math.min(this.slots.length, this.range.end + half - this.pageSize);\n let triggered = false;\n for (let i = triggerFrom; i < triggerTo && !triggered; i++) triggered = this.needsRead(i);\n if (!triggered) return undefined;\n readFrom = Math.max(0, this.range.start - margin - this.pageSize);\n readTo = Math.min(this.slots.length, this.range.end + margin - this.pageSize);\n }\n let start = -1;\n let end = -1;\n let gap = false;\n for (let i = readFrom; i < readTo; i++) {\n if (!this.needsRead(i)) continue;\n if (start < 0) start = i;\n end = i + 1;\n if (this.slots[i] === undefined) gap = true;\n }\n if (start < 0) return undefined;\n return { start, end, urgent: gap || (this.range !== undefined && this.rangeMoved) };\n }\n\n private schedulePump(): void {\n if (this.pumpQueued) return;\n this.pumpQueued = true;\n queueMicrotask(() => {\n this.pumpQueued = false;\n void this.pump();\n });\n }\n\n /**\n * The one loop that reads past the first page, so a re-read and a next page\n * never run at the same time and interleave their offsets.\n */\n private async pump(): Promise<void> {\n if (this.pumping) return;\n this.pumping = true;\n try {\n while (!this.disposed && this.head !== undefined) {\n const refresh = this.nextRefresh();\n if (refresh) {\n // A view asking for more rows, or looking at rows not read\n // since, is not kept waiting: the re-read runs now.\n const wait = refresh.urgent || this.wanted() > 0 ? 0 : this.rereadWait();\n if (wait > 0) {\n this.armReread(wait);\n } else {\n this.rangeMoved = false;\n await this.reread(refresh.start, refresh.end);\n this.lastRereadEndedAt = Date.now();\n continue;\n }\n }\n const wanted = this.wanted();\n if (wanted > 0) {\n await this.readNext(wanted);\n continue;\n }\n break;\n }\n } finally {\n this.pumping = false;\n }\n this.emit();\n }\n\n /** How long a re-read due now still has to wait. 0 after a quiet spell. */\n private rereadWait(): number {\n if (this.lastRereadEndedAt === undefined) return 0;\n const interval = this.options.rereadIntervalMs ?? REREAD_INTERVAL_MS;\n return Math.max(0, this.lastRereadEndedAt + interval - Date.now());\n }\n\n private armReread(wait: number): void {\n if (this.rereadTimer !== undefined || this.disposed) return;\n this.rereadTimer = setTimeout(() => {\n this.rereadTimer = undefined;\n void this.pump();\n }, wait);\n }\n\n private async readNext(wanted: number): Promise<void> {\n const offset = this.pageSize + this.slots.length;\n const limit = Math.min(MAX_LIST_LIMIT, wanted);\n const version = this.version;\n this.loadingMore = true;\n this.emit();\n try {\n const response = await this.accessor.find(this.oneShot(limit, offset));\n if (this.disposed) return;\n const raw = response.data ?? [];\n const processed = await this.process(raw);\n if (this.disposed) return;\n this.slots = this.slots.concat(processed.map((row) => ({ row, version })));\n if (raw.length < limit) this.tailEnded = true;\n } catch (error) {\n if (this.disposed) return;\n this.tailError = toError(error);\n } finally {\n this.loadingMore = false;\n }\n this.emit();\n }\n\n /**\n * Read the held rows in slots `[from, to)` again, and swap them in at once.\n * A read that comes back short says where the collection ends now: the\n * rows held past that are dropped.\n */\n private async reread(from: number, to: number): Promise<void> {\n const span = to - from;\n if (span <= 0) return;\n const version = this.version;\n const fresh: Entity<M>[] = [];\n let ended = false;\n let offset = this.pageSize + from;\n try {\n while (fresh.length < span) {\n const limit = Math.min(MAX_LIST_LIMIT, span - fresh.length);\n const response = await this.accessor.find(this.oneShot(limit, offset));\n if (this.disposed) return;\n const raw = response.data ?? [];\n fresh.push(...await this.process(raw));\n if (this.disposed) return;\n offset += raw.length;\n if (raw.length < limit) {\n ended = true;\n break;\n }\n }\n } catch (error) {\n if (this.disposed) return;\n this.tailError = toError(error);\n this.emit();\n return;\n }\n // Rows held past a target that shrank while this ran stay dropped.\n const keep = Math.max(0, this.target - this.pageSize);\n const slots = this.slots.slice(0, Math.min(from, keep));\n for (const row of fresh) {\n if (slots.length >= keep) break;\n slots.push({ row, version });\n }\n if (ended) {\n this.tailEnded = slots.length <= keep;\n } else {\n for (let i = to; i < this.slots.length && slots.length < keep; i++) slots.push(this.slots[i]);\n }\n this.slots = slots;\n this.emit();\n }\n\n /**\n * Every one-shot read the window makes: its query, never counted.\n *\n * Nothing here reads `meta.total` — a page ends the window by coming back\n * short — and the `COUNT(*)` beside each page read every matching row to\n * report a number that was thrown away: scrolling a table to 10,000 rows\n * ran 199 of them. The first page's subscription is the accessor's and is\n * left as it is.\n */\n private oneShot(limit: number, offset?: number): FindParams<M> {\n return { ...this.query, limit, ...(offset !== undefined && { offset }), count: \"none\" };\n }\n\n private async process(rows: Entity<M>[]): Promise<Entity<M>[]> {\n return this.options.process ? await this.options.process(rows) : rows;\n }\n\n private complete(): boolean {\n if (this.head === undefined) return false;\n return !this.headFull || this.tailEnded;\n }\n\n private hasGaps(): boolean {\n for (const slot of this.slots) if (slot === undefined) return true;\n return false;\n }\n\n private emit(): void {\n if (this.disposed) return;\n const error = this.headError ?? this.tailError;\n if (!this.settled && this.head !== undefined) {\n const held = this.pageSize + this.slots.length;\n const enough = this.complete() || held >= Math.min(this.holdUntil, this.target) || this.tailError;\n // Gaps are only shown to a view that draws them: one that reports\n // what it shows. Any other waits until they are read.\n if (enough && (this.range !== undefined || this.tailError || !this.hasGaps())) {\n this.settled = true;\n }\n }\n let rows: Entity<M>[] | undefined;\n let sparse: (Entity<M> | undefined)[] | undefined;\n if (this.settled) {\n const built = this.rows();\n rows = built.rows;\n sparse = built.sparse;\n this.emittedOffsets = built.offsets;\n }\n this.options.onChange({\n rows,\n ...(sparse && { sparse }),\n loading: (this.head === undefined && !this.headError) || this.loadingMore || (!this.settled && !error),\n error,\n complete: this.complete()\n });\n }\n\n /**\n * The rows to show, in order, each id once — the copy read last wins, the\n * first page counting as read now — with gaps kept as positions in\n * `sparse`, and the offset each position stands for.\n */\n private rows(): { rows: Entity<M>[]; sparse?: (Entity<M> | undefined)[]; offsets: number[] } {\n const head = this.head ?? [];\n if (this.slots.length === 0) {\n return { rows: head, offsets: head.map((_, i) => i) };\n }\n // Which copy of each id to keep: the newest version, then the first.\n const keep = new Map<string, { version: number; offset: number }>();\n const consider = (row: Entity<M>, version: number, offset: number) => {\n const key = String(row.id);\n const held = keep.get(key);\n if (!held || version > held.version) keep.set(key, { version, offset });\n };\n head.forEach((row, i) => consider(row, Infinity, i));\n this.slots.forEach((slot, i) => {\n if (slot) consider(slot.row, slot.version, this.pageSize + i);\n });\n const rows: Entity<M>[] = [];\n const positions: (Entity<M> | undefined)[] = [];\n const offsets: number[] = [];\n let gaps = false;\n const place = (row: Entity<M> | undefined, offset: number) => {\n if (row && keep.get(String(row.id))?.offset !== offset) return;\n if (row) rows.push(row);\n else gaps = true;\n positions.push(row);\n offsets.push(offset);\n };\n head.forEach((row, i) => place(row, i));\n // Gaps start where the first page ends: a page that came back with\n // fewer rows than it holds now (a delete) leaves no hole of its own.\n this.slots.forEach((slot, i) => place(slot?.row, this.pageSize + i));\n return gaps ? { rows, offsets, sparse: positions } : { rows, offsets };\n }\n\n /** Positions in the last state reported, as offsets in the collection. */\n private toOffsets(range: { start: number; end: number }): { start: number; end: number } {\n const offsets = this.emittedOffsets;\n const start = Math.max(0, Math.floor(range.start));\n const end = Math.max(start, Math.ceil(range.end));\n if (!offsets || offsets.length === 0) return { start, end };\n const at = (position: number) => position < offsets.length\n ? offsets[position]\n : offsets[offsets.length - 1] + 1 + (position - offsets.length);\n return { start: at(start), end: end > start ? at(end - 1) + 1 : at(start) };\n }\n}\n\nfunction normalizeTarget(target: number): number {\n if (target === Infinity) return Infinity;\n if (!Number.isFinite(target)) return 0;\n return Math.max(0, Math.floor(target));\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n","import { User } from \"@rebasepro/types\";\nimport { AuthController } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { AuthControllerContext } from \"../contexts/AuthControllerContext\";\n\n/**\n * Hook to retrieve the AuthContext.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see AuthController\n * @group Hooks and utilities\n */\nexport const useAuthController = <USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>>(): AuthControllerType => {\n const authController = useContext(AuthControllerContext);\n if (!authController) throw new Error(\"useAuthController must be used inside <Rebase>\");\n return authController as AuthControllerType;\n};\n","import { useContext } from \"react\";\nimport { RebaseClientInstanceContext } from \"../contexts/RebaseClientInstanceContext\";\n\n/**\n * Hook to retrieve the full RebaseClient instance from context.\n * Returns `undefined` if no client was provided to `<Rebase>`.\n */\nexport function useRebaseClient<T = any>(): T | undefined {\n return useContext(RebaseClientInstanceContext) as T | undefined;\n}\n","import { StorageSource } from \"@rebasepro/types\";\nimport { StorageSourceContext } from \"../contexts/StorageSourceContext\";\nimport { useContext } from \"react\";\n\n/**\n * Use this hook to get the storage source being used\n * @group Hooks and utilities\n */\nexport const useStorageSource = (): StorageSource => {\n const storageSource = useContext(StorageSourceContext);\n if (storageSource === null) throw new Error(\"useStorageSource must be used inside <Rebase>\");\n // `undefined` is a different thing: inside the tree, but the project\n // configured no storage. `<Rebase>` warns about that on the console, and\n // every upload field then fails on its own. Throwing here instead would\n // take the whole admin down with it, because `useRebaseContext` calls this\n // unconditionally — so the return type stays a promise this hook cannot\n // keep, until the seven callers can be told the truth.\n return storageSource as StorageSource;\n};\n","import type { SnackbarAction, SnackbarMessageType } from \"@rebasepro/cms-types\";\nimport React, { useCallback, useMemo } from \"react\";\nimport { useSnackbar } from \"notistack\";\nimport { Button } from \"@rebasepro/ui\";\n\n/**\n * Hook to retrieve the SnackbarContext.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see SnackbarController\n * @group Hooks and utilities\n */\nexport const useSnackbarController = () => {\n\n const {\n enqueueSnackbar,\n closeSnackbar\n } = useSnackbar();\n\n const open = useCallback((props: {\n type: SnackbarMessageType;\n title?: string;\n message: React.ReactNode;\n autoHideDuration?: number;\n action?: SnackbarAction;\n }) => {\n const {\n type,\n message,\n autoHideDuration,\n action\n } = props;\n enqueueSnackbar({\n message: props.title ? <div className={\"flex flex-col\"}>\n <strong>{props.title}</strong>\n {message}\n </div> : message,\n variant: type,\n autoHideDuration,\n // The provider sets `preventDuplicate`, which collapses two\n // snackbars carrying the same message into one. That is right for a\n // confirmation and wrong for an action: deleting two rows in a row\n // produces the same \"Deleted\" text twice, and swallowing the second\n // would leave the second deletion with no way to undo it. A key\n // makes each one distinct.\n ...(action ? { key: nextActionKey() } : {}),\n action: action\n ? (key) => (\n <Button variant={\"text\"}\n size={\"small\"}\n className={\"text-inherit\"}\n onClick={() => {\n action.onClick();\n // The offer has been taken; leaving it up\n // invites a second click that undoes nothing,\n // or worse, undoes something else.\n closeSnackbar(key);\n }}>\n {action.label}\n </Button>\n )\n : undefined\n })\n }, [enqueueSnackbar, closeSnackbar]);\n\n const close = useCallback(() => {\n closeSnackbar();\n }, [closeSnackbar]);\n\n return useMemo(() => ({\n open,\n close\n }), [open, close]);\n\n};\n\nlet actionKeySeq = 0;\nconst nextActionKey = () => `rebase-snackbar-action-${actionKeySeq++}`;\n","import { UserConfigurationPersistence } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { UserConfigurationPersistenceContext } from \"../contexts/UserConfigurationPersistenceContext\";\n\n/**\n * Use this controller to access the configuration that is stored externally,\n * and not defined in code\n *\n * @group Hooks and utilities\n */\nexport const useUserConfigurationPersistence = (): UserConfigurationPersistence | undefined => useContext(UserConfigurationPersistenceContext);\n","import type { DialogsController } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { DialogsControllerContext } from \"../contexts/DialogsProvider\";\n;\n\n/**\n * Use this hook to open a dialog imperatively.\n * Alternatively, you can use dialogs declaratively using the `Dialog` component.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @group Hooks and utilities\n */\nexport const useDialogsController = (): DialogsController => {\n const controller = useContext(DialogsControllerContext);\n if (!controller) throw new Error(\"useDialogsController must be used inside <Rebase>\");\n return controller;\n};\n","import type { CustomizationController } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { CustomizationControllerContext } from \"../contexts/CustomizationControllerContext\";\n\n/**\n * Use this hook to retrieve the customization controller.\n * This hook includes all the customization options that can be used\n * to customize the admin.\n *\n * You will likely not need to use this hook directly.\n *\n * @group Hooks and utilities\n */\nexport const useCustomizationController = (): CustomizationController => {\n const controller = useContext(CustomizationControllerContext);\n if (!controller) throw new Error(\"useCustomizationController must be used inside <Rebase>\");\n return controller;\n};\n","import { useContext } from \"react\";\nimport { AnalyticsController } from \"@rebasepro/cms-types\";\nimport { AnalyticsContext } from \"../contexts/AnalyticsContext\";\n\n/**\n * @group Hooks and utilities\n */\nexport const useAnalyticsController = (): AnalyticsController => useContext(AnalyticsContext);\n","import { useContext } from \"react\";\nimport { EffectiveRoleControllerContext } from \"../contexts/EffectiveRoleController\";\n\n/**\n * Hook to retrieve the {@link EffectiveRoleController}\n *\n * @see EffectiveRoleController\n * @category Hooks and utilities\n */\nexport const useEffectiveRoleController = () => useContext(EffectiveRoleControllerContext);\n","import React from \"react\";\nimport { DatabaseAdmin } from \"@rebasepro/types\";\n\nexport const DatabaseAdminContext = React.createContext<DatabaseAdmin | undefined>(undefined);\n","import { User } from \"@rebasepro/types\";\nimport { AuthController, RebaseContext } from \"@rebasepro/cms-types\";\nimport { wrapAsSdkData } from \"@rebasepro/common\";\nimport { useAuthController } from \"./useAuthController\";\nimport { useRebaseClient } from \"./useRebaseClient\";\nimport { useData } from \"./data/useData\";\nimport { useStorageSource } from \"./useStorageSource\";\nimport { useSnackbarController } from \"./useSnackbarController\";\nimport { useUserConfigurationPersistence } from \"./useUserConfigurationPersistence\";\nimport { useDialogsController } from \"./useDialogsController\";\nimport { useCustomizationController } from \"./useCustomizationController\";\nimport { useAnalyticsController } from \"./useAnalyticsController\";\nimport { useEffectiveRoleController } from \"./useEffectiveRoleController\";\nimport React, { useContext } from \"react\";\n\n\n// DatabaseAdmin is provided by <Rebase> via DatabaseAdminContext.\nimport { DatabaseAdminContext } from \"../contexts/DatabaseAdminContext\";\n\n/**\n * Hook to retrieve the {@link RebaseContext}.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase` component.\n *\n * @see RebaseContext\n * @group Hooks and utilities\n */\nexport const useRebaseContext = <USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>>(): RebaseContext<USER, AuthControllerType> => {\n\n const client = useRebaseClient<any>();\n\n const authController = useAuthController<USER, AuthControllerType>();\n // `context.data` is the flat SDK view — identical in shape to the backend\n // `context.data` and the frontend SDK client, so callbacks behave the same\n // everywhere. The admin reads Entities via `useData()` directly.\n const entityData = useData();\n const data = React.useMemo(() => wrapAsSdkData(entityData), [entityData]);\n const storageSource = useStorageSource();\n const snackbarController = useSnackbarController();\n const userConfigPersistence = useUserConfigurationPersistence();\n const dialogsController = useDialogsController();\n const customizationController = useCustomizationController();\n const analyticsController = useAnalyticsController();\n const effectiveRoleController = useEffectiveRoleController();\n\n\n // Will get `databaseAdmin` from context\n const databaseAdmin = useContext(DatabaseAdminContext);\n\n // Built during render, so it is the context of *this* render. It used to be\n // kept in a ref and refreshed from an effect, which put every reader one\n // render behind: a sign-in or sign-out that caused no further render was\n // never seen by anything that read `context.authController`.\n return React.useMemo<RebaseContext<USER, AuthControllerType>>(() => ({\n authController,\n data,\n storageSource,\n snackbarController,\n userConfigPersistence,\n dialogsController,\n customizationController,\n analyticsController,\n effectiveRoleController,\n databaseAdmin,\n client: client! // Client should be provided\n }), [authController, data, storageSource, snackbarController, userConfigPersistence,\n dialogsController, customizationController, analyticsController,\n effectiveRoleController, databaseAdmin, client]);\n}\n","\nimport { useEffect, useState, useMemo } from \"react\";\nimport { Entity, User } from \"@rebasepro/types\";\nimport { RebaseContext, AdminCollection } from \"@rebasepro/cms-types\";\nimport { useData } from \"./useData\";\nimport { useRebaseContext } from \"../useRebaseContext\";\nimport { isConnectionLostError } from \"../../util/realtime\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\n\n/**\n * @group Hooks and utilities\n */\nexport interface FetchProps<M extends Record<string, any>, USER extends User = User> {\n path: string;\n entityId?: string | number;\n databaseId?: string;\n collection: AdminCollection<M, USER>;\n useCache?: boolean;\n /**\n * Load the collection's relation properties into the record, as a list\n * read loads them into each row. The record views ask for it: a form built\n * on a record without them shows a many-to-many field empty, and saving it\n * sets that empty membership. A preview leaves it off, since it would load\n * every related row of the record it previews.\n */\n relations?: boolean;\n}\n\n/**\n * @group Hooks and utilities\n */\nexport interface FetchResult<M extends Record<string, any>> {\n entity?: Entity<M>,\n dataLoading: boolean,\n dataLoadingError?: Error\n}\n\n/**\n * The most records {@link useFetch}'s cache holds. Past it, the record written\n * or read least recently goes first.\n *\n * The cache is what lets a record open with its values already on screen while\n * its listener catches up. It used to be fed every row a collection view held,\n * on every update of the view, and never let go of one: a table scrolled to\n * 100,000 rows kept ~260 MB alive after it was closed. A record is opened from\n * a list by clicking it, so the click is what puts it here now (see\n * `populateFetchCache`), and this bounds whatever else does.\n */\nconst FETCH_CACHE_LIMIT = 2_000;\n\n/**\n * Key: `${path}/${id}`. Holds what the signed-in user read, so it is emptied on\n * sign-out (`clearFetchCache`, from `session_caches.ts`). A `Map` for its\n * insertion order: reading or writing an entry moves it to the end, and the\n * first entry is the one to evict.\n */\nconst CACHE = new Map<string, Entity<any>>();\n\nfunction readCache<M extends Record<string, any>>(key: string): Entity<M> | undefined {\n const entity = CACHE.get(key);\n if (entity !== undefined) {\n CACHE.delete(key);\n CACHE.set(key, entity);\n }\n return entity as Entity<M> | undefined;\n}\n\nfunction writeCache(key: string, entity: Entity<any> | undefined): void {\n CACHE.delete(key);\n if (entity === undefined) return;\n CACHE.set(key, entity);\n if (CACHE.size > FETCH_CACHE_LIMIT) {\n const oldest = CACHE.keys().next().value;\n if (oldest !== undefined) CACHE.delete(oldest);\n }\n}\n\n/**\n * Put records in the entity fetch cache, so a view that opens one renders it at\n * once while the background fetch/listener brings in fresh data. The cache\n * keeps the 2,000 records written or read most recently.\n * @param path - The collection path (e.g. \"products\")\n * @param entities - Array of entities to cache\n */\nexport function populateFetchCache<M extends Record<string, any>>(path: string, entities: Entity<M>[]): void {\n for (const entity of entities) {\n writeCache(`${path}/${entity.id}`, entity);\n }\n}\n\n/**\n * Clear the entity fetch cache. Call this on auth state changes (e.g. logout)\n * to prevent stale data from a previous session leaking into the next.\n */\nexport function clearFetchCache(): void {\n CACHE.clear();\n}\n\n/**\n * `delivered`, with every relation property it does not carry taken from the\n * record already on screen.\n *\n * The record's read names the collection's relation properties (see\n * `useFetch`), so a frame normally carries them. One that does not — from a\n * server that ignores a row subscription's `include`, or a data source that\n * cannot load relations — has the key absent, not empty. The list row a click\n * opens the record on does carry it. Replaced wholesale, such a frame took\n * `tags` off the screen; the form follows an untouched field, so the field\n * emptied, and a tag added to it was saved as the whole set — which a\n * many-to-many save takes as the new membership, unlinking every other tag.\n * Absent is \"not delivered\": the value the record was opened with stands until\n * a frame carries one (an empty array included). Same record only; nothing\n * survives a deletion.\n */\nfunction keepUndeliveredRelations<M extends Record<string, any>>(\n shown: Entity<M> | undefined,\n delivered: Entity<M>,\n collection: AdminCollection<M, any>\n): Entity<M> {\n if (!shown || String(shown.id) !== String(delivered.id)) return delivered;\n const properties = collection.properties;\n if (!properties) return delivered;\n let values: M | undefined;\n for (const [name, property] of Object.entries(properties)) {\n if (property?.type !== \"relation\") continue;\n if (name in (delivered.values ?? {}) || !(name in (shown.values ?? {}))) continue;\n values ??= { ...delivered.values };\n values[name as keyof M] = shown.values[name];\n }\n return values ? { ...delivered, values } : delivered;\n}\n\n/**\n * The relations a record's read loads: the ones a list read of the same\n * collection loads into each row. Typed as `keepUndeliveredRelations` takes its\n * collection, since `useFetch`'s own `USER` reaches the export callbacks.\n */\nfunction relationsToRead<M extends Record<string, any>>(collection: AdminCollection<M, any>): { include: string[] } | undefined {\n const include = getRelationIncludeParams(collection);\n return include ? { include } : undefined;\n}\n\n/**\n * This hook is used to fetch a entity.\n * It gives real time updates if the driver supports it.\n * @param path\n * @param collection\n * @param entityId\n * @param useCache\n * @group Hooks and utilities\n */\n\nexport function useFetch<M extends Record<string, any>, USER extends User = User>(\n {\n path,\n entityId,\n collection,\n databaseId,\n useCache = false,\n relations = false\n }: FetchProps<M, USER>): FetchResult<M> {\n\n const dataClient = useData();\n\n const context: RebaseContext<USER> = useRebaseContext();\n\n // Seed initial state from the cache to avoid skeleton flashes.\n // Even when useCache is false, we show cached data instantly while\n // the background fetch/listener brings in fresh data.\n const cacheKey = entityId ? `${path}/${entityId}` : undefined;\n // Read once per mount, not per render: a read also marks the entry used.\n const [cachedEntity] = useState<Entity<M> | undefined>(() => cacheKey ? readCache<M>(cacheKey) : undefined);\n\n const [entity, setEntity] = useState<Entity<M> | undefined>(cachedEntity);\n const [dataLoading, setDataLoading] = useState<boolean>(!cachedEntity);\n const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();\n\n useEffect(() => {\n\n const key = `${path}/${entityId}`;\n const cached = readCache<M>(key);\n\n // Only show loading state if we have no cached entity to display\n if (!cached) {\n setDataLoading(true);\n }\n\n // Whether a record is on screen — the cached one counts.\n let showingEntity = Boolean(cached);\n // The record on screen, so a frame can be read against it.\n let shown: Entity<M> | undefined = cached;\n\n const onEntityUpdate = async (delivered?: Entity<M> | null) => {\n const updatedEntity = delivered ? keepUndeliveredRelations(shown, delivered, collection) : delivered;\n shown = updatedEntity ?? undefined;\n showingEntity = Boolean(updatedEntity);\n writeCache(key, updatedEntity ?? undefined);\n setEntity(updatedEntity ?? undefined);\n setDataLoading(false);\n setDataLoadingError(undefined);\n };\n\n const onError = (error: Error) => {\n // The connection is down, not the record. Dropping the entity here\n // unmounted an open edit form, and everything typed into it, over\n // an outage the client recovers from on its own: the listener is\n // kept, and its next update is the fresh record.\n if (showingEntity && isConnectionLostError(error)) return;\n console.error(\"ERROR fetching entity\", error);\n setDataLoading(false);\n setEntity(undefined);\n setDataLoadingError(error);\n };\n\n if (entityId && useCache && cached) {\n setEntity(cached);\n setDataLoading(false);\n setDataLoadingError(undefined);\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n return () => {\n };\n } else if (entityId && path && collection) {\n const accessor = dataClient.collection(path);\n // The relations the form edits, read with the record exactly as a\n // list read includes them. Without them a to-many relation was\n // absent from the record, and one opened by URL — nothing cached\n // to fall back on — showed its many-to-many field empty; a save\n // from it set that empty membership, unlinking every related row.\n const readOptions = relations ? relationsToRead(collection) : undefined;\n\n if (accessor.listenById) {\n return accessor.listenById(entityId, (entity) => onEntityUpdate(entity as Entity<M> | undefined), onError, readOptions);\n } else {\n // The one-shot fallback, taken whenever the client has no\n // socket. `listenById` above cancels on cleanup; a promise\n // cannot, so the cleanup disowns its result instead. `entityId`\n // is an effect dependency, and where this hook's caller is not\n // remounted per record — the side panel replaces its contents\n // in place — a slow response for the record just left would\n // otherwise land on top of the one now showing.\n let cancelled = false;\n accessor.findById(entityId, readOptions)\n .then((entity) => {\n if (cancelled) return;\n onEntityUpdate(entity as Entity<M> | undefined);\n })\n .catch((e) => {\n if (cancelled) return;\n onError(e);\n });\n return () => {\n cancelled = true;\n };\n }\n }\n // if no entityId is provided we do nothing\n else {\n onEntityUpdate(undefined);\n return () => {\n };\n }\n }, [entityId, path, dataClient, collection, useCache, databaseId, relations]);\n\n return useMemo(() => ({\n entity,\n dataLoading,\n dataLoadingError\n }), [entity, dataLoading, dataLoadingError]);\n\n}\n","import { useCallback, useMemo, useSyncExternalStore } from \"react\";\nimport type { CollectionAccessor, Entity, FindResponse, RebaseData } from \"@rebasepro/types\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { resolvePrimaryKeys } from \"@rebasepro/common\";\nimport { useData } from \"./useData\";\nimport { isConnectionLostError } from \"../../util/realtime\";\nimport type { FetchResult } from \"./useFetch\";\n\n/**\n * The most ids one batch reads. The same ceiling the API puts on a page.\n */\nconst MAX_BATCH = 1_000;\n\n/** What one record looks like to the previews that show it. */\ninterface Snapshot {\n entity?: Entity<any>;\n dataLoading: boolean;\n dataLoadingError?: Error;\n}\n\nconst LOADING: Snapshot = Object.freeze({ dataLoading: true });\n\ninterface Batch {\n /** Ids this batch still answers for; a slot that leaves drops out. */\n ids: Set<string>;\n stop?: () => void;\n}\n\ninterface Slot {\n snapshot: Snapshot;\n listeners: Set<() => void>;\n refs: number;\n batch?: Batch;\n}\n\n/**\n * One collection's batched record reads, for the previews of references.\n *\n * Every id a preview asks for in the same tick is read by one query — `where\n * <key> in [ids]` — and kept live by ONE subscription to that query, instead\n * of one `listenById` per id. A reference column showing 23 distinct targets\n * was 23 subscriptions, 23 single-row reads and 23 server refetches per write\n * to the target collection; it is one of each now.\n *\n * Authorization is unchanged: the read goes through the same accessor, as the\n * signed-in user, that each `listenById` did. Nothing is shared between data\n * clients — a batcher belongs to one `RebaseData`, and a sign-out replaces it.\n *\n * Kept per id: a reference counter. A slot lives while a preview shows it; the\n * batch's subscription closes when the last id it answers for is let go.\n * Releases are settled a microtask later, so a preview that remounts at once\n * (React's StrictMode, a list re-keying) keeps its record and its subscription.\n */\nclass RecordBatcher {\n private readonly slots = new Map<string, Slot>();\n private readonly pending = new Set<string>();\n private readonly released = new Set<string>();\n private flushScheduled = false;\n private settleScheduled = false;\n\n constructor(\n private readonly accessor: CollectionAccessor<any>,\n /** The one key column, and its type — `undefined` for a composite key. */\n private readonly key: { fieldName: string; type: \"string\" | \"number\" } | undefined\n ) {}\n\n peek(id: string): Snapshot {\n return this.slots.get(id)?.snapshot ?? LOADING;\n }\n\n subscribe(id: string, listener: () => void): () => void {\n let slot = this.slots.get(id);\n if (!slot) {\n slot = { snapshot: LOADING, listeners: new Set(), refs: 0 };\n this.slots.set(id, slot);\n this.pending.add(id);\n this.scheduleFlush();\n }\n slot.refs++;\n slot.listeners.add(listener);\n const owned = slot;\n return () => {\n owned.listeners.delete(listener);\n owned.refs--;\n if (owned.refs === 0) {\n this.released.add(id);\n this.scheduleSettle();\n }\n };\n }\n\n private scheduleFlush(): void {\n if (this.flushScheduled) return;\n this.flushScheduled = true;\n queueMicrotask(() => {\n this.flushScheduled = false;\n const ids = [...this.pending];\n this.pending.clear();\n for (let i = 0; i < ids.length; i += MAX_BATCH) this.start(ids.slice(i, i + MAX_BATCH));\n });\n }\n\n private scheduleSettle(): void {\n if (this.settleScheduled) return;\n this.settleScheduled = true;\n queueMicrotask(() => {\n this.settleScheduled = false;\n for (const id of this.released) {\n const slot = this.slots.get(id);\n if (!slot || slot.refs > 0) continue;\n this.slots.delete(id);\n this.pending.delete(id);\n const batch = slot.batch;\n if (!batch) continue;\n batch.ids.delete(id);\n if (batch.ids.size === 0) batch.stop?.();\n }\n this.released.clear();\n });\n }\n\n private set(id: string, batch: Batch, snapshot: Snapshot): void {\n const slot = this.slots.get(id);\n if (!slot || slot.batch !== batch) return;\n slot.snapshot = snapshot;\n for (const listener of [...slot.listeners]) listener();\n }\n\n private start(ids: string[]): void {\n const batch: Batch = { ids: new Set(ids) };\n for (const id of ids) {\n const slot = this.slots.get(id);\n if (slot) slot.batch = batch;\n }\n\n const onError = (error: Error) => {\n for (const id of batch.ids) {\n const current = this.slots.get(id)?.snapshot;\n // The connection is down, not the record: what is on screen\n // stays, and the subscription's next frame is the fresh one.\n if (current?.entity && isConnectionLostError(error)) continue;\n this.set(id, batch, { dataLoading: false, dataLoadingError: error });\n }\n };\n\n // A composite key has no single column to put an `in` on: each record\n // is read on its own, as before.\n if (!this.key) {\n const stops = ids.map(id => this.readOne(id, batch, onError));\n batch.stop = () => stops.forEach(stop => stop());\n return;\n }\n\n const values = ids.map(id => this.key!.type === \"number\" && !isNaN(Number(id)) ? Number(id) : id);\n const params = { where: { [this.key.fieldName]: [\"in\", values] }, limit: ids.length };\n const deliver = (response: FindResponse<any>) => {\n const byId = new Map(response.data.map(entity => [String(entity.id), entity]));\n for (const id of batch.ids) {\n // Absent from the answer is \"not there\" — deleted, or not\n // readable by this user — exactly as `listenById` reports it.\n this.set(id, batch, { entity: byId.get(id), dataLoading: false });\n }\n };\n\n if (this.accessor.listen) {\n batch.stop = this.accessor.listen(params as never, deliver, onError);\n return;\n }\n // The one-shot fallback, for a client with no socket.\n let stopped = false;\n batch.stop = () => { stopped = true; };\n this.accessor.find(params as never)\n .then(response => { if (!stopped) deliver(response); })\n .catch(error => { if (!stopped) onError(error instanceof Error ? error : new Error(String(error))); });\n }\n\n private readOne(id: string, batch: Batch, onError: (error: Error) => void): () => void {\n const deliver = (entity: Entity<any> | undefined | null) =>\n this.set(id, batch, { entity: entity ?? undefined, dataLoading: false });\n if (this.accessor.listenById) return this.accessor.listenById(id, deliver, onError);\n let stopped = false;\n this.accessor.findById(id)\n .then(entity => { if (!stopped) deliver(entity); })\n .catch(error => { if (!stopped) onError(error instanceof Error ? error : new Error(String(error))); });\n return () => { stopped = true; };\n }\n}\n\n/**\n * Batchers by data client, then by collection path.\n *\n * Key: the `RebaseData` instance (weakly — a client that is dropped takes its\n * batchers with it) and the path. A batcher holds only records some preview\n * still shows; nothing outlives its last subscriber.\n */\nconst BATCHERS = new WeakMap<RebaseData, Map<string, RecordBatcher>>();\n\nfunction batcherFor(data: RebaseData, path: string, collection: AdminCollection<any>): RecordBatcher {\n let byPath = BATCHERS.get(data);\n if (!byPath) {\n byPath = new Map();\n BATCHERS.set(data, byPath);\n }\n let batcher = byPath.get(path);\n if (!batcher) {\n const keys = resolvePrimaryKeys(collection as never);\n batcher = new RecordBatcher(\n data.collection(path),\n keys.length === 1 ? { fieldName: keys[0].fieldName, type: keys[0].type } : undefined\n );\n byPath.set(path, batcher);\n }\n return batcher;\n}\n\n/**\n * {@link useFetch} for a record many previews on one screen ask for at once —\n * the target of a reference in a table cell, a card, an array of references.\n *\n * The ids every preview asks for in one tick are read together: one query and\n * one live subscription per batch, not one `listenById` per record. Updates\n * reach a preview per batch — a write to any record of the batch refetches the\n * batch — which is what a preview needs.\n *\n * For one record a view edits, use {@link useFetch}: it follows that record\n * alone and seeds from the record cache.\n *\n * @group Hooks and utilities\n */\nexport function useBatchedFetch<M extends Record<string, any>>({\n path,\n entityId,\n collection\n}: {\n path: string;\n entityId?: string | number;\n collection: AdminCollection<M>;\n}): FetchResult<M> {\n const data = useData();\n const id = entityId === undefined || entityId === null || entityId === \"\" ? undefined : String(entityId);\n // The batcher depends on whether there is an id, not on which one.\n const hasId = id !== undefined;\n const batcher = useMemo(\n () => hasId ? batcherFor(data, path, collection) : undefined,\n [data, path, collection, hasId]\n );\n\n const subscribe = useCallback(\n (listener: () => void) => batcher && id !== undefined ? batcher.subscribe(id, listener) : () => undefined,\n [batcher, id]\n );\n const getSnapshot = useCallback(\n () => batcher && id !== undefined ? batcher.peek(id) : NO_RECORD,\n [batcher, id]\n );\n const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n return snapshot as FetchResult<M>;\n}\n\nconst NO_RECORD: Snapshot = Object.freeze({ dataLoading: false });\n","\nimport { useCallback, useEffect, useRef, useState, useMemo } from \"react\";\nimport { useData } from \"./useData\";\nimport { Entity, EntityRelation, FilterValues } from \"@rebasepro/types\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\nimport { CollectionWindow } from \"./collectionWindow\";\nimport { useStableFilterValues } from \"./useStableFilterValues\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nexport interface RelationItem {\n id: string | number;\n label: string;\n description?: string;\n data: Entity<any>;\n relation: EntityRelation;\n}\n\nexport interface UseRelationSelectorProps<M extends Record<string, any> = any> {\n /**\n * Full path where the relation data is located\n */\n path: string;\n /**\n * The collection that represents the relation entities\n */\n collection: AdminCollection<M>;\n /**\n * Force filter to be applied to the relation search\n */\n fixedFilter?: FilterValues<string>;\n /**\n * Page size for pagination\n */\n pageSize?: number;\n /**\n * Function to extract the label from a entity\n */\n getLabelFromEntity?: (entity: Entity<M>) => string;\n /**\n * Function to extract the description from a entity\n */\n getDescriptionFromEntity?: (entity: Entity<M>) => string | undefined;\n /**\n * Property name to use as the secondary display field\n */\n descriptionProperty?: keyof M;\n /**\n * Whether the list should be fetched at all. Defaults to `true`.\n *\n * A picker that is mounted is not a picker that is open, and the two used\n * to be the same thing here: the fetch ran on mount, so a collection table\n * with a relation column paid for one query — or one realtime subscription\n * — per rendered row before anyone clicked a cell. Pass `false` until the\n * list is actually needed and nothing is requested; flipping it to `true`\n * fetches once, and it never goes back.\n */\n enabled?: boolean;\n}\n\nexport interface RelationSelectorController {\n items: RelationItem[];\n isLoading: boolean;\n error: Error | undefined;\n search: (searchString: string) => void;\n loadMore: () => void;\n hasMore: boolean;\n entityToRelationItem: (entity: Entity<any>, relation: EntityRelation) => RelationItem;\n}\n\nconst DEFAULT_PAGE_SIZE = 10;\n\n/**\n * Hook to manage relation selection with data fetching from Rebase data source\n */\nexport function useRelationSelector<M extends Record<string, any> = any>(\n {\n path,\n collection,\n fixedFilter,\n pageSize = DEFAULT_PAGE_SIZE,\n getLabelFromEntity,\n getDescriptionFromEntity,\n descriptionProperty,\n enabled = true\n }: UseRelationSelectorProps<M>\n): RelationSelectorController {\n\n const dataClient = useData();\n // Held by content, not identity: callers write it inline.\n const stableFixedFilter = useStableFilterValues(fixedFilter);\n\n const [items, setItems] = useState<RelationItem[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const isLoadingRef = useRef(false);\n const [error, setError] = useState<Error | undefined>();\n const [hasMore, setHasMore] = useState(true);\n const [currentSearch, setCurrentSearch] = useState<string>(\"\");\n const [limit, setLimit] = useState<number>(pageSize);\n\n const unsubscribeRef = useRef<(() => void) | null>(null);\n const searchTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n // Whether a fetch has ever completed. Between `enabled` flipping and the\n // effect running there is one paint with no items and no request in\n // flight; without this the list shows \"no results\" for that frame.\n const hasLoadedRef = useRef(false);\n\n const setLoading = useCallback((loading: boolean) => {\n isLoadingRef.current = loading;\n setIsLoading(loading);\n }, []);\n\n // Function to convert entity to RelationItem\n const entityToRelationItem = useCallback((entity: Entity<M>, relation?: EntityRelation): RelationItem => {\n let label: string;\n let description: string | undefined;\n\n if (getLabelFromEntity) {\n label = getLabelFromEntity(entity);\n } else {\n // Fallback: try common label properties\n const commonLabelProps = [\"name\", \"title\", \"label\", \"displayName\"];\n let foundProp: string | undefined;\n\n if (entity.values) {\n foundProp = commonLabelProps.find(prop => entity.values[prop] != null && entity.values[prop] !== \"\");\n }\n\n if (foundProp && entity.values[foundProp]) {\n label = String(entity.values[foundProp]);\n } else {\n // Ultimate fallback: use entity ID\n label = String(entity.id);\n }\n }\n\n if (getDescriptionFromEntity) {\n description = getDescriptionFromEntity(entity);\n } else if (descriptionProperty && entity.values && entity.values[descriptionProperty]) {\n description = String(entity.values[descriptionProperty]);\n }\n\n return {\n id: entity.id,\n label,\n description,\n data: entity,\n relation: relation ? relation : new EntityRelation(entity.id, path)\n };\n }, [getLabelFromEntity, getDescriptionFromEntity, descriptionProperty]);\n\n // Clean up any existing subscription\n const cleanupSubscription = useCallback(() => {\n if (unsubscribeRef.current) {\n unsubscribeRef.current();\n unsubscribeRef.current = null;\n }\n }, []);\n\n // Eagerly include relations to avoid N+1 fetches. Referentially stable, so\n // it can be a dependency below without re-triggering the fetch.\n const includeParams = getRelationIncludeParams(collection);\n\n // How many rows the picker wants, read by the window below a page at a\n // time. A ref so that asking for more grows the window instead of\n // re-opening it.\n const limitRef = useRef(limit);\n limitRef.current = limit;\n const windowRef = useRef<CollectionWindow<Record<string, unknown>> | null>(null);\n\n const fetchData = useCallback(() => {\n cleanupSubscription();\n setError(undefined);\n setLoading(true);\n\n // fixedFilter is already FilterValues — pass directly\n const whereParams = stableFixedFilter && Object.keys(stableFixedFilter).length > 0 ? stableFixedFilter : undefined;\n\n // The first page is live when the client has a socket; every later\n // page is read by offset, past the rows already held, and never above\n // the API's read ceiling. \"Load more\" used to raise one read's\n // `limit`, which re-read every option before it and was refused once\n // it passed 1,000.\n //\n // `dispose` is what keeps this hook's results matching the query that\n // asked for them: an answer for \"ab\" that lands after the window for\n // \"abc\" opened is dropped, not painted.\n const collectionWindow = new CollectionWindow({\n accessor: dataClient.collection(path),\n query: {\n where: whereParams,\n searchString: currentSearch || undefined,\n include: includeParams\n },\n pageSize,\n target: limitRef.current,\n onChange: (state) => {\n if (state.rows) {\n hasLoadedRef.current = true;\n setItems((state.rows as Entity<M>[]).map((e) => entityToRelationItem(e)));\n setHasMore(!state.complete && !state.error);\n }\n if (state.error) {\n console.error(\"useRelationSelector: Error fetching data:\", state.error);\n hasLoadedRef.current = true;\n }\n setError(state.error);\n setLoading(state.loading);\n }\n });\n windowRef.current = collectionWindow;\n collectionWindow.start();\n\n unsubscribeRef.current = () => {\n collectionWindow.dispose();\n if (windowRef.current === collectionWindow) windowRef.current = null;\n };\n }, [dataClient, path, stableFixedFilter, pageSize, currentSearch, entityToRelationItem, cleanupSubscription, setLoading, includeParams]);\n\n // \"Load more\" asks the open window for the next page.\n useEffect(() => {\n windowRef.current?.setTarget(limit);\n }, [limit]);\n\n // Search function with debouncing\n const search = useCallback((searchString: string) => {\n // Clear existing timeout\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n\n // Debounce search\n searchTimeoutRef.current = setTimeout(() => {\n setLimit(pageSize);\n setCurrentSearch(searchString);\n }, searchString.trim() ? 300 : 0);\n }, [pageSize]);\n\n // Load more function\n const loadMore = useCallback(() => {\n if (!isLoadingRef.current && hasMore && items.length > 0) {\n setLoading(true);\n setLimit(prev => prev + pageSize);\n }\n }, [hasMore, items.length, pageSize, setLoading]);\n\n // Load initial data and update upon changes\n useEffect(() => {\n if (!enabled) return;\n fetchData();\n\n return () => {\n cleanupSubscription();\n };\n }, [fetchData, enabled, cleanupSubscription]);\n\n useEffect(() => {\n return () => {\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n };\n }, []);\n\n return useMemo(() => ({\n items,\n // Enabled but not answered yet still counts as loading, so the frame\n // between opening the picker and the request starting shows a spinner\n // rather than \"no results\".\n isLoading: isLoading || (enabled && !hasLoadedRef.current),\n error,\n search,\n loadMore,\n hasMore,\n entityToRelationItem\n }), [items, isLoading, error, search, loadMore, hasMore, entityToRelationItem, enabled]);\n}\n","\nimport { Entity, EntityStatus, EntityValues } from \"@rebasepro/types\";\nimport { RebaseContext, AdminCollection } from \"@rebasepro/cms-types\";\nimport { RebaseData } from \"@rebasepro/types\";\n\n/**\n * @group Hooks and utilities\n */\nexport type SaveEntityWithCallbacksProps<M extends Record<string, unknown>> = {\n path: string;\n values: Partial<EntityValues<M>>;\n entityId?: string | number;\n previousValues?: Partial<EntityValues<M>>;\n collection?: AdminCollection<M>;\n status: EntityStatus;\n /**\n * The version the edit was made against — the edited entity's\n * {@link Entity.etag}. An update is then refused with `412\n * PRECONDITION_FAILED` if the record has changed since, rather than\n * writing over the change. Ignored for a create.\n */\n ifMatch?: string;\n afterSave?: (updatedEntity: Entity<M>) => void,\n afterSaveError?: (e: Error) => void\n}\n\n/**\n * This function is in charge of saving a entity.\n *\n * It runs the collection's **`admin.browserCallbacks`** around the write —\n * `beforeSave`, then `afterSave` or `afterSaveError`. Not `callbacks`: that\n * block belongs to the server, which runs it inside the write it serves, and\n * its bodies are stripped from this bundle entirely.\n *\n * Which matters most for a collection on a `direct`/`custom` transport, where\n * the panel talks to the store itself and no server sees the write at all —\n * before this ran them, such a collection had no write callbacks anywhere. This\n * function has been named `saveEntityWithCallbacks` since it was written and\n * did not run any.\n *\n * A `beforeSave` that throws blocks the write, exactly as the server's does:\n * nothing is sent, and the error reaches `afterSaveError` and the caller.\n *\n * `afterSave`/`afterSaveError` below are the *caller's* UI callbacks — the\n * form's \"close the dialog\", the table's \"clear the editing state\" — and are\n * unrelated to the collection's. Both run: the collection's first. A\n * collection `afterSave` that throws does not undo the save: the write has\n * committed, so it is reported as a warning and the caller's `afterSave` runs.\n *\n * @param collection\n * @param path\n * @param entityId\n * @param values\n * @param previousValues\n * @param status\n * @param data\n * @param context\n * @param afterSave\n * @param afterSaveError\n * @group Hooks and utilities\n */\nexport async function saveEntityWithCallbacks<M extends Record<string, unknown>>({\n collection,\n path,\n entityId,\n values,\n previousValues,\n status,\n ifMatch,\n data,\n context,\n afterSave,\n afterSaveError\n}: Omit<SaveEntityWithCallbacksProps<M>, \"collection\"> & {\n collection: AdminCollection<M>,\n data: RebaseData,\n context: RebaseContext,\n}\n): Promise<Entity<M>> {\n\n if (status !== \"new\" && status !== \"copy\" && !entityId) {\n throw new Error(\"Entity id must be specified when updating an existing entity\");\n }\n\n const browserCallbacks = collection.browserCallbacks;\n\n let valuesToSave = values;\n if (browserCallbacks?.beforeSave) {\n try {\n valuesToSave = await browserCallbacks.beforeSave({\n collection,\n path,\n id: entityId,\n values,\n previousValues,\n status,\n context\n });\n } catch (e) {\n // A throw here means \"do not save\", so the write never starts. The\n // caller still needs to hear about it, and so does afterSaveError:\n // to the form this is indistinguishable from a rejected write.\n const error = e instanceof Error ? e : new Error(String(e));\n await browserCallbacks.afterSaveError?.({\n collection,\n path,\n id: entityId,\n values,\n previousValues,\n status,\n error,\n context\n });\n if (afterSaveError) afterSaveError(error);\n throw error;\n }\n }\n\n const accessor = data.collection(path);\n\n let savePromise: Promise<Entity<M>>;\n if (status === \"new\" || status === \"copy\") {\n savePromise = accessor.create(valuesToSave, entityId) as Promise<Entity<M>>;\n } else {\n savePromise = (ifMatch\n ? accessor.update(entityId!, valuesToSave, { ifMatch })\n : accessor.update(entityId!, valuesToSave)) as Promise<Entity<M>>;\n }\n\n let entity: Entity<M>;\n try {\n entity = await savePromise;\n } catch (e) {\n await browserCallbacks?.afterSaveError?.({\n collection,\n path,\n id: entityId,\n values: valuesToSave,\n previousValues,\n status,\n error: e as Error,\n context\n });\n if (afterSaveError) afterSaveError(e as Error);\n throw e;\n }\n\n // Awaited, and before the caller's: an afterSave that writes a related\n // row should have finished before the form closes over it.\n //\n // `entity.values`, not the values sent: \"after save\" means the row as\n // saved, and the two differ whenever the write path adds something. The\n // auth create response carries `temporaryPassword` / `invitationSent`\n // beside the columns, and the panel's own injected afterSave — the one\n // that shows the credentials dialog — can only read them here.\n //\n // The write has committed by now, so a throw here is not a failed save.\n // It used to be reported as one: the form stayed on \"new\", and the next\n // Save created a second row. It is said for what it is, and the save\n // completes.\n try {\n await browserCallbacks?.afterSave?.({\n collection,\n path,\n id: entity.id,\n values: entity.values,\n previousValues,\n status,\n context\n });\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e));\n console.error(`afterSave of \"${path}\" failed after the record was saved`, error);\n context.snackbarController?.open({ type: \"warning\", message: error.message });\n }\n if (afterSave)\n afterSave(entity);\n return entity;\n}\n","\nimport { Entity, User } from \"@rebasepro/types\";\nimport { RebaseContext, AdminCollection } from \"@rebasepro/cms-types\";\nimport { RebaseData } from \"@rebasepro/types\";\n\n/**\n * @group Hooks and utilities\n */\nexport type DeleteEntityWithCallbacksProps<M extends Record<string, any>, USER extends User = User> = {\n entity: Entity<M>;\n collection?: AdminCollection<M>;\n onDeleteSuccess?: (entity: Entity<M>) => void;\n onDeleteFailure?: (entity: Entity<M>, e: Error) => void;\n}\n\n/**\n * This function is in charge of deleting a entity.\n *\n * It runs the collection's **`admin.browserCallbacks`** around the delete —\n * `beforeDelete`, then `afterDelete`. Not `callbacks`: that block belongs to\n * the server, which runs it inside the delete it serves, and its bodies are\n * stripped from this bundle entirely.\n *\n * Which matters most for a collection on a `direct`/`custom` transport, where\n * the panel talks to the store itself and no server sees the delete at all —\n * before this ran them, such a collection had no delete callbacks anywhere.\n * This function has been named `deleteEntityWithCallbacks` since it was written\n * and did not run any; it even took a `callbacks` prop and ignored it.\n *\n * A `beforeDelete` that throws blocks the delete, exactly as the server's does:\n * nothing is sent, and `onDeleteFailure` hears about it.\n *\n * @param data\n * @param entity\n * @param collection\n * @param onDeleteSuccess\n * @param onDeleteFailure\n * @param context\n * @group Hooks and utilities\n */\nexport async function deleteEntityWithCallbacks<M extends Record<string, any>, USER extends User>({\n data,\n entity,\n collection,\n onDeleteSuccess,\n onDeleteFailure,\n context\n}: DeleteEntityWithCallbacksProps<M> & {\n collection: AdminCollection<M>,\n data: RebaseData,\n context: RebaseContext<USER>\n}\n): Promise<boolean> {\n\n console.debug(\"Deleting entity\", entity.path, entity.id);\n\n const browserCallbacks = collection.browserCallbacks;\n\n if (browserCallbacks?.beforeDelete) {\n try {\n await browserCallbacks.beforeDelete({\n collection,\n path: entity.path,\n id: entity.id,\n row: { id: entity.id, ...entity.values },\n context\n });\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e));\n if (onDeleteFailure) onDeleteFailure(entity, error);\n return false;\n }\n }\n\n return data.collection(entity.path).delete(entity.id).then(async () => {\n await browserCallbacks?.afterDelete?.({\n collection,\n path: entity.path,\n id: entity.id,\n row: { id: entity.id, ...entity.values },\n context\n });\n if (onDeleteSuccess) onDeleteSuccess(entity);\n return true;\n }).catch((e) => {\n if (onDeleteFailure) onDeleteFailure(entity, e);\n return false;\n });\n}\n","import React, { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport {\n Blocker,\n BlockerFunction,\n Location,\n NavigationType,\n UNSAFE_DataRouterContext,\n UNSAFE_DataRouterStateContext,\n useBlocker\n} from \"react-router\";\n\nconst IDLE_BLOCKER: Blocker = {\n state: \"unblocked\",\n proceed: undefined,\n reset: undefined,\n location: undefined\n};\n\ntype NavigationBlockerContextValue = {\n register: (id: string, predicate: BlockerFunction) => void;\n unregister: (id: string) => void;\n blocker: Blocker;\n /** Id of the registration that caused the current block, if any. */\n blockedBy: string | null;\n};\n\nconst NavigationBlockerContext = createContext<NavigationBlockerContextValue | null>(null);\n\n/**\n * Owns the single navigation guard for the whole app.\n *\n * Under a React Router **data router** (`createBrowserRouter` +\n * `<RouterProvider>`) it holds the one `useBlocker` in the tree. React Router\n * only honours one blocker at a time: `shouldBlockNavigation` picks the\n * last-registered blocker function and silently ignores every other one (it\n * only logs a dev warning). Because blockers register in a `useEffect`, the\n * winner is whichever surface mounted most recently — so an unsaved-changes\n * guard could be disabled by an unrelated component mounting after it. This\n * provider registers the only one and multiplexes it, so every surface that\n * guards navigation gets a say regardless of mount order.\n *\n * Under any **other** router (a plain `<BrowserRouter>`, a `<MemoryRouter>`)\n * there is no `useBlocker` to call — it throws outside a data router — and no\n * way to intercept an in-app navigation. The guards then degrade to the\n * browser's own: leaving the page (reload, tab close, typing a URL) asks for\n * confirmation while any registered guard would block leaving.\n *\n * Surfaces register through {@link useNavigationBlocker}.\n */\nexport function NavigationBlockerProvider({ children }: { children: React.ReactNode }) {\n // Both contexts are set by `<RouterProvider>` and by nothing else, and\n // `useBlocker` reads both. Which provider renders is fixed by where this\n // sits, so the branch never switches hooks under a mounted component.\n const dataRouter = useContext(UNSAFE_DataRouterContext);\n const dataRouterState = useContext(UNSAFE_DataRouterStateContext);\n return dataRouter && dataRouterState\n ? <DataRouterBlockerProvider>{children}</DataRouterBlockerProvider>\n : <BeforeUnloadBlockerProvider>{children}</BeforeUnloadBlockerProvider>;\n}\n\n/** The registered guards, and which of them caused the current block. */\nfunction useGuardRegistry() {\n const predicates = useRef(new Map<string, BlockerFunction>());\n\n // State, not a ref: the owning registration only renders its dialog once\n // this has propagated, so it has to go through React.\n const [blockedBy, setBlockedBy] = useState<string | null>(null);\n\n const register = useCallback((id: string, predicate: BlockerFunction) => {\n predicates.current.set(id, predicate);\n }, []);\n\n const unregister = useCallback((id: string) => {\n predicates.current.delete(id);\n setBlockedBy((current) => (current === id ? null : current));\n }, []);\n\n return { predicates, blockedBy, setBlockedBy, register, unregister };\n}\n\nfunction DataRouterBlockerProvider({ children }: { children: React.ReactNode }) {\n const { predicates, blockedBy, setBlockedBy, register, unregister } = useGuardRegistry();\n\n const shouldBlock = useCallback<BlockerFunction>((args) => {\n for (const [id, predicate] of predicates.current) {\n if (predicate(args)) {\n setBlockedBy(id);\n return true;\n }\n }\n setBlockedBy(null);\n return false;\n }, [predicates, setBlockedBy]);\n\n const blocker = useBlocker(shouldBlock);\n\n const value = useMemo<NavigationBlockerContextValue>(() => ({\n register,\n unregister,\n blocker,\n blockedBy\n }), [register, unregister, blocker, blockedBy]);\n\n return (\n <NavigationBlockerContext.Provider value={value}>\n {children}\n </NavigationBlockerContext.Provider>\n );\n}\n\n/**\n * Where a page unload goes, as a guard sees it: somewhere that is not this\n * app. No path, so it matches no record, tab or panel a guard lets through.\n */\nconst OUTSIDE_THE_APP: Location = {\n pathname: \"\",\n search: \"\",\n hash: \"\",\n state: null,\n key: \"beforeunload\"\n};\n\nfunction BeforeUnloadBlockerProvider({ children }: { children: React.ReactNode }) {\n const { predicates, register, unregister } = useGuardRegistry();\n\n useEffect(() => {\n const onBeforeUnload = (event: BeforeUnloadEvent) => {\n const here: Location = {\n pathname: window.location.pathname,\n search: window.location.search,\n hash: window.location.hash,\n state: null,\n key: \"default\"\n };\n for (const predicate of predicates.current.values()) {\n if (predicate({ currentLocation: here, nextLocation: OUTSIDE_THE_APP, historyAction: NavigationType.Pop })) {\n event.preventDefault();\n // Still what Chrome and Safari read to show the prompt.\n event.returnValue = \"\";\n return;\n }\n }\n };\n window.addEventListener(\"beforeunload\", onBeforeUnload);\n return () => window.removeEventListener(\"beforeunload\", onBeforeUnload);\n }, [predicates]);\n\n const value = useMemo<NavigationBlockerContextValue>(() => ({\n register,\n unregister,\n blocker: IDLE_BLOCKER,\n blockedBy: null\n }), [register, unregister]);\n\n return (\n <NavigationBlockerContext.Provider value={value}>\n {children}\n </NavigationBlockerContext.Provider>\n );\n}\n\n/**\n * Guard navigation with `predicate`, sharing the app-wide blocker.\n *\n * Returns a {@link Blocker} that is only ever in the `blocked` state when *this*\n * registration is what blocked the navigation — so several guards can coexist\n * without each of them popping a dialog.\n *\n * Returns an idle blocker when no {@link NavigationBlockerProvider} is mounted\n * above, rather than competing for React Router's single blocker slot.\n */\nexport function useNavigationBlocker(predicate: BlockerFunction): Blocker {\n\n const context = useContext(NavigationBlockerContext);\n const id = useId();\n\n // Keep the latest predicate without re-registering on every render.\n const predicateRef = useRef(predicate);\n predicateRef.current = predicate;\n\n const register = context?.register;\n const unregister = context?.unregister;\n\n useEffect(() => {\n if (!register || !unregister) return;\n register(id, (args) => predicateRef.current(args));\n return () => unregister(id);\n }, [register, unregister, id]);\n\n if (!context) return IDLE_BLOCKER;\n return context.blockedBy === id ? context.blocker : IDLE_BLOCKER;\n}\n","import { useCallback, useEffect, useState, useMemo } from \"react\";\nimport { UnsavedChangesDialogProps } from \"../components/UnsavedChangesDialog\";\nimport { useNavigationBlocker } from \"./useNavigationBlocker\";\n\n/**\n * A single, unified hook to prevent navigation when there are unsaved changes.\n *\n * It automatically handles:\n * 1. Internal React Router navigation using `useBlocker`.\n * 2. External browser navigation (page refresh, tab close) using `beforeunload`.\n */\nexport function useUnsavedChangesDialog(\n when: boolean,\n onOk: () => void\n): {\n dialogProps: UnsavedChangesDialogProps;\n triggerDialog: () => void;\n} {\n const [manualDialogOpen, setManualDialogOpen] = useState(false);\n\n const blocker = useNavigationBlocker(\n useCallback(\n ({ currentLocation, nextLocation }) =>\n when && currentLocation.pathname !== nextLocation.pathname,\n [when]\n )\n );\n\n useEffect(() => {\n if (!when) return;\n\n const handleBeforeUnload = (e: BeforeUnloadEvent) => {\n e.preventDefault();\n e.returnValue = \"\";\n };\n\n window.addEventListener(\"beforeunload\", handleBeforeUnload);\n return () => window.removeEventListener(\"beforeunload\", handleBeforeUnload);\n }, [when]);\n\n const handleOk = useCallback(() => {\n onOk();\n if (blocker.state === \"blocked\") {\n blocker.proceed();\n }\n setManualDialogOpen(false);\n }, [blocker, onOk]);\n\n const handleCancel = useCallback(() => {\n if (blocker.state === \"blocked\") {\n blocker.reset();\n }\n setManualDialogOpen(false);\n }, [blocker]);\n\n const triggerDialog = useCallback(() => setManualDialogOpen(true), []);\n\n return useMemo(() => ({\n dialogProps: {\n open: manualDialogOpen || blocker.state === \"blocked\",\n handleOk,\n handleCancel,\n body: \"There are unsaved changes in this collection\"\n },\n triggerDialog\n }), [manualDialogOpen, blocker.state, handleOk, handleCancel, triggerDialog]);\n}\n","import { Entity, FilterValues } from \"@rebasepro/types\";\n\n/**\n * How many (collection, filters) pairs keep a scroll position. Past it, the\n * one written least recently goes. Every combination of filters a user ever\n * applied used to keep an entry, with the rows it showed, for the rest of the\n * session.\n */\nconst SCROLL_CACHE_LIMIT = 20;\n\n/**\n * Where a collection view was, and the rows to show when it comes back.\n *\n * `data` is the rows around what was on screen — a page either side, when the\n * view reports what it draws — starting at row `dataOffset` (0 when absent:\n * `data` then starts at the first row). It used to be every row the view held,\n * which a table scrolled to 100,000 rows kept for the rest of the session and\n * read again in full on the way back.\n */\nexport type CollectionScrollEntry = {\n scrollOffset: number;\n data: Entity<any>[];\n dataOffset?: number;\n};\n\n/** Key: path plus filters (`createCacheKey`). Emptied on sign-out. */\nconst collectionScrollCache = new Map<string, CollectionScrollEntry>();\n\n/**\n * Forget every collection's scroll position and the rows kept with it.\n *\n * The rows are what the signed-in user was allowed to read, and a table seeds\n * its first render from them, so they must not outlive that user's session.\n */\nexport function clearCollectionScrollCache(): void {\n collectionScrollCache.clear();\n}\n\nexport type ScrollRestorationController = {\n\n getCollectionScroll: (path: string,\n filters?: FilterValues<any>) => CollectionScrollEntry | undefined;\n\n updateCollectionScroll: (props: CollectionScrollEntry & {\n path: string,\n filters?: FilterValues<any>;\n }) => void;\n\n}\n\nexport function useScrollRestoration(): ScrollRestorationController {\n\n const updateCollectionScroll = ({\n path,\n filters,\n scrollOffset,\n data,\n dataOffset\n }: CollectionScrollEntry & {\n path: string;\n filters?: FilterValues<any>;\n }) => {\n const key = createCacheKey(path, filters);\n // Re-inserted, so the Map's order is the order of last use.\n collectionScrollCache.delete(key);\n collectionScrollCache.set(key, {\n scrollOffset,\n data,\n ...(dataOffset !== undefined && dataOffset > 0 && { dataOffset })\n });\n if (collectionScrollCache.size > SCROLL_CACHE_LIMIT) {\n const oldest = collectionScrollCache.keys().next().value;\n if (oldest !== undefined) collectionScrollCache.delete(oldest);\n }\n }\n\n const getCollectionScroll = (path: string,\n filters?: FilterValues<any>) => {\n return collectionScrollCache.get(createCacheKey(path, filters));\n }\n\n return {\n getCollectionScroll,\n updateCollectionScroll\n }\n}\n\nfunction createCacheKey(path: string, filters?: FilterValues<any>) {\n\n if (!filters) {\n return path;\n }\n\n // codify the filters into a url friendly string\n const filtersString = filters ? Object.keys(filters).map(key => {\n const value = JSON.stringify(filters[key]);\n return `${key}=${value}`;\n }).join(\"&\") : \"\";\n\n return `${path}?${filtersString}`;\n}\n","import { EntityReference, EntityRelation, GeoPoint, Vector } from \"@rebasepro/types\";\nimport { isObject, isPlainObject } from \"@rebasepro/utils\";\n\n// Define a unique prefix for entity keys in sessionStorage to avoid key collisions\nconst LOCAL_STORAGE_PREFIX = \"entity_cache::\";\n\n/**\n * The in-session handoff channel: an edit in flight, parked here by the layout\n * that is being replaced and picked up by the one taking over — the split's\n * \"hide list\", full screen's \"show list\", the side panel's \"open full screen\".\n * A record loaded from it opens *dirty*, because that is what it is for.\n *\n * Deliberately **not** hydrated from `sessionStorage`, and it is the one thing\n * here that isn't. The persisted half of this file is the local-changes backup:\n * a draft that outlives a reload, offered back through the banner or applied on\n * open, according to the collection's `localChangesBackup`. Loading those\n * drafts into this map on startup made every one of them look like a handoff —\n * the first visit to the record after a reload silently opened dirty carrying a\n * draft the user had walked away from, and the banner that exists to ask about\n * it never appeared.\n */\nconst entityCache: Map<string, object> = new Map();\n\n// Check `sessionStorage` availability once during initialization\nconst isSessionStorageAvailable = typeof sessionStorage !== \"undefined\";\n\n// Define custom replacer for JSON.stringify\nfunction customReplacer(this: Record<string, unknown>, key: string): unknown {\n\n const value = this[key];\n\n // Handle Date objects\n if (value instanceof Date) {\n return {\n __type: \"Date\",\n value: value.toISOString()\n };\n }\n\n // Handle EntityReference\n if (value instanceof EntityReference) {\n return {\n __type: \"EntityReference\",\n id: value.id,\n path: value.path,\n driver: value.driver,\n databaseId: value.databaseId\n };\n }\n\n if (value instanceof EntityRelation) {\n return {\n __type: \"EntityRelation\",\n id: value.id,\n path: value.path,\n data: value.data\n };\n }\n\n // Handle GeoPoint\n if (value instanceof GeoPoint) {\n return {\n __type: \"GeoPoint\",\n latitude: value.latitude,\n longitude: value.longitude\n };\n }\n\n // Handle Vector\n if (value instanceof Vector) {\n return {\n __type: \"Vector\",\n value: value.value\n };\n }\n\n return value;\n}\n\n// Define custom reviver for JSON.parse\nfunction customReviver(_key: string, value: unknown): unknown {\n if (value && typeof value === \"object\" && \"__type\" in value) {\n const record = value as Record<string, unknown>;\n switch (record.__type) {\n case \"date\":\n case \"Date\":\n return new Date(record.value as string);\n case \"reference\":\n case \"EntityReference\":\n return new EntityReference({\n id: record.id as string,\n path: record.path as string,\n driver: record.driver as string | undefined,\n databaseId: record.databaseId as string | undefined\n });\n case \"relation\":\n case \"EntityRelation\":\n return new EntityRelation(record.id as string, record.path as string, record.data as Record<string, unknown> | undefined);\n case \"GeoPoint\":\n return new GeoPoint(record.latitude as number, record.longitude as number);\n case \"Vector\":\n return new Vector(record.value as number[]);\n default:\n return value;\n }\n }\n return value;\n}\n\n/**\n * Saves data to the local-changes backup in `sessionStorage`.\n *\n * The backup only — a draft that survives a reload is not an edit in flight.\n * {@link saveEntityToMemoryCache} is the other channel; see {@link entityCache}\n * for what separates them.\n * @param path - The unique path/key for the data.\n * @param data - The data to cache and persist.\n */\nexport function saveEntityToCache(path: string, data: object): void {\n // Persist the data individually in sessionStorage\n if (isSessionStorageAvailable) {\n try {\n const key = LOCAL_STORAGE_PREFIX + path;\n\n const entityString = JSON.stringify(data, customReplacer);\n sessionStorage.setItem(key, entityString);\n } catch (error) {\n console.error(\n `Failed to save entity for path \"${path}\" to sessionStorage:`,\n error\n );\n }\n }\n}\n\n/**\n * Consumes a handoff. The channel is one-shot: whoever picks an edit up owns it\n * from then on, and an edit left behind here is one that reopens a record dirty\n * long after the user stopped looking at it.\n */\nexport function removeEntityFromMemoryCache(path: string): void {\n entityCache.delete(path);\n}\n\n/**\n * Parks an edit in flight for the layout about to take over. See\n * {@link entityCache}: this is the handoff, not the backup.\n */\nexport function saveEntityToMemoryCache(path: string, data: object): void {\n entityCache.set(path, data);\n}\n\nexport function getEntityFromMemoryCache(path: string): object | undefined {\n return entityCache.get(path);\n}\n\n/**\n * Drops every edit in flight. They were parked by a user who is no longer\n * signed in, so nobody is taking them over.\n */\nexport function clearEntityMemoryCache(): void {\n entityCache.clear();\n}\n\n/**\n * Drops the whole local-changes backup: every draft in `sessionStorage`, for\n * every record. For when the drafts belong to somebody other than the user now\n * signed in.\n */\nexport function clearEntityDrafts(): void {\n if (!isSessionStorageAvailable) return;\n try {\n const keys: string[] = [];\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (key?.startsWith(LOCAL_STORAGE_PREFIX)) keys.push(key);\n }\n for (const key of keys) sessionStorage.removeItem(key);\n } catch (error) {\n console.error(\"Failed to clear the local-changes backup from sessionStorage:\", error);\n }\n}\n\n\n/**\n * Retrieves a entity from the local-changes backup in `sessionStorage`.\n *\n * The backup only — the handoff channel is read through\n * {@link getEntityFromMemoryCache}, and the two mean different things to the\n * form that receives them.\n * @param path - The unique path/key for the entity.\n * @returns The cached entity or `undefined` if not found.\n */\nexport function getEntityFromCache(path: string): object | undefined {\n\n // If not in the cache, attempt to load it from sessionStorage\n if (isSessionStorageAvailable) {\n try {\n const key = LOCAL_STORAGE_PREFIX + path;\n const entityString = sessionStorage.getItem(key);\n if (entityString) {\n const entity: object = JSON.parse(entityString, customReviver);\n return entity;\n }\n } catch (error) {\n console.error(\n `Failed to load entity for path \"${path}\" from sessionStorage:`,\n error\n );\n }\n }\n\n // Entity not found\n return undefined;\n}\n\n/**\n * Removes a entity from both the in-memory cache and `sessionStorage`.\n * @param path - The unique path/key for the entity to remove.\n */\nexport function removeEntityFromCache(path: string): void {\n\n console.debug(\"Removing entity from cache\", path);\n\n // Remove from the in-memory cache\n entityCache.delete(path);\n\n // Remove from sessionStorage\n if (isSessionStorageAvailable) {\n try {\n const key = LOCAL_STORAGE_PREFIX + path;\n sessionStorage.removeItem(key);\n } catch (error) {\n console.error(\n `Failed to remove entity for path \"${path}\" from sessionStorage:`,\n error\n );\n }\n }\n}\n\n\nexport function flattenKeys(obj: Record<string, unknown> | unknown[], prefix = \"\", result: string[] = []): string[] {\n\n if (isObject(obj) || Array.isArray(obj)) {\n const plainObject = isPlainObject(obj);\n if (!plainObject && prefix) {\n result.push(prefix);\n } else {\n const record = obj as Record<string, unknown>;\n for (const key in record) {\n if (Object.prototype.hasOwnProperty.call(record, key)) {\n const newKey = prefix\n ? Array.isArray(obj)\n ? `${prefix}[${key}]`\n : `${prefix}.${key}`\n : key;\n const val = record[key];\n if (isObject(val) || Array.isArray(val)) {\n flattenKeys(val as Record<string, unknown> | unknown[], newKey, result);\n } else {\n result.push(newKey);\n }\n }\n }\n }\n }\n return result;\n}\n","/**\n * The store behind a computed display value.\n *\n * A record's title is asked for far more often than it changes, and by many\n * components at once: a list of fifty rows, each row's relation chips, the\n * breadcrumb above them. Resolving per component is what makes an async display\n * value a bad idea — fifty rows becomes fifty reads, then fifty more on the next\n * render.\n *\n * So resolution is keyed by record *and* role, in-flight calls are shared, and\n * results are kept until something says otherwise. Deliberately not a React\n * thing: the same store answers an imperative caller (an export, a breadcrumb\n * built outside the tree), and it is testable without a renderer.\n */\nimport type { EntityDisplayRole } from \"@rebasepro/cms-types\";\n\ntype CacheEntry = {\n /** Set once resolved. `null` means \"resolved to nothing\", not \"unknown\". */\n value: unknown;\n} | {\n /** Shared by every caller that arrives while the first one is in flight. */\n promise: Promise<unknown>;\n};\n\nexport type EntityDisplayKey = string;\n\n/** The identity of one role of one record, as a cache key. */\nexport function entityDisplayKey(\n path: string,\n entityId: string | number | undefined,\n role: EntityDisplayRole\n): EntityDisplayKey {\n return `${role} ${path} ${entityId ?? \"\"}`;\n}\n\n/**\n * One shared store, so every surface agrees on a record and resolves it once.\n *\n * Module-level rather than a provider: two app instances on one page share a\n * cache keyed by collection path and record id, which *is* the same record.\n * A resolved title is what the signed-in user was allowed to read, though, so\n * the store is emptied with the rest of the session's caches when that user\n * signs out (`clearSessionCaches`).\n *\n * Built on first use rather than at module scope. Importing a module should not\n * construct anything: it runs during SSR where there is nothing to cache, and it\n * made the modules that read this store unimportable from any test that stubs\n * `@rebasepro/app`.\n */\nlet sharedCache: EntityDisplayCache | undefined;\n\nexport function getSharedEntityDisplayCache(): EntityDisplayCache {\n if (!sharedCache) sharedCache = new EntityDisplayCache();\n return sharedCache;\n}\n\nexport class EntityDisplayCache {\n\n private readonly entries = new Map<EntityDisplayKey, CacheEntry>();\n private readonly listeners = new Set<() => void>();\n\n /**\n * The resolved value, or `undefined` when this pair has not been resolved\n * yet. `null` is a resolved absence, and the two must stay distinct: a\n * caller that reads \"not yet\" as \"nothing\" flickers its fallback in on every\n * mount.\n */\n peek(key: EntityDisplayKey): unknown | undefined {\n const entry = this.entries.get(key);\n if (!entry || \"promise\" in entry) return undefined;\n return entry.value;\n }\n\n /** True while a resolution for this pair is in flight. */\n isLoading(key: EntityDisplayKey): boolean {\n const entry = this.entries.get(key);\n return Boolean(entry && \"promise\" in entry);\n }\n\n /**\n * Resolve once per record and role. Concurrent callers share the first\n * call's promise; later callers get the cached value with no promise at all.\n *\n * A resolver that throws is recorded as \"nothing\" rather than retried: the\n * alternative is every render re-running a call that just failed. And it is\n * reported here, which is a correction.\n *\n * It used to say \"the caller that saw the rejection is the one that logs\n * it\", and `useEntityDisplay` duly attached a `.catch()` that warned. But\n * both failure paths below swallow and return a *resolved* promise, so that\n * catch could never run — the two halves each did the reasonable thing and\n * between them the log was unreachable. A resolver that blew up produced a\n * blank chip and total silence, which is the failure mode\n * `EntityDisplayResolver`'s own contract (\"treated as `undefined` and logged\n * once\") exists to rule out.\n *\n * Reporting belongs here for the reason the caller could not do it: this is\n * the one place that runs exactly once per key, so \"once\" is a property of\n * the code rather than a hope about how many components mount.\n */\n resolve(key: EntityDisplayKey, resolver: () => unknown): Promise<unknown> {\n const entry = this.entries.get(key);\n if (entry) {\n return \"promise\" in entry ? entry.promise : Promise.resolve(entry.value);\n }\n\n let produced: unknown;\n try {\n produced = resolver();\n } catch (error: unknown) {\n this.fail(key, error);\n return Promise.resolve(null);\n }\n\n // A synchronous resolver never enters the loading state. Putting it\n // through one would render every caller's fallback for a frame, for\n // nothing.\n if (!isPromise(produced)) {\n const value = normalize(produced);\n this.set(key, value);\n return Promise.resolve(value);\n }\n\n const promise = produced\n .then(resolved => {\n const value = normalize(resolved);\n this.set(key, value);\n return value;\n })\n .catch((error: unknown) => {\n this.fail(key, error);\n return null;\n });\n\n this.entries.set(key, { promise });\n return promise;\n }\n\n /**\n * Drop what is known about a record, so the next ask resolves again. Called\n * after a write: the row that just saved may be called something else now.\n */\n invalidate(path: string, entityId?: string | number): void {\n const suffix = ` ${path} ${entityId ?? \"\"}`;\n let changed = false;\n for (const key of [...this.entries.keys()]) {\n // `undefined` id means the whole collection — after an import, or a\n // locale switch that changes what every title in it reads.\n const matches = entityId === undefined\n ? key.includes(` ${path} `) || key.endsWith(` ${path} `)\n : key.endsWith(suffix);\n if (matches) {\n this.entries.delete(key);\n changed = true;\n }\n }\n if (changed) this.emit();\n }\n\n /** Drop everything. The user signed out, or the app swapped datasource. */\n clear(): void {\n if (this.entries.size === 0) return;\n this.entries.clear();\n this.emit();\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private set(key: EntityDisplayKey, value: unknown): void {\n this.entries.set(key, { value });\n this.emit();\n }\n\n /**\n * Record a failed resolution as \"nothing\", and say so once.\n *\n * The key is the message: it is `<role> <path> <id>`, which is exactly what a\n * reader needs to find the resolver that blew up. A warning with no key would\n * tell them a display resolver failed somewhere in a list of fifty rows.\n *\n * `console.warn` rather than a thrown error, because this runs while a row is\n * rendering: the contract is that a title which cannot be fetched must not\n * take down the row that shows it.\n */\n private fail(key: EntityDisplayKey, error: unknown): void {\n console.warn(`[rebase] Could not resolve display value for ${key}:`, error);\n this.set(key, null);\n }\n\n private emit(): void {\n for (const listener of [...this.listeners]) listener();\n }\n}\n\n/**\n * Empty strings and empty arrays are absences, not values — a title of `\" \"`\n * would otherwise beat the derived one and render as a blank heading.\n */\nfunction normalize(value: unknown): unknown {\n if (value === undefined || value === null) return null;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n if (Array.isArray(value)) return value.length > 0 ? value : null;\n return value;\n}\n\nfunction isPromise(value: unknown): value is Promise<unknown> {\n return typeof (value as Promise<unknown> | undefined)?.then === \"function\";\n}\n","import { clearFetchCache } from \"../hooks/data/useFetch\";\nimport { clearCollectionScrollCache } from \"../components/common/useScrollRestoration\";\nimport { clearEntityDrafts, clearEntityMemoryCache } from \"../util/entity_cache\";\nimport { getSharedEntityDisplayCache } from \"../collections/entity-display-cache\";\n\n/**\n * Who the tab's cached state was read or written as. Kept in `sessionStorage`\n * as well as in memory because the local-changes backup is: a reload keeps the\n * drafts, so it has to keep the name of the user they belong to.\n */\nconst OWNER_STORAGE_KEY = \"rebase::session_cache_owner\";\nlet ownerInMemory: string | undefined;\n\nfunction readOwner(): string | undefined {\n try {\n if (typeof sessionStorage !== \"undefined\") {\n return sessionStorage.getItem(OWNER_STORAGE_KEY) ?? ownerInMemory;\n }\n } catch {\n // Storage refused (privacy mode, sandboxed frame): memory is all there is.\n }\n return ownerInMemory;\n}\n\nfunction writeOwner(userId: string): void {\n ownerInMemory = userId;\n try {\n if (typeof sessionStorage !== \"undefined\") {\n sessionStorage.setItem(OWNER_STORAGE_KEY, userId);\n }\n } catch {\n // As above.\n }\n}\n\n/**\n * Empty every module-level cache that holds data read as the signed-in user:\n * fetched records, each table's scroll position and the rows kept with it,\n * edits parked for a layout handoff, and resolved display values (the titles\n * on relation chips and breadcrumbs).\n *\n * All of them are keyed by path and id only, with no user in the key, and the\n * views seed their first render from them — so without this the next user to\n * sign in to the tab is shown what the last one could read. Called by both auth\n * controllers on `SIGNED_OUT`.\n *\n * The local-changes backup is not cleared here: a sign-out is also how a\n * rejected refresh token ends a session, and the backup exists for that user\n * coming back. {@link bindSessionCachesToUser} drops it when somebody else\n * signs in instead.\n */\nexport function clearSessionCaches(): void {\n clearFetchCache();\n clearCollectionScrollCache();\n clearEntityMemoryCache();\n getSharedEntityDisplayCache().clear();\n}\n\n/**\n * Record that the tab now acts as `userId`. When that is not who the caches\n * were filled for, everything goes — the session caches, and the drafts the\n * other user left in the local-changes backup.\n *\n * Call it before the new user is rendered: the views read these caches in\n * their first render, before any effect of the auth controller would run.\n */\nexport function bindSessionCachesToUser(userId: string): void {\n const owner = readOwner();\n if (owner !== undefined && owner !== userId) {\n clearSessionCaches();\n clearEntityDrafts();\n }\n if (owner !== userId) writeOwner(userId);\n}\n","import { useState, useEffect, useMemo, useCallback } from \"react\";\nimport { deepEqual } from \"fast-equals\";\nimport { AuthClient, User } from \"@rebasepro/types\";\nimport { AuthController } from \"@rebasepro/cms-types\";\nimport { bindSessionCachesToUser, clearSessionCaches } from \"../auth/session_caches\";\n\n/**\n * Sets the user, first making sure the tab's caches were filled for them.\n * Before the state update, not in an effect: the views read those caches in\n * the very render the new user arrives in.\n */\nfunction adoptUser(user: User | null): User | null {\n if (user) bindSessionCachesToUser(user.uid);\n return user;\n}\n\n/**\n * The state update for a user the SDK handed over. A token refresh hands over\n * a freshly mapped user every time; the same user, field for field, keeps the\n * object already held, so the controller — and every context consumer — does\n * not change with it.\n */\nfunction keepIfEqual(next: User | null) {\n return (previous: User | null) => (previous && next && deepEqual(previous, next)) ? previous : next;\n}\n\nexport function useAuthSubscription(authClient?: AuthClient): AuthController {\n\n // Check initial state\n const currentSession = authClient?.getSession();\n const [user, setUser] = useState<User | null>(() => adoptUser(currentSession?.user ?? null));\n\n const [authLoading, setAuthLoading] = useState(false);\n const [authError, setAuthError] = useState<Error>();\n const [loginSkipped, setLoginSkipped] = useState(false);\n const [extra, setExtra] = useState<any>();\n\n /**\n * Whether asking the server \"who am I?\" could possibly answer.\n *\n * A client configured with `persistSession: false` and JSON auth — the\n * shape used when one client borrows another's credential, as the hosted\n * Studio does — has no stored session and no auth cookie, so the probe\n * below is guaranteed to 401. Sending it anyway put three failing\n * `GET /auth/me` calls on the wire per mount, each one landing in the\n * *customer's* request log as an authentication failure against their own\n * backend.\n *\n * A client that does not implement the capability is treated as \"might\n * work\" — the historical behaviour.\n */\n const mayHaveRestorableSession = authClient?.canRestoreSession?.() ?? true;\n\n /**\n * `true` only while a probe is genuinely outstanding.\n *\n * It used to be seeded from `!currentSession` alone, which left a client\n * that cannot restore a session — and therefore never runs the probe that\n * clears the flag — reporting \"still loading\" forever. Anything gated on\n * `initialLoading` (a spinner, a redirect to the login view) would never\n * resolve.\n */\n const [initialLoading, setInitialLoading] = useState(!currentSession && mayHaveRestorableSession);\n\n /**\n * `true` until the client has finished restoring a session on its own.\n *\n * The first `getSession()` above is provisional while that runs: the SDK\n * holds an expired stored session during its boot refresh, and when the\n * refresh is rejected it drops the session without emitting anything. So\n * the user is read again once the restore settles, and the app does not\n * render as signed in before then.\n */\n const [restoring, setRestoring] = useState(Boolean(authClient?.isInitialized));\n\n useEffect(() => {\n if (!authClient?.isInitialized) {\n setRestoring(false);\n return;\n }\n let cancelled = false;\n setRestoring(true);\n authClient.isInitialized()\n .catch(() => {\n // A restore that failed has left no session behind; reading\n // the session below is still the answer.\n })\n .then(() => {\n if (cancelled) return;\n setUser(keepIfEqual(adoptUser(authClient.getSession()?.user ?? null)));\n setRestoring(false);\n });\n return () => {\n cancelled = true;\n };\n }, [authClient]);\n\n useEffect(() => {\n if (!authClient) return;\n // If we don't have a session initially, try to get user which restores session if a persistent token exists\n if (!currentSession && mayHaveRestorableSession) {\n setInitialLoading(true);\n authClient.getUser()\n .then(user => {\n if (user) {\n setUser(adoptUser(user));\n }\n setAuthError(undefined);\n })\n .catch((e: unknown) => {\n // A 401 or 403 is the ordinary first load of an anonymous\n // visitor: there is no session, which is not an error.\n //\n // Everything else is. This used to swallow the lot with\n // \"Ignore, user just isn't logged in\", leaving `authError`\n // — a field this controller declares and `Rebase` renders a\n // full-screen \"Error loading auth\" view for — permanently\n // undefined. So the view was unreachable, and a backend that\n // was down, misconfigured, or blocked by CORS looked exactly\n // like being signed out: the app showed the login form.\n const status = (e as { status?: number } | undefined)?.status;\n if (status === 401 || status === 403) {\n setAuthError(undefined);\n return;\n }\n setAuthError(e instanceof Error ? e : new Error(String(e)));\n })\n .finally(() => {\n setInitialLoading(false);\n });\n }\n }, [authClient, currentSession, mayHaveRestorableSession]);\n\n useEffect(() => {\n if (!authClient) return;\n const unsubscribe = authClient.onAuthStateChange((event, session) => {\n if (event === \"SIGNED_IN\" || event === \"USER_UPDATED\" || event === \"TOKEN_REFRESHED\") {\n setUser(keepIfEqual(adoptUser(session?.user ?? null)));\n } else if (event === \"SIGNED_OUT\") {\n // See `clearSessionCaches`: what this session read must not be\n // what the next user in the tab is shown first.\n clearSessionCaches();\n setUser(null);\n }\n });\n return unsubscribe;\n }, [authClient]);\n\n const signOut = useCallback(async () => {\n if (!authClient) return;\n setAuthLoading(true);\n try {\n await authClient.signOut();\n } finally {\n setAuthLoading(false);\n }\n }, [authClient]);\n\n const getAuthToken = useCallback(async () => {\n if (!authClient) return \"\";\n const session = authClient.getSession();\n if (!session) return \"\";\n if (session.expiresAt < Date.now()) {\n try {\n const refreshed = await authClient.refreshSession();\n return refreshed.accessToken;\n } catch (e) {\n return \"\";\n }\n }\n return session.accessToken;\n }, [authClient]);\n\n return useMemo(() => ({\n user,\n initialLoading: authClient ? initialLoading || restoring : false,\n authLoading,\n signOut,\n authError,\n getAuthToken,\n loginSkipped,\n extra,\n setExtra\n } as AuthController), [\n user, initialLoading, restoring, authLoading, signOut, authError,\n getAuthToken, loginSkipped, extra, setExtra, authClient\n ]);\n}\n","import { AdminModeControllerContext } from \"../contexts/AdminModeController\";\nimport { useContext } from \"react\";\n\n/**\n * Use this controller to change the admin mode: `\"cms\"` for editing data,\n * `\"studio\"` for the developer tools.\n * @group Hooks and utilities\n */\nexport interface AdminModeController {\n mode: \"cms\" | \"studio\";\n setMode: (mode: \"cms\" | \"studio\") => void;\n}\n\n/**\n * Hook to retrieve the current admin mode (`\"cms\"` | `\"studio\"`), and `setMode`\n * to change it.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see AdminModeController\n * @group Hooks and utilities\n */\nexport const useAdminModeController = () => useContext(AdminModeControllerContext);\n","/**\n * localStorage that tolerates not being there.\n *\n * `typeof window !== \"undefined\"` was the guard these call sites used, and it\n * answers the wrong question: it says \"am I in a browser\", not \"can I read\n * storage\". Three things make that distinction real rather than theoretical:\n *\n * - A browser can have storage **disabled**. Safari in private mode, a blocked\n * third-party cookie policy, and a sandboxed iframe all give you a `window`\n * whose `localStorage` property *throws on access* — a SecurityError raised\n * before any method is called, which no amount of null-checking the result\n * catches.\n * - A test environment can be **half torn down**. jsdom is disposed at the end\n * of a file while React is still finishing a concurrent render, so `window`\n * survives as a husk and `localStorage.getItem` is no longer a function.\n * That is how this was found: `TypeError: localStorage.getItem is not a\n * function`, thrown out of a render, failing a suite in which every one of\n * 709 tests passed.\n * - Server rendering has no `window` at all, which is the only case the old\n * guard actually covered.\n *\n * Reading a UI preference is never worth a crash. Every function here fails to\n * `null` / no-op, so a user with storage switched off gets the default\n * appearance instead of a blank page.\n */\n\n/** The Storage object, or null when it is absent, blocked, or not usable. */\nfunction usableStorage(): Storage | null {\n try {\n if (typeof window === \"undefined\") return null;\n const candidate = window.localStorage;\n // Not `!= null`: a torn-down jsdom leaves an object behind whose\n // methods are gone, which is exactly the shape that threw.\n return typeof candidate?.getItem === \"function\" ? candidate : null;\n } catch {\n // Access itself throws when storage is blocked by policy.\n return null;\n }\n}\n\n/** The stored string for `key`, or null if it is unset or unreadable. */\nexport function readStoredString(key: string): string | null {\n try {\n return usableStorage()?.getItem(key) ?? null;\n } catch {\n return null;\n }\n}\n\n/** Persist `value` under `key`. A no-op when storage is unavailable. */\nexport function writeStoredString(key: string, value: string): void {\n try {\n usableStorage()?.setItem(key, value);\n } catch {\n // Also the quota path: a full store throws on write but reads fine.\n }\n}\n\n/** Remove `key`. A no-op when storage is unavailable. */\nexport function removeStoredString(key: string): void {\n try {\n usableStorage()?.removeItem(key);\n } catch {\n /* nothing to undo */\n }\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport type { AdminModeController } from \"./useAdminModeController\";\nimport { readStoredString, writeStoredString } from \"../util/local_storage\";\n\n/**\n * Use this hook to build an admin mode controller that determines\n * whether the UI shows Developer or Editor tools.\n */\nexport function useBuildAdminModeController(): AdminModeController {\n\n // The content mode was renamed to \"cms\" when the panel's CMS half became a\n // product name. The value is persisted, so a browser that used the panel\n // before the rename still has \"content\" in local storage — read as-is it\n // casts to a mode nothing matches, and the drawer renders neither half.\n // Migrating on read is the exception the no-shims rule allows for stored data.\n //\n // Anything else stored under this key falls back to \"cms\" for the same\n // reason, rather than being cast to a mode: the union used to carry a third\n // value, `\"settings\"`, that nothing set and nothing read, and a cast is how\n // a value outside the union reaches state in the first place.\n const stored = readStoredString(\"rebase-admin-mode\");\n const migrated = stored === \"content\" ? \"cms\" : stored;\n const savedMode = migrated === \"cms\" || migrated === \"studio\" ? migrated : null;\n const [mode, setMode] = useState<\"cms\" | \"studio\">(savedMode ?? \"cms\");\n\n const setModeInternal = useCallback((newMode: \"cms\" | \"studio\") => {\n writeStoredString(\"rebase-admin-mode\", newMode);\n setMode(newMode);\n }, []);\n\n return useMemo(() => ({\n mode,\n setMode: setModeInternal\n }), [mode, setModeInternal]);\n}\n","import type { EffectiveRoleController } from \"@rebasepro/types\";\nimport { useCallback, useState, useMemo } from \"react\";\nimport { readStoredString, removeStoredString, writeStoredString } from \"../util/local_storage\";\n;\n\n/**\n * Use this hook to build an effective role controller that determines\n * what role is simulated in Editor mode when Dev mode is active.\n *\n * It uses localStorage to persist the simulated role across reloads.\n */\nexport function useBuildEffectiveRoleController(): EffectiveRoleController {\n\n const savedRole = readStoredString(\"rebase-effective-role\");\n const [effectiveRole, setEffectiveRole] = useState<string | null>(savedRole ?? null);\n\n const setRoleInternal = useCallback((newRole: string | null) => {\n if (newRole) {\n writeStoredString(\"rebase-effective-role\", newRole);\n } else {\n removeStoredString(\"rebase-effective-role\");\n }\n setEffectiveRole(newRole);\n }, []);\n\n return useMemo(() => ({\n effectiveRole,\n setEffectiveRole: setRoleInternal\n }), [effectiveRole, setRoleInternal]);\n}\n","import { ModeControllerContext } from \"../contexts/ModeController\";\nimport { useContext } from \"react\";\n\n/**\n * Use this controller to change color mode\n * @group Hooks and utilities\n */\nexport interface ModeController {\n mode: \"light\" | \"dark\";\n setMode: (mode: \"light\" | \"dark\" | \"system\") => void;\n}\n\n/**\n * Hook to retrieve the current mode (\"light\" | \"dark\"), and `setMode`\n * or `toggle` functions to change it.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see ModeController\n * @group Hooks and utilities\n */\nexport const useModeController = () => useContext(ModeControllerContext);\n","// FORKED FROM https://github.com/fayeed/use-clipboard\n\nimport { MutableRefObject, useCallback, useEffect, useRef, useState, useMemo } from \"react\";\n\nexport interface UseClipboardProps {\n /**\n * It's callback function that is called after the `copy` command\n * is executed.\n *\n * @param text: The selected clipboard text.\n */\n onSuccess?: (text: string) => void;\n\n /**\n * Triggers when the hook encounters an error.\n * If passed hook won't throw an error.\n *\n * @param error: cause of the error\n */\n onError?: (error: string) => void;\n\n /**\n * Disables the new clipboard API `navigator.clipboard` even if\n * it is supported.\n */\n disableClipboardAPI?: boolean;\n\n /**\n * revert back the isCopied flag to false again if a value is set.\n */\n copiedDuration?: number;\n}\n\nexport interface useClipboardReturnType {\n /**\n * Use ref to pull the text content from.\n */\n ref: MutableRefObject<any>;\n\n /**\n * Use it to perform the copy operation\n */\n copy: (text?: string) => void;\n\n /**\n * Use it to perform the cut operation\n */\n cut: () => void;\n\n /**\n * Indicates wheater the content was successfully copied or not.\n */\n isCoppied: boolean;\n\n /**\n * Current selected clipboard content.\n */\n clipboard: string;\n\n /**\n * Clears the user clipboard.\n */\n clearClipboard: () => void;\n\n /**\n * Check to see if the browser supports the new `navigator.clipboard` API.\n */\n isSupported: () => boolean;\n}\n\nexport const useClipboard = (\n options?: UseClipboardProps\n): useClipboardReturnType => {\n const { onSuccess, onError, disableClipboardAPI = false, copiedDuration } =\n options || {};\n const ref = useRef<any>(null);\n const [isCoppied, setIsCoppied] = useState(false);\n const [clipboard, setClipbaord] = useState(\"\");\n\n useEffect(() => {\n if (copiedDuration) setTimeout(() => setIsCoppied(false), copiedDuration);\n }, [isCoppied]);\n\n const isSupported = useCallback(() => navigator.clipboard !== undefined, []);\n\n const handleError = useCallback((error: string) => {\n if (onError) onError(error);\n else throw new Error(error);\n }, [onError]);\n\n const handleSuccess = useCallback((text: string) => {\n if (onSuccess) onSuccess(text);\n setIsCoppied(true);\n setClipbaord(text);\n }, [onSuccess]);\n\n const copyToClipboard = useCallback((text: string) => {\n navigator.clipboard\n .writeText(text)\n .then(() => handleSuccess(text))\n .catch((err) => {\n handleError(err);\n setIsCoppied(false);\n });\n }, [handleError, handleSuccess]);\n\n const clearClipboard = useCallback(() => {\n if (isSupported()) {\n navigator.clipboard.writeText(\"\");\n }\n }, [isSupported]);\n\n const action = useCallback(\n (operation = \"copy\", text?: string) => {\n const element = ref.current as HTMLElement;\n\n const isInput =\n element &&\n (element.tagName === \"INPUT\" || element.tagName === \"TEXTAREA\");\n\n const input = ref.current as HTMLInputElement;\n\n if (isSupported() && !disableClipboardAPI) {\n if (text) {\n copyToClipboard(text);\n } else if (element) {\n if (isInput) {\n copyToClipboard(input.value);\n\n if (operation === \"cut\") {\n input.value = \"\";\n }\n } else {\n copyToClipboard(element.innerText);\n }\n } else {\n handleError(\"Both the ref & text were undefined\");\n }\n }\n },\n [disableClipboardAPI, copyToClipboard, handleError]\n );\n\n const copy = useCallback((text?: string) =>\n action(\"copy\", typeof text === \"object\" ? undefined : text), [action]);\n\n const cut = useCallback(() => action(\"cut\"), [action]);\n\n return useMemo(() => ({\n ref,\n isCoppied,\n clipboard,\n clearClipboard,\n isSupported,\n copy,\n cut\n }), [isCoppied, clipboard, clearClipboard, isSupported, copy, cut]);\n};\n","import { useSyncExternalStore } from \"react\";\n\nconst breakpoints = {\n xs: 0,\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n \"2xl\": 1536,\n \"3xl\": 1920\n}\n\n/**\n * Who is reading the layout, and what it was at the last `resize`.\n *\n * One `resize` listener on `window` serves every reader. It is added when the\n * first reader mounts and removed when the last one unmounts — never by\n * importing this module, which an app can do without rendering anything.\n */\nconst subscribers = new Set<() => void>();\nlet lastKnown: boolean | undefined;\n\nfunction onResize() {\n const next = checkLargeLayout(\"lg\");\n if (next === lastKnown) return;\n lastKnown = next;\n subscribers.forEach(notify => notify());\n}\n\nfunction subscribe(notify: () => void): () => void {\n if (subscribers.size === 0 && typeof window !== \"undefined\") {\n lastKnown = checkLargeLayout(\"lg\");\n window.addEventListener(\"resize\", onResize);\n }\n subscribers.add(notify);\n return () => {\n subscribers.delete(notify);\n if (subscribers.size === 0 && typeof window !== \"undefined\") {\n window.removeEventListener(\"resize\", onResize);\n lastKnown = undefined;\n }\n };\n}\n\nfunction getSnapshot(): boolean {\n // While listened to, the value the listener keeps; before the first\n // reader subscribes, the layout as it is now.\n return lastKnown ?? checkLargeLayout(\"lg\");\n}\n\nfunction getServerSnapshot(): boolean {\n return false;\n}\n\nexport const useLargeLayout = (): boolean =>\n useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n\nfunction checkLargeLayout(breakpoint: \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" = \"lg\"): boolean {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\")\n return false;\n return window.matchMedia(`(min-width: ${breakpoints[breakpoint] + 1}px)`).matches;\n}\n","import { useCallback, useEffect, useState, useMemo } from \"react\";\n\nconst STORAGE_KEY_PREFIX = \"rebase-collapsed-groups\";\n\n/**\n * Custom hook for managing collapsed/expanded state of navigation groups\n * with localStorage persistence. Automatically cleans up stale group entries\n * when groups are removed from the navigation.\n *\n * Groups that have never been toggled by the user fall back to\n * `defaults[groupName]` (driven by `collapsedByDefault` in config).\n *\n * @param groupNames - Array of group names to track\n * @param namespace - Namespace for localStorage key (e.g., \"home\", \"drawer\") to allow independent state\n * @param defaults - Optional map of group name → collapsed boolean from config\n */\nexport function useCollapsedGroups(\n groupNames: string[],\n namespace = \"default\",\n defaults?: Record<string, boolean>\n) {\n const storageKey = `${STORAGE_KEY_PREFIX}-${namespace}`;\n\n // Load collapsed groups from localStorage on mount\n const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() => {\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : {};\n } catch {\n return {};\n }\n });\n\n // Save to localStorage whenever collapsedGroups changes\n useEffect(() => {\n try {\n localStorage.setItem(storageKey, JSON.stringify(collapsedGroups));\n } catch {\n // Silently fail if localStorage is not available\n }\n }, [collapsedGroups, storageKey]);\n\n // Clean up collapsed groups state when groups change - remove entries for groups that no longer exist\n useEffect(() => {\n // Only clean up if we have actual groups loaded (avoid cleaning up during initial load)\n if (groupNames.length === 0) return;\n\n const currentGroupNames = new Set(groupNames);\n\n setCollapsedGroups(prev => {\n const cleaned = Object.fromEntries(\n Object.entries(prev).filter(([groupName]) => currentGroupNames.has(groupName))\n );\n\n // Only update if something actually changed\n const prevKeys = Object.keys(prev);\n const cleanedKeys = Object.keys(cleaned);\n\n if (prevKeys.length === cleanedKeys.length && prevKeys.every(key => cleanedKeys.includes(key))) {\n return prev;\n }\n\n return cleaned;\n });\n }, [groupNames]);\n\n const isGroupCollapsed = useCallback((name: string) => {\n // If the user has explicitly toggled this group, use that value\n if (name in collapsedGroups) {\n return collapsedGroups[name];\n }\n // Otherwise fall back to the config default\n return defaults?.[name] ?? false;\n }, [collapsedGroups, defaults]);\n\n const toggleGroupCollapsed = useCallback((name: string) => {\n setCollapsedGroups(prev => {\n // Resolve current effective state (explicit or default)\n const currentlyCollapsed = name in prev\n ? prev[name]\n : (defaults?.[name] ?? false);\n return { ...prev,\n[name]: !currentlyCollapsed };\n });\n }, [defaults]);\n\n return useMemo(() => ({\n isGroupCollapsed,\n toggleGroupCollapsed\n }), [isGroupCollapsed, toggleGroupCollapsed]);\n}\n\n/**\n * Build a defaults map from navigationGroupMappings for a given namespace.\n * Returns a Record<groupName, collapsed> that can be passed to useCollapsedGroups.\n */\nexport function buildCollapsedDefaults(\n mappings: Array<{ name: string; collapsedByDefault?: boolean | { drawer?: boolean; home?: boolean } }> | undefined,\n namespace: \"drawer\" | \"home\"\n): Record<string, boolean> {\n if (!mappings) return {};\n const result: Record<string, boolean> = {};\n for (const mapping of mappings) {\n const val = mapping.collapsedByDefault;\n if (val === undefined) continue;\n if (typeof val === \"boolean\") {\n result[mapping.name] = val;\n } else {\n const ns = val[namespace];\n if (ns !== undefined) {\n result[mapping.name] = ns;\n }\n }\n }\n return result;\n}\n","import { useEffect } from \"react\";\n\nconst rebaseLogo = \"data:image/png;base64,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\";\n\n/**\n * Internal hook to handle the browser title and icon\n * @param name\n * @param logo\n */\nexport function useBrowserTitleAndIcon(name: string, logo?: string) {\n useEffect(() => {\n if (document) {\n document.title = `${name} - Rebase`;\n let link = document.querySelector(\"link[rel~='icon']\") as HTMLLinkElement | null;\n if (!link) {\n link = document.createElement(\"link\");\n link.rel = \"icon\";\n document.getElementsByTagName(\"head\")[0].appendChild(link);\n }\n link.href = logo ?? rebaseLogo;\n }\n }, [name, logo]);\n}\n","import type { SlotName, SlotRegistry } from \"@rebasepro/cms-types\";\nimport React, { useMemo } from \"react\";\n;\nimport { useCustomizationController } from \"./useCustomizationController\";\nimport { ErrorBoundary } from \"@rebasepro/ui\";\n\n/**\n * Hook that retrieves and renders all slot contributions for a given slot name.\n *\n * @param slot - The slot name to render contributions for.\n * @param props - Props passed to each slot component.\n * @returns An array of rendered React nodes, each wrapped in an ErrorBoundary.\n *\n * @example\n * ```tsx\n * const actions = useSlot(\"home.actions\", { context });\n * return <div>{actions}</div>;\n * ```\n *\n * @group Hooks\n */\n/**\n * Are these two prop objects the same, one level down?\n *\n * Its own function so the comparison can be typed on `object` rather than on\n * the slot's props. `SlotRegistry[K]` is a union of interfaces, and an\n * interface has no implicit index signature, so reading it as\n * `Record<string, unknown>` — which the loop this replaces did, to both\n * arguments — is a conversion tsc refuses and `as unknown as` was suppressing.\n * `Object.keys` needs no such claim.\n */\nfunction shallowEqual(a: object, b: object): boolean {\n if (a === b) return true;\n const keys = Object.keys(a);\n if (keys.length !== Object.keys(b).length) return false;\n return keys.every((key) => a[key as keyof typeof a] === b[key as keyof typeof b]);\n}\n\nexport function useSlot<K extends SlotName>(\n slot: K,\n props: SlotRegistry[K]\n): React.ReactNode[] {\n const { resolvedSlots } = useCustomizationController();\n\n const propsRef = React.useRef(props);\n if (!shallowEqual(props, propsRef.current)) {\n propsRef.current = props;\n }\n\n const stableProps = propsRef.current;\n\n return useMemo(() => {\n return resolvedSlots\n .filter(s => s.slot === slot)\n .sort((a, b) => (a.order ?? 50) - (b.order ?? 50))\n .map((s, i) => {\n // `filter` cannot narrow a discriminated union through a\n // callback, so `s.Component` is still \"some slot's component\"\n // here and its props are the union of every slot's. The line\n // above is what makes this safe, and it is one line above.\n //\n // This one deliberate cast is the price of `SlotContribution`\n // declaring `ComponentType<SlotRegistry[K]>` instead of\n // `ComponentType<any>` — which is what turns a component\n // written against the wrong slot's props into an error where\n // it is registered, rather than `undefined` at render.\n const Component = s.Component as React.ComponentType<SlotRegistry[K]>;\n return (\n <ErrorBoundary key={`${slot}_${i}`}>\n <Component {...stableProps} {...(s.props ?? {})}/>\n </ErrorBoundary>\n );\n });\n }, [resolvedSlots, slot, stableProps]);\n}\n","import { useCallback, useEffect, useRef, useState, useMemo } from \"react\";\nimport { PartialCollectionConfig, UserConfigurationPersistence } from \"@rebasepro/cms-types\";\nimport { stripCollectionPath } from \"@rebasepro/common\";\nimport { isArrayValue, isRecordValue, mergeDeep, readStoredJson, writeStoredJson } from \"@rebasepro/utils\";\n\nexport function useBuildLocalConfigurationPersistence(): UserConfigurationPersistence {\n\n const configCache = useRef<Record<string, PartialCollectionConfig>>({});\n\n // Read during render by every collection view, so an unreadable value here\n // used to throw the view away rather than fall back to an unconfigured one.\n const getCollectionFromStorage = useCallback(<M extends Record<string, any>>(storageKey: string): PartialCollectionConfig<M> => {\n return readStoredJson<PartialCollectionConfig<M>>(storageKey, { fallback: {}, accept: isRecordValue });\n }, []);\n\n const getCollectionConfig = useCallback(<M extends Record<string, any>>(path: string): PartialCollectionConfig<M> => {\n const storageKey = `collection_config::${stripCollectionPath(path)}`;\n if (configCache.current[storageKey]) {\n return configCache.current[storageKey] as PartialCollectionConfig<M>;\n }\n return getCollectionFromStorage(storageKey);\n }, [getCollectionFromStorage]);\n\n // Bumped on every write. The collection views merge this store into their\n // collection while rendering, so a write that is only a ref mutation is\n // invisible to them: the new column width reaches storage, the table keeps\n // rendering the old one, and the next re-render — a row arriving, a\n // selection, a filter — rebuilds the columns from the stale config and\n // snaps the column back. Making a write a state change is what lets the\n // views re-read it.\n const [configVersion, setConfigVersion] = useState(0);\n\n const onCollectionModified = useCallback(<M extends Record<string, any>>(path: string, data: PartialCollectionConfig<M>) => {\n const storageKey = `collection_config::${stripCollectionPath(path)}`;\n // Read before writing. `data` is a partial by type and by this\n // interface's contract, so what is already stored is the other half of\n // the result — writing `data` first and merging afterwards read back\n // the value that had just been overwritten, and every key the caller\n // left out was dropped.\n const merged = mergeDeep(configCache.current[storageKey] ?? getCollectionFromStorage(storageKey), data);\n configCache.current[storageKey] = merged;\n writeStoredJson(storageKey, merged);\n setConfigVersion(version => version + 1);\n }, [getCollectionFromStorage]);\n\n const [recentlyVisitedPaths, _setRecentlyVisitedPaths] = useState<string[]>([]);\n const [favouritePaths, _setFavouritePaths] = useState<string[]>([]);\n const [collapsedGroups, _setCollapsedGroups] = useState<string[]>([]);\n\n useEffect(() => {\n const readPaths = (key: string) => readStoredJson<string[]>(key, { fallback: [], accept: isArrayValue });\n _setRecentlyVisitedPaths(readPaths(\"recently_visited_paths\"));\n _setFavouritePaths(readPaths(\"favourite_paths\"));\n _setCollapsedGroups(readPaths(\"collapsed_groups\"));\n }, []);\n\n const setRecentlyVisitedPaths = useCallback((paths: string[]) => {\n writeStoredJson(\"recently_visited_paths\", paths);\n _setRecentlyVisitedPaths(paths);\n }, []);\n\n const setFavouritePaths = useCallback((paths: string[]) => {\n writeStoredJson(\"favourite_paths\", paths);\n _setFavouritePaths(paths);\n }, []);\n\n const setCollapsedGroups = useCallback((paths: string[]) => {\n writeStoredJson(\"collapsed_groups\", paths);\n _setCollapsedGroups(paths);\n }, []);\n\n return useMemo(() => ({\n onCollectionModified,\n getCollectionConfig,\n recentlyVisitedPaths,\n setRecentlyVisitedPaths,\n favouritePaths,\n setFavouritePaths,\n collapsedGroups,\n setCollapsedGroups\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `configVersion`\n // is deliberate and the rule cannot see why: it contributes nothing to\n // the value and everything to its IDENTITY. The stored configs live in a\n // ref, so nothing else in this array changes when they do, and this is\n // the only thing telling the views that read them during render that\n // they have. Removing it as \"unnecessary\" is what would break it.\n }), [\n configVersion,\n onCollectionModified,\n getCollectionConfig,\n recentlyVisitedPaths,\n setRecentlyVisitedPaths,\n favouritePaths,\n setFavouritePaths,\n collapsedGroups,\n setCollapsedGroups\n ]);\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { ModeController } from \"./useModeController\";\nimport { readStoredString, removeStoredString, writeStoredString } from \"../util/local_storage\";\n\nconst STORAGE_KEY = \"prefers-dark-mode\";\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\n/**\n * @group Hooks and utilities\n */\nexport interface BuildModeControllerOptions {\n /**\n * `false` builds a controller that touches nothing outside React: no `dark`\n * class on `<html>`, no `prefers-color-scheme` listener, no localStorage.\n * `<Rebase>` passes it when the host app hands over its own\n * `modeController`. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\nfunction systemPrefersDark(): boolean {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return false;\n return window.matchMedia(DARK_QUERY).matches;\n}\n\n/** The stored choice, or the system's when none is stored. */\nfunction preferredMode(): \"light\" | \"dark\" {\n const stored = readStoredString(STORAGE_KEY);\n const prefersDark = stored != null ? stored === \"true\" : systemPrefersDark();\n return prefersDark ? \"dark\" : \"light\";\n}\n\n/**\n * Use this hook to build a color mode controller that determines\n * the theme of the admin.\n *\n * While enabled it owns the page's theme: it puts the `dark` class on\n * `document.documentElement`, follows `prefers-color-scheme` until the user\n * picks a mode, and remembers that pick in localStorage. When the component\n * using it unmounts, it takes away the `dark` class if it was the one that\n * added it.\n *\n * @group Hooks and utilities\n */\nexport function useBuildModeController(options: BuildModeControllerOptions = {}): ModeController {\n const enabled = options.enabled !== false;\n\n const [mode, setMode] = useState<\"light\" | \"dark\">(() => enabled ? preferredMode() : \"light\");\n\n // Whether the `dark` class on <html> is one this controller put there. A\n // class the page had before is the page's, and stays when this goes.\n const addedDarkClass = useRef(false);\n const applyToDocument = useCallback((next: \"light\" | \"dark\") => {\n const classList = document.documentElement.classList;\n if (next === \"dark\") {\n if (!classList.contains(\"dark\")) {\n classList.add(\"dark\");\n addedDarkClass.current = true;\n }\n } else {\n classList.remove(\"dark\");\n addedDarkClass.current = false;\n }\n }, []);\n\n useEffect(() => {\n if (!enabled) return;\n const initial = preferredMode();\n setMode(initial);\n applyToDocument(initial);\n\n const mediaQuery = typeof window.matchMedia === \"function\" ? window.matchMedia(DARK_QUERY) : undefined;\n const handleChange = (e: MediaQueryListEvent) => {\n if (readStoredString(STORAGE_KEY) == null) {\n const next = e.matches ? \"dark\" : \"light\";\n setMode(next);\n applyToDocument(next);\n }\n };\n mediaQuery?.addEventListener(\"change\", handleChange);\n return () => {\n mediaQuery?.removeEventListener(\"change\", handleChange);\n if (addedDarkClass.current) {\n document.documentElement.classList.remove(\"dark\");\n addedDarkClass.current = false;\n }\n };\n }, [enabled, applyToDocument]);\n\n const setModeInternal = useCallback((next: \"light\" | \"dark\" | \"system\") => {\n const resolved = next === \"system\" ? (enabled ? (systemPrefersDark() ? \"dark\" : \"light\") : \"light\") : next;\n if (enabled) {\n applyToDocument(resolved);\n if (next === \"system\") removeStoredString(STORAGE_KEY);\n else writeStoredString(STORAGE_KEY, next === \"dark\" ? \"true\" : \"false\");\n }\n setMode(resolved);\n }, [enabled, applyToDocument]);\n\n return useMemo(() => ({\n mode,\n setMode: setModeInternal\n }), [mode, setModeInternal]);\n}\n","import React, { createContext, useContext, useState, useCallback, useMemo, useRef } from \"react\";\nimport type { RebaseRegistryController, RebaseCMSConfig, RebaseStudioConfig, RebaseAuthViewConfig } from \"@rebasepro/cms-types\";\n\n/**\n * Split into two contexts to prevent infinite re-render loops:\n * - DispatchContext: stable register/unregister functions (never changes identity)\n * - StateContext: the current config values (changes when modules register)\n *\n * Feature components (RebaseAuth, RebaseCMS, RebaseStudio) only consume\n * the dispatch context, so registering does NOT cause them to re-render.\n * RebaseShell consumes state context to read the collected configs.\n */\n\ninterface RegistryDispatch {\n registerAdmin: (config: RebaseCMSConfig) => void;\n unregisterAdmin: () => void;\n registerStudio: (config: RebaseStudioConfig) => void;\n unregisterStudio: () => void;\n registerAuth: (config: RebaseAuthViewConfig) => void;\n unregisterAuth: () => void;\n}\n\ninterface RegistryState {\n cmsConfig: RebaseCMSConfig | null;\n studioConfig: RebaseStudioConfig | null;\n authConfig: RebaseAuthViewConfig | null;\n}\n\nconst RegistryDispatchContext = createContext<RegistryDispatch | undefined>(undefined);\nconst RegistryStateContext = createContext<RegistryState>({\n cmsConfig: null,\n studioConfig: null,\n authConfig: null\n});\n\nexport function RebaseRegistryProvider({ children }: { children: React.ReactNode }) {\n const [cmsConfig, setCmsConfig] = useState<RebaseCMSConfig | null>(null);\n const [studioConfig, setStudioConfig] = useState<RebaseStudioConfig | null>(null);\n const [authConfig, setAuthConfig] = useState<RebaseAuthViewConfig | null>(null);\n\n // Dispatch functions are stable — never change identity\n const dispatch = useMemo<RegistryDispatch>(() => ({\n registerAdmin: (config: RebaseCMSConfig) => setCmsConfig(config),\n unregisterAdmin: () => setCmsConfig(null),\n registerStudio: (config: RebaseStudioConfig) => setStudioConfig(config),\n unregisterStudio: () => setStudioConfig(null),\n registerAuth: (config: RebaseAuthViewConfig) => setAuthConfig(config),\n unregisterAuth: () => setAuthConfig(null)\n }), []);\n\n const state = useMemo<RegistryState>(() => ({\n cmsConfig,\nstudioConfig,\nauthConfig\n }), [cmsConfig, studioConfig, authConfig]);\n\n return (\n <RegistryDispatchContext.Provider value={dispatch}>\n <RegistryStateContext.Provider value={state}>\n {children}\n </RegistryStateContext.Provider>\n </RegistryDispatchContext.Provider>\n );\n}\n\n/**\n * Returns the full registry (state + dispatch).\n * Use this in RebaseShell where you need to read configs.\n */\nexport function useRebaseRegistry(): RebaseRegistryController {\n const dispatch = useContext(RegistryDispatchContext);\n const state = useContext(RegistryStateContext);\n if (!dispatch) {\n throw new Error(\"useRebaseRegistry must be used inside <Rebase>\");\n }\n return useMemo(() => ({ ...state,\n...dispatch }), [state, dispatch]);\n}\n\n/**\n * Returns only the stable dispatch functions.\n * Use this in feature components (RebaseAuth, RebaseCMS, RebaseStudio)\n * to avoid re-render loops.\n */\nexport function useRebaseRegistryDispatch(): RegistryDispatch {\n const dispatch = useContext(RegistryDispatchContext);\n if (!dispatch) {\n throw new Error(\"useRebaseRegistryDispatch must be used inside <Rebase>\");\n }\n return dispatch;\n}\n","\nimport { useAuthController } from \"./useAuthController\";\nimport { Entity } from \"@rebasepro/types\";\nimport { canCreateEntity, canEditEntity, canDeleteEntity, canReadCollection } from \"@rebasepro/common\";\nimport { useCallback, useMemo } from \"react\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\n/**\n * Hook to evaluate roles and permissions for the current user.\n * It abstracts away the need to pass `authController` to permission evaluation functions.\n */\nexport function usePermissions() {\n const authController = useAuthController();\n\n const canCreate = useCallback(\n (collection: AdminCollection<any>, path: string) =>\n canCreateEntity(collection, authController, path, null),\n [authController]\n );\n\n const canEdit = useCallback(\n (collection: AdminCollection<any>, path: string, entity: Entity<any> | null) =>\n canEditEntity(collection, authController, path, entity),\n [authController]\n );\n\n const canDelete = useCallback(\n (collection: AdminCollection<any>, path: string, entity: Entity<any> | null) =>\n canDeleteEntity(collection, authController, path, entity),\n [authController]\n );\n\n const canRead = useCallback(\n (collection: AdminCollection<any>) =>\n canReadCollection(collection, authController),\n [authController]\n );\n\n return useMemo(() => ({\n canCreate,\n canEdit,\n canDelete,\n canRead\n }), [canCreate, canEdit, canDelete, canRead]);\n}\n","import React, { useContext } from \"react\";\n\n/**\n * Configuration for API connectivity. Passed once at the top level\n * and available to any hook that needs `apiUrl` or `getAuthToken`.\n *\n * Individual hooks can still accept explicit overrides — this context\n * serves as a fallback to eliminate repetitive threading.\n */\nexport interface ApiConfig {\n apiUrl: string;\n /**\n * The path the backend mounts its API under, appended to {@link apiUrl}.\n *\n * `\"/api\"` by default, which is the server's default `basePath`. It is\n * carried here because a good deal of UI builds request URLs by hand\n * instead of going through the client's typed methods, and every one of\n * those sites used to write `/api` as a literal — so a backend configured\n * with any other `basePath` served an admin panel whose auth-provider\n * discovery, storage browser, history panel, user picker and Studio tools\n * all requested paths that did not exist.\n */\n apiPath: string;\n getAuthToken?: () => Promise<string | null>;\n}\n\n/** What the server uses when `basePath` is not configured. */\nexport const DEFAULT_API_PATH = \"/api\";\n\nconst ApiConfigContext = React.createContext<ApiConfig | undefined>(undefined);\n\n/**\n * Read the API config from context. Returns `undefined` if no provider is present,\n * allowing hooks to fall back to their own props.\n */\nexport function useApiConfig(): ApiConfig | undefined {\n return useContext(ApiConfigContext);\n}\n\n/**\n * `apiUrl` and `apiPath` joined, with no trailing slash — the prefix to build a\n * request URL from.\n *\n * Returns `undefined` when there is no provider, so a caller can keep its own\n * fallback rather than silently requesting a relative path.\n */\nexport function useApiBase(): string | undefined {\n const config = useApiConfig();\n if (!config?.apiUrl) return undefined;\n return config.apiUrl.replace(/\\/+$/, \"\") + (config.apiPath || DEFAULT_API_PATH);\n}\n\n/**\n * The same prefix, derived from a client rather than from context.\n *\n * For the code that holds a `RebaseClient` but sits outside (or above) an\n * `ApiConfigProvider`. Returns `undefined` when the client has no base URL,\n * which is the signal every caller already treats as \"cannot build a request\".\n */\nexport function apiBaseOf(client?: { baseUrl?: string; apiPath?: string }): string | undefined {\n if (!client?.baseUrl) return undefined;\n return client.baseUrl.replace(/\\/+$/, \"\") + (client.apiPath || DEFAULT_API_PATH);\n}\n\n/**\n * Provide API configuration (apiUrl, apiPath, getAuthToken) to the entire subtree.\n * Typically rendered inside `<Rebase>` or at the app root.\n */\nexport function ApiConfigProvider({\n apiUrl,\n apiPath = DEFAULT_API_PATH,\n getAuthToken,\n children\n}: Omit<ApiConfig, \"apiPath\"> & { apiPath?: string; children: React.ReactNode }) {\n const value = React.useMemo(() => ({ apiUrl,\napiPath,\ngetAuthToken }), [apiUrl, apiPath, getAuthToken]);\n return (\n <ApiConfigContext.Provider value={value}>\n {children}\n </ApiConfigContext.Provider>\n );\n}\n","import { useTranslation as useI18nTranslation } from \"react-i18next\";\nimport { useCallback, useMemo } from \"react\";\n\nconst REBASE_NS = \"rebase_core\";\n\n/**\n * Internal hook for translating Rebase UI strings.\n *\n * Uses the `rebase_core` i18next namespace that is initialised by\n * `RebaseI18nProvider`. Do NOT use `react-i18next` directly in internal\n * components — always go through this hook so the namespace is consistent.\n *\n * @example\n * const { t } = useTranslation();\n * <Button>{t(\"save\")}</Button>\n *\n * @internal\n */\nexport function useTranslation() {\n const { t, i18n } = useI18nTranslation(REBASE_NS);\n\n /**\n * Typed translation function scoped to RebaseTranslations keys.\n * Also supports i18next interpolation variables, e.g.\n * t(\"add_to_field\", { fieldName: \"Tags\" })\n * t(\"error_deleting\", { message: err.message })\n * t(\"sort_key_position\", { position: 2 })\n *\n * Numbers are accepted as well as strings: i18next interpolates them\n * either way, and a signature that took only strings pushed a `String()`\n * onto every call site with a count in it — `{{count}}`, `{{position}}`.\n */\n const typedT = useCallback((key: string, vars?: Record<string, string | number>): string =>\n t(key, vars) as string, [t]);\n\n return useMemo(() => ({ t: typedT,\ni18n }), [typedT, i18n]);\n}\n","import { useCallback } from \"react\";\nimport { useTranslation } from \"./useTranslation\";\n\n/**\n * The display label for a navigation group.\n *\n * A group *name* is an identifier: `StudioHomePage` orders the built-in groups\n * by comparing against `[\"Database\", \"Compute\", …]`, `navigationGroupMappings`\n * keys its icons off it, and `AppView.group` sorts views into one by string\n * equality. Translating the name at the point it is declared therefore breaks\n * the ordering and drops the icons in every locale but English — which is\n * exactly what happened the first time the Studio tool list was translated.\n *\n * So the name stays English and the *label* is translated here, at the one\n * place it is drawn. A group Rebase does not ship — anything an app declares\n * itself — has no key and is rendered as written.\n *\n * @group Hooks and utilities\n */\nexport function useNavigationGroupLabel(): (group: string) => string {\n const { t } = useTranslation();\n return useCallback((group: string) => {\n const key = `studio_group_${group.toLowerCase().replace(/[^a-z0-9]+/g, \"_\")}`;\n // i18next answers a miss with the key itself.\n const label = t(key);\n return label === key ? group : label;\n }, [t]);\n}\n","import React, { useMemo } from \"react\";\nimport { lazyChunk } from \"@rebasepro/ui\";\nimport type { ComponentRef, LazyComponentRef } from \"@rebasepro/types\";\nimport { isLazyComponentRef } from \"@rebasepro/types\";\n\n/**\n * Internal cache for resolved lazy components.\n *\n * `React.lazy()` must return the SAME wrapper across renders — if we call\n * `lazy(loader)` on every render, React will treat each result as a new\n * component type and unmount/remount on each render cycle.\n *\n * This WeakMap keeps a stable mapping from a `ComponentRef` (object/function)\n * to the `React.lazy()` wrapper it produced. Strings are keyed by a separate\n * plain Map since they can't be WeakMap keys.\n */\n\nconst lazyCache = new WeakMap<object | ((...args: any[]) => any), React.ComponentType<any>>();\n\n/**\n * Resolves a `ComponentRef` into a renderable `React.ComponentType`.\n *\n * This hook handles all three forms of `ComponentRef`:\n *\n * 1. **`LazyComponentRef`** (produced by the Vite plugin from string paths):\n * Wraps the lazy loader with `React.lazy()` for automatic code-splitting.\n *\n * 2. **`() => Promise<{ default: ComponentType }>`** (manual lazy import):\n * Also wraps with `React.lazy()`. Distinguished from regular components\n * by checking that the function has no parameters and is not a known\n * React internal (no `$$typeof`).\n *\n * 3. **Direct `React.ComponentType`**:\n * Returned as-is.\n *\n * If the ref is `undefined` or a raw string (which should never happen at\n * runtime in the browser since the Vite plugin transforms strings), returns `undefined`.\n *\n * The returned component is stable across re-renders as long as the `ref`\n * is referentially stable.\n *\n * **Usage:** Wrap the rendered component in `<Suspense>` to handle the\n * loading state of lazy components.\n *\n * @example\n * ```tsx\n * const ResolvedField = useResolvedComponent(property.ui?.Field);\n * if (!ResolvedField) return null;\n * return (\n * <Suspense fallback={<CircularProgress />}>\n * <ResolvedField {...fieldProps} />\n * </Suspense>\n * );\n * ```\n * */\nexport function useResolvedComponent<P = unknown>(\n ref: ComponentRef<P> | undefined\n): React.ComponentType<P> | undefined {\n return useMemo(() => resolveComponentRef(ref), [ref]);\n}\n\n/**\n * Wraps a loader function with `React.lazy()`, caching the result so the\n * same loader always returns the same lazy component identity.\n */\nfunction getOrCreateLazy<P>(\n key: object | ((...args: any[]) => any),\n loader: () => Promise<{ default: React.ComponentType<P> }>\n): React.ComponentType<P> {\n const cached = lazyCache.get(key);\n if (cached) return cached as React.ComponentType<P>;\n\n // SAFETY: React.lazy returns LazyExoticComponent which is structurally compatible with ComponentType<P>\n // `lazyChunk`, not `lazy`: a custom view is a chunk like any other, and a\n // tab left open across a deploy cannot fetch it either.\n const LazyComponent = lazyChunk(loader) as React.ComponentType<P>;\n lazyCache.set(key, LazyComponent);\n return LazyComponent;\n}\n\n/**\n * Pure function version of the resolver, for use outside React components.\n * Same resolution logic as `useResolvedComponent`.\n *\n * Results are cached per reference identity — calling this multiple times\n * with the same `ref` object returns the same `React.ComponentType`.\n */\nexport function resolveComponentRef<P = unknown>(\n ref: ComponentRef<P> | undefined\n): React.ComponentType<P> | undefined {\n if (ref == null) return undefined;\n\n // 1. String — should not happen at runtime (Vite transforms them).\n // Log a warning and bail out.\n if (typeof ref === \"string\") {\n console.warn(\n `[Rebase] Encountered a raw string ComponentRef (\"${ref}\") at runtime. ` +\n \"This usually means the Vite transform plugin did not process this file. \" +\n \"Ensure the file is inside the configured collectionsDir.\"\n );\n return undefined;\n }\n\n // 2. LazyComponentRef — produced by the Vite plugin from string paths.\n // The object has { __rebaseLazy: true, load: () => import(...) }.\n if (isLazyComponentRef(ref)) {\n return getOrCreateLazy<P>(\n ref as object,\n // `load()` resolves to `ComponentLike<P>` — the structural stand-in\n // that lets `ComponentRef` live in the React-free core. This function\n // is the one place that boundary is crossed, so it is the one place\n // the widening is asserted: `ComponentLike` accepts a return type of\n // `unknown` where React wants `ReactNode`. What actually arrives is\n // whatever the collection file pointed at, and rendering it is\n // React's problem either way.\n () => (ref as LazyComponentRef<P>).load() as Promise<{ default: React.ComponentType<P> }>\n );\n }\n\n // 3. Function — either a React component or a lazy import loader.\n if (typeof ref === \"function\") {\n const fn = ref as (...args: any[]) => any;\n\n // Class components (React.Component / PureComponent) have this flag\n if (fn.prototype?.isReactComponent) {\n return ref as React.ComponentType<P>;\n }\n\n // React internals (forwardRef, memo, etc.) carry $$typeof\n if (\"$$typeof\" in fn) {\n return ref as React.ComponentType<P>;\n }\n\n // A function with declared parameters (fn.length > 0) is a regular\n // component that accepts props — return as-is.\n if (fn.length > 0) {\n return ref as React.ComponentType<P>;\n }\n\n // Zero-parameter function — either a React component that takes no props,\n // or a lazy loader `() => import(...)`.\n //\n // Nothing here can be decided with certainty from the outside, so the\n // signals are ordered by how much they can be trusted, and the strongest\n // one is what the function *does*, not what it is called.\n //\n // The name alone is not usable evidence, which is what this used to rely on.\n // `admin: { Preview: () => import(\"./BodyPartsPreview\") }` gives the arrow\n // the *inferred* name \"Preview\" — JS names an anonymous function after the\n // property key it is assigned to — so the \"starts with an uppercase letter,\n // therefore a component\" rule matched every lazy loader written in the\n // documented way. The thunk was then handed to React as a component, React\n // called it, got a Promise back, and rendered nothing. That is what a blank\n // custom preview column in the demo was.\n const source = (() => {\n try {\n return Function.prototype.toString.call(fn);\n } catch {\n return \"\";\n }\n })();\n\n // A dynamic module load in the body is the strongest signal, and it outranks\n // the name: a toolchain cannot rename it away without breaking the fetch,\n // whereas the name is often not the author's at all.\n //\n // Both spellings are checked because the body reaching us depends on the\n // transform. Vite and any ESM build keep `import(...)`; ts-jest and other\n // CommonJS transforms rewrite it to `require(...)`. Matching only the first\n // passes in the browser and fails in the test suite, which is precisely how\n // this went unnoticed. A zero-argument *component* containing either call is\n // not a thing — components import at module scope.\n const loadsAChunk = /\\b(?:import|require)\\s*\\(/.test(source);\n\n if (!loadsAChunk && fn.name && /^[A-Z]/.test(fn.name)) {\n // Named like a component and does not load a chunk: a component.\n return ref as React.ComponentType<P>;\n }\n\n // Treat as a lazy loader — wrap with React.lazy, cached by identity.\n return getOrCreateLazy<P>(\n fn,\n ref as () => Promise<{ default: React.ComponentType<P> }>\n );\n }\n\n // 4. React wrapper objects (React.forwardRef, React.memo) —\n // These are objects with $$typeof but are not functions.\n if (typeof ref === \"object\" && \"$$typeof\" in (ref as object)) {\n return ref as unknown as React.ComponentType<P>;\n }\n\n // 5. Unknown shape — return undefined to be safe\n return undefined;\n}\n","import React, { useContext, useMemo } from \"react\";\nimport type { ComponentOverrideMap, OverridableComponentName } from \"@rebasepro/cms-types\";\nimport { ComponentOverrideContext } from \"../contexts/ComponentOverrideContext\";\nimport { resolveComponentRef } from \"./useResolvedComponent\";\n\n/**\n * Resolves a potentially overridden component.\n *\n * The two scopes compose, innermost first:\n * 1. Default component\n * 2. Global override (`<Rebase components>`), applied to the default\n * 3. Collection-scoped override (`admin.components`), applied to the result\n * of 2\n *\n * Supports two override modes:\n * - **Eject** (default): The override component fully replaces what it is\n * applied to.\n * - **Wrap** (`wrap: true`): The override component wraps what it is applied\n * to, passed as `OriginalComponent` in props — so a collection's wrapper\n * wraps the global override when there is one, not the built-in default.\n *\n * @param name - The overridable component name (e.g. `\"Entity.Form\"`)\n * @param DefaultComponent - The built-in default component\n * @returns The resolved component — either the default, a full replacement, or a wrapper\n *\n * @example\n * ```tsx\n * import { useComponentOverride } from \"@rebasepro/app\";\n *\n * function EntityFormWrapper(props: EntityFormProps) {\n * const ResolvedForm = useComponentOverride(\"Entity.Form\", DefaultEntityForm);\n * return <ResolvedForm {...props} />;\n * }\n * ```\n *\n * @group Hooks\n */\nexport function useComponentOverride<P>(\n name: OverridableComponentName,\n DefaultComponent: React.ComponentType<P>\n): React.ComponentType<P> {\n const { globalOverrides, collectionOverrides } = useContext(ComponentOverrideContext);\n\n return useMemo(() => {\n const AfterGlobal = applyOverride(name, globalOverrides[name], DefaultComponent);\n return applyOverride(name, collectionOverrides[name], AfterGlobal);\n }, [collectionOverrides, globalOverrides, name, DefaultComponent]);\n}\n\n/**\n * One override applied to the component below it: the override itself when it\n * ejects, a wrapper handing it `Base` as `OriginalComponent` when it wraps, and\n * `Base` unchanged when there is no override or it cannot be resolved.\n */\nfunction applyOverride<P>(\n name: OverridableComponentName,\n override: ComponentOverrideMap[OverridableComponentName],\n Base: React.ComponentType<P>\n): React.ComponentType<P> {\n if (!override) return Base;\n\n // `Component` is a `ComponentRef`, so a collection may name its override\n // by module path — which is the only form a `config/collections` file\n // can use without importing React into the backend. The resolver turns\n // a path (already rewritten to a lazy ref by the Vite transform) or an\n // `import()` into a component, and hands a direct reference straight\n // back.\n //\n // Resolved at the map's own props type — `ComponentOverride` is declared\n // without a type argument there, so the override is written against\n // `Record<string, unknown>` and the single widening to `P` happens at\n // the return, exactly where it did before this was a ref.\n const UserComponent = resolveComponentRef(override.Component);\n // An override that cannot be resolved is not an override. The resolver\n // has already said why on the console; rendering what it would have\n // replaced beats rendering nothing at all.\n if (!UserComponent) return Base;\n\n if (override.wrap) {\n const Wrapper = (props: P) => (\n <UserComponent {...(props as Record<string, unknown>)} OriginalComponent={Base} />\n );\n Wrapper.displayName = `Wrapped(${name})`;\n return Wrapper as React.ComponentType<P>;\n }\n\n return UserComponent as React.ComponentType<P>;\n}\n","import React from \"react\";\nimport { Tooltip, TooltipProps } from \"@rebasepro/ui\";\n\nexport function ErrorTooltip(props: TooltipProps) {\n return (\n <Tooltip {...props}\n className={props.className}\n tooltipClassName={\"text-red-500! bg-red-50\"}>\n {props.children}\n </Tooltip>\n );\n}\n","import React from \"react\";\nimport { ErrorTooltip } from \"./ErrorTooltip\";\nimport { AlertTriangleIcon, Button, Typography, iconSize } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\n/**\n * @group Components\n */\nexport interface ErrorViewProps {\n title?: string;\n error: Error | React.ReactElement | string,\n tooltip?: string,\n onRetry?: () => void;\n}\n\n/**\n * Generic error view. Displayed for example when an unexpected value comes\n * from the driver in a collection view.\n * @param title\n * @param error\n * @param tooltip\n * @param onRetry\n\n * @group Components\n */\nexport function ErrorView({\n title,\n error,\n tooltip,\n onRetry\n}: ErrorViewProps): React.ReactElement {\n const { t } = useTranslation();\n const message = error instanceof Error ? error.message : error;\n // Extract error code from ApiError instances (e.g. PG error codes like \"42P01\")\n const errorCode = error instanceof Error && \"code\" in error\n ? (error as Error & { code?: string }).code\n : undefined;\n\n const body = (\n <div className=\"flex flex-col m-2\">\n <div className=\"flex items-start gap-2.5\">\n <AlertTriangleIcon\n size={iconSize.smallest}\n className=\"shrink-0 text-red-500 dark:text-red-400 mt-0.5\"\n />\n <div className=\"flex-1 min-w-0\">\n {title && (\n <Typography\n variant=\"body2\"\n color=\"primary\"\n className=\"font-semibold mb-0.5\"\n >\n {title}\n </Typography>\n )}\n <Typography\n variant=\"body2\"\n color=\"secondary\"\n className=\"leading-relaxed\"\n >\n {message}\n </Typography>\n {errorCode && (\n <span\n className=\"inline-block mt-1 px-1.5 py-0.5 text-[10px] font-mono rounded bg-surface-raised text-text-secondary\"\n >\n {errorCode}\n </span>\n )}\n {onRetry && (\n <div className=\"mt-3\">\n <Button\n variant=\"outlined\"\n color=\"neutral\"\n size=\"small\"\n onClick={onRetry}\n className=\"font-semibold\"\n >\n {t(\"retry\")}\n </Button>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n\n if (tooltip) {\n return (\n <ErrorTooltip title={tooltip}>\n {body}\n </ErrorTooltip>\n );\n }\n return body;\n}\n","import React from \"react\";\nimport { deepEqual as equal } from \"fast-equals\";\n\n/**\n * Hack to prevent data updates for incomplete callbacks from Firestore\n * triggers.\n * If any deps change, the update is immediate\n * @param data\n * @param deps\n * @param timeoutMs\n */\nexport function useDebouncedData<T>(data: T[], deps: unknown, timeoutMs = 5000) {\n\n const [deferredData, setDeferredData] = React.useState(data);\n const dataLength = React.useRef(deferredData.length ?? 0);\n const pendingUpdate = React.useRef(false);\n const currentDeps = React.useRef(deps);\n\n const haveDepsChanged = !equal(currentDeps.current, deps);\n const immediateUpdate = data.length >= dataLength.current || haveDepsChanged;\n\n React.useEffect(() => {\n\n const performUpdate = () => {\n if (!equal(deferredData, data)) {\n currentDeps.current = deps;\n dataLength.current = data.length;\n setDeferredData(data);\n }\n pendingUpdate.current = false;\n };\n\n pendingUpdate.current = true;\n\n let handler: ReturnType<typeof setTimeout> | undefined;\n if (immediateUpdate)\n performUpdate()\n else\n handler = setTimeout(performUpdate, timeoutMs);\n\n return () => {\n clearTimeout(handler);\n if (pendingUpdate.current && immediateUpdate)\n performUpdate();\n };\n }, [data, timeoutMs, deps, immediateUpdate]);\n\n return immediateUpdate ? data : deferredData;\n}\n","import type { Properties, Property } from \"@rebasepro/types\";\n\n/**\n * The property at a dotted path, walking `map` children — `address.street`.\n *\n * The value counterpart is `getValueInPath` in `@rebasepro/utils`; this is the\n * schema half, and the two have to be used together. Reading a dotted path off\n * an entity while looking its property up with a flat `properties[path]` gives\n * the value and `undefined` for how to render it, which is how a declared title\n * on a nested field silently fell back to a derived one.\n *\n * There were three copies of this: one private to `useColumnsIds`, one exported\n * from the admin layer, and the flat lookup in the title resolver that was not\n * this function at all. This is the one, in the lowest layer that needs it —\n * admin re-exports it under the name it already published.\n */\nexport function getPropertyInPath(properties: Properties, path: string): Property | undefined {\n if (typeof properties !== \"object\" || !properties) return undefined;\n if (path in properties) {\n return (properties as Record<string, Property>)[path];\n }\n if (path.includes(\".\")) {\n const pathSegments = path.split(\".\");\n const childProperty = (properties as Record<string, Property>)[pathSegments[0]];\n if (typeof childProperty === \"object\" && childProperty?.type === \"map\" && childProperty.properties) {\n return getPropertyInPath(childProperty.properties, pathSegments.slice(1).join(\".\"));\n }\n }\n return undefined;\n}\n","/**\n * Property presentation helpers.\n *\n * These read a property's admin block — `readOnly`, `disabled.hidden`, the\n * declarative `conditions` — and lived in `@rebasepro/common`, which is on the\n * backend's dependency path. Nothing in core ever called them: `isReadOnly`,\n * `isHidden` and `applyPropertyConditions` are the panel's alone.\n *\n * `applyPropertyConditions` is called by the record form, through\n * `resolveFormProperty`, both where a field is laid out and where the form is\n * judged on save — so a rule the collection editor writes hides, disables and\n * requires what it says it does, and a field it hides is not held against the\n * save. Until that was wired, the evaluator was reached only from its own tests.\n *\n * A condition may also be a literal: `hidden`/`readOnly`/`disabled` stated as a\n * plain boolean rather than as a rule. A literal needs no context, so\n * `isHidden`/`isReadOnly`/`isDisabled` answer it directly, and those three\n * gates are consulted everywhere a field is laid out — including places with\n * no entity to evaluate a rule against.\n */\nimport type { ConditionContext, ConditionRule, EnumValueConfig, Property, PropertyConditions, ReferenceProperty } from \"@rebasepro/types\";\nimport type { AdminArrayOptions, AdminReferenceOptions } from \"@rebasepro/cms-types\";\nimport { evaluateCondition } from \"@rebasepro/common\";\n\n/**\n * A condition stated as a literal rather than as a rule.\n *\n * `PropertyConditions` accepts either, and the two are answered in different\n * places: a rule needs a context and so can only be evaluated while rendering a\n * particular entity, but a literal is already the answer. Reading it here is\n * what makes `hidden: true` work without every gate below having to build a\n * condition context first — and without the caller reaching for\n * `{ \"==\": [1, 1] }` to say something it can say with a boolean.\n */\nfunction literalCondition(condition: ConditionRule | undefined): boolean {\n return condition === true;\n}\n\nexport function isReadOnly(property: Property): boolean {\n if (property.admin?.readOnly)\n return true;\n if (literalCondition(property.conditions?.readOnly))\n return true;\n if (property.type === \"date\") {\n if (property.autoValue)\n return true;\n }\n if (property.type === \"reference\") {\n return !property.path && !(\"Field\" in (property.admin || {}) && property.admin?.Field);\n }\n return false;\n}\n\nexport function isHidden(property: Property): boolean {\n if (literalCondition(property.conditions?.hidden)) return true;\n return typeof property.admin?.disabled === \"object\" && Boolean(property.admin?.disabled.hidden);\n}\n\n/**\n * Whether the field is disabled by its own declaration, ignoring form state.\n *\n * The `admin.disabled` block and `conditions.disabled: true` say the same thing\n * two ways, so every caller that gated on the first now asks here instead of\n * growing a second check of its own.\n */\nexport function isDisabled(property: Property): boolean {\n return Boolean(property.admin?.disabled) || literalCondition(property.conditions?.disabled);\n}\n\nexport function applyPropertyConditions(\n property: Property,\n context: ConditionContext\n): Property {\n const { conditions } = property;\n if (!conditions) return property;\n\n const result = { ...property };\n // The admin block is the collection's own object, shared by every record\n // the form opens. Written into in place, a rule that disabled one record's\n // field disabled it for every record after, whatever their values.\n if (result.admin) result.admin = { ...result.admin };\n\n // ═══════════════════════════════════════════════════════════════════════\n // FIELD STATE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Evaluate disabled condition\n if (conditions.disabled) {\n const isDisabled = evaluateCondition(conditions.disabled, context);\n if (isDisabled) {\n result.admin = result.admin || {};\n result.admin.disabled = {\n clearOnDisabled: conditions.clearOnDisabled ?? false,\n disabledMessage: conditions.disabledMessage,\n hidden: false\n };\n }\n }\n\n // Evaluate hidden condition\n if (conditions.hidden) {\n const isHidden = evaluateCondition(conditions.hidden, context);\n if (isHidden) {\n result.admin = result.admin || {};\n result.admin.disabled = {\n ...(typeof result.admin?.disabled === \"object\" ? result.admin.disabled : {}),\n hidden: true,\n clearOnDisabled: conditions.clearOnDisabled ?? false\n };\n }\n }\n\n // Evaluate readOnly condition\n if (conditions.readOnly) {\n const isReadOnly = evaluateCondition(conditions.readOnly, context);\n if (isReadOnly) {\n result.admin = result.admin || {};\n result.admin.readOnly = true;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALIDATION CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Evaluate required condition\n if (conditions.required !== undefined) {\n const isRequired = Boolean(evaluateCondition(conditions.required, context));\n result.validation = {\n ...result.validation,\n required: isRequired,\n requiredMessage: conditions.requiredMessage ?? result.validation?.requiredMessage\n };\n }\n\n // A bound for a number's value, a string's length or an array's size —\n // the same `validation.min`/`max` each of those types already reads.\n if ((conditions.min !== undefined || conditions.max !== undefined)\n && (result.type === \"number\" || result.type === \"string\" || result.type === \"array\")) {\n const bound = (rule: PropertyConditions[\"min\"]): number | undefined => {\n if (rule === undefined) return undefined;\n const value = evaluateCondition(rule, context);\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n };\n const min = bound(conditions.min);\n const max = bound(conditions.max);\n result.validation = {\n ...result.validation,\n ...(min !== undefined ? { min } : {}),\n ...(max !== undefined ? { max } : {})\n };\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALUE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Apply default value for new entities\n if (context.isNew && conditions.defaultValue !== undefined) {\n result.defaultValue = evaluateCondition(conditions.defaultValue, context) as Property[\"defaultValue\"];\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // ENUM CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (\"enum\" in result && result.enum && (conditions.enumConditions || conditions.allowedEnumValues || conditions.excludedEnumValues)) {\n (result as Record<string, unknown>).enum = applyEnumConditions(\n result.enum as EnumValueConfig[],\n conditions,\n context\n );\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFERENCE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"reference\") {\n if (conditions.referencePath) {\n (result as ReferenceProperty).path = evaluateCondition(conditions.referencePath, context) as string;\n }\n if (conditions.referenceFilter) {\n result.admin = result.admin || {};\n (result.admin as AdminReferenceOptions).fixedFilter =\n evaluateCondition(conditions.referenceFilter, context) as AdminReferenceOptions[\"fixedFilter\"];\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // ARRAY CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"array\") {\n if (conditions.canAddElements !== undefined) {\n result.admin = result.admin || {};\n (result.admin as AdminArrayOptions).canAddElements = evaluateCondition(conditions.canAddElements, context) as boolean;\n }\n if (conditions.sortable !== undefined) {\n result.admin = result.admin || {};\n (result.admin as AdminArrayOptions).sortable = evaluateCondition(conditions.sortable, context) as boolean;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // STORAGE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"string\" && result.storage && (conditions.acceptedFiles !== undefined || conditions.maxFileSize !== undefined)) {\n const storage = { ...result.storage };\n if (conditions.acceptedFiles !== undefined) {\n const accepted = objectToArray(evaluateCondition(conditions.acceptedFiles, context));\n if (accepted.length > 0) storage.acceptedFiles = accepted;\n }\n if (conditions.maxFileSize !== undefined) {\n const maxSize = evaluateCondition(conditions.maxFileSize, context);\n if (typeof maxSize === \"number\" && Number.isFinite(maxSize)) storage.maxSize = maxSize;\n }\n result.storage = storage;\n }\n\n return result;\n}\n\n/**\n * Convert an object with numeric keys back to an array.\n * Firestore stores arrays as {\"0\": \"a\", \"1\": \"b\"} to avoid nested arrays.\n */\nfunction objectToArray(obj: unknown): string[] {\n if (Array.isArray(obj)) return obj.map(String);\n if (obj && typeof obj === \"object\") {\n const keys = Object.keys(obj);\n if (keys.length > 0 && keys.every(k => !isNaN(Number(k)))) {\n return keys\n .sort((a, b) => Number(a) - Number(b))\n .map(k => (obj as Record<string, unknown>)[k])\n .filter((v): v is string => typeof v === \"string\" || typeof v === \"number\")\n .map(String);\n }\n }\n return [];\n}\n\n/**\n * Apply enum-specific conditions to filter and modify enum values.\n */\nfunction applyEnumConditions(\n enumValues: EnumValueConfig[],\n conditions: PropertyConditions,\n context: ConditionContext\n): EnumValueConfig[] {\n let result = [...enumValues];\n\n // Apply allowedEnumValues filter\n if (conditions.allowedEnumValues) {\n const allowed = evaluateCondition(conditions.allowedEnumValues, context);\n // Handle both array format and object-with-numeric-keys format (Firestore workaround)\n const allowedArray = objectToArray(allowed);\n if (allowedArray.length > 0) {\n result = result.filter(ev => allowedArray.includes(String(ev.id)));\n }\n }\n\n // Apply excludedEnumValues filter\n if (conditions.excludedEnumValues) {\n const excluded = evaluateCondition(conditions.excludedEnumValues, context);\n // Handle both array format and object-with-numeric-keys format\n const excludedArray = objectToArray(excluded);\n if (excludedArray.length > 0) {\n result = result.filter(ev => !excludedArray.includes(String(ev.id)));\n }\n }\n\n // Apply individual enum conditions\n if (conditions.enumConditions) {\n result = result\n .map(ev => {\n const evConditions = conditions.enumConditions?.[ev.id];\n if (!evConditions) return ev;\n\n // Check hidden condition first\n if (evConditions.hidden && evaluateCondition(evConditions.hidden, context)) {\n return null; // Will be filtered out\n }\n\n // Check disabled condition\n if (evConditions.disabled && evaluateCondition(evConditions.disabled, context)) {\n return {\n ...ev,\n disabled: true\n };\n }\n\n return ev;\n })\n .filter((ev): ev is EnumValueConfig => ev !== null);\n }\n\n return result;\n}\n","import type { Property, MapProperty, Properties, RelationProperty } from \"@rebasepro/types\";\nimport { useMemo } from \"react\";\n;\nimport { getChildViewDeclaringProperties, getChildViewRelationPropertyKeys, getDeclaredPrimaryKeys, getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { getPropertyInPath } from \"../../collections/property-path\";\nimport { isDisabled } from \"../../collections/property_presentation\";\n\nexport type PropertyColumnConfig = {\n key: string;\n disabled: boolean;\n};\n\nexport function getSubcollectionColumnId(collection: AdminCollection<any>) {\n return `subcollection:${collection.slug}`;\n}\n\n/**\n * The jump-to-tab columns a collection table does not need, because the relation\n * behind them already has a column of its own.\n *\n * Every child view gets a 200px button column that opens its tab. For a relation\n * declared in `relations` that button is the relation's only presence in the\n * table. For one declared as a property it is the second: the property's own\n * column is already there, hydrated by the list fetch's `include`\n * (`getRelationIncludeParams`), showing the child rows themselves — and carrying the *same heading*, because the tab\n * takes its name from the declaring property. Two columns called \"Applications\",\n * one of them a button, and nothing in the header to tell them apart.\n *\n * The property column wins: it shows what the children are, and each chip in it\n * opens one. The tab stays reachable by opening the record, which is what the\n * rest of the table's rows do anyway.\n *\n * Unless the author hid that column — `hideFromCollection` on the property, or a\n * `propertiesOrder` that omits it, is a statement about the column and not about\n * the relation, so the button comes back rather than the relation dropping out\n * of the table altogether.\n */\nexport function getRedundantChildViewColumnIds<M extends Record<string, any>>(collection: AdminCollection<M>): Set<string> {\n const redundant = new Set<string>();\n const properties = collection.properties ?? {};\n const order = collection.propertiesOrder as string[] | undefined;\n\n for (const [viewKey, propertyKey] of getChildViewDeclaringProperties(collection)) {\n const property = properties[propertyKey] as Property | undefined;\n if (!property || property.admin?.hideFromCollection) continue;\n if (order && !order.includes(propertyKey)) continue;\n redundant.add(`subcollection:${viewKey}`);\n }\n\n return redundant;\n}\n\nexport function useColumnIds<M extends Record<string, any>>(collection: AdminCollection<M>, includeSubcollections: boolean): PropertyColumnConfig[] {\n return useMemo(() => {\n const columns = collection.propertiesOrder\n ? hideAndExpandKeys(collection, collection.propertiesOrder)\n : getDefaultColumnKeys(collection, includeSubcollections);\n const keyInIdColumn = getKeyShownInIdColumn(collection);\n return keyInIdColumn ? columns.filter(column => column.key !== keyInIdColumn) : columns;\n }, [collection, includeSubcollections]);\n}\n\n/**\n * The property whose value a collection table's own ID column already shows.\n *\n * Every table opens with an ID column: the row's id, beside its checkbox and\n * menu. A single declared key *is* that id, so its property's column repeated\n * it — two columns headed \"ID\" with the same value, in the collection view and\n * in the relation picker alike. The record form treats that key the same way\n * (routed out of the fields and into the record block), and so does the CSV\n * export (its own `id` column, never the property's).\n *\n * A composite key is not the row's id — `entity.id` is a token built on top of\n * its columns, which are data — so its columns stay. Nor is an `id` property\n * no `isId` declares (see `getDeclaredPrimaryKeys`). With\n * `hideIdFromCollection` the ID column shows no id, and the property's column\n * is where it is read.\n */\nfunction getKeyShownInIdColumn<M extends Record<string, any>>(collection: AdminCollection<M>): string | undefined {\n if (collection.hideIdFromCollection) return undefined;\n const keys = getDeclaredPrimaryKeys(collection);\n return keys.length === 1 ? keys[0].fieldName : undefined;\n}\n\nfunction hideAndExpandKeys<M extends Record<string, any>>(collection: AdminCollection<M>, keys: string[]): PropertyColumnConfig[] {\n\n // First, figure out which spread map roots have individual child keys in the order\n // If so, we should NOT auto-expand them - just use the explicit child keys\n const rootsWithExplicitChildren = new Set<string>();\n for (const key of keys) {\n if (key.includes(\".\")) {\n const rootKey = key.split(\".\")[0];\n const rootProperty = collection.properties[rootKey];\n if (rootProperty && rootProperty.type === \"map\" && rootProperty.admin?.spreadChildren && rootProperty.properties) {\n rootsWithExplicitChildren.add(rootKey);\n }\n }\n }\n\n // Track processed keys to avoid duplicates\n const processedPropertyKeys = new Set<string>();\n\n // Both column paths funnel through here, including a `propertiesOrder` that\n // was saved back with the button column in it.\n const redundantChildViewColumns = getRedundantChildViewColumnIds(collection);\n\n const result = keys.flatMap((key) => {\n // Skip if already processed (handles duplicates in propertiesOrder)\n if (processedPropertyKeys.has(key)) return [null];\n if (redundantChildViewColumns.has(key)) return [null];\n\n // Check if it's a top-level property\n const property = collection.properties[key];\n if (property) {\n processedPropertyKeys.add(key);\n if (property.admin?.hideFromCollection)\n return [null];\n if (property.admin?.disabled && typeof property.admin?.disabled === \"object\" && property.admin?.disabled.hidden)\n return [null];\n\n if (property.type === \"map\" && property.admin?.spreadChildren && property.properties) {\n // Check if this spread map has explicit child keys in propertiesOrder\n if (rootsWithExplicitChildren.has(key)) {\n // DON'T auto-expand - the children are explicitly listed elsewhere\n return [null];\n }\n // Auto-expand all children\n const childConfigs = getColumnKeysForProperty(property, key);\n childConfigs.forEach(c => processedPropertyKeys.add(c.key));\n return childConfigs;\n }\n return [{\n key,\n disabled: isDisabled(property) || Boolean(property.admin?.readOnly)\n }];\n }\n\n // Check if it's a nested key like \"data.mode\" (for spread map properties)\n if (key.includes(\".\")) {\n const rootKey = key.split(\".\")[0];\n const rootProperty = collection.properties[rootKey];\n\n if (rootProperty && rootProperty.type === \"map\" && rootProperty.properties) {\n const nestedProperty = getPropertyInPath(collection.properties, key) as Property | undefined;\n if (nestedProperty) {\n processedPropertyKeys.add(key);\n // Mark root as seen\n processedPropertyKeys.add(rootKey);\n\n if (nestedProperty.admin?.hideFromCollection)\n return [null];\n if (nestedProperty.admin?.disabled && typeof nestedProperty.admin?.disabled === \"object\" && nestedProperty.admin?.disabled.hidden)\n return [null];\n\n return [{\n key,\n disabled: isDisabled(rootProperty) || Boolean(rootProperty.admin?.readOnly) ||\n isDisabled(nestedProperty) || Boolean(nestedProperty.admin?.readOnly)\n }];\n }\n }\n }\n\n // Check additional fields\n const additionalField = collection.additionalFields?.find(field => field.key === key);\n if (additionalField) {\n return [{\n key,\n disabled: true\n }];\n }\n\n // Check subcollections\n const subcollections = getSubcollections(collection);\n if (subcollections) {\n const subCollection = subcollections\n .find(subCol => getSubcollectionColumnId(subCol) === key);\n if (subCollection) {\n return [{\n key,\n disabled: true\n }];\n }\n }\n\n return [null];\n }).filter(Boolean) as PropertyColumnConfig[];\n\n // Add any missing properties that weren't in propertiesOrder\n // This ensures properties NEVER disappear\n for (const propKey of Object.keys(collection.properties)) {\n // Skip if already processed\n if (processedPropertyKeys.has(propKey)) continue;\n\n const property = collection.properties[propKey];\n if (!property) continue;\n if (property.admin?.hideFromCollection) continue;\n if (property.admin?.disabled && typeof property.admin?.disabled === \"object\" && property.admin?.disabled.hidden) continue;\n\n if (property.type === \"map\" && property.admin?.spreadChildren && property.properties) {\n // For spread maps, add all children that weren't already added\n const allChildConfigs = getColumnKeysForProperty(property as MapProperty, propKey);\n for (const childConfig of allChildConfigs) {\n if (!processedPropertyKeys.has(childConfig.key)) {\n result.push(childConfig);\n processedPropertyKeys.add(childConfig.key);\n }\n }\n } else {\n result.push({\n key: propKey,\n disabled: isDisabled(property) || Boolean(property.admin?.readOnly)\n });\n processedPropertyKeys.add(propKey);\n }\n }\n\n return result;\n}\n\nfunction getDefaultColumnKeys<M extends Record<string, any> = any>(collection: AdminCollection<M>, includeSubCollections: boolean) {\n const propertyKeys = Object.keys(collection.properties);\n\n const additionalFields = collection.additionalFields ?? [];\n const subCollections: AdminCollection[] = getSubcollections(collection) ?? [];\n\n const columnIds: string[] = [\n ...propertyKeys,\n // Filter out additional fields whose key already exists in propertyKeys to avoid duplicate column keys\n ...additionalFields.filter((field) => !propertyKeys.includes(field.key)).map((field) => field.key)\n ];\n\n if (includeSubCollections) {\n const subCollectionIds = subCollections\n .map((collection) => getSubcollectionColumnId(collection));\n columnIds.push(...subCollectionIds.filter((subColId) => !columnIds.includes(subColId)));\n }\n\n return hideAndExpandKeys(collection, columnIds);\n}\n\nexport function getColumnKeysForProperty(property: Property, key: string, disabled?: boolean): PropertyColumnConfig[] {\n // A key with no property behind it describes no column. Callers walk whole\n // property maps here to build a table's columns, so reading `.type` off a\n // hole threw away every other column with it.\n if (!property) return [];\n if (property.type === \"map\" && property.admin?.spreadChildren && property.properties) {\n return Object.entries(property.properties)\n .flatMap(([childKey, childProperty]) => getColumnKeysForProperty(\n childProperty as Readonly<Property>,\n `${key}.${childKey}`,\n disabled || isDisabled(property) || Boolean(property.admin?.readOnly))\n );\n }\n return [{\n key,\n disabled: disabled || isDisabled(property) || Boolean(property.admin?.readOnly)\n }];\n}\n\nexport function getFormFieldKeys(collection: AdminCollection): string[] {\n const properties = collection.properties ?? {};\n // A many-relation the entity view already lists as a tab is not an input:\n // the tab is the treatment, and rendering the same declaration again as a\n // picker asked the author to select a collection's own children from a\n // dropdown. `renderInForm` is how a project that wants the picker asks for\n // it back — opt in, because the tab is the default.\n const consumedByChildView = getChildViewRelationPropertyKeys(collection);\n const propertyKeys = Object.keys(properties).filter(key => {\n if (!consumedByChildView.has(key)) return true;\n return (properties[key] as RelationProperty).admin?.renderInForm === true;\n });\n const additionalFields = collection.additionalFields ?? [];\n const allKeys = [\n ...propertyKeys,\n ...additionalFields.map((field) => field.key)\n ];\n\n if (collection.propertiesOrder) {\n return collection.propertiesOrder.filter(key => allKeys.includes(key));\n }\n return allKeys;\n}\n","import { useMemo } from \"react\";\nimport { Entity } from \"@rebasepro/types\";\n\nexport interface DataOrderProps<M extends Record<string, any>> {\n data: Entity<M>[];\n entitiesDisplayedFirst?: Entity<M>[];\n}\n\n/**\n * This hook is used to have some entities at the beginning of data.\n *\n * The result is the same array until `data` or `entitiesDisplayedFirst`\n * changes. It used to be rebuilt on every call whenever rows were pinned, so\n * the table controller around it — and everything rendering from that — was\n * new on every render.\n *\n * @param path\n * @param entitiesDisplayedFirst\n * @group Hooks and utilities\n */\nexport function useDataOrder<M extends Record<string, any>>(\n {\n data,\n entitiesDisplayedFirst\n }: DataOrderProps<M>): Entity<M>[] {\n\n return useMemo(() => {\n if (!entitiesDisplayedFirst)\n return data;\n const displayedFirstId = new Set(entitiesDisplayedFirst.map((e) => e.id));\n return [...entitiesDisplayedFirst, ...data.filter((e) => !displayedFirstId.has(e.id))];\n }, [data, entitiesDisplayedFirst]);\n\n}\n","\nimport React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useLocation } from \"react-router\";\n\nimport { useData, useRebaseContext } from \"../../hooks\";\nimport { useDataOrder } from \"../../hooks/data/useDataOrder\";\nimport { toFindParams } from \"../../hooks/data/collectionQuery\";\nimport { CollectionWindow } from \"../../hooks/data/collectionWindow\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\nimport { Entity, EntityReference, EntityRelation, FilterValues, OrderBySpec, OrderByTuple, User, WhereFilterOp } from \"@rebasepro/types\";\nimport { normalizeOrderBy, serializeOrderBy } from \"@rebasepro/common\";\nimport { EntityTableController, RebaseContext, SelectedCellProps, AdminCollection } from \"@rebasepro/cms-types\";\nimport { ScrollRestorationController } from \"./useScrollRestoration\";\n\nexport const DEFAULT_PAGE_SIZE = 50;\n\n/**\n * Rows held with `pagination: false` past which development builds warn. The\n * docs promise every row, so they are all loaded; but tens of thousands of\n * them sit in memory and re-render on every change, and nothing said so.\n */\nexport const UNPAGINATED_WARNING_ROWS = 10_000;\n\n/** The collections already warned about, so a warning is said once per collection. */\nconst warnedUnpaginated = new Set<string>();\n\nexport type DataTableControllerProps<M extends Record<string, any> = any> = {\n /**\n * Full path where the data of this table is located\n */\n path: string;\n /**\n * The collection that is represented by this config.\n */\n collection: AdminCollection<M>;\n /**\n * List of entities that will be displayed on top, no matter the ordering.\n * This is used for reference fields selection\n */\n entitiesDisplayedFirst?: Entity<M>[];\n\n lastDeleteTimestamp?: number;\n\n /**\n * Force filter to be applied to the table.\n */\n fixedFilter?: FilterValues<string>;\n\n scrollRestoration?: ScrollRestorationController;\n\n /**\n * When set to true the filters and sort will be updated in the URL\n */\n updateUrl?: boolean;\n\n /**\n * Read rows at all. Defaults to `true`. `false` closes the subscription and\n * reads nothing — for a view that keeps the controller for its search and\n * filters but draws its rows some other way, like the board, whose columns\n * each read their own. The rows already held stay until it is enabled\n * again, which reads afresh.\n */\n enabled?: boolean;\n\n}\n\n/**\n * Use this hook to build a controller for the {@link DataCollectionTable}.\n * This controller is bound to data in a path in your specified driver.\n *\n * Note that you can build your own hook returning a {@link EntityTableController}\n * if you would like to display different data.\n *\n * @param path\n * @param collection\n * @param scrollRestoration\n * @param entitiesDisplayedFirst\n * @param lastDeleteTimestamp\n * @param fixedFilterFromProps\n * @param updateUrl\n */\nexport function useDataTableController<M extends Record<string, any> = any, USER extends User = User>(\n {\n path,\n collection,\n scrollRestoration,\n entitiesDisplayedFirst,\n lastDeleteTimestamp,\n fixedFilter: fixedFilterFromProps,\n updateUrl,\n enabled = true\n }: DataTableControllerProps<M>)\n : EntityTableController<M> {\n\n const {\n defaultFilter,\n sort,\n fixedFilter: fixedFilterFromCollection\n } = collection;\n\n const [popupCell, setPopupCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);\n const dataClient = useData();\n\n const fixedFilter = fixedFilterFromProps ?? fixedFilterFromCollection;\n const paginationEnabled = collection.pagination === undefined || Boolean(collection.pagination);\n // `pagination: 0` says *disabled*, not \"a page of no rows\" — which is why\n // it does not reach `paginationEnabled` above. It must not reach the page\n // size either: this value is handed on to the card, board and relation\n // views as the number of rows each of them reads, and a zero there is a\n // `limit=0` the API refuses.\n const pageSize = typeof collection.pagination === \"number\" && collection.pagination > 0\n ? collection.pagination\n : DEFAULT_PAGE_SIZE;\n\n const location = useLocation();\n\n const [searchString, setSearchString] = React.useState<string | undefined>(() => {\n if (updateUrl) {\n return parseSearchString(location.search);\n }\n return undefined;\n });\n\n const checkFilterCombination = useCallback((filterValues: FilterValues<any>,\n sortBy?: OrderByTuple[]) => {\n // PostgREST/SQL can handle arbitrary filter/sort combinations natively.\n return true;\n }, []);\n\n // The collection's default, in the list form the controller works in.\n // `collection.sort` accepts either spelling so a one-key default stays the\n // one-liner it always was.\n const sortInternal = useMemo(() => {\n const keys = normalizeOrderBy(sort as OrderBySpec | undefined);\n if (keys && fixedFilter && !checkFilterCombination(fixedFilter, keys)) {\n console.warn(\"Initial sort is not compatible with the force filter. Ignoring initial sort\");\n return undefined;\n }\n return keys;\n }, [sort, fixedFilter]);\n\n const {\n filterValues: filterUrl,\n sortBy: sortUrl\n } = parseFilterAndSort(location.search);\n\n const [filterValues, setFilterValues] = React.useState<FilterValues<Extract<keyof M, string> | (string & {})> | undefined>(\n () => applyFixedFilter((updateUrl ? filterUrl : undefined) ?? defaultFilter ?? undefined, fixedFilter));\n const [sortBy, setSortBy] = React.useState<OrderByTuple<Extract<keyof M, string> | (string & {})>[] | undefined>((updateUrl ? sortUrl : undefined) ?? sortInternal);\n\n // Sync filter/sort state from URL on browser navigation (back/forward).\n //\n // Only ever on an actual *change* of the URL, which is not the same as \"not\n // the first run\". `useUpdateUrl` writes with `window.history.replaceState`,\n // which react-router does not observe, so the `location` read here keeps\n // reporting the search string this view was mounted with — normally the\n // empty one — no matter what the address bar says. The guard used to be a\n // one-shot ref that skipped the first run and armed itself for every run\n // after; the *second* run then parsed that unchanged, empty search and\n // called `setSortBy(undefined)`, throwing away the collection's `sort`\n // before anything had asked for a different one. Re-running is easy to\n // trigger — this effect depends on `fixedFilter`, a prop most callers pass\n // as a fresh object literal.\n //\n // The visible symptom was a collection that ignored its own default sort: it\n // subscribed correctly, then immediately re-subscribed with no `orderBy` at\n // all, and the second answer replaced the first.\n //\n // Nor on a URL that only repeats what this hook wrote. Opening a record\n // carries the address bar's query onto the record URL (`withListState`), so\n // react-router reports a new `location.search` that is this hook's own\n // state coming back. Parsing it into the live filter made every record\n // click a round trip through the URL format, and the URL cannot say\n // everything the state can: an absent filter param reads back as \"the\n // collection's default\", so a default the user had cleared came straight\n // back on the next click.\n const lastSyncedSearchRef = React.useRef<string>(location.search);\n const lastWrittenListStateRef = React.useRef<string | undefined>(undefined);\n useEffect(() => {\n if (!updateUrl) return;\n // Unchanged URL — including the initial mount, where the state\n // initialisers have already applied the URL params and the collection\n // defaults — carries nothing to sync.\n if (lastSyncedSearchRef.current === location.search) return;\n lastSyncedSearchRef.current = location.search;\n\n const { filterValues: urlFilterValues, sortBy: urlSortBy } = parseFilterAndSort(location.search);\n const urlSearchString = parseSearchString(location.search);\n if (encodeListState(urlFilterValues, urlSortBy, urlSearchString) === lastWrittenListStateRef.current) return;\n\n setFilterValues(applyFixedFilter<Extract<keyof M, string> | (string & {})>(urlFilterValues ?? defaultFilter, fixedFilter));\n if (urlSortBy && fixedFilter && !checkFilterCombination(fixedFilter, urlSortBy)) {\n console.warn(\"URL sort is not compatible with the force filter.\");\n } else {\n // No `__sort` is the collection's default, the same reading the\n // state initialiser gives it on mount — not \"no sort at all\".\n setSortBy((urlSortBy ?? sortInternal) as OrderByTuple<Extract<keyof M, string> | (string & {})>[] | undefined);\n }\n\n setSearchString(urlSearchString);\n }, [location.search, updateUrl, fixedFilter, checkFilterCombination, sortInternal]);\n\n useUpdateUrl(filterValues, sortBy, searchString, updateUrl, lastWrittenListStateRef);\n\n const collectionScroll = scrollRestoration?.getCollectionScroll(path, filterValues);\n /**\n * How many rows to ask for on mount: as many as were loaded last time this\n * (path, filters) pair was on screen, so returning to a view that had been\n * scrolled does not snap back to the first page.\n *\n * The floor is not cosmetic. This used to be `?? pageSize`, which falls back\n * on `null`/`undefined` but not on `0` — and a saved entry whose `data` is\n * empty is entirely ordinary: `updateCollectionScroll` records what was on\n * screen, so any filter combination matching no rows persists `data: []`\n * under its own key. Restoring that gave `itemCount === 0`, which became\n * `limit=0` on the read, which the API rejects (400 `INVALID_LIMIT`) —\n * the collection rendered an error instead of a table, and a client bug\n * read as an API failure.\n *\n * The cache is left free to record an empty view honestly: that it *was*\n * empty is a true fact, and refusing to store it would leave the previous,\n * now-wrong offset and rows in place for a view whose rows have gone. What\n * is wrong is reading \"nothing was restored\" as \"ask for nothing\".\n */\n // The rows kept sit at `dataOffset` (0 when absent): the view held every\n // row up to the last of them.\n const restoredItemCount = collectionScroll ? (collectionScroll.dataOffset ?? 0) + collectionScroll.data.length : 0;\n const initialItemCount = restoredItemCount > 0 ? restoredItemCount : pageSize;\n\n /**\n * What a restored view shows before anything is read: the rows kept for\n * it, where they sat. Kept rows that start past the first row are\n * positions only (`sparseData`, the rows above them not read); `data`\n * holds no row until the window has read the first page, so a view that\n * draws `data` never draws them at the wrong place.\n */\n const [restored] = useState(() => {\n if (!collectionScroll || collectionScroll.data.length === 0) return undefined;\n const offset = collectionScroll.dataOffset ?? 0;\n return {\n seed: { offset, rows: collectionScroll.data as Entity<M>[] },\n rows: offset === 0 ? collectionScroll.data as Entity<M>[] : [],\n sparse: offset === 0\n ? undefined\n : Array.from({ length: offset + collectionScroll.data.length },\n (_, i) => i < offset ? undefined : collectionScroll.data[i - offset] as Entity<M>)\n };\n });\n // Handed to the first window only: a later one reads a different query.\n const seedRef = React.useRef(restored?.seed);\n\n useEffect(() => {\n if (scrollRestoration) {\n // Marks the entry used, as it was restored.\n scrollRestoration.updateCollectionScroll({\n path,\n scrollOffset: collectionScroll?.scrollOffset ?? 0,\n data: collectionScroll?.data ?? [],\n ...(collectionScroll?.dataOffset !== undefined && { dataOffset: collectionScroll.dataOffset }),\n filters: filterValues\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- once, on mount: marks the entry this view was restored from as used, with the values it was restored with.\n }, []);\n\n const [itemCount, setItemCount] = React.useState<number | undefined>(paginationEnabled ? initialItemCount : undefined);\n\n // The whole sort, as one string, so the effect below re-runs when any key\n // changes — a `sortBy` array is a new reference on every render and would\n // re-subscribe on each one if used as a dependency directly.\n const sortKey = sortBy ? serializeOrderBy(sortBy) : undefined;\n\n const context: RebaseContext<USER> = useRebaseContext();\n\n const [rawData, setRawData] = useState<Entity<M>[]>(restored?.rows ?? []);\n const [sparseData, setSparseData] = useState<(Entity<M> | undefined)[] | undefined>(restored?.sparse);\n const rawDataRef = React.useRef(rawData);\n rawDataRef.current = rawData;\n\n const heldRows = rawData.length;\n const collectionKey = collection.slug ?? path;\n useEffect(() => {\n if (paginationEnabled || heldRows <= UNPAGINATED_WARNING_ROWS) return;\n if (process.env.NODE_ENV === \"production\" || warnedUnpaginated.has(collectionKey)) return;\n warnedUnpaginated.add(collectionKey);\n console.warn(`Rebase: the collection \"${collectionKey}\" holds ${heldRows} rows with \\`pagination: false\\`, ` +\n \"and loads every one of them. Set `pagination` to a page size to read them as they are scrolled to. \" +\n \"(Shown once, in development only.)\");\n }, [paginationEnabled, heldRows, collectionKey]);\n const windowRef = React.useRef<CollectionWindow<M> | undefined>(undefined);\n\n /**\n * What comes back with the view: its offset, and the rows around what it\n * showed — a page either side of the rows on screen, where a view reports\n * them, rather than every row it held. A table scrolled to 100,000 rows\n * kept all of them here, and coming back read every one again before\n * showing any.\n */\n const onScroll = useCallback(({\n scrollOffset\n }: {\n scrollOffset: number\n }) => {\n if (!scrollRestoration) return;\n const snapshot = windowRef.current?.snapshot();\n scrollRestoration.updateCollectionScroll({\n path,\n scrollOffset,\n data: snapshot ? snapshot.rows : rawDataRef.current,\n ...(snapshot && snapshot.offset > 0 && { dataOffset: snapshot.offset }),\n filters: filterValues\n });\n }, [scrollRestoration, path, filterValues]);\n\n const [dataLoading, setDataLoading] = useState<boolean>(false);\n const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();\n const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);\n\n /**\n * Clear the user's filters. `fixedFilter` survives — it is the collection\n * forcing a scope, not something the user chose — but `defaultFilter` does\n * not: a default is where the view *opens*, not a floor it can never go\n * below.\n *\n * It used to reset to `defaultFilter`, which made \"clear\" unable to clear\n * whenever a collection defined one, and every caller here wanted the\n * opposite. `ClearFilterSortButton` is labelled \"clear filter\" and left one\n * set. `EditorCollectionActionStart` calls this and then re-applies\n * `collection.defaultFilter` on the next line — redundant under the old\n * behaviour, and the clearest statement of what it expected.\n * `FilterPresetsButton` documents \"clearing all filters deactivates all\n * chips\", which was false: it derives a chip's active state from the\n * filters, so a preset whose values equalled `defaultFilter` switched\n * itself straight back on. That chip could not be turned off at all — click\n * it, the keys are removed, the filter resets to the identical default, and\n * the chip lights up again.\n */\n const clearFilter = useCallback(() => setFilterValues(fixedFilter ?? undefined), [fixedFilter]);\n\n // The user's filters combine with the collection's `fixedFilter` (AND).\n // This used to return early with a console warning whenever a fixed\n // filter was set, while the filters dialog and the header filters went on\n // offering every other field: the user applied a filter, the dialog\n // closed, and the rows did not change.\n const updateFilterValues = useCallback((updatedFilter: FilterValues<Extract<keyof M, string> | (string & {})> | undefined) => {\n setFilterValues(applyFixedFilter(updatedFilter, fixedFilter));\n }, [fixedFilter]);\n\n // Without realtime the rows are one `find` per query, so nothing tells\n // the table a row went away. `lastDeleteTimestamp` is how the collection\n // view says it did (a delete, or linking existing rows), and a re-read is\n // the only way to show it. A live subscription already delivers the\n // change, so it is left alone.\n const canListen = Boolean(dataClient.collection(path).listen);\n const oneShotReadKey = canListen ? undefined : lastDeleteTimestamp;\n\n // How many rows the view wants held. Pagination off is a request for all\n // of them — read in pages the API serves, never as one unbounded read.\n const target = itemCount ?? Infinity;\n const targetRef = React.useRef(target);\n targetRef.current = target;\n\n // The rows the view says it draws, kept for a window opened after it said\n // so (the view's effects run before this hook's).\n const rangeRef = React.useRef<{ start: number; end: number } | undefined>(undefined);\n // Rows `entitiesDisplayedFirst` puts in front of the window's.\n const displayedFirstCount = entitiesDisplayedFirst?.length ?? 0;\n const displayedFirstCountRef = React.useRef(displayedFirstCount);\n displayedFirstCountRef.current = displayedFirstCount;\n\n const onRowsRendered = useCallback((range?: { start: number; end: number }) => {\n const first = displayedFirstCountRef.current;\n const next = range && {\n start: Math.max(0, range.start - first),\n end: Math.max(0, range.end - first)\n };\n rangeRef.current = next;\n windowRef.current?.setVisibleRange(next);\n }, []);\n\n useEffect(() => {\n\n if (!enabled) {\n setDataLoading(false);\n return;\n }\n\n // Cleared by this run's cleanup. A one-shot read has nothing to\n // unsubscribe from, so without it an answer for a superseded query\n // (the \"ch\" typed before \"chair\") landed on top of the newer one.\n let cancelled = false;\n\n setDataLoading(true);\n\n // `browserCallbacks`, not `callbacks`: the server has already run its\n // own `afterRead` before these rows arrived, and running that one\n // again here applied it twice. This block is the panel's.\n const afterRead = collection.browserCallbacks?.afterRead;\n const process = afterRead\n ? async (entities: Entity<M>[]): Promise<Entity<M>[]> => {\n try {\n // afterRead operates on flat rows; unwrap the Entity view-model\n // before invoking and re-wrap the processed row after.\n return await Promise.all(\n entities.map(async (entity) => {\n const processedRow = await afterRead({\n collection,\n path,\n row: { id: entity.id, ...entity.values },\n context\n });\n return {\n ...entity,\n values: processedRow as M\n };\n }));\n } catch (_e: unknown) {\n console.error(_e);\n return entities;\n }\n }\n : undefined;\n\n // filterValues is already FilterValues — pass directly to the accessor\n const whereParams = filterValues && Object.keys(filterValues).length > 0 ? filterValues : undefined;\n const orderByParams = sortBy && sortBy.length > 0\n ? sortBy.map(([field, direction]) => [String(field), direction] as OrderByTuple)\n : undefined;\n\n // Eagerly include relations to avoid N+1 fetches.\n const includeParams = getRelationIncludeParams(collection);\n\n // One page at a time: the first page live, every later one read by\n // offset, none above the API's ceiling — see `CollectionWindow`. The\n // query is assembled in one place (`toFindParams`); listing the fields\n // here is what let `searchExplain` reach three of four read paths.\n const seed = seedRef.current;\n seedRef.current = undefined;\n const collectionWindow = new CollectionWindow<M>({\n accessor: dataClient.collection<M>(path),\n query: toFindParams({ where: whereParams, orderBy: orderByParams, searchString, include: includeParams }),\n pageSize,\n target: targetRef.current,\n process,\n seed,\n onChange: (state) => {\n if (cancelled) return;\n // The rows do not go into the record cache here. They did, all\n // of them, on every update, so that opening one showed it at\n // once — and a table scrolled to 100,000 rows kept every one of\n // them alive after it closed. Opening a record from a list is a\n // click, and the click puts that one row there\n // (`CollectionViewBinding`'s `onEntityClick`).\n if (state.rows) {\n setRawData(state.rows);\n setSparseData(state.sparse);\n }\n if (state.error) console.error(\"ERROR\", state.error);\n setDataLoading(state.loading);\n setDataLoadingError(state.error);\n setNoMoreToLoad(state.complete);\n }\n });\n windowRef.current = collectionWindow;\n if (rangeRef.current) collectionWindow.setVisibleRange(rangeRef.current);\n collectionWindow.start();\n\n return () => {\n cancelled = true;\n collectionWindow.dispose();\n if (windowRef.current === collectionWindow) windowRef.current = undefined;\n };\n }, [dataClient, path, pageSize, sortKey, filterValues, searchString, oneShotReadKey, enabled]);\n\n // Scrolling asks for more rows of the same query: only the rows past the\n // ones held are read.\n useEffect(() => {\n windowRef.current?.setTarget(target);\n }, [target]);\n\n const orderedData = useDataOrder({\n data: rawData,\n entitiesDisplayedFirst\n });\n\n // hack to fix Firestore listeners firing with incomplete data\n // const data = useDebouncedData(orderedData, {\n // filterValues,\n // sortBy,\n // searchString,\n // lastDeleteTimestamp\n // });\n const data = orderedData;\n\n return useMemo(() => ({\n data,\n ...(sparseData && { sparseData }),\n onRowsRendered,\n dataLoading,\n noMoreToLoad,\n dataLoadingError,\n filterValues,\n setFilterValues: updateFilterValues,\n sortBy,\n setSortBy,\n searchString,\n setSearchString,\n clearFilter,\n itemCount,\n setItemCount,\n initialScroll: collectionScroll?.scrollOffset,\n onScroll,\n paginationEnabled,\n pageSize,\n checkFilterCombination,\n popupCell,\n setPopupCell\n }), [\n data,\n sparseData,\n onRowsRendered,\n dataLoading,\n noMoreToLoad,\n dataLoadingError,\n filterValues,\n updateFilterValues,\n sortBy,\n searchString,\n clearFilter,\n itemCount,\n collectionScroll?.scrollOffset,\n onScroll,\n paginationEnabled,\n pageSize,\n checkFilterCombination,\n popupCell\n ]);\n}\n\n/**\n * The user's filters with the collection's fixed filter applied on top. The\n * fixed fields are the collection's, so a value the user sends for one of them\n * never replaces it; every other field is the user's. An empty result is no\n * filter at all.\n */\nfunction applyFixedFilter<K extends string>(\n filter: FilterValues<K> | undefined,\n fixedFilter: FilterValues<string> | undefined\n): FilterValues<K> | undefined {\n const combined: FilterValues<K> = { ...(filter ?? {}), ...(fixedFilter ?? {}) };\n return Object.keys(combined).length > 0 ? combined : undefined;\n}\n\nfunction useUpdateUrl<M extends Record<string, any> = any>(\n filterValues: FilterValues<Extract<keyof M, string>> | undefined,\n sortBy: OrderByTuple<Extract<keyof M, string>>[] | undefined,\n searchString: string | undefined,\n updateUrl: boolean | undefined,\n lastWrittenListStateRef: React.MutableRefObject<string | undefined>\n) {\n\n useEffect(() => {\n if (updateUrl) {\n // Parse existing URL params to preserve non-filter/sort params like __view\n const existingParams = new URLSearchParams(window.location.search);\n const preservedParams = new URLSearchParams();\n\n // Preserve params that are not filter/sort related\n existingParams.forEach((value, key) => {\n if (key.startsWith(\"__\") && key !== \"__sort\" && key !== \"__sort_order\") {\n preservedParams.set(key, value);\n }\n });\n\n const listState = encodeListState(filterValues, sortBy, searchString);\n lastWrittenListStateRef.current = listState;\n\n // Combine preserved params with filter/sort state\n const preservedString = preservedParams.toString();\n const parts = [preservedString, listState].filter(Boolean);\n const state = parts.join(\"&\");\n\n // The entry's existing state goes back in unchanged: react-router\n // keeps its `idx` and `key` there. Replacing it with `{}` left Back\n // with no index to compute a delta from, and react-router lets a\n // POP with no delta through without asking any blocker — every\n // unsaved-changes guard was skipped.\n const hash = window.location.hash;\n if (state === \"\")\n window.history.replaceState(window.history.state, \"\", `${window.location.pathname}${hash}`);\n else\n window.history.replaceState(window.history.state, \"\", `?${state}${hash}`);\n }\n }, [filterValues, sortBy, searchString, updateUrl]);\n}\n\n/**\n * The part of the query string this hook owns — filters, sort and search — in\n * the one canonical spelling, so two states can be compared by what they would\n * write.\n */\nfunction encodeListState(filterValues: FilterValues<string> | undefined,\n sortBy: OrderByTuple[] | undefined,\n searchString: string | undefined): string {\n const search = searchString ? `search=${encodeURIComponent(searchString)}` : \"\";\n return [encodeFilterAndSort(filterValues, sortBy), search].filter(Boolean).join(\"&\");\n}\n\nfunction parseSearchString(search: string): string | undefined {\n // `URLSearchParams` has already decoded the value. Decoding it a second\n // time threw on any search containing a `%` (\"50% off\").\n return new URLSearchParams(search).get(\"search\") || undefined;\n}\n\nconst OP_SUFFIX = \"_op\";\nconst VALUE_SUFFIX = \"_value\";\n\nfunction encodeFilterAndSort(filterValues?: FilterValues<string>, sortBy?: OrderByTuple[] | undefined) {\n const entries: [string, string][] = [];\n if (sortBy && sortBy.length > 0) {\n // Comma-separated, positionally paired. A single key encodes exactly as\n // it did before — `__sort=name&__sort_order=asc` — so links already out\n // in the world keep working, and a reload of a two-key sort no longer\n // silently comes back sorted by the first key alone.\n entries.push([\"__sort\", sortBy.map(([field]) => encodeURIComponent(field)).join(\",\")]);\n entries.push([\"__sort_order\", sortBy.map(([, direction]) => direction).join(\",\")]);\n }\n if (filterValues) {\n Object.entries(filterValues).forEach(([key, value]) => {\n if (value) {\n const conditions: [WhereFilterOp, unknown][] = Array.isArray(value[0])\n ? (value as [WhereFilterOp, unknown][])\n : [value as [WhereFilterOp, unknown]];\n\n // One `_op`/`_value` pair per condition, repeated for a field\n // with several (`stock >= 5 AND stock < 10`). A single condition\n // spells exactly as it always has, which is the format links\n // composed outside the admin follow.\n for (const [op, val] of conditions) {\n if (!op) continue;\n let encodedValue: unknown = val;\n try {\n if (typeof val === \"object\") {\n if (val instanceof Date) {\n encodedValue = val.toISOString();\n } else if (Array.isArray(val)) {\n encodedValue = JSON.stringify(val, (k, v) => {\n if (v instanceof EntityRelation) {\n return encodeRelation(v);\n }\n if (v instanceof EntityReference) {\n return encodeReference(v);\n }\n return v;\n });\n } else if (val instanceof EntityRelation) {\n encodedValue = encodeRelation(val);\n } else if (val instanceof EntityReference) {\n encodedValue = encodeReference(val);\n }\n }\n } catch (e) {\n encodedValue = val;\n }\n if (encodedValue !== undefined) {\n entries.push([encodeURIComponent(`${key}${OP_SUFFIX}`), encodeURIComponent(op)]);\n // Only `null` is written as `null`. `false`, `0` and the\n // empty string are values: read back as `null` they\n // became an IS NULL filter on the server.\n entries.push([encodeURIComponent(`${key}${VALUE_SUFFIX}`),\n encodedValue === null ? \"null\" : encodeURIComponent(String(encodedValue))]);\n }\n }\n }\n });\n }\n return entries.map(([key, value]) => `${key}=${value}`).join(\"&\");\n}\n\nfunction parseFilterAndSort<M>(search: string): {\n filterValues: FilterValues<string> | undefined,\n sortBy?: OrderByTuple<Extract<keyof M, string>>[]\n} {\n const entries = new URLSearchParams(search);\n const filterValues: FilterValues<string> = {};\n let sortBy: OrderByTuple[] | undefined = undefined;\n entries.forEach((value, key) => {\n if (key === \"__sort\") {\n const directions = (entries.get(\"__sort_order\") ?? \"\").split(\",\");\n const keys = value\n .split(\",\")\n .map((field) => decodeURIComponent(field).trim())\n .filter(Boolean)\n // A direction missing from the URL — a hand-written link, or the\n // one-key form of an older bookmark — is ascending, the same\n // reading `?orderBy=name` gets everywhere else.\n .map((field, index): OrderByTuple => [field, directions[index] === \"desc\" ? \"desc\" : \"asc\"]);\n sortBy = keys.length > 0 ? keys : undefined;\n } else if (key.endsWith(OP_SUFFIX) && !(key.slice(0, -OP_SUFFIX.length) in filterValues)) {\n // The suffix, not the first `_op` in the name: `shop_open_op`\n // belongs to `shop_open`.\n const field = key.slice(0, -OP_SUFFIX.length);\n const ops = entries.getAll(key);\n const values = entries.getAll(`${field}${VALUE_SUFFIX}`);\n // Paired by position. An operator with no value beside it is half a\n // pair, and guessing the rest would invent a filter.\n const conditions: [WhereFilterOp, unknown][] = ops\n .slice(0, values.length)\n .map((op, index) => [decodeURIComponent(op) as WhereFilterOp, decodeString(values[index])]);\n if (conditions.length === 1) {\n filterValues[field] = conditions[0];\n } else if (conditions.length > 1) {\n filterValues[field] = conditions;\n }\n }\n });\n\n return {\n filterValues: Object.keys(filterValues).length ? filterValues : undefined,\n sortBy\n }\n}\n\nfunction isDate(dateString: string): boolean {\n // Define a regex pattern that matches the exact date format: 2025-01-07T23:00:00.000Z\n const regexPattern = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;\n\n // Test the dateString against the regex pattern\n if (!regexPattern.test(dateString)) {\n return false;\n }\n\n // If the regex matches, further validate if it is a valid UTC date\n const date = new Date(dateString);\n return date.toISOString() === dateString;\n}\n\nfunction encodeReference(val: EntityReference) {\n return `ref::${val.path}/${val.id}`;\n}\nfunction encodeRelation(val: EntityRelation) {\n return `rel::${val.path}/${val.id}`;\n}\n\n/**\n * Read a `ref::<path>/<id>` or `rel::<path>/<id>` filter value back.\n *\n * The id is the last segment and the path is everything before it. Taking the\n * first two segments instead turned a reference to\n * `content/de-DE/podcasts/abc123` into the record `de-DE` of `content`, and\n * every reference into a subcollection the same way.\n */\nfunction splitEncodedAddress(value: string): { path: string; id: string } {\n const address = value.slice(value.indexOf(\"::\") + 2);\n const separator = address.lastIndexOf(\"/\");\n return {\n path: address.substring(0, separator),\n id: address.substring(separator + 1)\n };\n}\n\nfunction decodeString(val: string): EntityReference | EntityRelation | Date | string {\n let parsedFilterVal: EntityReference | EntityRelation | Date | string = val;\n if (isDate(val)) {\n try {\n parsedFilterVal = new Date(val);\n } catch (_e) {\n // ignore\n }\n }\n if (typeof parsedFilterVal === \"string\") {\n try {\n parsedFilterVal = JSON.parse(parsedFilterVal, (key, value) => {\n if (typeof value === \"string\") {\n if (value.startsWith(\"ref::\")) {\n const { path, id } = splitEncodedAddress(value);\n return new EntityReference({ id,\npath });\n }\n if (value.startsWith(\"rel::\")) {\n const { path, id } = splitEncodedAddress(value);\n return new EntityRelation(id, path);\n }\n }\n return value;\n });\n } catch (_e) {\n // ignore\n }\n }\n\n if (typeof parsedFilterVal === \"string\") {\n if (parsedFilterVal.startsWith(\"ref::\")) {\n const { path, id } = splitEncodedAddress(parsedFilterVal);\n return new EntityReference({ id,\npath });\n }\n if (parsedFilterVal.startsWith(\"rel::\")) {\n const { path, id } = splitEncodedAddress(parsedFilterVal);\n return new EntityRelation(id, path);\n }\n }\n return parsedFilterVal;\n}\n","/**\n * @group Components\n */\nexport type TableSize = \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\";\n\nexport function getRowHeight(size: TableSize): number {\n switch (size) {\n // Density pass (2026-09-08): the old ladder was 54 / 80 / 140 / 280 / 400,\n // sized for image thumbnails at every step, so the default \"m\" row was\n // 140px of mostly air around one line of text. Now xs..m are text rows\n // (small previews: a chip, a date, one inline reference) and only l/xl\n // make room for medium and large thumbnails.\n case \"xl\":\n return 160;\n case \"l\":\n return 96;\n case \"m\":\n return 48;\n case \"s\":\n return 42;\n case \"xs\":\n return 36;\n default:\n throw Error(\"Missing mapping for collection size -> height\");\n }\n}\n","import React from \"react\";\nimport { Link } from \"react-router\";\nimport { Button, Typography } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks\";\n\nexport function NotFoundPage() {\n const { t } = useTranslation();\n\n return (\n <div className=\"flex w-full h-full\">\n <div className=\"m-auto flex items-center flex-col\"\n >\n <Typography variant={\"h4\"} align={\"center\"}\n gutterBottom={true}>\n {t(\"page_not_found\")}\n </Typography>\n <Typography align={\"center\"} gutterBottom={true}>\n {t(\"page_not_found_body\")}\n </Typography>\n <Button\n variant={\"text\"}\n component={Link}\n to={\"/\"}>{t(\"back_to_home\")}</Button>\n </div>\n </div>\n );\n}\n","import React from \"react\";\n\nimport { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks\";\n\nexport function ConfirmationDialog({\n open,\n onAccept,\n onCancel,\n title,\n loading,\n body\n}: {\n open: boolean,\n onAccept: () => void,\n onCancel: () => void,\n loading?: boolean,\n title: React.ReactNode,\n body?: React.ReactNode,\n}) {\n const { t } = useTranslation();\n return (\n <Dialog\n open={open}\n onOpenChange={(open) => !open ? onCancel() : undefined}\n >\n <DialogTitle variant={\"h6\"} className={\"mb-2\"}>{title}</DialogTitle>\n <DialogContent>\n {body}\n </DialogContent>\n\n <DialogActions>\n <Button\n variant={\"text\"}\n onClick={onCancel}\n autoFocus>{t(\"cancel\")}</Button>\n\n <LoadingButton\n type=\"submit\"\n loading={loading}\n onClick={onAccept}\n autoFocus>\n {t(\"ok\")}\n </LoadingButton>\n </DialogActions>\n </Dialog>\n );\n}\n","import React from \"react\";\n\nexport function RebaseLogo({\n width,\n height,\n className,\n style\n}: {\n width?: string,\n height?: string,\n className?: string,\n style?: React.CSSProperties\n}) {\n return (\n <svg\n width={width ?? \"100%\"} height={height ?? \"100%\"}\n version=\"1.1\"\n style={style}\n className={className}\n viewBox=\"112.1405 1079.711 306.058 306.058\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill=\"#34b6d9\" d=\"M237.01 1087.234a56 56 0 0 1 56.07 0l83.819 48.473a56 56 0 0 1 27.965 48.477v97.108a56 56 0 0 1-27.965 48.477l-83.819 48.473a56 56 0 0 1-56.07 0l-83.818-48.473a56 56 0 0 1-27.965-48.477v-97.108a56 56 0 0 1 27.965-48.477Z\"/>\n <path fill=\"#358fd8\" d=\"M264.64 1286.718c27.352 0 49.525 22.173 49.525 49.526 0 27.352-22.173 49.525-49.525 49.525-27.353 0-49.526-22.173-49.526-49.525Z\"/>\n <path fill=\"#ff9197\" d=\"M174.941 1131.547c27.352 0 49.526 22.174 49.526 49.526s-22.174 49.526-49.526 49.526-49.526-22.174-49.526-49.526Z\"/>\n <path fill=\"#358fd8\" d=\"M355.338 1131.547c27.352 0 49.526 22.174 49.526 49.526s-22.174 49.526-49.526 49.526-49.526-22.174-49.526-49.526Z\"/>\n <path fill=\"#fe9197\" d=\"M125.227 1196.44v-14.661c0-13.35 7.55-20.303 17.99-18.168l56.424 31.13 2.72 1.572 27.643 31.545 35.193 30.52q.173 1.522.229 3.013l-54.046-11.395-28.464-26.045Z\"/>\n <path fill=\"#013afd\" d=\"M151.207 1328.696c-14.348-8.285-25.98-28.432-25.98-45v-35.214l11.299-.401c.614.866 34.062 48.973 34.606 49.656.394.495 22.156 40.224 34.409 62.328Z\"/>\n <path fill=\"#2c09d1\" d=\"m211.38 1249.996 30.436 6.417 9.53 9.1-2.926 15.797 16.939 30.08-14.049 6.672-35.072-10.288-33.83-61.32 9.09-.323Z\"/>\n <path fill=\"#2ac1cf\" d=\"M240.774 1380.37a34 34 0 0 1-1.304-.716l-16.141-9.319-49.383-74.238 29.211 7.839Z\"/>\n <path fill=\"#2c42d0\" d=\"m173.359 1219.393 9.557 4.558 28.464 26.045-19.883-3.865-12.782.453-31.643-13.936-15.11-11.819Z\"/>\n <path fill=\"#8b66ed\" d=\"M257.113 1381.863c-4.336 2.13-10.043 1.783-16.34-1.493l-37.616-76.434 13.081 3.838Z\"/>\n <path fill=\"#2c09d1\" d=\"m145.888 1247.749 7.224-.257 23.615 41.804 11.98 1.728-24.421-43.544-.014-.383 10.725-.38 28.16 57.219-29.211-7.839-7.37-11.08Z\"/>\n <path fill=\"#2ac1cf\" d=\"M265.451 1311.554v53.1q0 .255-.004.505l-.25-.26-29.148-38.794-6.308-14.37 21.57 6.328 14.048-6.672Z\"/>\n <path fill=\"#fd485f\" d=\"m223.329 1370.335-17.788-10.27c-12.253-22.104-34.015-61.833-34.41-62.328-.543-.683-33.991-48.79-34.605-49.656l9.362-.332 20.688 37.269Z\"/>\n <path fill=\"#2d42d0\" d=\"m202.362 1196.313 37.108 21.424c13.11 7.57 23.953 25.043 25.727 40.641l-35.193-30.52Z\"/>\n <path fill=\"#2b0ad1\" d=\"M265.447 1365.16c-.095 6.58-2.056 11.56-5.304 14.604l-39.936-70.826 9.534 2.797 6.308 14.37 29.148 38.794Z\"/>\n <path fill=\"#fe9196\" d=\"M125.227 1240.59v-16.4l21.845 8.458 31.643 13.936-35.367 1.255Z\"/>\n <path fill=\"#8b66ed\" d=\"m174.997 1246.716 7.411-.263 33.83 61.32-13.08-3.837Z\"/>\n <path fill=\"#2cc5d2\" d=\"m153.112 1247.492 11.16-.395.014.383 24.421 43.544-11.98-1.728Z\"/>\n <path fill=\"#fc4962\" d=\"M125.227 1224.19v-8.878l30.211-4.464 17.92 8.545-41.396 1.436 15.11 11.82Z\"/>\n <path fill=\"#fe475f\" d=\"M265.451 1292.508v18.84l-.092.043-16.939-30.08 2.927-15.799.214.206Z\"/>\n <path fill=\"#2d43cd\" d=\"M125.227 1215.312v-18.871l30.211 14.407Z\"/>\n <path fill=\"#2ac4d1\" d=\"M260.143 1379.764a12.5 12.5 0 0 1-3.03 2.099l-40.875-74.09 3.969 1.165Z\"/>\n <path fill=\"#fe475f\" d=\"M265.426 1261.391q.025.677.025 1.346v16.241l-13.89-13.26-.186-.36-.028.154-9.53-9.099Z\"/>\n <path fill=\"#40b6d9\" d=\"M265.451 1278.978v13.53c-4.95-9.535-12.604-24.31-13.89-26.79Z\"/>\n <path fill=\"#013afd\" d=\"M125.227 1248.482v-7.892l18.12 7.249Z\"/>\n <path fill=\"#fe9197\" d=\"M143.217 1163.611c2.517.515 5.203 1.558 7.99 3.168l48.434 27.963Z\"/>\n <path fill=\"#fec404\" d=\"m251.347 1265.512.028-.154.186.36Z\"/>\n <path fill=\"#ccc\" d=\"M265.451 1311.347v.207l-.092-.163Z\"/>\n <path fill=\"#2fc7d5\" d=\"M383.274 1164.17a31 31 0 0 1-3.887 2.64l-2.59 1.495-95.242 18.988-50.727-18.022 25.55-32.892 63.642 26.919-61.075-31.394Z\"/>\n <path fill=\"#320fdd\" d=\"m215.866 1112.967 18.535-16.15 5.766 32.704 16.212 6.858-25.551 32.892-57.218-19.484Z\"/>\n <path fill=\"#fd4a61\" d=\"m305.806 1094.328 73.58 42.482c7.16 4.134 10.748 9.55 10.757 14.968l-40.264-5.624-25.491-7.867-33.1-30.491-18.842-4.065Z\"/>\n <path fill=\"#fec504\" d=\"M388.516 1158.077c-1.145 2.145-2.892 4.205-5.242 6.093l-124.33-32.266 6.47-29.689 25.874 5.58 33.1 30.492Z\"/>\n <path fill=\"#320fdd\" d=\"m179.744 1183.464-26.935-15.551 18.147-15.813 55.184 23.206-15.732 20.252Z\"/>\n <path fill=\"#33b6d9\" d=\"m358.403 1178.925-52.998 30.599-44.794-17.995 89.572-18.117Z\"/>\n <path fill=\"#fd4a63\" d=\"m234.401 1096.817 12.723-11.087 19.395 11.42-7.574 34.754 61.075 31.394-79.853-33.777Z\"/>\n <path fill=\"#fe9197\" d=\"m152.809 1167.913-1.91-1.103c-10.42-6.016-13.273-14.747-8.558-22.25l56.907-27.791 15.854-3.136Z\"/>\n <path fill=\"#8b69f1\" d=\"m305.405 1209.524-14.281 8.245c-5.252 3.032-11.697 4.954-18.462 5.767l-43.574-25.631 31.523-6.376Z\"/>\n <path fill=\"#3015d8\" d=\"M252.294 1080.973c13.06-2.81 28.331-1.183 38.83 4.879l14.682 8.476-33.36 9.403-7.031-1.516 1.104-5.064-19.395-11.42Z\"/>\n <path fill=\"#2c0ace\" d=\"M239.162 1085.852c3.85-2.223 8.342-3.85 13.132-4.88l-37.192 32.66-15.854 3.137-56.907 27.791c1.777-2.828 4.63-5.482 8.559-7.75Z\"/>\n <path fill=\"#2fc7d5\" d=\"m229.088 1197.905-8.773 1.774-9.907-4.121 15.732-20.252 37.462 15.618Z\"/>\n <path fill=\"#33b6d9\" d=\"M272.662 1223.536c-11.721 1.407-24.402-.515-33.5-5.767l-28.093-16.22 18.019-3.644Z\"/>\n <path fill=\"#fe9197\" d=\"m264.078 1190.828-.476.096-37.462-15.618 4.688-6.035 50.727 18.022ZM170.956 1152.1l2.654-2.313 57.218 19.484-4.688 6.035Z\"/>\n <path fill=\"#30c3d9\" d=\"M390.143 1151.778c.01 2.125-.533 4.25-1.627 6.3l-38.637-11.924Z\"/>\n <path fill=\"#ff4c60\" d=\"m211.07 1201.55-31.326-18.086 40.57 16.215Z\"/>\n <path fill=\"#2d08d0\" d=\"m376.798 1168.305-18.395 10.62-8.22-5.513Z\"/>\n <path fill=\"#2fc7d5\" d=\"M264.887 1262.737c0-16.568 11.632-36.715 25.98-45l40.425-23.339 11.932 35.4-25.718 46.274-26.284-2.855-1.382.145-1.411-.146-23.542.675Z\"/>\n <path fill=\"#32abd6\" d=\"M383.486 1164.684c2.376-.909 4.642-1.382 6.752-1.446l-7.859 43.045-.292 5.18 8.911 13.519 5.344-41.78 4.102-15.889c2.942 3.164 4.667 8.084 4.667 14.466v91.585h-1.324c-1.104 3.308-34.555 60.887-34.486 61.007l-21.13 12.2 8.305-32.902-10.115 14.693 10.115-20.342 47.315-78.499-7.45 6.694-15.674 18.243 2.62-89.698.155-.059Z\"/>\n <path fill=\"#2eabd6\" d=\"m324.54 1360.214-33.672 19.44c-13.695 7.907-24.915 2.15-25.91-12.796l8.385-12.077 47.855-71.354 7.12-26.81 5.119-9.209.57 31.212-13.987 50.442 6.42-5.847-2.408 22.126.459 8.254Z\"/>\n <path fill=\"#8b65f0\" d=\"M264.959 1366.858a33 33 0 0 1-.072-2.204v-88.582l24.953-2.71 26.235 2.554 1.43.156 10.813-19.454-7.12 26.81-47.855 71.353Z\"/>\n <path fill=\"#fd4861\" d=\"m378.764 1192.394 3.89-5.923c-1.987-.058-4.42 64.146-4.402 65.055.019.91-5.901 22.365-5.901 22.365l-17.658 29.778-14.983 14.696 9.72-45.149.036-1.115 6.455-7.894Z\"/>\n <path fill=\"#32abd6\" d=\"m377.832 1167.529.229-.133.703 24.998-22.843 71.813-6.455 7.894.572-17.63-3.443-30.74Z\"/>\n <path fill=\"#8c66ef\" d=\"m328.775 1297.488.034-.126 20.657-25.261-.036 1.115-9.72 45.15 14.983-14.697-13.8 22.045-16.86 19.627 2.407-22.126-6.42 5.847Z\"/>\n <path fill=\"#2c08d3\" d=\"m331.292 1194.398 27.203-15.705 5.51 13.714-20.781 37.391Z\"/>\n <path fill=\"#300bd2\" d=\"m324.491 1353.595-.459-8.254 16.861-19.627 13.8-22.045 17.658-29.778 20.08-31.948 3.91-5.728 7.45-6.694-47.315 78.5-10.115 20.341-21.821 31.852Z\"/>\n <path fill=\"#2c08d3\" d=\"m333.437 1247.408 13.158-23.676 3.443 30.738-4.056 14.678-14.316 17.914 2.34-8.442Z\"/>\n <path fill=\"#8b68ef\" d=\"M405.111 1273.364v10.332c0 16.568-11.632 36.715-25.98 45l-9.83 5.675c-.07-.12 33.382-57.7 34.486-61.007Z\"/>\n <path fill=\"#fec504\" d=\"M390.238 1163.238c4.109-.125 7.625 1.3 10.206 4.075l-4.102 15.89-5.344 41.779-8.91-13.518.291-5.18Z\"/>\n <path fill=\"#300bd2\" d=\"m348.171 1346.57-23.631 13.644 31.936-46.545Z\"/>\n <path fill=\"#348fd8\" d=\"M372.35 1273.891s5.921-21.455 5.902-22.365 2.415-65.113 4.402-65.055l-1.987 67.987 15.675-18.243-3.91 5.728Z\"/>\n <path fill=\"#32abd6\" d=\"m358.495 1178.693 19.337-11.164-13.827 24.878Z\"/>\n <path fill=\"#fd4861\" d=\"m331.391 1288.05.275-.988 14.316-17.914 4.056-14.678-.572 17.63-20.657 25.262Z\"/>\n <path fill=\"#ccc\" fillOpacity=\".579\" d=\"m378.06 1167.396 1.07-.617a31 31 0 0 1 4.158-2.019l-.634 21.71-3.89 5.924Z\"/>\n <path fill=\"#2fc7d5\" d=\"M264.887 1276.072v-2.18l23.542-.676 1.411.146Z\"/>\n <path fill=\"#8b65f0\" d=\"m291.193 1273.502-1.353-.14 1.382-.145 24.853 2.7Z\"/>\n </svg>\n );\n\n}\n","import { Wand2Icon } from \"@rebasepro/ui\";\nimport React from \"react\";\n\nexport interface AIIconProps {\n size?: \"smallest\" | \"small\" | \"medium\" | \"large\";\n className?: string;\n}\n\n/**\n * AI-styled AutoAwesome icon with gradient coloring.\n * Used consistently across AI features for visual identification.\n */\nexport function AIIcon({ size = \"small\", className }: AIIconProps) {\n const sizeMap: Record<string, number> = {\n smallest: 16,\n small: 20,\n medium: 24,\n large: 28\n };\n const numericSize = typeof size === \"string\" ? sizeMap[size] || 20 : size;\n\n return (\n <Wand2Icon\n size={numericSize}\n className={className}\n style={{\n background: \"linear-gradient(to right, var(--color-primary), var(--color-secondary))\",\n WebkitBackgroundClip: \"text\",\n WebkitTextFillColor: \"transparent\",\n backgroundClip: \"text\"\n }}\n />\n );\n}\n\n/**\n * Small animated dot indicator for AI-modified elements.\n * Shows a pulsing gradient dot.\n */\nexport function AIModifiedIndicator({ className }: { className?: string }) {\n return (\n <div\n className={`w-2 h-2 rounded-full bg-gradient-to-r from-primary to-secondary animate-pulse ${className ?? \"\"}`}\n title=\"AI modified\"\n />\n );\n}\n","/**\n * What the settings screen and the link's screen say about a refused address\n * change: the codes a person can act on get the panel's own, translated words,\n * and anything else keeps the server's message.\n */\nexport function emailChangeErrorMessage(error: unknown, t: (key: string) => string): string {\n const code = error instanceof Error && \"code\" in error ? error.code : undefined;\n switch (code) {\n case \"EMAIL_EXISTS\":\n return t(\"email_change_taken\");\n case \"UNDELIVERABLE_ADDRESS\":\n return t(\"email_change_undeliverable\");\n case \"EMAIL_UNCHANGED\":\n return t(\"email_change_unchanged\");\n case \"AAL2_REQUIRED\":\n return t(\"email_change_needs_second_factor\");\n case \"INVALID_TOKEN\":\n return t(\"auth_link_invalid_or_expired\");\n default:\n return error instanceof Error ? error.message : String(error);\n }\n}\n","\nimport React, { useEffect, useRef, useState } from \"react\";\nimport {\n Alert,\n Avatar,\n Button,\n Card,\n Chip,\n CircularProgress,\n cls,\n IconButton,\n LoadingButton,\n Tab,\n Tabs,\n TextField,\n Trash2Icon,\n Typography\n} from \"@rebasepro/ui\";\nimport { useAuthController, useTranslation } from \"../hooks\";\nimport { emailChangeErrorMessage } from \"./email-change-message\";\n\ninterface SessionInfo {\n id: string;\n userAgent?: string;\n ipAddress?: string;\n createdAt: string;\n isCurrentSession?: boolean;\n}\n\ninterface ExtendedAuthController {\n user: { displayName?: string | null; photoURL?: string | null; email?: string | null; pendingEmail?: string | null } | null;\n updateProfile?: (displayName: string, photoURL: string) => Promise<void>;\n changePassword?: (oldPassword: string, newPassword: string) => Promise<void>;\n changeEmail?: (newEmail: string) => Promise<{ pendingEmail: string; expiresAt: string }>;\n fetchSessions?: () => Promise<SessionInfo[]>;\n revokeSession?: (id: string) => Promise<void>;\n revokeAllSessions?: () => Promise<void>;\n signOut: () => Promise<void>;\n}\n\ntype ActiveTab = \"profile\" | \"security\" | \"sessions\";\n\nexport function UserSettingsView() {\n const authController = useAuthController() as ExtendedAuthController;\n const user = authController.user;\n const { t } = useTranslation();\n\n const hasPasswordChange = !!authController.changePassword;\n const [activeTab, setActiveTab] = useState<ActiveTab>(\"profile\");\n\n // Profile state\n const [displayName, setDisplayName] = useState(user?.displayName || \"\");\n const [photoURL, setPhotoURL] = useState(user?.photoURL || \"\");\n const [savingProfile, setSavingProfile] = useState(false);\n const [profileError, setProfileError] = useState<string | null>(null);\n\n // Email change state. The address waiting for its link, as the server last\n // said — on load from the user, then from the request just made.\n const [newEmail, setNewEmail] = useState(user?.email || \"\");\n const [pendingEmail, setPendingEmail] = useState<string | null>(user?.pendingEmail ?? null);\n const [changingEmail, setChangingEmail] = useState(false);\n const [emailError, setEmailError] = useState<string | null>(null);\n\n // Password change state\n const [currentPassword, setCurrentPassword] = useState(\"\");\n const [newPassword, setNewPassword] = useState(\"\");\n const [confirmPassword, setConfirmPassword] = useState(\"\");\n const [changingPassword, setChangingPassword] = useState(false);\n const [passwordError, setPasswordError] = useState<string | null>(null);\n const [passwordSuccess, setPasswordSuccess] = useState<string | null>(null);\n\n // Sessions state\n const [sessions, setSessions] = useState<SessionInfo[]>([]);\n const [loadingSessions, setLoadingSessions] = useState(false);\n const [sessionsError, setSessionsError] = useState<string | null>(null);\n const [revokingSessionId, setRevokingSessionId] = useState<string | null>(null);\n const [revokingAll, setRevokingAll] = useState(false);\n\n useEffect(() => {\n setDisplayName(user?.displayName || \"\");\n setPhotoURL(user?.photoURL || \"\");\n setNewEmail(user?.email || \"\");\n setPendingEmail(user?.pendingEmail ?? null);\n if (activeTab === \"sessions\") {\n loadSessions();\n }\n }, [activeTab, user]);\n\n const handleSaveProfile = async () => {\n setSavingProfile(true);\n setProfileError(null);\n try {\n if (authController.updateProfile) {\n await authController.updateProfile(displayName, photoURL);\n } else {\n throw new Error(\"updateProfile not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setProfileError(e instanceof Error ? e.message : String(e));\n } finally {\n setSavingProfile(false);\n }\n };\n\n const handleChangeEmail = async () => {\n if (!authController.changeEmail) return;\n setChangingEmail(true);\n setEmailError(null);\n try {\n const { pendingEmail: waiting } = await authController.changeEmail(newEmail.trim());\n setPendingEmail(waiting);\n } catch (e: unknown) {\n setEmailError(emailChangeErrorMessage(e, t));\n } finally {\n setChangingEmail(false);\n }\n };\n\n const handleChangePassword = async () => {\n setPasswordError(null);\n setPasswordSuccess(null);\n\n // Validate\n if (newPassword.length < 8) {\n setPasswordError(t(\"password_too_short\"));\n return;\n }\n if (newPassword !== confirmPassword) {\n setPasswordError(t(\"passwords_dont_match\"));\n return;\n }\n\n setChangingPassword(true);\n try {\n if (authController.changePassword) {\n await authController.changePassword(currentPassword, newPassword);\n setPasswordSuccess(t(\"password_changed\"));\n setCurrentPassword(\"\");\n setNewPassword(\"\");\n setConfirmPassword(\"\");\n // The backend ends every other session and hands this device a\n // fresh one, which the controller adopts: nothing to sign out.\n }\n } catch (e: unknown) {\n setPasswordError(e instanceof Error ? e.message : String(e));\n } finally {\n setChangingPassword(false);\n }\n };\n\n const loadSessions = async () => {\n setLoadingSessions(true);\n setSessionsError(null);\n try {\n if (authController.fetchSessions) {\n const fetchedSessions = await authController.fetchSessions();\n const sortedSessions = (fetchedSessions || []).sort((a: SessionInfo, b: SessionInfo) =>\n new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n );\n setSessions(sortedSessions);\n } else {\n throw new Error(\"fetchSessions not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setSessionsError(e instanceof Error ? e.message : String(e));\n } finally {\n setLoadingSessions(false);\n }\n };\n\n const handleRevokeSession = async (id: string, isCurrentSession?: boolean) => {\n setRevokingSessionId(id);\n try {\n if (authController.revokeSession) {\n await authController.revokeSession(id);\n setSessions(sessions.filter(s => s.id !== id));\n if (isCurrentSession) {\n await authController.signOut();\n }\n } else {\n throw new Error(\"revokeSession not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setSessionsError(e instanceof Error ? e.message : String(e));\n } finally {\n setRevokingSessionId(null);\n }\n };\n\n const handleRevokeAll = async () => {\n setRevokingAll(true);\n try {\n if (authController.revokeAllSessions) {\n await authController.revokeAllSessions();\n } else {\n throw new Error(\"revokeAllSessions not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setSessionsError(e instanceof Error ? e.message : String(e));\n } finally {\n setRevokingAll(false);\n }\n };\n\n if (!user) return null;\n\n return (\n <div className=\"flex-grow max-w-4xl w-full mx-auto p-4 sm:p-6 md:p-12\">\n <Typography variant=\"h4\" className=\"mb-8\">{t(\"account_settings\")}</Typography>\n\n <Tabs value={activeTab} onValueChange={(v) => setActiveTab(v as ActiveTab)} className=\"mb-8\">\n <Tab value=\"profile\">{t(\"profile\")}</Tab>\n {hasPasswordChange && <Tab value=\"security\">{t(\"security\")}</Tab>}\n <Tab value=\"sessions\">{t(\"sessions\")}</Tab>\n </Tabs>\n\n {activeTab === \"profile\" && (\n <div className=\"flex flex-col gap-6 max-w-xl\">\n <div className=\"flex items-center gap-6 mb-2\">\n <Avatar src={photoURL || undefined} className=\"w-24 h-24 text-3xl\">\n {displayName ? displayName[0].toUpperCase() : (user.email ? user.email[0].toUpperCase() : \"A\")}\n </Avatar>\n </div>\n <TextField\n label={t(\"display_name\")}\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n />\n <TextField\n label={t(\"photo_url\")}\n value={photoURL}\n onChange={(e) => setPhotoURL(e.target.value)}\n />\n {profileError && <Typography color=\"error\">{profileError}</Typography>}\n <div className=\"mt-4\">\n <Button variant=\"filled\" onClick={handleSaveProfile} disabled={savingProfile}>\n {savingProfile ? t(\"saving\") : t(\"save_profile\")}\n </Button>\n </div>\n\n {authController.changeEmail && (\n <div className=\"flex flex-col gap-4 mt-10\">\n <div>\n <Typography variant=\"h6\" className=\"mb-1\">{t(\"email_address\")}</Typography>\n <Typography variant=\"body2\" color=\"secondary\">{t(\"email_change_description\")}</Typography>\n </div>\n <TextField\n label={t(\"email_address\")}\n type=\"email\"\n autoComplete=\"email\"\n value={newEmail}\n onChange={(e) => {\n setNewEmail(e.target.value);\n setEmailError(null);\n }}\n />\n {pendingEmail && (\n <Alert color=\"info\">\n {t(\"email_change_pending\", { email: pendingEmail })}\n </Alert>\n )}\n {emailError && <Typography color=\"error\">{emailError}</Typography>}\n <div>\n <LoadingButton\n variant=\"filled\"\n onClick={handleChangeEmail}\n loading={changingEmail}\n disabled={changingEmail || !newEmail.trim() || newEmail.trim().toLowerCase() === (user.email ?? \"\").toLowerCase()}\n >\n {t(\"email_change_button\")}\n </LoadingButton>\n </div>\n </div>\n )}\n </div>\n )}\n\n {activeTab === \"security\" && hasPasswordChange && (\n <div className=\"flex flex-col gap-6 max-w-xl\">\n <Typography variant=\"h6\" className=\"mb-2\">{t(\"change_password\")}</Typography>\n\n <TextField\n label={t(\"current_password\")}\n type=\"password\"\n value={currentPassword}\n onChange={(e) => setCurrentPassword(e.target.value)}\n autoComplete=\"current-password\"\n />\n <TextField\n label={t(\"new_password\")}\n type=\"password\"\n value={newPassword}\n onChange={(e) => setNewPassword(e.target.value)}\n autoComplete=\"new-password\"\n />\n <TextField\n label={t(\"confirm_password\")}\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n autoComplete=\"new-password\"\n />\n\n {passwordError && (\n <Typography color=\"error\">{passwordError}</Typography>\n )}\n {passwordSuccess && (\n <Alert color=\"success\">{passwordSuccess}</Alert>\n )}\n\n <div className=\"mt-4\">\n <Button\n variant=\"filled\"\n onClick={handleChangePassword}\n disabled={changingPassword || !currentPassword || !newPassword || !confirmPassword}\n >\n {changingPassword ? t(\"changing_password\") : t(\"change_password\")}\n </Button>\n </div>\n </div>\n )}\n\n\n {activeTab === \"sessions\" && (\n <div className=\"flex flex-col gap-4 max-w-3xl\">\n {loadingSessions ? (\n <div className=\"flex justify-center p-8\"><CircularProgress/></div>\n ) : sessionsError ? (\n <Typography color=\"error\">{sessionsError}</Typography>\n ) : sessions.length === 0 ? (\n <Typography>{t(\"no_active_sessions\")}</Typography>\n ) : (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex justify-end mb-2\">\n <Button\n variant=\"text\"\n color=\"error\"\n onClick={handleRevokeAll}\n disabled={revokingAll}\n >\n {revokingAll ? t(\"revoking\") : t(\"revoke_all_sessions\")}\n </Button>\n </div>\n {sessions.map(session => (\n <Card key={session.id} className=\"flex justify-between items-center p-4\">\n <div className=\"flex flex-col\">\n <div className=\"flex items-center gap-2 mb-1\">\n <Typography variant=\"body1\">\n {session.userAgent || t(\"unknown_device\")}\n </Typography>\n {session.isCurrentSession && (\n <Chip colorScheme=\"blue\" size=\"small\">\n {t(\"current\")}\n </Chip>\n )}\n </div>\n <Typography variant=\"caption\" color=\"secondary\">\n {t(\"session_details\", {\n ip: session.ipAddress || t(\"unknown_address\"),\n created: new Date(session.createdAt).toLocaleString()\n })}\n </Typography>\n </div>\n <div className=\"ml-4\">\n {revokingSessionId === session.id ? (\n <CircularProgress size=\"small\"/>\n ) : (\n <IconButton onClick={() => handleRevokeSession(session.id, session.isCurrentSession)} aria-label={t(\"revoke_session\")}>\n <Trash2Icon/>\n </IconButton>\n )}\n </div>\n </Card>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import React from \"react\";\nimport { CheckIcon, IconButton, iconSize, LanguagesIcon, Menu, MenuItem, Typography } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks\";\n\nexport function LanguageToggle() {\n const { t, i18n } = useTranslation();\n\n return (\n <Menu\n trigger={<IconButton\n aria-label={t(\"change_language\")}>\n <LanguagesIcon size={iconSize.small}/>\n </IconButton>}>\n <MenuItem onClick={() => i18n.changeLanguage(\"en\")}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === \"en\" ? \"font-semibold\" : \"\"}>English</Typography>\n {i18n.language === \"en\" && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n <MenuItem onClick={() => i18n.changeLanguage(\"es\")}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === \"es\" ? \"font-semibold\" : \"\"}>Español</Typography>\n {i18n.language === \"es\" && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n <MenuItem onClick={() => i18n.changeLanguage(\"de\")}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === \"de\" ? \"font-semibold\" : \"\"}>Deutsch</Typography>\n {i18n.language === \"de\" && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n <MenuItem onClick={() => i18n.changeLanguage(\"fr\")}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === \"fr\" ? \"font-semibold\" : \"\"}>Français</Typography>\n {i18n.language === \"fr\" && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n <MenuItem onClick={() => i18n.changeLanguage(\"it\")}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === \"it\" ? \"font-semibold\" : \"\"}>Italiano</Typography>\n {i18n.language === \"it\" && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n <MenuItem onClick={() => i18n.changeLanguage(\"hi\")}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === \"hi\" ? \"font-semibold\" : \"\"}>हिन्दी</Typography>\n {i18n.language === \"hi\" && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n <MenuItem onClick={() => i18n.changeLanguage(\"pt\")}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === \"pt\" ? \"font-semibold\" : \"\"}>Português</Typography>\n {i18n.language === \"pt\" && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n </Menu>\n );\n}\n","\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n CircleUserIcon,\n CircularProgress,\n cls,\n defaultBorderMixin,\n IconButton,\n iconSize,\n Popover,\n SearchBar,\n SearchIcon,\n Typography,\n XIcon\n} from \"@rebasepro/ui\";\nimport { User } from \"@rebasepro/types\";\n\n/**\n * Represents a selectable user item with optional role information.\n */\nexport interface SelectableUser {\n uid: string;\n displayName?: string | null;\n email?: string | null;\n photoURL?: string | null;\n roles?: string[];\n}\n\nexport interface UserSelectPopoverProps {\n /**\n * The currently selected user, or `null` for \"self\"/default.\n */\n selectedUser: SelectableUser | null;\n /**\n * Called when the user selection changes.\n * `null` means \"reset to self/default\".\n */\n onUserSelected: (user: SelectableUser | null) => void;\n /**\n * Full list of users to display.\n * The component handles client-side search/filter internally.\n */\n users: SelectableUser[];\n /**\n * Whether users are currently loading.\n */\n loading?: boolean;\n /**\n * Called with the search text each time it changes (debounced), for a\n * parent that searches its users on a server rather than passing them all\n * in `users`. The list is still filtered here by the same text.\n */\n onSearchTextChange?: (searchText: string) => void;\n /**\n * For a parent that lists only the first page of a server search: how many\n * users that search matched in all. Leave it out when `users` holds every\n * match. When set, the header counts the listed users against it and a\n * notice says the others are not listed.\n */\n totalCount?: number;\n /**\n * The current user (displayed as the \"self\" option at the top).\n */\n currentUser?: SelectableUser | null;\n /**\n * Label to display when no user is selected.\n * @default \"Current user\"\n */\n defaultLabel?: string;\n /**\n * Maximum number of users to render at a time (for performance).\n * Users can still be found via search.\n * @default 100\n */\n renderLimit?: number;\n /**\n * Additional class name for the trigger button.\n */\n className?: string;\n /**\n * Size variant.\n * @default \"small\"\n */\n size?: \"small\" | \"medium\";\n}\n\nconst ITEM_HEIGHT = 44;\nconst MAX_VISIBLE_ITEMS = 7;\n\n/**\n * A reusable user picker popover with search support.\n * Designed to handle very large user lists (100k+) by filtering\n * client-side and limiting the rendered set.\n *\n * @group Components\n */\nexport function UserSelectPopover({\n selectedUser,\n onUserSelected,\n users,\n loading = false,\n onSearchTextChange,\n totalCount,\n currentUser,\n defaultLabel = \"Current user\",\n renderLimit = 100,\n className,\n size = \"small\"\n}: UserSelectPopoverProps) {\n const [open, setOpen] = useState(false);\n const [searchText, setSearchText] = useState(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n // Effective user label for the trigger\n const effectiveUserLabel = selectedUser\n ? (selectedUser.displayName || selectedUser.email || selectedUser.uid)\n : (currentUser?.displayName || currentUser?.email || defaultLabel);\n\n // Filter users based on search text\n const filteredUsers = useMemo(() => {\n const query = searchText.trim().toLowerCase();\n const base = users.filter(u => u.uid !== currentUser?.uid);\n\n if (!query) return base.slice(0, renderLimit);\n\n const matched = base.filter(u => {\n const name = (u.displayName || \"\").toLowerCase();\n const email = (u.email || \"\").toLowerCase();\n const uid = u.uid.toLowerCase();\n const roles = (u.roles || []).join(\" \").toLowerCase();\n return (\n name.includes(query) ||\n email.includes(query) ||\n uid.includes(query) ||\n roles.includes(query)\n );\n });\n\n return matched.slice(0, renderLimit);\n }, [users, currentUser?.uid, searchText, renderLimit]);\n\n const totalFilterable = useMemo(() => {\n const query = searchText.trim().toLowerCase();\n const base = users.filter(u => u.uid !== currentUser?.uid);\n if (!query) return base.length;\n return base.filter(u => {\n const name = (u.displayName || \"\").toLowerCase();\n const email = (u.email || \"\").toLowerCase();\n const uid = u.uid.toLowerCase();\n const roles = (u.roles || []).join(\" \").toLowerCase();\n return name.includes(query) || email.includes(query) || uid.includes(query) || roles.includes(query);\n }).length;\n }, [users, currentUser?.uid, searchText]);\n\n const handleSelect = useCallback((user: SelectableUser | null) => {\n onUserSelected(user);\n setOpen(false);\n setSearchText(\"\");\n }, [onUserSelected]);\n\n const handleOpenChange = useCallback((isOpen: boolean) => {\n setOpen(isOpen);\n if (isOpen) {\n // Auto-focus the search input when opening\n setTimeout(() => inputRef.current?.focus(), 50);\n } else {\n setSearchText(\"\");\n }\n }, []);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") {\n setOpen(false);\n setSearchText(\"\");\n }\n }, []);\n\n const listHeight = Math.min(\n (filteredUsers.length + 1) * ITEM_HEIGHT, // +1 for the \"self\" option\n MAX_VISIBLE_ITEMS * ITEM_HEIGHT\n );\n\n return (\n <Popover\n open={open}\n onOpenChange={handleOpenChange}\n side=\"bottom\"\n align=\"end\"\n sideOffset={4}\n trigger={\n <button\n className={cls(\n \"flex items-center gap-1.5 text-xs font-medium transition-colors rounded border border-transparent\",\n \"text-text-secondary dark:text-text-secondary-dark\",\n \"hover:text-text-primary dark:hover:text-text-primary-dark\",\n \"bg-surface-raised hover:bg-surface-raised-hover\",\n size === \"small\" ? \"px-2 py-1\" : \"px-3 py-1.5\",\n className\n )}\n >\n {selectedUser?.photoURL ? (\n <img\n src={selectedUser.photoURL}\n alt=\"\"\n className=\"w-4 h-4 rounded-full object-cover\"\n />\n ) : (\n <svg\n className=\"w-3.5 h-3.5 text-text-disabled dark:text-text-disabled-dark\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\"\n />\n </svg>\n )}\n <span className=\"max-w-[120px] truncate\">{effectiveUserLabel}</span>\n {selectedUser && (\n <span className=\"text-[9px] text-amber-600 dark:text-amber-400 font-semibold uppercase\">\n impersonating\n </span>\n )}\n <svg className=\"w-3 h-3 opacity-50 ml-0.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\"/>\n </svg>\n </button>\n }\n >\n <div\n className=\"flex flex-col w-[320px] max-w-[90vw] overflow-hidden\"\n onKeyDown={handleKeyDown}\n >\n {/* Header */}\n <div className={cls(\"px-3 py-2 border-b flex items-center justify-between shrink-0\", defaultBorderMixin)}>\n <Typography\n variant=\"caption\"\n className=\"font-semibold uppercase tracking-wider text-[9px] text-text-disabled dark:text-text-disabled-dark\"\n >\n Run as user\n </Typography>\n {users.length > 0 && (\n <Typography\n variant=\"caption\"\n className=\"text-[9px] text-text-disabled dark:text-text-disabled-dark tabular-nums\"\n >\n {totalCount !== undefined\n ? `${filteredUsers.length} of ${totalCount} users`\n : `${totalFilterable} user${totalFilterable !== 1 ? \"s\" : \"\"}`}\n </Typography>\n )}\n </div>\n\n {/* Search input */}\n <div className={cls(\"px-2 py-1.5 border-b shrink-0\", defaultBorderMixin)}>\n <SearchBar\n inputRef={inputRef}\n size=\"smallest\"\n placeholder=\"Search by name, email, or role…\"\n onTextSearch={(val) => {\n setSearchText(val ?? \"\");\n onSearchTextChange?.(val ?? \"\");\n }}\n />\n </div>\n\n {/* User list */}\n <div\n ref={listRef}\n className=\"overflow-y-auto overscroll-contain\"\n style={{ maxHeight: MAX_VISIBLE_ITEMS * ITEM_HEIGHT }}\n >\n {/* Self (default) option — always shown unless search hides it */}\n {currentUser && (!searchText.trim() || matchesSearch(currentUser, searchText)) && (\n <UserRow\n user={currentUser}\n isSelected={!selectedUser}\n isSelf\n onClick={() => handleSelect(null)}\n />\n )}\n\n {/* Loading state */}\n {loading && (\n <div className=\"flex items-center justify-center py-6\">\n <CircularProgress size=\"small\"/>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && filteredUsers.length === 0 && searchText.trim() && (\n <div className=\"flex flex-col items-center justify-center py-6 px-4\">\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark text-center\">\n No users matching &ldquo;{searchText}&rdquo;\n </Typography>\n </div>\n )}\n\n {/* User items */}\n {!loading && filteredUsers.map(user => (\n <UserRow\n key={user.uid}\n user={user}\n isSelected={selectedUser?.uid === user.uid}\n onClick={() => handleSelect(user)}\n />\n ))}\n\n {/* The parent listed only the first page of its server search */}\n {!loading && totalCount !== undefined && (\n <div className={cls(\"px-3 py-2 border-t text-center\", defaultBorderMixin)}>\n <Typography\n variant=\"caption\"\n className=\"text-[10px] text-text-disabled dark:text-text-disabled-dark\"\n >\n Showing the first {filteredUsers.length} of {totalCount} users. Search to find the others.\n </Typography>\n </div>\n )}\n\n {/* Truncation notice */}\n {!loading && totalCount === undefined && totalFilterable > renderLimit && (\n <div className={cls(\"px-3 py-2 border-t text-center\", defaultBorderMixin)}>\n <Typography\n variant=\"caption\"\n className=\"text-[10px] text-text-disabled dark:text-text-disabled-dark\"\n >\n Showing {renderLimit} of {totalFilterable} results. Use search to narrow down.\n </Typography>\n </div>\n )}\n </div>\n </div>\n </Popover>\n );\n}\n\n// ─── Internal Components ─────────────────────────────────────────────\n\ninterface UserRowProps {\n user: SelectableUser;\n isSelected: boolean;\n isSelf?: boolean;\n onClick: () => void;\n}\n\nfunction UserRow({ user, isSelected, isSelf, onClick }: UserRowProps) {\n return (\n <button\n onClick={onClick}\n className={cls(\n \"w-full flex items-center gap-2.5 px-3 py-2 text-left transition-colors\",\n \"hover:bg-surface-hover\",\n isSelected && \"bg-primary/5 dark:bg-primary-dark/10\"\n )}\n style={{ minHeight: ITEM_HEIGHT }}\n >\n {/* Avatar */}\n {user.photoURL ? (\n <img\n src={user.photoURL}\n alt=\"\"\n className=\"w-7 h-7 rounded-full object-cover shrink-0\"\n />\n ) : (\n <div className=\"w-7 h-7 rounded-full bg-surface-raised flex items-center justify-center shrink-0\">\n <CircleUserIcon\n size={iconSize.smallest}\n className=\"text-text-disabled dark:text-text-disabled-dark\"\n />\n </div>\n )}\n\n {/* User info */}\n <div className=\"flex flex-col min-w-0 flex-grow\">\n <div className=\"flex items-center gap-1.5\">\n <span\n className={cls(\n \"text-xs font-medium truncate\",\n isSelected\n ? \"text-primary dark:text-primary-dark\"\n : \"text-text-primary dark:text-text-primary-dark\"\n )}\n >\n {user.displayName || user.email || user.uid}\n </span>\n {isSelf && (\n <span className=\"text-[9px] text-text-disabled dark:text-text-disabled-dark font-medium shrink-0\">\n (you)\n </span>\n )}\n </div>\n {(user.email || user.roles?.length) && (\n <span className=\"text-[10px] text-text-disabled dark:text-text-disabled-dark truncate\">\n {user.email && user.displayName ? user.email : \"\"}\n {user.email && user.displayName && user.roles?.length ? \" · \" : \"\"}\n {user.roles?.length ? user.roles.join(\", \") : \"\"}\n </span>\n )}\n </div>\n\n {/* Selection indicator */}\n {isSelected && (\n <svg\n className=\"w-4 h-4 text-primary dark:text-primary-dark shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2.5} d=\"M5 13l4 4L19 7\"/>\n </svg>\n )}\n </button>\n );\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────\n\nfunction matchesSearch(user: SelectableUser, searchText: string): boolean {\n const query = searchText.trim().toLowerCase();\n if (!query) return true;\n const name = (user.displayName || \"\").toLowerCase();\n const email = (user.email || \"\").toLowerCase();\n const uid = user.uid.toLowerCase();\n return name.includes(query) || email.includes(query) || uid.includes(query);\n}\n","import { CircleUserIcon, cls, defaultBorderMixin } from \"@rebasepro/ui\";\nimport { User } from \"@rebasepro/types\";\n\n/**\n * Component to render a single user with name and email\n */\nexport function UserDisplay({\n user\n}: { user: User | null }) {\n if (!user) {\n return <span className={cls(\"italic\", \"text-text-disabled dark:text-text-disabled-dark\", \"text-sm\")}>Not set</span>;\n }\n\n const avatarSizeClass = \"w-6 h-6\";\n\n return (\n <div className={cls(\n \"inline-flex items-center gap-4 px-2 py-1 rounded-xl text-left max-w-full overflow-hidden\",\n \"bg-surface-raised\",\n \"border\",\n defaultBorderMixin\n )}>\n {user.photoURL ? (\n <img\n src={user.photoURL}\n alt={user.displayName || user.email || \"User\"}\n className={cls(\n \"rounded-full object-cover\",\n avatarSizeClass\n )}\n />\n ) : (\n <CircleUserIcon\n className={cls(\n \"text-text-secondary dark:text-text-secondary-dark\",\n avatarSizeClass\n )}\n />\n )}\n <div className=\"flex flex-col min-w-0\">\n <span className={cls(\"font-regular truncate\", \"text-sm\")}>\n {user.displayName || user.email || \"-\"}\n </span>\n {user.displayName && user.email && (\n <span className={cls(\"text-text-secondary dark:text-text-secondary-dark truncate\",\n \"text-xs\"\n )}>\n {user.email}\n </span>\n )}\n </div>\n </div>\n );\n}\n","/**\n * The browser half of the OAuth authorization-code flow.\n *\n * The server only ever sees a `code` and a `redirectUri` taken from the\n * request body, so `state`, PKCE and the binding between \"this browser started\n * a login\" and \"this code came back\" are, by construction, the client's job.\n * In the admin login they had been nobody's job: the authorize URL carried no\n * `state`, and the return leg accepted any `?code=` as long as a localStorage\n * marker naming the *provider* was set — a marker written on button click and\n * removed only on a callback that carried a code, so abandoning the flow left\n * it set indefinitely.\n *\n * Everything here is provider-agnostic on purpose. A button that wants a new\n * provider calls {@link startOAuthRedirect} and gets state, expiry and PKCE\n * without deciding anything, which is what stops the next provider shipping\n * without them.\n */\n\n/** sessionStorage, not localStorage: a login attempt belongs to one tab. */\nconst STORAGE_KEY = \"rebase_oauth_redirect\";\n\n/** How long a started authorization stays valid. */\nconst PENDING_TTL_MS = 10 * 60 * 1000;\n\nexport interface OAuthRedirectRequest {\n /** Provider id, as mounted at `POST /auth/<id>`. */\n provider: string;\n /** The provider's authorization endpoint. */\n authorizeUrl: string;\n clientId: string;\n scope: string;\n /** Where the provider sends the browser back. Echoed to the token exchange. */\n redirectUri: string;\n /** Set when the provider implements PKCE. */\n pkce?: boolean;\n /** Extra authorize-endpoint parameters (`response_type`, and so on). */\n params?: Record<string, string>;\n}\n\n/** What the browser remembers between leaving for the provider and coming back. */\nexport interface PendingOAuthRedirect {\n provider: string;\n state: string;\n codeVerifier?: string;\n redirectUri: string;\n startedAt: number;\n}\n\nexport type OAuthCallbackResult =\n /** No OAuth callback in this URL. */\n | { status: \"none\" }\n /** The provider reported a failure, or the user declined. */\n | { status: \"error\"; error: string }\n /**\n * A code arrived that this browser cannot account for: no pending\n * authorization, an expired one, or a `state` that does not match. This is\n * what a login-CSRF / code-injection attempt looks like.\n */\n | { status: \"mismatch\" }\n | { status: \"ok\"; provider: string; code: string; codeVerifier?: string; redirectUri: string };\n\ntype Storage = Pick<globalThis.Storage, \"getItem\" | \"setItem\" | \"removeItem\">;\n\nfunction defaultStorage(): Storage | null {\n try {\n return window.sessionStorage;\n } catch {\n return null;\n }\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction randomToken(byteLength = 32): string {\n const bytes = new Uint8Array(byteLength);\n crypto.getRandomValues(bytes);\n return base64Url(bytes);\n}\n\nasync function pkceChallenge(verifier: string): Promise<string> {\n const digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(verifier));\n return base64Url(new Uint8Array(digest));\n}\n\nexport function readPendingOAuthRedirect(storage: Storage | null = defaultStorage()): PendingOAuthRedirect | null {\n if (!storage) return null;\n const raw = storage.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as PendingOAuthRedirect;\n if (!parsed?.provider || !parsed?.state) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function clearPendingOAuthRedirect(storage: Storage | null = defaultStorage()): void {\n storage?.removeItem(STORAGE_KEY);\n}\n\n/**\n * Build the authorize URL and the pending record that will validate its\n * callback. Split out from {@link startOAuthRedirect} so it can be tested\n * without navigating.\n */\nexport async function buildOAuthAuthorization(\n request: OAuthRedirectRequest,\n now: number = Date.now()\n): Promise<{ url: string; pending: PendingOAuthRedirect }> {\n const state = randomToken();\n const url = new URL(request.authorizeUrl);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", request.clientId);\n url.searchParams.set(\"redirect_uri\", request.redirectUri);\n url.searchParams.set(\"scope\", request.scope);\n url.searchParams.set(\"state\", state);\n for (const [key, value] of Object.entries(request.params ?? {})) {\n url.searchParams.set(key, value);\n }\n\n let codeVerifier: string | undefined;\n if (request.pkce) {\n codeVerifier = randomToken(32);\n url.searchParams.set(\"code_challenge\", await pkceChallenge(codeVerifier));\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n }\n\n return {\n url: url.toString(),\n pending: { provider: request.provider, state, codeVerifier, redirectUri: request.redirectUri, startedAt: now }\n };\n}\n\n/** Remember the authorization and send the browser to the provider. */\nexport async function startOAuthRedirect(\n request: OAuthRedirectRequest,\n storage: Storage | null = defaultStorage()\n): Promise<void> {\n const { url, pending } = await buildOAuthAuthorization(request);\n storage?.setItem(STORAGE_KEY, JSON.stringify(pending));\n window.location.href = url;\n}\n\n/**\n * Interpret a return from the provider.\n *\n * Clears the pending record on **every** path that saw a callback — including\n * `?error=` and a state mismatch — so a declined or abandoned consent screen\n * cannot leave the browser primed to accept somebody else's code later.\n */\nexport function consumeOAuthCallback(\n search: string,\n storage: Storage | null = defaultStorage(),\n now: number = Date.now()\n): OAuthCallbackResult {\n const params = new URLSearchParams(search);\n const code = params.get(\"code\");\n const state = params.get(\"state\");\n const error = params.get(\"error\");\n\n if (!code && !error && !state) return { status: \"none\" };\n\n const pending = readPendingOAuthRedirect(storage);\n clearPendingOAuthRedirect(storage);\n\n if (error) return { status: \"error\", error };\n if (!code) return { status: \"mismatch\" };\n if (!pending) return { status: \"mismatch\" };\n if (now - pending.startedAt > PENDING_TTL_MS) return { status: \"mismatch\" };\n if (!state || state !== pending.state) return { status: \"mismatch\" };\n\n return {\n status: \"ok\",\n provider: pending.provider,\n code,\n codeVerifier: pending.codeVerifier,\n redirectUri: pending.redirectUri\n };\n}\n","/**\n * What the login screen says about a refused sign-in.\n *\n * The server's message is written for whoever reads the API response, and some\n * of them are instructions for a developer. A Google sign-in onto an address\n * that already has an unverified password account used to put this in front of\n * the visitor:\n *\n * … Sign in with your existing method, then POST to /auth/link/google to\n * link google to your account.\n *\n * So the codes a person can act on get the screen's own, translated words, and\n * every other error keeps the server's message, which is still the most\n * specific thing there is to show.\n */\nexport function authErrorMessage(error: unknown, t: (key: string) => string): string {\n if (error instanceof Error && \"code\" in error && error.code === \"EMAIL_NOT_VERIFIED\") {\n // `local-account-unverified` is the one reason that says how the\n // existing account signs in: it holds a password.\n const reason = \"details\" in error && typeof error.details === \"object\" && error.details !== null\n && \"reason\" in error.details\n ? error.details.reason\n : undefined;\n return reason === \"local-account-unverified\"\n ? t(\"auth_account_exists_sign_in_with_password\")\n : t(\"auth_account_exists_with_different_credential\");\n }\n // Confirm-first registration: the password is right, the address is not\n // confirmed yet, and a new link is on its way.\n if (error instanceof Error && \"code\" in error && error.code === \"EMAIL_NOT_CONFIRMED\") {\n return t(\"auth_email_not_confirmed\");\n }\n return error instanceof Error ? error.message : String(error);\n}\n","/**\n * The links the backend puts in its auth emails, as the login view reads them.\n *\n * The server builds them from the configured frontend URL:\n * `<frontend>/reset-password?token=…` for a forgotten password, an admin's\n * \"send reset email\" and every invitation, `<frontend>/verify-email?token=…`\n * to confirm an address, `<frontend>/confirm-email-change?token=…` to move an\n * account to a new one, and `<frontend>/auth/magic-link?token=…` to sign in.\n * The frontend URL may carry a base path (`/admin`), so the action is read off\n * the *end* of the path, not the whole path.\n */\nexport type EmailLinkAction =\n | { kind: \"reset-password\"; token: string }\n | { kind: \"verify-email\"; token: string }\n | { kind: \"confirm-email-change\"; token: string }\n | { kind: \"magic-link\"; token: string };\n\n/** Each action, and the path it ends with. A magic link's is two segments. */\nconst ACTIONS: { kind: EmailLinkAction[\"kind\"]; path: string }[] = [\n { kind: \"reset-password\", path: \"/reset-password\" },\n { kind: \"verify-email\", path: \"/verify-email\" },\n { kind: \"confirm-email-change\", path: \"/confirm-email-change\" },\n { kind: \"magic-link\", path: \"/auth/magic-link\" }\n];\n\nexport function readEmailLinkAction(location: { pathname: string; search: string }): EmailLinkAction | null {\n const token = new URLSearchParams(location.search).get(\"token\");\n if (!token) return null;\n const pathname = location.pathname.replace(/\\/+$/, \"\");\n const action = ACTIONS.find(({ path }) => pathname.endsWith(path));\n return action ? { kind: action.kind, token } : null;\n}\n\n/**\n * Where the app lives: the link's own address without the action's path and\n * its token. `/admin/reset-password?token=…` becomes `/admin/`, and\n * `/admin/auth/magic-link?token=…` too.\n */\nexport function appAddressOfEmailLink(location: { origin: string; pathname: string }): string {\n const pathname = location.pathname.replace(/\\/+$/, \"\");\n const action = ACTIONS.find(({ path }) => pathname.endsWith(path));\n const withoutAction = action\n ? pathname.slice(0, pathname.length - action.path.length)\n : pathname.replace(/\\/[^/]*$/, \"\");\n return `${location.origin}${withoutAction}/`;\n}\n","import type { AuthControllerExtended, MfaFactorSummary } from \"@rebasepro/cms-types\";\n\n/**\n * A sign-in that is waiting for its second factor.\n *\n * The server refuses the first factor of an account with MFA enrolled with\n * `401 MFA_REQUIRED`, and puts in `details` what the second step needs: a\n * pending token, good for five minutes and for the two challenge routes only,\n * and the factors the account can answer with.\n */\nexport interface PendingMfaSignIn {\n mfaToken: string;\n factors: MfaFactorSummary[];\n}\n\nfunction isFactor(value: unknown): value is MfaFactorSummary {\n return typeof value === \"object\" && value !== null\n && \"id\" in value && typeof value.id === \"string\" && value.id.length > 0\n && \"factorType\" in value && typeof value.factorType === \"string\";\n}\n\n/**\n * The pending sign-in an `MFA_REQUIRED` refusal describes, or `null` for any\n * other error — including an `MFA_REQUIRED` without the token or a factor to\n * answer with, which no code step could finish.\n */\nexport function readMfaRequired(error: unknown): PendingMfaSignIn | null {\n if (!(error instanceof Error) || !(\"code\" in error) || error.code !== \"MFA_REQUIRED\") return null;\n const details = \"details\" in error ? error.details : undefined;\n if (typeof details !== \"object\" || details === null) return null;\n const mfaToken = \"mfaToken\" in details ? details.mfaToken : undefined;\n const factors = \"factors\" in details && Array.isArray(details.factors) ? details.factors.filter(isFactor) : [];\n if (typeof mfaToken !== \"string\" || !mfaToken || factors.length === 0) return null;\n return { mfaToken, factors };\n}\n\n/** Whether this controller can take a sign-in through its second step. */\nexport function canAnswerMfa(authController: AuthControllerExtended): boolean {\n return Boolean(authController.startMfaChallenge && authController.verifyMfaChallenge);\n}\n\n/**\n * What a refused challenge means for the code step.\n *\n * - `invalid-code`: the code was wrong; the same challenge takes another.\n * - `exhausted`: the challenge has had its five attempts; the next code needs\n * a new one.\n * - `expired`: the sign-in itself is over. The pending token lasts five\n * minutes from the password, and once it has lapsed both routes refuse the\n * caller as unauthenticated; a challenge that lapsed, or a sign-in revoked\n * meanwhile, ends the same way. Only a new sign-in gets a new token.\n */\nexport function classifyMfaRefusal(error: unknown): \"invalid-code\" | \"exhausted\" | \"expired\" | \"other\" {\n if (!(error instanceof Error)) return \"other\";\n const code = \"code\" in error && typeof error.code === \"string\" ? error.code : undefined;\n const status = \"status\" in error && typeof error.status === \"number\" ? error.status : undefined;\n if (code === \"INVALID_CODE\") return \"invalid-code\";\n if (code === \"CHALLENGE_EXHAUSTED\") return \"exhausted\";\n if (code === \"INVALID_CHALLENGE\" || code === \"SESSION_REVOKED\") return \"expired\";\n if (status === 401 && (code === undefined || code === \"UNAUTHORIZED\")) return \"expired\";\n return \"other\";\n}\n","import React, { ReactNode, useCallback, useEffect, useId, useRef, useState } from \"react\";\n\n/** Google Identity Services SDK — injected by the GIS <script> tag. */\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n oauth2: {\n initCodeClient(config: {\n client_id: string;\n scope: string;\n ux_mode: \"popup\" | \"redirect\";\n callback: (response: { code?: string; error?: string }) => void;\n }): { requestCode(): void };\n };\n };\n };\n }\n}\n\nimport {\n ArrowLeftIcon,\n Button,\n CheckCircle2Icon,\n Checkbox,\n CircularProgress,\n cls,\n IconButton,\n iconSize,\n LoadingButton,\n MailIcon,\n Menu,\n MenuItem,\n MoonIcon,\n Select,\n SelectItem,\n SunIcon,\n SunMoonIcon,\n TextField,\n Typography,\n isKeyHandled\n} from \"@rebasepro/ui\";\nimport { User } from \"@rebasepro/types\";\nimport { AuthControllerExtended, MfaFactorSummary } from \"@rebasepro/cms-types\";\nimport { ErrorView } from \"../ErrorView\";\nimport { RebaseLogo } from \"../RebaseLogo\";\nimport { LanguageToggle } from \"../LanguageToggle\";\nimport { useModeController, useTranslation } from \"../../hooks\";\nimport { consumeOAuthCallback, startOAuthRedirect } from \"./oauth-redirect-flow\";\nimport { authErrorMessage } from \"./auth-error-message\";\nimport { appAddressOfEmailLink, readEmailLinkAction } from \"./email-link\";\nimport { emailChangeErrorMessage } from \"../email-change-message\";\nimport { canAnswerMfa, classifyMfaRefusal, PendingMfaSignIn, readMfaRequired } from \"./mfa-required\";\n\n/**\n * Props for the generic LoginView.\n * Consumes {@link AuthControllerExtended} — works with any backend\n * (Rebase custom backend, Firebase, etc.)\n */\nexport interface LoginViewProps {\n /**\n * Auth controller — must implement AuthControllerExtended.\n */\n authController: AuthControllerExtended;\n\n /**\n * Path to the logo displayed in the login screen\n */\n logo?: string;\n\n /**\n * Enable the skip login button\n */\n allowSkipLogin?: boolean;\n\n /**\n * Disable the login buttons\n */\n disabled?: boolean;\n\n /**\n * Prevent users from creating new accounts.\n * If not set, checks `authController.capabilities.registrationEnabled`.\n */\n disableSignupScreen?: boolean;\n\n /**\n * Display this component when no user is found\n */\n noUserComponent?: ReactNode;\n\n /**\n * Display this component below the sign-in buttons\n */\n additionalComponent?: ReactNode;\n\n /**\n * Display this component above the sign-in buttons\n */\n topComponent?: ReactNode;\n\n /**\n * Error message when user is not allowed access\n */\n notAllowedError?: string | Error;\n\n\n /**\n * Google client ID for Google OAuth.\n * Required when Google login is enabled via ID token flow.\n */\n googleClientId?: string;\n\n /**\n * GitHub client ID for GitHub OAuth.\n */\n githubClientId?: string;\n\n /**\n * LinkedIn client ID for LinkedIn OAuth.\n */\n linkedinClientId?: string;\n\n /**\n * Optional custom title shown above options\n */\n title?: string;\n\n /**\n * Optional custom subtitle shown above options\n */\n subtitle?: string;\n\n /**\n * When true, shows bootstrap/setup UI (first-user creation).\n * If not set, derived from `authController` if it exposes `needsSetup`.\n */\n needsSetup?: boolean;\n\n /**\n * Whether registration is enabled.\n * If not set, derived from `authController.capabilities.registrationEnabled`.\n */\n registrationEnabled?: boolean;\n\n /**\n * Pre-fill the email field (e.g. for demo or testing environments).\n */\n defaultEmail?: string;\n\n /**\n * Pre-fill the password field (e.g. for demo or testing environments).\n */\n defaultPassword?: string;\n\n /**\n * When set, a \"Join the newsletter\" opt-in checkbox is offered. Called with\n * the address that just authenticated — by any method — if the box was\n * ticked. Wire it to whatever stores the subscription; failures are the\n * callback's problem, the login flow never waits on it.\n *\n * The checkbox sits on the **provider screen**, beside the buttons that\n * choose how to sign in, rather than on the credentials form. It is a\n * decision about the visitor, not about the password: asking on the\n * credentials form put it in front of only the people who got that far by\n * typing an address, so anyone signing in with Google was never offered it\n * at all. Bootstrap mode is the exception — there is no provider screen\n * there, so the form keeps it.\n */\n onNewsletterOptIn?: (email: string) => void;\n}\n\ntype AuthMode = \"buttons\" | \"login\" | \"register\" | \"forgot\" | \"reset-password\" | \"verify-email\" | \"confirm-email-change\" | \"magic-link\";\n\n/**\n * The shared field background mixin (`dark:bg-black/30`) is invisible on the\n * near-black login card, so login inputs get an explicit border in dark mode.\n */\nconst loginFieldClasses = \"w-full dark:border dark:border-surface-700/70 dark:hover:border-surface-600\";\n\n/** One warning per provider per page load — this is a config hint, not a log stream. */\nconst warnedProviders = new Set<string>();\n\n/**\n * An OAuth button needs a client id in the frontend *and* the provider\n * configured on the backend. Half a configuration renders nothing at all, with\n * no error anywhere — the button simply is not there, which reads as \"the\n * feature broke\" rather than \"one env var is missing\". Say which half is\n * missing instead.\n */\nfunction warnAboutHalfConfiguredOAuth(\n provider: string,\n clientId: string | undefined,\n backendProviders: string[]\n) {\n const backendHasIt = backendProviders.includes(provider);\n if (Boolean(clientId) === backendHasIt) return; // both or neither — nothing to say\n if (warnedProviders.has(provider)) return;\n warnedProviders.add(provider);\n\n const envVar = `${provider.toUpperCase()}_CLIENT_ID`;\n console.warn(\n clientId\n ? `[Rebase] ${provider} login is hidden: the login view has a client id, but the backend reports no \"${provider}\" provider. `\n + `Set ${envVar} (and ${provider.toUpperCase()}_CLIENT_SECRET) on the server and restart it.`\n : `[Rebase] ${provider} login is hidden: the backend has a \"${provider}\" provider, but the login view was given no client id. `\n + `Pass it to the login view (e.g. VITE_${envVar}) and restart the frontend so the new env var is picked up.`\n );\n}\n\n/**\n * Whether a provider's error code means \"the visitor backed out\" rather than\n * \"the sign-in failed\". Closing the popup is an answer, not a fault, and\n * showing it in red reads as a broken login.\n */\nfunction isUserCancellation(code: string | undefined): boolean {\n if (!code) return false;\n return [\n \"access_denied\",\n \"popup_closed\",\n \"popup_closed_by_user\",\n \"user_cancel\",\n \"immediate_failed\"\n ].includes(code);\n}\n\n/**\n * The controller's last refused sign-in, as a sign-in screen should show it:\n * not at all once a user is present — a stale failure must not sit over a\n * screen that has since succeeded — and not at all for an `MFA_REQUIRED` this\n * view can take to its code step, where it is a cue rather than a failure.\n */\nfunction signInRefusal(authController: AuthControllerExtended): unknown {\n const error = authController.authProviderError;\n if (!error || authController.user) return null;\n if (canAnswerMfa(authController) && readMfaRequired(error)) return null;\n return error;\n}\n\n/**\n * Generic login view component that works with any AuthControllerExtended.\n * Feature-detects capabilities to show/hide login methods.\n * @group Core\n */\nexport function LoginView({\n logo,\n authController,\n noUserComponent,\n disableSignupScreen = false,\n disabled = false,\n notAllowedError,\n googleClientId,\n githubClientId,\n linkedinClientId,\n title,\n subtitle,\n needsSetup,\n registrationEnabled,\n additionalComponent,\n topComponent,\n defaultEmail,\n defaultPassword,\n onNewsletterOptIn\n}: LoginViewProps) {\n\n const modeState = useModeController();\n const { mode: colorMode, setMode: setColorMode } = modeState;\n const { t } = useTranslation();\n\n // A link from an auth email opens this screen on its own step: setting a\n // new password (a reset, or an invitation's first password) or confirming\n // an address. Read once — the token is spent by the step it opens.\n const [emailLink] = useState(() => typeof window === \"undefined\" ? null : readEmailLinkAction(window.location));\n const [mode, setMode] = useState<AuthMode>(emailLink?.kind ?? \"buttons\");\n const [fadeIn, setFadeIn] = useState(false);\n const [viewVisible, setViewVisible] = useState(true);\n // Failures that never reach the auth controller: a provider that answers the\n // popup with an error, a redirect whose `state` does not match, a Google\n // script that never loaded. The controller records everything it is *given*\n // in `authProviderError`, so it cannot speak for the half of the flow that\n // happens before the code reaches it.\n const [providerError, setProviderError] = useState<string | null>(null);\n // Lives here, not in LoginForm: the box is ticked on the provider screen\n // and read after a sign-in that happens one or two screens later, so it has\n // to outlive both. The form also unmounts on every login↔register switch.\n const [newsletterOptIn, setNewsletterOptIn] = useState(false);\n // A sign-in waiting for its second factor. Every sign-in method — the\n // email form, Google, an OAuth redirect — reports an `MFA_REQUIRED`\n // refusal through the controller, so this is taken from there rather\n // than from any one of them, and shown in place of whichever screen\n // started it. Back clears it and that screen is still there.\n const [pendingMfa, setPendingMfa] = useState<PendingMfaSignIn | null>(null);\n const mfaAnswerable = canAnswerMfa(authController);\n useEffect(() => {\n if (!mfaAnswerable || authController.user) return;\n const pending = readMfaRequired(authController.authProviderError);\n if (!pending) return;\n setProviderError(null);\n setPendingMfa(pending);\n }, [authController.authProviderError, authController.user, mfaAnswerable]);\n\n // A magic link has done its job once somebody is signed in: by its own\n // token, by the code step after it, or before it was ever opened. The app\n // starts at its own address, not at the link's — and an already signed-in\n // visitor does not spend the link at all.\n const signedIn = Boolean(authController.user);\n useEffect(() => {\n if (emailLink?.kind === \"magic-link\" && signedIn) leaveEmailLink();\n }, [emailLink, signedIn]);\n\n // The controller as of the latest render. A provider callback resolves long\n // after the click that started it, and the `authController` captured in that\n // closure is the one from the render that mounted the button — which, for a\n // controller replaced on each render, has no `user` on it yet.\n const authControllerRef = useRef(authController);\n authControllerRef.current = authController;\n\n /**\n * Subscribe the address that just authenticated, if the visitor asked for\n * it. Every sign-in path calls this, which is the point: the checkbox sits\n * beside the provider buttons, so it has to mean the same thing whichever\n * one is pressed.\n *\n * Only ever from a resolution path — a ticked box on a *failed* attempt\n * must not subscribe an address nobody proved they control.\n */\n const subscribeIfOptedIn = useCallback((email?: string | null) => {\n if (!newsletterOptIn || !onNewsletterOptIn || !email) return;\n onNewsletterOptIn(email);\n }, [newsletterOptIn, onNewsletterOptIn]);\n\n const switchMode = (newMode: AuthMode) => {\n // A message about the last Google attempt has nothing to say about the\n // email form the visitor just opened.\n setProviderError(null);\n setViewVisible(false);\n setTimeout(() => {\n setMode(newMode);\n setViewVisible(true);\n }, 150);\n };\n\n // Resolve capabilities — explicit props override authController.capabilities\n const caps = authController.capabilities ?? {};\n const isBootstrapMode = needsSetup\n ?? (\"needsSetup\" in authController && !!(authController as { needsSetup?: boolean }).needsSetup)\n ?? false;\n const canRegister = registrationEnabled ?? caps.registrationEnabled ?? false;\n // Every OAuth button needs BOTH halves: a client id here and the matching\n // provider configured on the backend. `enabledProviders` is always an array\n // (the controller defaults it to `[]`), so a missing entry means \"the\n // backend has no such provider\" — never \"unknown\". A client id on its own\n // shows nothing, which is silent enough that `warnAboutHalfConfiguredOAuth`\n // below says so out loud.\n const backendProviders = caps.enabledProviders ?? [];\n const hasGoogleLogin = Boolean(googleClientId) && backendProviders.includes(\"google\");\n const hasGitHubLogin = githubClientId && backendProviders.includes(\"github\");\n const hasLinkedinLogin = linkedinClientId && backendProviders.includes(\"linkedin\");\n\n useEffect(() => {\n // `enabledProviders` is empty until /auth/config lands, which looks\n // exactly like \"the backend has no providers\" — so wait for the value\n // to settle. A config that arrives late re-runs this effect and cancels\n // the pending warning.\n const timer = setTimeout(() => {\n warnAboutHalfConfiguredOAuth(\"google\", googleClientId, backendProviders);\n warnAboutHalfConfiguredOAuth(\"github\", githubClientId, backendProviders);\n warnAboutHalfConfiguredOAuth(\"linkedin\", linkedinClientId, backendProviders);\n }, 3000);\n return () => clearTimeout(timer);\n }, [googleClientId, githubClientId, linkedinClientId, backendProviders.join(\",\")]);\n const hasPasswordReset = caps.passwordReset ?? !!authController.forgotPassword;\n\n const showRegistration = !disableSignupScreen && canRegister;\n\n useEffect(() => {\n const timer = setTimeout(() => setFadeIn(true), 50);\n return () => clearTimeout(timer);\n }, []);\n\n // Effect to handle incoming redirect OAuth codes (GitHub, LinkedIn, etc.).\n //\n // The `code` is only spent when it belongs to an authorization this browser\n // started: `consumeOAuthCallback` matches the returned `state` against the\n // one generated at button-click time. Without that, an attacker who starts\n // their own authorization, captures the code and gets the victim to load\n // `?code=<theirs>` hands the victim a session on the *attacker's* account.\n useEffect(() => {\n const result = consumeOAuthCallback(window.location.search);\n if (result.status === \"none\") return;\n\n // Clear URL search params without page reload. The entry's state is\n // kept as it is: it is the router's `{ usr, key, idx }`, and an entry\n // without its index makes the next Back a navigation the router cannot\n // measure, which it lets through past every unsaved-changes blocker.\n const cleanUrl = window.location.origin + window.location.pathname;\n window.history.replaceState(window.history.state, document.title, cleanUrl);\n\n if (result.status === \"error\") {\n console.error(`OAuth sign-in failed: ${result.error}`);\n if (!isUserCancellation(result.error)) {\n setProviderError(`Sign-in failed: ${result.error}`);\n }\n return;\n }\n if (result.status === \"mismatch\") {\n console.error(\"Ignoring an OAuth code that does not match a sign-in this browser started.\");\n setProviderError(\"This sign-in could not be verified as one you started in this browser. Please try again.\");\n return;\n }\n\n if (authController.oauthLogin) {\n // The rejection is recorded in `authProviderError`, which the screen\n // renders — the catch is here so a shown error does not also surface\n // as an unhandled rejection.\n authController.oauthLogin(result.provider, {\n code: result.code,\n redirectUri: result.redirectUri,\n ...(result.codeVerifier ? { codeVerifier: result.codeVerifier } : {})\n }).catch((err: unknown) => {\n console.error(`${result.provider} login failed:`, err);\n });\n }\n }, [authController]);\n\n\n\n let logoComponent;\n if (logo) {\n logoComponent = <img src={logo}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\"\n }}\n alt={\"Logo\"}/>;\n } else {\n logoComponent = <RebaseLogo/>;\n }\n\n // The controller's own record of the last rejected sign-in — see\n // `signInRefusal`. `LoginForm` renders the same value for the email path.\n const refusal = signInRefusal(authController);\n const controllerError = refusal ? authErrorMessage(refusal, t) : null;\n const buttonsErrorMessage = providerError ?? controllerError;\n\n let notAllowedMessage: string | undefined;\n if (notAllowedError) {\n if (typeof notAllowedError === \"string\") {\n notAllowedMessage = notAllowedError;\n } else if (notAllowedError instanceof Error) {\n notAllowedMessage = notAllowedError.message;\n } else {\n notAllowedMessage = \"It looks like you don't have access, based on the specified access configuration\";\n }\n }\n\n return (\n <div\n className={cls(\n \"relative flex items-center justify-center h-screen w-screen p-4 transition-opacity duration-500 bg-surface-frame overflow-hidden\",\n fadeIn ? \"opacity-100\" : \"opacity-0\"\n )}>\n\n {/* Top-right controls */}\n <div className=\"absolute top-4 right-4 flex items-center gap-1 z-10\">\n <LanguageToggle/>\n <Menu\n trigger={<IconButton\n aria-label=\"Toggle theme\">\n {colorMode === \"dark\"\n ? <MoonIcon size={iconSize.small}/>\n : <SunIcon size={iconSize.small}/>}\n </IconButton>}>\n <MenuItem onClick={() => setColorMode(\"dark\")}><MoonIcon size={iconSize.smallest}/> {t(\"dark_mode\")}</MenuItem>\n <MenuItem onClick={() => setColorMode(\"light\")}><SunIcon size={iconSize.smallest}/> {t(\"light_mode\")}</MenuItem>\n <MenuItem onClick={() => setColorMode(\"system\")}><SunMoonIcon size={iconSize.smallest}/> {t(\"system_mode\")}</MenuItem>\n </Menu>\n </div>\n\n <div className=\"relative flex flex-col items-center w-[440px] max-w-full p-8 sm:p-10 bg-surface-card/70 backdrop-blur-xl border border-hairline-strong rounded-2xl shadow-2xl z-10 transition-all duration-300 hover:shadow-primary/5\">\n {/* Logo */}\n <div className=\"w-24 h-24 m-2 mb-4 drop-shadow-md\">\n {logoComponent}\n </div>\n\n {notAllowedMessage && (\n <div className=\"p-4 w-full\">\n <ErrorView error={notAllowedMessage}/>\n </div>\n )}\n\n <div className={cls(\n \"w-full transition-opacity duration-150\",\n viewVisible ? \"opacity-100\" : \"opacity-0\"\n )}>\n\n {/* Bootstrap mode: show setup form directly */}\n {isBootstrapMode && !authController.user && (\n <LoginForm\n authController={authController}\n registrationMode={true}\n onClose={() => {}}\n onForgotPassword={() => {}}\n disableSignupScreen={false}\n bootstrapMode={true}\n defaultEmail={defaultEmail}\n defaultPassword={defaultPassword}\n onSignedIn={subscribeIfOptedIn}\n newsletterOptIn={newsletterOptIn}\n setNewsletterOptIn={setNewsletterOptIn}\n showNewsletterOptIn={Boolean(onNewsletterOptIn)}\n />\n )}\n\n {/* The second step of a sign-in, whichever screen began it */}\n {!isBootstrapMode && pendingMfa && (\n <MfaChallengeForm\n key={pendingMfa.mfaToken}\n pending={pendingMfa}\n authController={authController}\n onBack={() => setPendingMfa(null)}\n onSignedIn={() => subscribeIfOptedIn(authControllerRef.current.user?.email)}\n />\n )}\n\n {/* Normal mode */}\n {!isBootstrapMode && !pendingMfa && (\n <>\n {/* Provider buttons screen */}\n {mode === \"buttons\" && (\n <div className=\"w-full flex flex-col gap-3 mt-2\">\n {/* Every provider button fails here, and this\n screen used to render nothing for it: a\n refused Google sign-in closed the popup\n and returned the visitor to an unchanged\n login screen, with the reason only in the\n browser console. */}\n {buttonsErrorMessage && (\n <ErrorView error={buttonsErrorMessage}/>\n )}\n {(title || subtitle) && (\n <div className=\"text-center mb-2\">\n {title && (\n <Typography variant=\"h6\" className=\"mb-0.5 font-semibold\">\n {title}\n </Typography>\n )}\n {subtitle && (\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-4\">\n {subtitle}\n </Typography>\n )}\n </div>\n )}\n {topComponent && (\n <div className=\"w-full\">\n {topComponent}\n </div>\n )}\n {/* Above the buttons, not below them: it is a\n condition on the sign-in you are about to\n make, and it reads as one more line of the\n consent block a host puts in\n `topComponent` — the demo's privacy tick\n sits directly above it.\n\n Which is why it pulls back most of the\n column's `gap-3`: at the full gap the two\n ticks sat 24px apart and read as two\n unrelated questions rather than one\n consent block. The offset is against this\n column's own gap, not against whatever\n margins the host's `topComponent` happens\n to carry, so it lands the same way under\n any of them — but only when there is\n something above to hug. With no header\n and no `topComponent` this row is the\n column's first child, and pulling back a\n gap that is not there would crowd it into\n the logo. */}\n {onNewsletterOptIn && (\n <label className={cls(\n \"flex items-center gap-2 cursor-pointer\",\n (topComponent || title || subtitle) && \"-mt-3\"\n )}>\n <Checkbox\n checked={newsletterOptIn}\n onCheckedChange={(checked) => setNewsletterOptIn(checked === true)}\n size=\"small\"\n />\n <Typography variant=\"caption\" color=\"secondary\" className=\"select-none\">\n {t(\"join_newsletter\")}\n </Typography>\n </label>\n )}\n <LoginButton\n disabled={disabled}\n text={\"Sign in with email\"}\n icon={<MailIcon/>}\n onClick={() => switchMode(\"login\")}\n />\n {hasGoogleLogin && googleClientId && (\n <GoogleLoginButton\n disabled={disabled}\n googleClientId={googleClientId}\n authController={authController}\n onSignedIn={() => subscribeIfOptedIn(authControllerRef.current.user?.email)}\n onError={setProviderError}\n />\n )}\n {hasGitHubLogin && githubClientId && (\n <GitHubLoginButton\n disabled={disabled}\n githubClientId={githubClientId}\n />\n )}\n {hasLinkedinLogin && linkedinClientId && (\n <LinkedInLoginButton\n disabled={disabled}\n linkedinClientId={linkedinClientId}\n />\n )}\n {showRegistration && (\n <div className=\"mt-2 text-center\">\n <Typography variant=\"body2\" color=\"secondary\">\n Don&apos;t have an account?{\" \"}\n <button\n type=\"button\"\n className=\"font-semibold hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={() => switchMode(\"register\")}\n >\n Create one\n </button>\n </Typography>\n </div>\n )}\n </div>\n )}\n\n {/* Login form */}\n {mode === \"login\" && (\n <LoginForm\n authController={authController}\n registrationMode={false}\n onClose={() => switchMode(\"buttons\")}\n onForgotPassword={hasPasswordReset ? () => switchMode(\"forgot\") : undefined}\n noUserComponent={noUserComponent}\n disableSignupScreen={disableSignupScreen}\n switchToRegister={showRegistration ? () => switchMode(\"register\") : undefined}\n defaultEmail={defaultEmail}\n defaultPassword={defaultPassword}\n onSignedIn={subscribeIfOptedIn}\n />\n )}\n\n {/* Registration form */}\n {mode === \"register\" && (\n <LoginForm\n authController={authController}\n registrationMode={true}\n onClose={() => switchMode(\"buttons\")}\n onForgotPassword={hasPasswordReset ? () => switchMode(\"forgot\") : undefined}\n noUserComponent={noUserComponent}\n disableSignupScreen={disableSignupScreen}\n switchToLogin={() => switchMode(\"login\")}\n defaultEmail={defaultEmail}\n defaultPassword={defaultPassword}\n onSignedIn={subscribeIfOptedIn}\n />\n )}\n\n {/* Forgot password form */}\n {mode === \"forgot\" && authController.forgotPassword && (\n <ForgotPasswordForm\n authController={authController}\n onClose={() => switchMode(\"login\")}\n />\n )}\n\n {/* Opened from a reset or invitation email */}\n {mode === \"reset-password\" && emailLink?.kind === \"reset-password\" && (\n <ResetPasswordForm\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n\n {/* Opened from a verification email */}\n {mode === \"verify-email\" && emailLink?.kind === \"verify-email\" && (\n <VerifyEmailView\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n\n {/* Opened from a magic link */}\n {mode === \"magic-link\" && emailLink?.kind === \"magic-link\" && !signedIn && (\n <MagicLinkView\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n\n {/* Opened from the link an address change mails to the new address */}\n {mode === \"confirm-email-change\" && emailLink?.kind === \"confirm-email-change\" && (\n <ConfirmEmailChangeView\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n </>\n )}\n </div>\n\n {additionalComponent && !isBootstrapMode && mode === \"buttons\" && !pendingMfa && (\n <div className=\"w-full\">\n {additionalComponent}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction LoginButton({\n icon,\n onClick,\n text,\n disabled\n}: { icon: React.ReactNode, onClick: () => void, text: string, disabled?: boolean }) {\n return (\n <Button\n disabled={disabled}\n className=\"w-full transition-transform duration-200 active:scale-[0.98]\"\n variant=\"outlined\"\n size=\"large\"\n onClick={onClick}>\n <div className=\"flex items-center justify-center w-full gap-3 py-1\">\n <span className=\"flex items-center justify-center w-5 h-5\">\n {icon}\n </span>\n <Typography variant=\"button\">{text}</Typography>\n </div>\n </Button>\n );\n}\n\nconst GoogleIcon = () => (\n <svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"/>\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/>\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/>\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/>\n </svg>\n);\n\nfunction GoogleLoginButton({\n disabled,\n googleClientId,\n authController,\n onSignedIn,\n onError\n}: {\n disabled?: boolean,\n googleClientId: string,\n authController: AuthControllerExtended,\n /** Called once the controller has accepted the provider's code. */\n onSignedIn?: () => void,\n /**\n * Reports a failure the auth controller never saw — Google answering the\n * popup with an error, or its script never having loaded. A rejected\n * `googleLogin` is not reported here: the controller already records it.\n */\n onError?: (message: string | null) => void\n}) {\n const codeClientRef = useRef<{ requestCode(): void } | null>(null);\n // The code client is built once and its callback closes over this render's\n // props forever. A ref keeps the callback reaching the *current* handler\n // rather than the one that existed when Google's script happened to load.\n const onSignedInRef = useRef(onSignedIn);\n onSignedInRef.current = onSignedIn;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n\n /**\n * Build Google's code client, if its script has arrived. Google's script\n * tag is `async`, so it routinely lands after this button has mounted:\n * the click tries again rather than trusting whatever the mount saw.\n */\n const ensureCodeClient = useCallback(() => {\n if (codeClientRef.current || !authController.googleLogin) return codeClientRef.current;\n\n const google = window.google;\n if (!google) return null;\n\n codeClientRef.current = google.accounts.oauth2.initCodeClient({\n client_id: googleClientId,\n scope: \"openid email profile\",\n ux_mode: \"popup\",\n callback: async (response: { code?: string; error?: string }) => {\n if (response.error || !response.code) {\n console.error(\"Google login error:\", response.error);\n if (!isUserCancellation(response.error)) {\n onErrorRef.current?.(\n response.error\n ? `Google sign-in failed: ${response.error}`\n : \"Google sign-in failed. Please try again.\"\n );\n }\n return;\n }\n onErrorRef.current?.(null);\n try {\n // Send the authorization code to the backend.\n // redirectUri \"postmessage\" is required when using popup ux_mode.\n await authController.googleLogin!({\n code: response.code,\n redirectUri: \"postmessage\"\n });\n // After the await, and only on the resolution path: a\n // newsletter tick must not subscribe an address whose\n // sign-in the controller rejected.\n onSignedInRef.current?.();\n } catch (err: unknown) {\n console.error(\"Google login error:\", err);\n }\n }\n });\n return codeClientRef.current;\n }, [googleClientId, authController]);\n\n useEffect(() => {\n ensureCodeClient();\n }, [ensureCodeClient]);\n\n const handleClick = () => {\n const codeClient = ensureCodeClient();\n if (!codeClient) {\n console.error(\"Google Sign-In not loaded\");\n onErrorRef.current?.(\"Google Sign-In could not be loaded. Check your connection or any script blockers, then try again.\");\n return;\n }\n onErrorRef.current?.(null);\n codeClient.requestCode();\n };\n\n return (\n <LoginButton\n disabled={disabled}\n text=\"Sign in with Google\"\n icon={<GoogleIcon/>}\n onClick={handleClick}\n />\n );\n}\n\nconst GitHubIcon = () => (\n <svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\">\n <path d=\"M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.464-1.11-1.464-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.579.688.481C19.137 20.162 22 16.418 22 12c0-5.523-4.477-10-10-10z\"/>\n </svg>\n);\n\nfunction GitHubLoginButton({\n disabled,\n githubClientId\n}: {\n disabled?: boolean,\n githubClientId: string\n}) {\n const handleClick = () => {\n // GitHub OAuth Apps do not implement PKCE, so `state` is the whole\n // binding between this click and the code that comes back.\n void startOAuthRedirect({\n provider: \"github\",\n authorizeUrl: \"https://github.com/login/oauth/authorize\",\n clientId: githubClientId,\n redirectUri: window.location.origin + window.location.pathname,\n scope: \"read:user,user:email\"\n });\n };\n\n return (\n <LoginButton\n disabled={disabled}\n text=\"Sign in with GitHub\"\n icon={<GitHubIcon/>}\n onClick={handleClick}\n />\n );\n}\n\nconst LinkedInIcon = () => (\n <svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\">\n <path d=\"M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z\"/>\n </svg>\n);\n\nfunction LinkedInLoginButton({\n disabled,\n linkedinClientId\n}: {\n disabled?: boolean,\n linkedinClientId: string\n}) {\n const handleClick = () => {\n void startOAuthRedirect({\n provider: \"linkedin\",\n authorizeUrl: \"https://www.linkedin.com/oauth/v2/authorization\",\n clientId: linkedinClientId,\n redirectUri: window.location.origin + window.location.pathname,\n scope: \"openid profile email\"\n });\n };\n\n return (\n <LoginButton\n disabled={disabled}\n text=\"Sign in with LinkedIn\"\n icon={<LinkedInIcon/>}\n onClick={handleClick}\n />\n );\n}\n\nfunction LoginForm({\n onClose,\n onForgotPassword,\n authController,\n registrationMode,\n noUserComponent,\n disableSignupScreen,\n bootstrapMode = false,\n switchToRegister,\n switchToLogin,\n defaultEmail,\n defaultPassword,\n onSignedIn,\n newsletterOptIn = false,\n setNewsletterOptIn,\n showNewsletterOptIn = false\n}: {\n onClose: () => void,\n onForgotPassword?: () => void,\n authController: AuthControllerExtended,\n registrationMode: boolean,\n noUserComponent?: ReactNode,\n disableSignupScreen: boolean,\n bootstrapMode?: boolean,\n switchToRegister?: () => void,\n switchToLogin?: () => void,\n defaultEmail?: string,\n defaultPassword?: string,\n /** The address the controller just accepted, reported after every success. */\n onSignedIn?: (email: string) => void,\n newsletterOptIn?: boolean,\n setNewsletterOptIn?: (checked: boolean) => void,\n /**\n * Render the newsletter opt-in here. Only bootstrap mode does: everywhere\n * else it lives on the provider screen, which bootstrap mode never shows.\n */\n showNewsletterOptIn?: boolean\n}) {\n const passwordRef = useRef<HTMLInputElement | null>(null);\n const { t } = useTranslation();\n\n // `Typography variant=\"label\"` already renders a real <label> element, it just\n // never pointed at anything, so each field fell back to naming itself after its\n // own placeholder — the password field announced as eight bullets. Associating\n // the existing labels beats passing the kit's `label` prop here: that one moves\n // the text inside the box (`pt-6 pb-2` at this size) and hides the placeholder\n // until focus, which would redesign the login screen to fix a name.\n const emailId = useId();\n const passwordId = useId();\n const [confirmationSent, setConfirmationSent] = useState(false);\n const displayNameId = useId();\n\n const [email, setEmail] = useState<string | undefined>(defaultEmail);\n const [password, setPassword] = useState<string | undefined>(defaultPassword);\n const [displayName, setDisplayName] = useState<string>();\n\n useEffect(() => {\n if (!document) return;\n const escFunction = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && !isKeyHandled(event)) {\n event.preventDefault();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", escFunction, false);\n return () => {\n document.removeEventListener(\"keydown\", escFunction, false);\n };\n }, [onClose]);\n\n // Both controller methods record the failure in `authProviderError` — which\n // this form renders above — and then rethrow for programmatic callers. This\n // is not one of those: without a catch here every rejected sign-in becomes an\n // unhandled rejection, reported as a crash by anything listening for one,\n // while the user has already been shown the error.\n // Fires only on the resolution path, i.e. after the controller accepted\n // the credentials — a ticked box on a failed attempt must not subscribe\n // an address its owner never proved they control.\n function reportSignedIn(email: string) {\n onSignedIn?.(email);\n }\n\n function handleEnterPassword() {\n if (email && password && authController.emailPasswordLogin) {\n void Promise.resolve(authController.emailPasswordLogin(email, password))\n .then(() => reportSignedIn(email))\n .catch(() => undefined);\n }\n }\n\n function handleRegistration() {\n if (email && password && authController.register) {\n void Promise.resolve(authController.register(email, password, displayName))\n .then((result) => {\n // Confirm-first: nobody is signed in until the link in the\n // mail is followed.\n if (result?.confirmationRequired) setConfirmationSent(true);\n else reportSignedIn(email);\n })\n .catch(() => undefined);\n }\n }\n\n const handleSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n if (registrationMode)\n handleRegistration();\n else\n handleEnterPassword();\n };\n\n const title = bootstrapMode\n ? \"Welcome!\"\n : registrationMode\n ? \"Create account\"\n : \"Sign in\";\n\n const subtitle = bootstrapMode\n ? \"Create your admin account to get started. This account will have admin privileges.\"\n : registrationMode\n ? \"Fill in your details to create a new account\"\n : \"Enter your credentials to continue\";\n\n const buttonLabel = registrationMode ? \"Create account\" : \"Sign in\";\n\n if (confirmationSent) {\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_confirm_email_sent_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_confirm_email_sent_body\")}\n </Typography>\n </div>\n <Button onClick={onClose} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n {!bootstrapMode && (\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton aria-label={t(\"back\")} onClick={onClose}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n )}\n\n {(() => {\n const err = signInRefusal(authController);\n if (!err) return null;\n const msg = authErrorMessage(err, t);\n return (\n <div className=\"w-full mb-2\">\n <ErrorView error={msg}/>\n </div>\n );\n })()}\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {title}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {subtitle}\n </Typography>\n\n {registrationMode && !bootstrapMode && noUserComponent && (\n <div className=\"w-full mb-2\">\n {noUserComponent}\n </div>\n )}\n\n {registrationMode && (\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={displayNameId}>\n Display Name\n </Typography>\n <TextField placeholder=\"Jane Doe (optional)\"\n id={displayNameId}\n className={loginFieldClasses}\n value={displayName ?? \"\"}\n disabled={authController.initialLoading}\n type=\"text\"\n size=\"medium\"\n onChange={(event) => setDisplayName(event.target.value)}/>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={emailId}>\n Email\n </Typography>\n <TextField placeholder=\"you@example.com\"\n id={emailId}\n className={loginFieldClasses}\n autoFocus\n value={email ?? \"\"}\n disabled={authController.initialLoading}\n type=\"email\"\n size=\"medium\"\n onChange={(event) => setEmail(event.target.value)}/>\n </div>\n\n <div className=\"w-full mb-1\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={passwordId}>\n Password\n </Typography>\n <TextField placeholder=\"••••••••\"\n id={passwordId}\n className={loginFieldClasses}\n value={password ?? \"\"}\n disabled={authController.initialLoading}\n inputRef={passwordRef}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setPassword(event.target.value)}/>\n </div>\n\n {registrationMode && (\n <Typography variant=\"caption\" color=\"secondary\" className=\"mb-3\">\n Password must be 8+ characters with uppercase, lowercase, and a number\n </Typography>\n )}\n\n {!registrationMode && onForgotPassword && (\n <div className=\"w-full text-right mb-3\">\n <button\n type=\"button\"\n className=\"text-xs font-medium hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={onForgotPassword}\n >\n Forgot password?\n </button>\n </div>\n )}\n\n {/* Bootstrap mode only — see `showNewsletterOptIn`. Every other\n route to this form came through the provider screen, which is\n where the box now is. */}\n {showNewsletterOptIn && (\n <label className=\"flex items-center gap-2 cursor-pointer mt-1 mb-1\">\n <Checkbox\n checked={newsletterOptIn}\n onCheckedChange={(checked) => setNewsletterOptIn?.(checked === true)}\n size=\"small\"\n />\n <Typography variant=\"caption\" color=\"secondary\" className=\"select-none\">\n {t(\"join_newsletter\")}\n </Typography>\n </label>\n )}\n\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={authController.authLoading}\n disabled={authController.authLoading || !email || !password}\n >\n {buttonLabel}\n </LoadingButton>\n\n {/* Switch between login/register */}\n {switchToRegister && (\n <div className=\"mt-4 text-center\">\n <Typography variant=\"body2\" color=\"secondary\">\n Don&apos;t have an account?{\" \"}\n <button\n type=\"button\"\n className=\"font-semibold hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={switchToRegister}\n >\n Create one\n </button>\n </Typography>\n </div>\n )}\n\n {switchToLogin && (\n <div className=\"mt-4 text-center\">\n <Typography variant=\"body2\" color=\"secondary\">\n Already have an account?{\" \"}\n <button\n type=\"button\"\n className=\"font-semibold hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={switchToLogin}\n >\n Sign in\n </button>\n </Typography>\n </div>\n )}\n </form>\n );\n}\n\n/** How a factor is named in the picker: the name its owner gave it, if any. */\nfunction factorName(factor: MfaFactorSummary, index: number, t: (key: string) => string): string {\n if (factor.friendlyName) return factor.friendlyName;\n const kind = factor.factorType === \"totp\" ? t(\"auth_mfa_factor_totp\") : factor.factorType;\n return `${kind} ${index + 1}`;\n}\n\n/**\n * The second step of a sign-in refused with `MFA_REQUIRED`: a code from the\n * authenticator app, or one of the recovery codes, in the same field — the\n * server tries the one and then the other.\n *\n * The challenge is opened on the first submit and answered by every code\n * after it until it is spent, which is after five wrong ones: the next code\n * then opens a new one. The pending token behind both lasts five minutes from\n * the password; once it has lapsed nothing here can help, so the step says so\n * and sends the visitor back to sign in again.\n */\nfunction MfaChallengeForm({\n pending,\n authController,\n onBack,\n onSignedIn\n}: {\n pending: PendingMfaSignIn,\n authController: AuthControllerExtended,\n /** Back to the sign-in screen the refusal came from. */\n onBack: () => void,\n /** Called once the controller has accepted a code. */\n onSignedIn?: () => void\n}) {\n const { t } = useTranslation();\n const factorFieldId = useId();\n const codeId = useId();\n const [factorId, setFactorId] = useState(pending.factors[0].id);\n const [code, setCode] = useState(\"\");\n const [challengeId, setChallengeId] = useState<string | null>(null);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [expired, setExpired] = useState(false);\n\n // A challenge belongs to one factor: another factor needs its own.\n const chooseFactor = (id: string) => {\n setFactorId(id);\n setChallengeId(null);\n setError(null);\n };\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n const answer = code.trim();\n const { startMfaChallenge, verifyMfaChallenge } = authController;\n if (!answer || submitting || expired || !startMfaChallenge || !verifyMfaChallenge) return;\n\n setError(null);\n setSubmitting(true);\n try {\n const id = challengeId ?? await startMfaChallenge(pending.mfaToken, factorId);\n setChallengeId(id);\n await verifyMfaChallenge(pending.mfaToken, id, answer);\n onSignedIn?.();\n } catch (err: unknown) {\n switch (classifyMfaRefusal(err)) {\n case \"invalid-code\":\n setCode(\"\");\n setError(t(\"auth_mfa_code_invalid\"));\n break;\n case \"exhausted\":\n setCode(\"\");\n setChallengeId(null);\n setError(t(\"auth_mfa_challenge_exhausted\"));\n break;\n case \"expired\":\n setExpired(true);\n setError(t(\"auth_mfa_expired\"));\n break;\n default:\n setError(authErrorMessage(err, t));\n }\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton onClick={onBack} aria-label={t(\"back\")}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_mfa_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {t(\"auth_mfa_subtitle\")}\n </Typography>\n\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n\n {pending.factors.length > 1 && (\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={factorFieldId}>\n {t(\"auth_mfa_factor_label\")}\n </Typography>\n <Select\n id={factorFieldId}\n aria-label={t(\"auth_mfa_factor_label\")}\n value={factorId}\n onValueChange={chooseFactor}\n disabled={submitting || expired}\n size=\"medium\"\n fullWidth\n >\n {pending.factors.map((factor, index) => (\n <SelectItem key={factor.id} value={factor.id}>\n {factorName(factor, index, t)}\n </SelectItem>\n ))}\n </Select>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={codeId}>\n {t(\"auth_mfa_code_label\")}\n </Typography>\n {/* Text, not numeric: a recovery code has letters in it. */}\n <TextField\n id={codeId}\n className={loginFieldClasses}\n autoFocus\n autoComplete=\"one-time-code\"\n autoCapitalize=\"none\"\n spellCheck={false}\n value={code}\n disabled={expired}\n type=\"text\"\n size=\"medium\"\n onChange={(event) => setCode(event.target.value)}\n />\n </div>\n\n {expired\n ? (\n <Button onClick={onBack} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full mt-1\">\n {t(\"auth_mfa_sign_in_again\")}\n </Button>\n )\n : (\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={submitting}\n disabled={submitting || !code.trim()}\n >\n {t(\"auth_mfa_verify\")}\n </LoadingButton>\n )}\n </form>\n );\n}\n\n/**\n * Leave an email link for the app's own address, with a fresh load.\n *\n * The router, when there is one, still stands on `/reset-password`: rewriting\n * the address under it would leave it rendering a route that does not exist\n * the moment the user signs in. A load starts it where the app starts, and the\n * spent token leaves the address bar and the history entry with it.\n */\nfunction leaveEmailLink() {\n window.location.replace(appAddressOfEmailLink(window.location));\n}\n\n/** What to say about a refused email-link token, or any other failure. */\nfunction emailLinkErrorMessage(error: unknown, t: (key: string) => string): string {\n if (error instanceof Error && \"code\" in error && error.code === \"INVALID_TOKEN\") {\n return t(\"auth_link_invalid_or_expired\");\n }\n return authErrorMessage(error, t);\n}\n\n/**\n * The step a reset link opens: a new password for the account the token was\n * issued to. An invitation sends the same link, so this is also where an\n * invited user — created without a password — sets their first one.\n */\nfunction ResetPasswordForm({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n /** Back to the app's own address, and the sign-in screen. */\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const passwordId = useId();\n const confirmationId = useId();\n const [password, setPassword] = useState(\"\");\n const [confirmation, setConfirmation] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [changed, setChanged] = useState(false);\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n setError(null);\n\n if (!authController.resetPassword) {\n setError(t(\"auth_password_reset_unavailable\"));\n return;\n }\n if (password !== confirmation) {\n setError(t(\"passwords_dont_match\"));\n return;\n }\n\n setSubmitting(true);\n try {\n await authController.resetPassword(token, password);\n setChanged(true);\n } catch (err: unknown) {\n setError(emailLinkErrorMessage(err, t));\n } finally {\n setSubmitting(false);\n }\n };\n\n if (changed) {\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_password_changed_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_password_changed_body\")}\n </Typography>\n </div>\n\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton onClick={onDone} aria-label={t(\"back\")}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_new_password_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {t(\"auth_new_password_subtitle\")}\n </Typography>\n\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={passwordId}>\n {t(\"new_password\")}\n </Typography>\n <TextField\n id={passwordId}\n className={loginFieldClasses}\n autoFocus\n autoComplete=\"new-password\"\n value={password}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setPassword(event.target.value)}\n />\n </div>\n\n <div className=\"w-full mb-1\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={confirmationId}>\n {t(\"confirm_password\")}\n </Typography>\n <TextField\n id={confirmationId}\n className={loginFieldClasses}\n autoComplete=\"new-password\"\n value={confirmation}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setConfirmation(event.target.value)}\n />\n </div>\n\n <Typography variant=\"caption\" color=\"secondary\" className=\"mb-3\">\n {t(\"auth_password_requirements\")}\n </Typography>\n\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={submitting}\n disabled={submitting || !password || !confirmation}\n >\n {t(\"auth_set_password\")}\n </LoadingButton>\n </form>\n );\n}\n\n/**\n * The step a verification link opens.\n *\n * The link proves the inbox, not who registered the address. So when the\n * account holds a password, the server asks for it before keeping it\n * (`PROOF_REQUIRED`): the owner types the password they chose and is signed\n * in; someone who never set one — whose address a stranger registered —\n * verifies without it, and the stranger's password is removed.\n */\nfunction VerifyEmailView({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const [status, setStatus] = useState<\"verifying\" | \"proof\" | \"verified\" | \"failed\">(\"verifying\");\n const [error, setError] = useState<string | null>(null);\n const [password, setPassword] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [passwordRemoved, setPasswordRemoved] = useState(false);\n const passwordId = useId();\n // Once per token. A second call — a development double-mount, say —\n // would race the first for the same token.\n const requestedRef = useRef(false);\n\n const verify = useCallback(async (options?: { password?: string; removeUnproven?: boolean }) => {\n setError(null);\n try {\n if (!authController.verifyEmail) return;\n const result = await authController.verifyEmail(token, options);\n setPasswordRemoved(result?.passwordRemoved === true);\n setStatus(\"verified\");\n } catch (err: unknown) {\n if (err instanceof Error && \"code\" in err && err.code === \"PROOF_REQUIRED\") {\n setStatus(\"proof\");\n return;\n }\n if (options?.password !== undefined && err instanceof Error && \"code\" in err && err.code === \"INVALID_CREDENTIALS\") {\n setError(t(\"auth_verify_email_wrong_password\"));\n return;\n }\n setError(emailLinkErrorMessage(err, t));\n setStatus(\"failed\");\n }\n }, [authController, token, t]);\n\n useEffect(() => {\n if (requestedRef.current) return;\n requestedRef.current = true;\n if (!authController.verifyEmail) {\n setError(t(\"auth_email_verification_unavailable\"));\n setStatus(\"failed\");\n return;\n }\n void verify();\n }, [authController, verify, t]);\n\n if (status === \"verifying\") {\n return (\n <div className=\"flex flex-col items-center w-full gap-4 mt-6 mb-4\">\n <CircularProgress size=\"small\"/>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_verifying_email\")}\n </Typography>\n </div>\n );\n }\n\n if (status === \"proof\") {\n const submit = (options: { password?: string; removeUnproven?: boolean }) => {\n setSubmitting(true);\n void verify(options).finally(() => setSubmitting(false));\n };\n return (\n <form\n className=\"flex flex-col w-full gap-1 mt-2\"\n onSubmit={(event) => {\n event.preventDefault();\n if (password) submit({ password });\n }}\n >\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_verify_email_proof_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {t(\"auth_verify_email_proof_body\")}\n </Typography>\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={passwordId}>\n {t(\"auth_verify_email_password_label\")}\n </Typography>\n <TextField\n id={passwordId}\n className={loginFieldClasses}\n autoFocus\n autoComplete=\"current-password\"\n value={password}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setPassword(event.target.value)}\n />\n </div>\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={submitting}\n disabled={submitting || !password}\n >\n {t(\"auth_verify_email_with_password\")}\n </LoadingButton>\n <Button\n variant=\"text\"\n className=\"w-full mt-1\"\n disabled={submitting}\n onClick={() => submit({ removeUnproven: true })}\n >\n {t(\"auth_verify_email_without_password\")}\n </Button>\n </form>\n );\n }\n\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n {status === \"verified\"\n ? (\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_email_verified_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {passwordRemoved ? t(\"auth_email_verified_password_removed_body\") : t(\"auth_email_verified_body\")}\n </Typography>\n </div>\n )\n : (\n <>\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_email_verification_failed_title\")}\n </Typography>\n {error && <ErrorView error={error}/>}\n </>\n )}\n\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n}\n\n/**\n * The step a magic link opens: it signs in with the link's token as soon as the\n * screen loads. Success is not shown here — the user is signed in, and the\n * view leaves for the app's address. A second factor takes over the screen\n * the way it does after any sign-in, because the controller records the\n * refusal where the code step reads it.\n */\nfunction MagicLinkView({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const [error, setError] = useState<string | null>(null);\n // Once per token: a magic link is single use, and a second request would\n // find it spent and say so over a sign-in that worked.\n const requestedRef = useRef(false);\n\n useEffect(() => {\n if (requestedRef.current) return;\n requestedRef.current = true;\n if (!authController.magicLinkLogin) {\n setError(t(\"auth_magic_link_unavailable\"));\n return;\n }\n authController.magicLinkLogin(token).catch((err: unknown) => {\n // The code step answers this one; it is not a failure.\n if (err instanceof Error && \"code\" in err && err.code === \"MFA_REQUIRED\") return;\n setError(emailLinkErrorMessage(err, t));\n });\n }, [authController, token, t]);\n\n if (!error) {\n return (\n <div className=\"flex flex-col items-center w-full gap-4 mt-6 mb-4\">\n <CircularProgress size=\"small\"/>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_signing_in_with_link\")}\n </Typography>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_magic_link_failed_title\")}\n </Typography>\n <ErrorView error={error}/>\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n}\n\n/**\n * The step an address-change link opens: the account moves onto its new\n * address as soon as the screen loads, signed in or not — the link proves the\n * new inbox, which is all the move needs.\n */\nfunction ConfirmEmailChangeView({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const [status, setStatus] = useState<\"confirming\" | \"confirmed\" | \"failed\">(\"confirming\");\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<{ email: string; removedProviders: string[] } | null>(null);\n // Once per token: a second request — a development double-mount — would\n // find it spent and report a failure over a change that happened.\n const requestedRef = useRef(false);\n\n useEffect(() => {\n if (requestedRef.current) return;\n requestedRef.current = true;\n if (!authController.confirmEmailChange) {\n setError(t(\"auth_email_change_unavailable\"));\n setStatus(\"failed\");\n return;\n }\n authController.confirmEmailChange(token).then((moved) => {\n setResult(moved);\n setStatus(\"confirmed\");\n }).catch((err: unknown) => {\n setError(emailChangeErrorMessage(err, t));\n setStatus(\"failed\");\n });\n }, [authController, token, t]);\n\n if (status === \"confirming\") {\n return (\n <div className=\"flex flex-col items-center w-full gap-4 mt-6 mb-4\">\n <CircularProgress size=\"small\"/>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_confirming_email_change\")}\n </Typography>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n {status === \"confirmed\" && result\n ? (\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_email_change_confirmed_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_email_change_confirmed_body\", { email: result.email })}\n </Typography>\n {result.removedProviders.length > 0 && (\n <Typography variant=\"body2\" color=\"secondary\" className=\"mt-2\">\n {t(\"auth_email_change_providers_removed\", { providers: result.removedProviders.join(\", \") })}\n </Typography>\n )}\n </div>\n )\n : (\n <>\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_email_change_failed_title\")}\n </Typography>\n {error && <ErrorView error={error}/>}\n </>\n )}\n\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_email_change_continue\")}\n </Button>\n </div>\n );\n}\n\nfunction ForgotPasswordForm({\n onClose,\n authController\n}: {\n onClose: () => void,\n authController: AuthControllerExtended\n}) {\n const { t } = useTranslation();\n const [email, setEmail] = useState<string>(\"\");\n const [submitted, setSubmitted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const emailId = useId();\n\n useEffect(() => {\n if (!document) return;\n const escFunction = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && !isKeyHandled(event)) {\n event.preventDefault();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", escFunction, false);\n return () => {\n document.removeEventListener(\"keydown\", escFunction, false);\n };\n }, [onClose]);\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n setError(null);\n\n if (!email) {\n setError(\"Please enter your email address\");\n return;\n }\n\n if (!authController.forgotPassword) {\n setError(\"Password reset is not available with this auth provider.\");\n return;\n }\n\n try {\n await authController.forgotPassword(email);\n setSubmitted(true);\n } catch (err: unknown) {\n // Check for EMAIL_NOT_CONFIGURED error\n if (err instanceof Error && (err as { code?: string }).code === \"EMAIL_NOT_CONFIGURED\") {\n setError(\"Password reset is not available. Please contact your administrator.\");\n } else {\n // Still show success (security: don't reveal if email exists)\n setSubmitted(true);\n }\n }\n };\n\n if (submitted) {\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <div className=\"w-full -ml-2.5\">\n <IconButton aria-label={t(\"back\")} onClick={onClose}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <div className=\"text-center rounded-xl p-6 bg-surface-raised\">\n <div className=\"text-3xl mb-3\">📧</div>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n Check your email\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n If an account exists for <strong>{email}</strong>, you&apos;ll receive a password reset link shortly.\n </Typography>\n </div>\n\n <Button onClick={onClose} variant=\"text\" className=\"mt-2\">\n Back to sign in\n </Button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton aria-label={t(\"back\")} onClick={onClose}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n Reset password\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n Enter your email and we&apos;ll send you a reset link.\n </Typography>\n\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={emailId}>\n Email\n </Typography>\n <TextField\n placeholder=\"you@example.com\"\n id={emailId}\n className={loginFieldClasses}\n autoFocus\n value={email}\n type=\"email\"\n size=\"medium\"\n onChange={(event) => setEmail(event.target.value)}\n />\n </div>\n\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n className=\"w-full\"\n size=\"large\"\n loading={authController.authLoading}\n disabled={authController.authLoading || !email}\n >\n Send reset link\n </LoadingButton>\n </form>\n );\n}\n","import React, { useLayoutEffect, useRef } from \"react\";\nimport { useRebaseRegistryDispatch } from \"../hooks\";\nimport type { RebaseAuthViewConfig } from \"@rebasepro/cms-types\";\n\n/**\n * Declarative component to configure authentication in Rebase.\n * Renders nothing — purely registers config into the RebaseRegistry.\n *\n * This is a framework-level component that lives in core since\n * authentication is cross-cutting (admin, Studio, any app area).\n * @group Core\n */\nexport function RebaseAuth({ loginView }: RebaseAuthViewConfig) {\n const dispatch = useRebaseRegistryDispatch();\n const registeredRef = useRef(false);\n\n useLayoutEffect(() => {\n dispatch.registerAuth({ loginView });\n registeredRef.current = true;\n return () => {\n registeredRef.current = false;\n dispatch.unregisterAuth();\n };\n }, [dispatch, loginView]);\n\n return null;\n}\n","import React, { useCallback, useSyncExternalStore } from \"react\";\nimport { Alert, Typography } from \"@rebasepro/ui\";\nimport type { RealtimeConnectionState, RebaseClient } from \"@rebasepro/types\";\nimport { useRebaseClient } from \"../hooks/useRebaseClient\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\nconst noUnsubscribe = () => undefined;\n\n/**\n * The realtime connection's state, re-rendering on every change.\n *\n * `undefined` when there is no client, or it was built without realtime —\n * there is no connection to describe.\n *\n * @group Hooks and utilities\n */\nexport function useRealtimeConnectionState(): RealtimeConnectionState | undefined {\n const ws = useRebaseClient<RebaseClient>()?.ws;\n // A client implementation that predates the state (or is not the Rebase\n // SDK at all) has nothing to subscribe to, which reads as \"no state\".\n const observable = ws && typeof ws.onStateChange === \"function\" ? ws : undefined;\n const subscribe = useCallback(\n (notify: () => void) => observable ? observable.onStateChange(notify) : noUnsubscribe,\n [observable]\n );\n const read = useCallback(() => observable?.state, [observable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport interface ConnectionLostBannerProps {\n className?: string;\n}\n\n/**\n * Says that live updates have stopped, while they have.\n *\n * Shown once the realtime client reports the connection `disconnected`: the\n * socket has been down for longer than a blip, so tables, boards and open\n * records are showing what they last received and nothing else will arrive\n * until it is back. They keep their data rather than turning into errors — this\n * banner is how the user learns it may be out of date. It disappears by itself\n * when the connection returns, and every live view then refreshes.\n *\n * A brief drop (`reconnecting`) shows nothing: a deploy blips every socket for\n * a second or two, and a banner that flashes on each one teaches people to\n * ignore it.\n *\n * @group Components\n */\nexport function ConnectionLostBanner({ className }: ConnectionLostBannerProps) {\n const state = useRealtimeConnectionState();\n const { t } = useTranslation();\n\n if (state !== \"disconnected\") return null;\n\n return (\n <div role=\"status\" aria-live=\"polite\" className={className}>\n <Alert color=\"warning\" size=\"small\" role={null}>\n <div className=\"flex flex-col gap-0.5\">\n <Typography variant=\"label\">\n {t(\"realtime_connection_lost_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"realtime_connection_lost_body\")}\n </Typography>\n </div>\n </Alert>\n </div>\n );\n}\n","import { RebaseTranslations } from \"@rebasepro/cms-types\";\n\n/**\n * English baseline translations for @rebasepro/app.\n *\n * This is the single source of truth for all default UI strings.\n * Override any key via the `translations` prop on Rebase entry-point components.\n *\n * @group Core\n */\nexport const en: RebaseTranslations = {\n // ─── Form actions ────────────────────────────────────────────\n save: \"Save\",\n create: \"Create\",\n create_copy: \"Create copy\",\n save_and_close: \"Save and close\",\n create_copy_and_close: \"Create copy and close\",\n create_and_close: \"Create and close\",\n discard: \"Discard\",\n clear: \"Clear\",\n cancel: \"Cancel\",\n\n // ─── Entity actions ──────────────────────────────────────────\n edit: \"Edit\",\n copy: \"Copy\",\n delete: \"Delete\",\n delete_not_allowed: \"You have selected at least one entity you cannot delete\",\n edit_entity: \"Edit\",\n back_to_detail: \"Back to details\",\n\n // ─── Delete dialog ───────────────────────────────────────────\n delete_confirmation_title: \"Delete?\",\n delete_confirmation_body: \"This will delete the entity. Are you sure?\",\n delete_multiple_confirmation_body: \"This will delete the selected entities. Are you sure?\",\n\n // ─── Unsaved-changes dialog ───────────────────────────────────\n unsaved_changes_title: \"Unsaved changes\",\n unsaved_changes_body: \"You have unsaved changes. Do you want to discard them?\",\n discard_changes: \"Discard changes\",\n keep_editing: \"Keep editing\",\n clear_form: \"Clear form?\",\n discard_changes_confirmation: \"All unsaved changes will be lost. This cannot be undone.\",\n clear_form_confirmation: \"All entered values will be cleared. This cannot be undone.\",\n\n // ─── Collection table / toolbar ──────────────────────────────\n search: \"Search\",\n find_by_id: \"Find by ID\",\n find_entity_by_id: \"Find entity by ID\",\n filter: \"Filter\",\n filters: \"Filters\",\n records_in_view: \"Records in this view\",\n clear_filter: \"Clear filter\",\n clear_filter_sort: \"Clear filter/sort\",\n clear_sort: \"Clear sort\",\n sort: \"Sort\",\n sort_by: \"Sort by\",\n sort_then_by: \"Then by\",\n sort_ascending: \"Sort ascending\",\n sort_descending: \"Sort descending\",\n sort_remove: \"Remove sort\",\n sort_move_up: \"Make this key more important\",\n sort_move_down: \"Make this key less important\",\n sort_remove_key: \"Remove this sort key\",\n sort_key_position: \"Sort key {{position}}\",\n sort_shift_click_hint: \"Shift-click to add a column under the current sort\",\n save_entity_before_subcollections: \"Save this record before adding related records.\",\n clear_all: \"Clear all\",\n no_items: \"No items\",\n no_entries_found: \"No entries found\",\n all_entries_loaded: \"All {{count}} entries loaded\",\n error_loading_data_message: \"Error loading data: {{message}}\",\n clear_search: \"Clear search\",\n open_time_picker: \"Open time picker\",\n relative_just_now: \"just now\",\n relative_in_a_moment: \"in a moment\",\n relative_minutes_ago: \"{{count}}m ago\",\n relative_in_minutes: \"in {{count}}m\",\n relative_hours_ago: \"{{count}}h ago\",\n relative_in_hours: \"in {{count}}h\",\n relative_days_ago: \"{{count}}d ago\",\n relative_in_days: \"in {{count}}d\",\n create_your_first_entry: \"Create your first entry\",\n no_results_filter_sort: \"No results with the applied filter/sort\",\n no_results_filter: \"No results with the applied filters\",\n no_results_search: \"No results found for \\\"{{search}}\\\"\",\n add: \"Add\",\n remove: \"Remove\",\n multiple_entities: \"Multiple entities\",\n unsaved_changes: \"You have unsaved changes in this {{collectionName}}.\",\n so_empty: \"So empty...\",\n no_results: \"No results with the applied filter/sort\",\n refresh_data: \"Refresh data\",\n dark_mode: \"Dark\",\n light_mode: \"Light\",\n system_mode: \"System\",\n join_newsletter: \"Join the newsletter, no spam\",\n ok: \"Ok\",\n save_collection_config: \"Save collection structure\",\n search_for_more_icons: \"Search for more icons…\",\n ai_modified: \"AI modified\",\n size_label: \"Size\",\n group_by: \"Group by\",\n initialize_kanban_order: \"Initialize Kanban Order\",\n copy_id: \"Copy ID\",\n add_specific: \"Add {{name}}\",\n add_named: \"Add \\\"{{name}}\\\"\",\n select_specific: \"Select {{name}}\",\n select_from: \"Select from {{name}}\",\n done: \"Done\",\n log_out: \"Log out\",\n column_cannot_be_edited: \"This column can't be edited directly\",\n close: \"Close\",\n hide_list: \"Hide list\",\n show_list: \"Show list\",\n unsaved_local_changes: \"Unsaved Local changes\",\n unsaved_local_changes_description: \"This document was edited locally and has unsaved changes. These local changes will be lost if you don't apply them.\",\n preview_changes: \"Preview Changes\",\n apply_changes: \"Apply Changes\",\n discard_local_changes: \"Discard Local Changes\",\n preview_local_changes: \"Preview Local Changes\",\n preview_local_changes_description: \"These are the local changes that will be applied to the form.\",\n type: \"Type\",\n string: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n date: \"date\",\n map: \"map\",\n array: \"array\",\n arrays_of_arrays_not_supported: \"Arrays of arrays are not supported.\",\n data_type_not_supported: \"Data type {{dataType}} not supported yet\",\n passkey_error_unsupported: \"Your device or browser doesn't support passkeys.\",\n\n // ─── Entity form feedback ─────────────────────────────────────\n saved_correctly: \"Saved successfully\",\n error_before_saving: \"Error preparing data\",\n error_after_saving: \"Error in post-save hook\",\n error_saving_entity: \"Error saving entity\",\n error_record_changed_elsewhere: \"This record changed since you opened it. Your edits are kept: review the fields marked as updated elsewhere, then save again.\",\n entity_does_not_exist: \"This entity does not exist in the database\",\n form_modified: \"This form has been modified\",\n form_in_sync: \"The current form is in sync with the database\",\n fix_errors_before_saving: \"Fix highlighted errors before saving\",\n form_predating_rule_violations: \"Some fields you did not change do not meet their current rules. They do not block saving:\",\n\n admin: \"Admin\",\n home: \"Home\",\n this_form_has_errors: \"This form has errors\",\n error_loading_navigation: \"Error loading navigation\",\n error_loading_auth: \"Error loading auth\",\n this_form_has_been_modified: \"This form has been modified\",\n current_form_in_sync: \"The current form is in sync with the database\",\n open_in_console: \"Open in the console\",\n collection_does_not_exist: \"The specified collection does not exist. Check console\",\n unexpected_value: \"Unexpected value\",\n unexpected_value_click_to_edit: \"Unexpected value. Click to edit\",\n unexpected_reference_value: \"Unexpected reference value. Click to edit\",\n copy_url_to_clipboard: \"Copy url to clipboard\",\n open_image_in_new_tab: \"Open image in new tab\",\n reference_not_set: \"Reference not set\",\n reference_does_not_exist: \"Reference does not exist\",\n entity_not_found: \"Entity not found\",\n entity_not_found_body: \"This record does not exist, or it may be hidden from you by row-level security.\",\n collection_not_found: \"Collection not found\",\n collection_not_found_body: \"Nothing is registered for \\\"{{path}}\\\".\",\n collection_not_found_hint: \"The URL names a collection the panel does not know about. It may have been renamed or removed from the collections array, or the slug may not match the path.\",\n back_to_collection: \"Back to {{name}}\",\n file_not_found: \"File not found\",\n unsaved_changes_in_entity: \"You have unsaved changes in this entity.\",\n delete_this_role: \"Delete this role\",\n no_roles_yet: \"You don't have any roles yet.\",\n create_default_roles: \"Create default roles\",\n delete_role_confirmation: \"Are you sure you want to delete this role?\",\n delete_this_user: \"Delete this user\",\n no_users_yet: \"There are no users yet\",\n add_logged_user_as_admin: \"Add the logged user as an admin\",\n add_current_user_as_admin: \"Add current user as admin\",\n create_default_roles_and_add_admin: \"Create default roles and add current user as admin\",\n delete_user_confirmation: \"Are you sure you want to delete this user?\",\n create_your_users_and_roles: \"Create your users and roles\",\n no_users_or_roles_defined: \"You have no users or roles defined. You can create default roles and add the current user as admin.\",\n save_before_changing_schema: \"You need to save the document before changing the schema\",\n edit_schema_for_this_form: \"Edit schema for this form\",\n no_permissions_to_edit_collection: \"You don't have permissions to edit this collection\",\n browser_does_not_support_audio: \"Your browser does not support the audio element.\",\n user_not_found: \"User not found: {{value}}\",\n\n // ─── Collection view actions ──────────────────────────────────\n delete_selected: \"Delete\",\n cannot_delete_selected: \"You have selected at least one entity you cannot delete\",\n\n // ─── Array / field containers ─────────────────────────────────\n add_entry: \"Add\",\n add_on_top: \"Add on top\",\n add_below: \"Add below\",\n add_to_field: \"Add to {{fieldName}}\",\n value: \"Value\",\n key: \"Key\",\n drag_drop_multiple: \"Drag 'n' drop some files here, or click to select files. Drag to reorder.\",\n drag_drop_single: \"Drag 'n' drop a file here, or click to select one\",\n\n // ─── Navigation / scaffold ────────────────────────────────────\n open_menu: \"Open menu\",\n close_drawer: \"Close drawer\",\n navigation_drawer: \"Navigation drawer\",\n collapse: \"Collapse\",\n expand: \"Expand\",\n change_language: \"Change language\",\n toggle_theme: \"Toggle theme\",\n user_menu: \"User menu\",\n resize_sidebar: \"Resize the sidebar\",\n resize_editor: \"Resize the editor\",\n resize_list: \"Resize the list\",\n panel_mode: \"Panel mode\",\n\n // ─── Error states ─────────────────────────────────────────────\n error: \"Error\",\n error_loading_data: \"Could not load data\",\n error_check_server_logs: \"Check server logs for details.\",\n error_technical_details: \"Technical details\",\n error_uploading_file: \"Error uploading file\",\n error_deleting: \"Error deleting\",\n error_before_delete: \"Error before delete\",\n error_updating_asset: \"Error updating asset\",\n error_deleting_asset: \"Error deleting asset\",\n error_firestore_index: \"A Firestore index is required for this query.\",\n realtime_connection_lost_title: \"Live updates paused\",\n realtime_connection_lost_body: \"The connection to the server was lost, so what you see may be out of date. It refreshes as soon as the connection is back.\",\n create_index: \"Create Index\",\n value_is_not_reference: \"Value is not a reference.\",\n click_to_edit: \"Click to edit\",\n data_is_not_array_of_references: \"Data is not an array of references\",\n\n // ─── Misc ─────────────────────────────────────────────────────\n loading: \"Loading\",\n local_changes_applied: \"Local changes applied to the form\",\n local_changes_discarded: \"Local changes discarded\",\n are_you_sure_leave: \"Are you sure you want to leave this page?\",\n see_console_details: \"See console for more details.\",\n drop_here_create_group: \"Drop here to create a new group\",\n filter_for_null_values: \"Filter for null values\",\n value_updated_elsewhere: \"This value has been updated elsewhere\",\n entity_deleted_elsewhere: \"This record was deleted elsewhere. What you see here has not been saved; save it as a new record to keep it.\",\n save_as_new: \"Save as new\",\n add_property: \"Add property\",\n edit_name: \"Edit {{name}}\",\n this_entity_not_exist: \"This entity does not exist in the database\",\n internal_error: \"Internal ERROR\",\n\n // ─── Rename group dialog ──────────────────────────────────────\n rename_group: \"Rename Group\",\n group_name_label: \"Group Name\",\n group_name_empty_error: \"Group name cannot be empty.\",\n group_name_exists_error: \"This group name already exists.\",\n\n // ─── Search ───────────────────────────────────────────────────\n search_collections: \"Search collections\",\n\n // ─── Navigation groups ────────────────────────────────────────\n views_group: \"Views\",\n\n // ─── Entity Edit View ─────────────────────────────────────────\n youd_need_to_save_before_additional_collections: \"Save this record before adding related records.\",\n\n // ─── Not Found Page ───────────────────────────────────────────\n page_not_found: \"Page not found\",\n page_not_found_body: \"This page does not exist or you may not have access to it\",\n back_to_home: \"Back to home\",\n\n // ─── Collection Editor ─────────────────────────────────────────\n default_collection_view: \"Default collection view\",\n table_view: \"Table\",\n cards_view: \"Cards\",\n kanban_view: \"Kanban\",\n choose_how_entities_displayed_default: \"Choose how entities should be displayed by default\",\n\n document_view: \"Document view\",\n side_panel: \"Side panel\",\n full_screen: \"Full screen\",\n should_documents_opened_full_screen: \"Should documents be opened full screen or in an inline side dialog\",\n\n select_custom_view: \"Select custom view\",\n no_custom_views_defined: \"No custom views defined. Define your custom views in the customization settings, before using this dialog.\",\n\n select_custom_action: \"Select custom action\",\n no_custom_actions_defined: \"No custom actions defined. Define your custom actions in the customization settings, before using this dialog.\",\n\n no_collections_found: \"No collections found\",\n start_building_collections: \"Start building collections in Rebase easily. Map them to your existing database data, import from files, or use our templates.\",\n create_first_collection: \"Create your first collection\",\n define_collections_programmatically: \"You can also define collections programmatically.\",\n edit_collection: \"Edit collection\",\n no_permissions_edit_collection: \"You don't have permissions to edit this collection\",\n no_permissions_create_collection: \"You don't have permissions to create collections\",\n create_collection: \"Create collection\",\n update_collection: \"Update collection\",\n\n new_collection: \"New collection\",\n add_new_collection: \"Add new collection\",\n collection_with_name: \"{{name}} collection\",\n change_icon: \"Change icon\",\n is_subcollection_of: \"This is a subcollection of\",\n name: \"Name\",\n collection_name_description: \"Name of this collection, usually a plural name (e.g. Products)\",\n path: \"Path\",\n relative_path_to_parent: \"Relative path to the parent (no need to include the parent path)\",\n path_in_database: \"Path or table name where this collection is stored in the database\",\n singular_name: \"Singular name\",\n singular_name_description: \"Optionally define a singular name for your entities\",\n description: \"Description\",\n description_of_collection: \"Description of the collection, you can use markdown\",\n collection_id: \"Collection ID\",\n collection_id_description: \"This ID identifies this collection. Typically the same as the path or table name.\",\n collection_group: \"Collection group\",\n collection_group_description: \"A collection group consists of all collections with the same path. This allows you to query over multiple collections at once.\",\n advanced_settings: \"Advanced settings\",\n doc_history_global: \"Document history revisions enabled if enabled globally\",\n doc_history_enabled: \"Document history revisions ENABLED\",\n doc_history_not_enabled: \"Document history revisions NOT enabled\",\n doc_history_description: \"When enabled, each document in this collection will have a history of changes. This is useful for auditing purposes. The data is stored in a subcollection of the document in your database, called __history.\",\n document_id_generation: \"Document IDs generation\",\n code_defined: \"Code defined\",\n users_must_define_id: \"Users must define an ID\",\n users_can_define_id: \"Users can define an ID, but it is not required\",\n doc_id_auto_generated: \"Document ID is generated automatically\",\n config_doc_id_generation: \"Configure how document IDs are generated when creating new entities.\",\n enable_text_search: \"Enable text search for this collection\",\n text_search_description: \"Allow text search for this collection. If you have not specified a text search delegate, this will use the built-in local text search. This is not recommended for large collections, as it may incur in performance and cost issues.\",\n database_id: \"Database ID\",\n default_text: \"(default)\",\n\n custom_actions: \"Custom actions\",\n more_info: \"More info\",\n define_custom_actions_cli: \"Define your own custom actions by uploading them with the CLI.\",\n action_defined_in_code: \"This action is defined in code with key\",\n add_custom_entity_action: \"Add custom entity action\",\n remove_this_action: \"Remove this action?\",\n remove_action_warning: \"This will not delete any data, only the action in the admin panel\",\n\n subcollections_of: \"Subcollections of\",\n add_subcollection: \"Add subcollection\",\n custom_views: \"Custom views\",\n define_custom_views_cli: \"Define your own custom views by uploading them with the CLI.\",\n view_defined_in_code: \"This view is defined in code with key\",\n add_custom_entity_view: \"Add custom entity view\",\n delete_this_subcollection: \"Delete this subcollection?\",\n remove_collection_warning: \"This will not delete any data, only the collection in the admin panel\",\n remove_this_view: \"Remove this view?\",\n remove_view_warning: \"This will not delete any data, only the view in the admin panel\",\n\n no_collection_selected: \"No collection selected\",\n code_for_collection: \"Code for\",\n use_config_define_json: \"Use this config to define the collection in JSON format.\",\n customise_collection_code: \"If you want to customise the collection in code, you can add this collection code to your admin app configuration.\",\n copied: \"Copied\",\n\n property_cant_be_edited: \"This property can't be edited\",\n property_not_editable_description: \"You may not have permission to edit it or it is defined in code and cannot be modified.\",\n delete_this_property: \"Delete this property?\",\n delete_property_warning: \"This will not delete any data, only modify the collection.\",\n error_must_specify_id: \"You must specify an id for the field\",\n error_id_format: \"The id can only contain letters, numbers and underscores (_), and not start with a number\",\n error_id_already_exists: \"There is another field with this ID already\",\n error_must_specify_title: \"You must specify a title for the field\",\n custom_or_other: \"Custom/Other\",\n select_property_widget: \"Select a property widget\",\n error_changing_data_type: \"This widget uses a different data type than the initially selected widget. This can cause errors with existing data.\",\n required: \"Required\",\n\n enum_form_dialog: \"Enum form dialog\",\n imported_data_preview: \"Imported data preview\",\n entities_with_same_id_overwritten: \"Entities with the same id will be overwritten\",\n collection_editor: \"Collection editor\",\n properties_in_this_group: \"Properties in this group\",\n data_property_mapping: \"Data property mapping\",\n property_edit_view: \"Property edit view\",\n all_of_these: \"All of these\",\n any_of_these: \"Any of these\",\n\n only_admins_edit_roles: \"Only admins can edit roles\",\n error_user_not_found: \"User not found\",\n all_roles: \"All Roles\",\n role: \"Role\",\n name_of_this_role: \"Name of this role\",\n id_of_this_role: \"ID of this role\",\n create_entities: \"Create entities\",\n read_entities: \"Read entities\",\n update_entities: \"Update entities\",\n delete_entities: \"Delete entities\",\n all_collections: \"All collections\",\n create_entities_in_collections: \"Create entities in collections\",\n access_all_data_in_every_collection: \"Access all data in every collection\",\n update_data_in_any_collection: \"Update data in any collection\",\n delete_data_in_any_collection: \"Delete data in any collection\",\n allow_all_permissions_in_this_collections: \"Allow all permissions in this collections\",\n all: \"All\",\n customise_permissions_description: \"You can customise the permissions that the users related to this role can perform in the entities of each collection\",\n create_collections: \"Create collections\",\n yes: \"Yes\",\n no: \"No\",\n can_user_create_collections: \"Can the user create collections\",\n edit_collections: \"Edit collections\",\n only_own_collections: \"Only his/her own\",\n own: \"Own\",\n can_user_edit_collections: \"Can the user edit collections\",\n delete_collections: \"Delete collections\",\n can_user_delete_collections: \"Can the user delete collections\",\n error_saving_role: \"There was an error saving this role\",\n create_role: \"Create role\",\n update: \"Update\",\n\n only_admins_change_roles: \"Only admins can change roles\",\n must_be_at_least_one_admin: \"There must be at least one admin\",\n logged_user_not_found: \"Logged user not found\",\n user: \"User\",\n user_id: \"User ID\",\n name_of_this_user: \"Name of this user\",\n email_of_this_user: \"Email of this user\",\n roles: \"Roles\",\n create_user: \"Create user\",\n\n users: \"Users\",\n add_user: \"Add user\",\n add_role: \"Add role\",\n is_admin: \"Is Admin\",\n default_permissions: \"Default permissions\",\n created_on: \"Created on\",\n email: \"Email\",\n id: \"ID\",\n read: \"Read\",\n\n column_in_file: \"Column in file\",\n map_to_property: \"Map to Property\",\n default_values: \"Default values\",\n default_values_description: \"You can select a default value for unmapped columns and empty values:\",\n property: \"Property\",\n default_value: \"Default value\",\n autogenerate_id: \"Autogenerate ID\",\n id_column_description: \"Column that will be used as ID for each document\",\n do_not_set_value: \"Do not set value\",\n set_value_to_true: \"Set value to true\",\n set_value_to_false: \"Set value to false\",\n drag_and_drop_file: \"Drag and drop a file here or click to upload\",\n error_saving_data: \"Error saving data\",\n retry: \"Retry\",\n saving_data: \"Saving data\",\n entities_saved: \"entities saved\",\n do_not_close_tab: \"Do not close this tab or the import will be interrupted\",\n import: \"Import\",\n import_data: \"Import data\",\n upload_file_description: \"Upload a CSV, Excel or JSON file and map it to your existing schema\",\n back: \"Back\",\n next: \"Next\",\n save_data: \"Save data\",\n use_column_as_id: \"Use this column as ID\",\n do_not_import_property: \"Do not import this property\",\n import_problems_title: \"Values that cannot be imported: {{count}}\",\n import_problems_description: \"These cells do not convert to the type of the field they map to, so they will be left empty. Go back to map the column to a text field, or correct the file and upload it again.\",\n import_problems_column: \"{{column}} → {{property}} ({{type}}): {{count}} not imported\",\n import_problems_example: \"Row {{row}}: “{{value}}”, {{reason}}\",\n import_problems_more: \"…and {{count}} more\",\n import_problem_not_a_number: \"not a number\",\n import_problem_number_leading_zero: \"a number would drop its leading zero\",\n import_problem_number_too_precise: \"more digits than a number holds exactly\",\n import_problem_not_a_boolean: \"not yes or no\",\n import_problem_not_a_date: \"not a date\",\n import_problem_ambiguous_date: \"could be day/month or month/day\",\n import_problem_not_a_vector: \"not a list of numbers\",\n import_problem_not_a_map: \"not a map (expected the JSON of an object)\",\n import_problem_not_a_geopoint: \"not a geopoint (expected {\\\"latitude\\\": …, \\\"longitude\\\": …})\",\n entities_will_be_overwritten: \"Entities with the same id will be overwritten\",\n data_imported_successfully: \"Data imported successfully\",\n export: \"Export\",\n export_data: \"Export data\",\n download_table_csv: \"Download the content of this table as a CSV\",\n csv: \"CSV\",\n json: \"JSON\",\n dates_as_timestamps: \"Dates as timestamps\",\n dates_as_strings: \"Dates as strings\",\n flatten_arrays: \"Flatten arrays\",\n download: \"Download\",\n large_number_of_documents: \"This collection has a large number of documents ({{count}}).\",\n too_many_documents_to_export: \"This collection has more documents ({{count}}) than the browser can export in a single file (limit {{limit}}). Filter it down before exporting.\",\n include_undefined_values: \"Include undefined values\",\n submit: \"Submit\",\n\n no_filterable_properties: \"No filterable properties available\",\n apply_filters: \"Apply filters\",\n\n // ─── Filter Presets ──────────────────────────────────────────\n filter_presets: \"Presets\",\n filter_preset_apply: \"Apply preset\",\n filter_preset_active: \"Active: {{label}}\",\n\n list: \"List\",\n table_view_mode: \"Table\",\n cards: \"Cards\",\n board: \"Board\",\n initialize_kanban_order_desc: \"This will assign sequential order values to all items that don't have one. Items will maintain their current order within each column.\",\n kanban_view_not_available: \"Kanban view is not available\",\n kanban_view_requires_enum: \"Kanban view requires a string property with enum values to group entities into columns. Please add an enum property to your collection schema to use this view.\",\n no_enum_values_configured: 'No enum values configured for property \"{{property}}\"',\n items_need_backfill: \"Some items don't have order values. Initialize to enable drag-and-drop reordering.\",\n kanban_order_not_configured: \"Drag-and-drop ordering is not configured. Set an order property in the collection settings to persist card positions.\",\n initialize: \"Initialize\",\n confirm_multiple_delete: \"Confirm multiple delete?\",\n delete_entity_confirm_title: \"Would you like to delete this {{entityName}}?\",\n add_existing: \"Add existing\",\n unlink_entity_confirm_title: \"Remove this {{entityName}} from this record?\",\n unlink_entity_confirm_body: \"It stays in {{collectionName}} and remains available to other records.\",\n confirm_multiple_unlink: \"remove these from this record?\",\n remove_from_record: \"Remove from this record\",\n removed_from_record: \"Removed from this record\",\n no_filter: \"No filter\",\n is_true: \"is true\",\n is_false: \"is false\",\n error_uploading_file_size: \"Error uploading file: File is larger than {{maxSize}} bytes\",\n error_uploading_file_type: \"Error uploading file: File type is not supported\",\n drag_drop_files: \"Drag 'n' drop some files here, or click here to edit\",\n drag_drop_file: \"Drag 'n' drop a file here, or click here to edit\",\n multiple_deleted: \"Multiple deleted\",\n some_entities_deleted: \"Some of the entities have been deleted, but not all\",\n error_deleting_entities: \"Error deleting entities\",\n delete_rows_failed: \"{{failed}} of {{total}} not deleted. {{reason}}\",\n deleted: \"Deleted\",\n selection_options: \"Selection options\",\n selection_menu_all_loaded: \"All on this page\",\n selection_menu_all_matching: \"All {{total}} {{collection}}\",\n selection_menu_none: \"None\",\n selection_select_all_loaded: \"Select all loaded rows\",\n selection_deselect_all: \"Deselect all\",\n selection_reading_rows: \"Reading rows… {{loaded}} of {{total}}\",\n selection_reading_rows_unknown: \"Reading rows… {{loaded}} so far\",\n selection_deleting_progress: \"Deleted {{completed}} of {{total}}\",\n confirm_delete_selection: \"Delete {{total}} {{collection}}?\",\n confirm_delete_selection_unknown: \"Delete every row matching the current filter?\",\n confirm_delete_selection_body: \"This cannot be undone. Each row is deleted individually, so this may take a while.\",\n\n export_selection_count: \"Download the {{total}} selected rows as a {{format}}\",\n export_selection_all_matching: \"Download every {{collection}} matching the current filter\",\n\n select_reference: \"Select reference\",\n select_references: \"Select references\",\n account_settings: \"Account Settings\",\n profile: \"Profile\",\n security: \"Security\",\n sessions: \"Sessions\",\n change_password: \"Change Password\",\n current_password: \"Current Password\",\n new_password: \"New Password\",\n confirm_password: \"Confirm New Password\",\n password_changed: \"Password changed. Your other devices were signed out.\",\n passwords_dont_match: \"Passwords don't match\",\n password_too_short: \"Password must be at least 8 characters\",\n password_change_not_available: \"Password change is not available for accounts using external sign-in providers.\",\n changing_password: \"Changing...\",\n display_name: \"Display Name\",\n photo_url: \"Photo URL\",\n save_profile: \"Save Profile\",\n saving: \"Saving...\",\n no_active_sessions: \"No active sessions found.\",\n revoking: \"Revoking...\",\n revoke_all_sessions: \"Revoke All Sessions\",\n unknown_device: \"Unknown Device\",\n unknown_address: \"Unknown\",\n session_details: \"IP: {{ip}} • Created: {{created}}\",\n revoke_session: \"Revoke session\",\n current: \"Current\",\n role_id: \"Role ID\",\n role_name: \"Role Name\",\n add_reference: \"Add reference\",\n add_reference_to: \"Add reference to {{name}}\",\n\n /** RolesView — table & permissions */\n role_deleted_successfully: \"Role deleted successfully\",\n error_deleting_role: \"Error deleting role\",\n collection_permissions: \"Collection permissions\",\n collection: \"Collection\",\n no_collections_configured: \"No collections configured\",\n no_security_rules_defined: \"No security rules defined — all operations unrestricted\",\n no_rules: \"no rules\",\n\n /** UsersView — snackbar */\n bootstrap_admin_success: \"You are now an admin! Refreshing...\",\n failed_to_bootstrap_admin: \"Failed to bootstrap admin\",\n user_deleted_successfully: \"User deleted successfully\",\n error_deleting_user: \"Error deleting user\",\n user_created_successfully: \"User created successfully\",\n invitation_sent: \"An invitation email has been sent to {{email}}. They can use the link to set their password.\",\n invitation_sent_title: \"Invitation Sent\",\n temporary_password: \"Temporary Password\",\n temporary_password_description: \"Email is not configured. Share this temporary password with the user securely. It will not be shown again.\",\n temporary_password_email_failed_description: \"The email could not be delivered. Share this temporary password with the user securely. It will not be shown again.\",\n copy_password: \"Copy password\",\n password_copied: \"Password copied to clipboard\",\n\n /** UsersView — pagination & search */\n search_users: \"Search users\",\n created: \"Created\",\n actions: \"Actions\",\n no_users_found: \"No users found\",\n reset_password: \"Reset Password\",\n reset_password_success: \"Password reset successfully\",\n reset_password_confirmation: \"Are you sure you want to reset this user's password?\",\n reset_password_send_email: \"Send a password reset email\",\n reset_password_set_manually: \"Set a password manually\",\n reset_password_set_manually_description: \"The password is updated immediately and no email is sent. Share it with the user securely.\",\n\n /** Permission-denied empty states */\n no_permission_to_view_users: \"You don't have permission to view users\",\n no_permission_to_view_roles: \"You don't have permission to view roles\",\n no_permission_description: \"Contact an administrator if you need access to this section.\",\n error_resetting_password: \"Error resetting password\",\n\n /** Editor table-bubble */\n add_row_before: \"Add row before\",\n add_row_after: \"Add row after\",\n delete_row: \"Delete row\",\n add_column_before: \"Add column before\",\n add_column_after: \"Add column after\",\n delete_column: \"Delete column\",\n delete_table: \"Delete table\",\n\n /** Editor image-bubble */\n alt_text: \"Alt text\",\n title: \"Title\",\n\n /** MapFieldBinding */\n a_property_of_this_map_has_error: \"A property of this map has an error\",\n\n /** AI Collection Generator Popover */\n generate_collection_with_ai: \"Generate Collection with AI\",\n modify_collection_with_ai: \"Modify Collection with AI\",\n describe_collection_to_create: \"Describe the collection you want to create.\",\n describe_changes_to_make: \"Describe the changes you want to make to this collection.\",\n ai_placeholder_create: \"e.g., Create a products collection with name, price, description, and category...\",\n ai_placeholder_modify: \"e.g., Add a thumbnail image field with storage, make price required...\",\n ai_assist: \"AI Assist\",\n generating: \"Generating...\",\n\n /** Recently extracted strings for collection editor */\n this_is_subcollection_of: \"This is a subcollection of\",\n use_existing_paths_database: \"Use one of the existing paths in your database:\",\n describe_collection_ai: \"Describe your collection to AI:\",\n generate_with_ai: \"Generate with AI\",\n create_from_json_config: \"Create from JSON configuration:\",\n paste_json_config: \"Paste JSON Configuration\",\n create_collection_from_file_formats: \"Create a collection from a file (csv, json, xls, xslx...)\",\n select_template: \"Select a template:\",\n products: \"Products\",\n collection_products_subtitle: \"A collection of products with images, prices and stock\",\n collection_users_subtitle: \"A collection of users with emails, names and roles\",\n blog_posts: \"Blog posts\",\n collection_blog_posts_subtitle: \"A collection of blog posts with images, authors and complex content\",\n pages: \"Pages\",\n collection_pages_subtitle: \"A collection of pages with images, authors and complex content\",\n continue_from_scratch: \"Continue from scratch\",\n\n /** Admin views config */\n admin_users: \"Admin Users\",\n roles_menu: \"Roles\",\n project_settings: \"Project settings\",\n\n by_signing_in_you_agree_to_our: \"By signing in you agree to our\",\n terms_and_conditions: \"Terms and Conditions\",\n and_our: \"and our\",\n privacy_policy: \"Privacy policy\",\n email_password: \"Email/password\",\n sign_in_with_google: \"Sign in with Google\",\n\n // --- Auth error messages ---\n auth_user_not_found: \"User not found\",\n auth_wrong_password: \"Wrong password. Please try again.\",\n auth_user_disabled: \"User disabled. Please contact support.\",\n auth_account_exists_with_different_credential: \"An account with this email already exists. Sign in the way you did before.\",\n auth_account_exists_sign_in_with_password: \"An account with this email already exists. Sign in with your email and password instead.\",\n auth_email_already_in_use: \"The email is already in use\",\n auth_google_permissions_required: \"You need to grant additional permissions in order to manage your Google Cloud projects\",\n auth_invalid_email_password: \"Please enter both email and password\",\n auth_enter_email_first: \"Please enter your email first\",\n auth_password_reset_sent: \"Password reset email sent\",\n auth_sign_in_account: \"Sign in to your account\",\n auth_create_new_account: \"Create a new account\",\n auth_password: \"Password\",\n auth_reset_password: \"Reset password\",\n auth_new_user: \"New user?\",\n auth_have_account: \"Have an account?\",\n auth_sign_in: \"Sign In\",\n auth_sign_up: \"Sign Up\",\n auth_new_password_title: \"Set a new password\",\n auth_new_password_subtitle: \"Choose the password you will sign in with from now on.\",\n auth_password_requirements: \"Password must be 8+ characters with uppercase, lowercase, and a number\",\n auth_set_password: \"Set password\",\n auth_password_changed_title: \"Password changed\",\n auth_password_changed_body: \"Sign in with your new password.\",\n auth_continue_to_sign_in: \"Continue to sign in\",\n auth_link_invalid_or_expired: \"This link is invalid or has expired. Request a new one from the sign-in screen.\",\n auth_password_reset_unavailable: \"Password reset is not available on this backend.\",\n auth_verifying_email: \"Confirming your email address…\",\n auth_email_verified_title: \"Email confirmed\",\n auth_email_verified_body: \"Your email address is confirmed. You can sign in now.\",\n auth_email_verification_failed_title: \"Email not confirmed\",\n auth_email_verification_unavailable: \"Email verification is not available on this backend.\",\n auth_verify_email_proof_title: \"Confirm it is your account\",\n auth_verify_email_proof_body: \"This account has a password. Enter it to keep it and sign in. If you never set one, someone else may have registered your address: confirm it without the password, and theirs is removed.\",\n auth_verify_email_password_label: \"The password you chose\",\n auth_verify_email_with_password: \"Confirm and sign in\",\n auth_verify_email_without_password: \"I didn't set a password\",\n auth_verify_email_wrong_password: \"That is not this account's password.\",\n auth_email_verified_password_removed_body: \"Your email address is confirmed. A password was set on this account before the address was confirmed, so it was removed. Sign in with a link, or set a new password with \\\"Forgot password\\\".\",\n auth_confirm_email_sent_title: \"Check your inbox\",\n auth_confirm_email_sent_body: \"We sent a link to your email address. Follow it to confirm your address, then sign in.\",\n auth_email_not_confirmed: \"Confirm your email address first. We sent a new link to it.\",\n auth_mfa_title: \"Two-step verification\",\n auth_mfa_subtitle: \"Enter the code from your authenticator app, or one of your recovery codes.\",\n auth_mfa_factor_label: \"Verify with\",\n auth_mfa_factor_totp: \"Authenticator app\",\n auth_mfa_code_label: \"Verification code\",\n auth_mfa_verify: \"Verify\",\n auth_mfa_code_invalid: \"That code is not right. Try the current code from your authenticator app, or a recovery code.\",\n auth_mfa_challenge_exhausted: \"Too many wrong codes. Enter a new code from your authenticator app to try again.\",\n auth_mfa_expired: \"This sign-in has expired. Sign in again to continue.\",\n auth_mfa_sign_in_again: \"Sign in again\",\n email_address: \"Email address\",\n email_change_description: \"We send a link to the new address. Your account moves to it when the link is followed.\",\n email_change_button: \"Change email\",\n email_change_pending: \"We sent a link to {{email}}. Your email address changes when it is followed.\",\n email_change_taken: \"Another account already uses that address.\",\n email_change_undeliverable: \"No mail can reach that address.\",\n email_change_unchanged: \"That is already your email address.\",\n email_change_needs_second_factor: \"Sign in again with your second factor before changing your email address.\",\n auth_confirming_email_change: \"Changing your email address…\",\n auth_email_change_confirmed_title: \"Email address changed\",\n auth_email_change_confirmed_body: \"Your account now uses {{email}}.\",\n auth_email_change_providers_removed: \"Signing in with {{providers}} was removed, because it was linked to your old address.\",\n auth_email_change_failed_title: \"Email address not changed\",\n auth_email_change_continue: \"Continue\",\n auth_email_change_unavailable: \"Changing an email address is not available on this backend.\",\n auth_signing_in_with_link: \"Signing you in…\",\n auth_magic_link_failed_title: \"Sign-in link not accepted\",\n auth_magic_link_unavailable: \"Sign-in links are not available on this backend.\",\n reset_mfa_title: \"Reset two-step verification\",\n reset_mfa_description: \"Removes this user's authenticator apps and recovery codes and signs them out everywhere. They sign in with their password alone and can set up two-step verification again.\",\n reset_mfa_confirm: \"Reset\",\n reset_mfa_success: \"Two-step verification reset\",\n account_access_title: \"Account access\",\n account_access_action: \"Disable or enable account\",\n account_disabled_label: \"Account disabled\",\n account_disabled_description: \"A disabled account cannot sign in, and every session and token it holds stops working at once. Its data stays; switch it back on to restore access.\",\n account_disabled_success: \"Account disabled\",\n account_enabled_success: \"Account enabled\",\n\n\n auto_setup_collections_button: \"Automatically set up collections\",\n auto_setup_collections_title: \"Automatically set up collections?\",\n auto_setup_collections_desc: \"This will automatically create collection configs for collections that are <b>NOT</b> already mapped\",\n this_can_take_a_minute: \"This can take a minute or two\",\n no_collections_found_to_setup: \"No collections found to setup.\",\n collections_have_been_setup: \"Collections have been automatically setup.\",\n error_setting_up_collections: \"Error automatically setting up collections\",\n\n // --- Home Suggestions ---\n\n admin_panel_ready_bring_data: \"Your admin panel is ready. Let's bring in your data.\",\n admin_panel_ready_get_started: \"Your admin panel is ready. Here's how to get started.\",\n auto_detect_collections: \"Auto-detect collections\",\n auto_detect_collections_desc: \"Let AI scan your database and automatically generate collection schemas.\",\n create_a_collection: \"Create a collection\",\n create_collection_desc: \"Manually define your first collection from scratch using the visual editor.\",\n read_the_docs: \"Read the docs\",\n read_the_docs_desc: \"Learn how to customize fields, views, actions and more.\",\n explore_docs: \"Explore docs\",\n want_to_customize_with_code: \"Want to customize with code? Run\",\n to_scaffold_a_local_project: \"to scaffold a local project.\",\n\n // ─── Collection Editor — Validation ──────────────────────────\n validation: \"Validation\",\n unique: \"Unique\",\n required_message: \"Required message\",\n required_tooltip: \"You won't be able to save this entity if this value is not set\",\n unique_tooltip: \"There cannot be multiple entities with the same value\",\n lowercase: \"Lowercase\",\n uppercase: \"Uppercase\",\n trim: \"Trim\",\n exact_length: \"Exact length\",\n min_length: \"Min length\",\n max_length: \"Max length\",\n varchar_narrowing_warning: \"Saving narrows this {{columnType}} column to {{max}} characters. rebase db push asks before it narrows a column, and the change fails while a stored value is longer.\",\n matches_regex: \"Matches regex\",\n not_valid_regexp: \"Not a valid regexp\",\n regex_helper: \"e.g. /^\\\\d+$/ for digits only\",\n min_value: \"Min value\",\n max_value: \"Max value\",\n less_than: \"Less than\",\n more_than: \"More than\",\n positive_value: \"Positive value\",\n negative_value: \"Negative value\",\n integer_value: \"Integer value\",\n\n // ─── Collection Editor — Property Edit ───────────────────────\n invalid_regular_expression: \"Invalid regular expression\",\n must_specify_target_collection: \"You must specify a target collection for the field\",\n need_specify_repeat_field: \"You need to specify a repeat field\",\n need_specify_block_properties: \"You need to specify the properties of this block\",\n incomplete_condition: \"Incomplete condition - please select a field\",\n field_name: \"Field name\",\n\n // ─── Collection Editor — Display & Config ────────────────────\n kanban_column_property: \"Kanban Column Property\",\n select_a_property: \"Select a property\",\n kanban_property_not_found: \"Property \\\"{{property}}\\\" does not exist or is not an enum string property. Please select a valid property or clear the selection.\",\n no_enum_string_properties: \"No enum string properties found. Add a string property with enumValues to use Kanban view.\",\n kanban_column_description: \"Select a string property with enum values to group entities into columns\",\n create_property: \"+ Create \\\"{{property}}\\\" property\",\n order_property: \"Order Property\",\n order_property_not_found: \"Property \\\"{{property}}\\\" does not exist or is not a text property. Please select a valid property or clear the selection.\",\n no_number_properties: \"No text properties found. Add a text property to enable ordering.\",\n order_property_description: \"Select a text property to persist the order of items\",\n display_settings: \"Display settings\",\n default_row_size: \"Default row size\",\n side_dialog_width: \"Side dialog width\",\n side_dialog_width_description: \"Optionally define the width (in pixels) of entities side dialog. Default is 768px\",\n inline_editing_enabled: \"Data can be edited directly in the table view\",\n inline_editing_disabled: \"Data can be edited only in the form view\",\n inline_editing_description: \"Allow editing data directly in the table view, without opening the form view.\",\n include_json_view: \"Include JSON view\",\n no_json_view: \"Do not include JSON view\",\n json_view_description: \"Include the JSON representation of the document.\",\n not_found_suffix: \"not found\",\n\n // ─── Editor ─────────────────────────────────────────────────\n editor_text: \"Text\",\n editor_text_description: \"Just start typing with plain text.\",\n editor_heading_1: \"Heading 1\",\n editor_heading_1_description: \"Big section heading.\",\n editor_heading_2: \"Heading 2\",\n editor_heading_2_description: \"Medium section heading.\",\n editor_heading_3: \"Heading 3\",\n editor_heading_3_description: \"Small section heading.\",\n editor_todo_list: \"To-do List\",\n editor_todo_list_description: \"Track tasks with a to-do list.\",\n editor_bullet_list: \"Bullet List\",\n editor_bullet_list_description: \"Create a simple bulleted list.\",\n editor_numbered_list: \"Numbered List\",\n editor_numbered_list_description: \"Create a list with numbering.\",\n editor_quote: \"Quote\",\n editor_quote_description: \"Capture a quote.\",\n editor_code: \"Code\",\n editor_code_description: \"Capture a code snippet.\",\n editor_image: \"Image\",\n editor_image_description: \"Upload an image from your computer.\",\n editor_multiple: \"Multiple\",\n editor_link: \"Link\",\n editor_save: \"Save\",\n editor_cancel: \"Cancel\",\n editor_remove_link: \"Remove link\",\n editor_paste_or_type_link: \"Paste or type link\",\n editor_invalid_url: \"That is not a link — try a full address like example.com\",\n editor_open_in_new_window: \"Open in new window\",\n editor_bold: \"Bold\",\n editor_italic: \"Italic\",\n editor_underline: \"Underline\",\n editor_strikethrough: \"Strikethrough\",\n editor_autocomplete: \"Autocomplete\",\n editor_autocomplete_description: \"Add text based on the context.\",\n\n // ─── Text Search Dialog ─────────────────────────────────────\n text_search_dialog_title: \"Enable text search\",\n text_search_local_not_recommended: \"Local text search is not recommended for large collections.\",\n text_search_local_fetch_warning: \"Note that enabling local text search will need to fetch all documents from your collection and store them in the browser. This can be inefficient for large collections. It can also incur in additional costs.\",\n text_search_external_suggestion: \"For larger collections, you are encouraged to use an external search engine such as Algolia or Elastic Search, and assign a search delegate to your config.\",\n text_search_local_description: \"Local text search is the simplest way to enable text search in your collection. It loads all documents in the collection in the browser and performs the search locally. This is the recommended option for small collections.\",\n text_search_own_implementation: \"You have implemented your own text search controller. You enable text search for your collection.\",\n text_search_enable_for_collection: \"Enable for this collection\",\n text_search_enable_for_project: \"Enable for project\",\n text_search_enabled_snackbar: \"Local text search enabled\",\n\n settings_heading: \"Settings\",\n settings_project_name: \"Project name\",\n settings_default_language: \"Default language\",\n settings_default_language_caption: \"Select the base language for this project. Users can override this preference in their personal settings.\",\n settings_enable_local_text_search: \"Enable local text search\",\n settings_local_text_search_caption: \"Enable local text search for all collections. This will allow you to search text fields in your collections using the Rebase search bar. Note that this feature can incur in higher read counts, as it will index all text fields in your collections.\",\n settings_doc_history_all_collections: \"Document history enabled for all collections\",\n settings_doc_history_caption: \"When true, all collections will have the history enabled by default. You can override this setting in each collection. History will be saved in the __history subcollection of each document.\",\n settings_theme: \"Theme\",\n settings_primary_color: \"Primary color\",\n settings_secondary_color: \"Secondary color\",\n settings_sample_theme_components: \"Sample theme components\",\n settings_drag_drop_logo: \"Drag and drop your logo here\",\n settings_security_rules: \"Security rules\",\n settings_security_rules_description: \"Rebase uses granular security rules to restrict access to data. When creating a new user through Rebase, custom claims are added to the user. By adding the following security rules to your project, you ensure Rebase users can access data securely.\",\n settings_security_rules_add_domain: \"Remember to add the domain {{domain}} to your provider allowed domains\",\n settings_security_rules_caption: \"These rules restrict access to data to Rebase users only, but do not enforce the permissions at the database level. The permissions are enforced in the frontend though, which will work fine for most projects. If you need to enforce the permissions at the database level, you can modify these security rules yourself to suit your needs. The roles assigned to a user are set as custom claims in the auth token, so you can use them in your security rules.\",\n\n // ─── Studio: SQL Editor ─────────────────────────────────────\n studio_sql_executing_query: \"EXECUTING QUERY...\",\n studio_sql_query_error: \"Query Error\",\n studio_sql_run_query_placeholder: \"Run a query to see results\",\n studio_sql_visual_execution_plan: \"Visual Execution Plan\",\n studio_sql_success: \"SUCCESS\",\n studio_sql_no_results: \"Query executed successfully but returned no results.\",\n studio_sql_rows: \"Rows:\",\n studio_sql_time: \"Time:\",\n studio_sql_copy_markdown: \"Copy Markdown\",\n studio_sql_export_json: \"Export JSON\",\n studio_sql_export_json_typed: \"Export typed JSON\",\n studio_sql_export_csv: \"Export CSV\",\n studio_sql_format_sql: \"Format SQL\",\n studio_sql_explain: \"Explain\",\n studio_sql_limit_1000: \"Limit 1000\",\n studio_sql_remove_from_favorites: \"Remove from Favorites\",\n studio_sql_add_to_favorites: \"Add to Favorites\",\n studio_sql_save: \"Save\",\n studio_sql_run: \"Run\",\n studio_sql_cancel_run: \"Cancel run\",\n studio_sql_run_cancelled: \"Run cancelled.\",\n studio_sql_database: \"Database\",\n studio_sql_role: \"Role\",\n studio_sql_admin: \"(Admin)\",\n studio_sql_select_db: \"Select DB\",\n studio_sql_query_results: \"Query Results\",\n studio_sql_save_snippet: \"Save SQL Snippet\",\n studio_sql_snippet_name: \"Snippet Name\",\n studio_sql_snippet_name_placeholder: \"e.g., Get All Users\",\n studio_sql_snippet_saved_local: \"This will be saved to your local storage.\",\n studio_sql_cancel: \"Cancel\",\n studio_sql_dangerous_operation: \"Dangerous Operation Detected\",\n studio_sql_dangerous_operation_body: \"The query you are about to run contains potentially destructive operations (DELETE, DROP, TRUNCATE, or UPDATE without WHERE). Are you sure you want to proceed?\",\n studio_sql_snippet_saved: \"Snippet \\\"{{name}}\\\" saved.\",\n studio_sql_markdown_copied: \"Results copied as Markdown!\",\n studio_sql_markdown_copy_failed: \"Failed to copy Markdown to clipboard.\",\n studio_sql_row_updated: \"Row updated successfully.\",\n studio_sql_cannot_edit_missing_query: \"Cannot edit rows: The underlying query is missing.\",\n studio_sql_edit_unreadable_query: \"The console could not read this query, so it cannot tell which row a cell came from. Cells of this result cannot be edited.\",\n studio_sql_edit_not_a_select: \"Only the rows of a single SELECT can be edited here.\",\n studio_sql_edit_duplicate_column: \"The result has more than one column named \\\"{{column}}\\\". Give each one its own alias to edit it.\",\n studio_sql_edit_computed_column: \"\\\"{{column}}\\\" is not read from a table column (it is computed, a literal or an aggregate), so there is nothing to write it back to.\",\n studio_sql_edit_not_a_table: \"\\\"{{column}}\\\" comes from {{table}}, which is not a table. Only rows of a table can be edited here.\",\n studio_sql_edit_inherited_table: \"Other tables inherit {{table}}, so its primary key can match a row in each of them. Edit the row in the table that holds it.\",\n studio_sql_edit_no_primary_key: \"{{table}} has no primary key, so a row of it cannot be found again to update it.\",\n studio_sql_edit_key_missing: \"To edit columns of {{table}}, select its primary key ({{columns}}) under a name no other column of the result has.\",\n studio_sql_edit_table_read_twice: \"The query reads {{table}} more than once, so a row's key and this cell may come from different rows of it.\",\n studio_sql_missing_pk: \"Row is missing primary key column(s): {{columns}}. Cannot safely update.\",\n studio_sql_cannot_edit_other_connection: \"These rows were read from another database or as another role. Run the query again to edit them.\",\n studio_sql_update_failed: \"Failed to update: {{message}}\",\n studio_sql_update_no_row: \"No row was updated: the row has changed or been deleted since it was read, or the selected role may not update it. Run the query again to see what is stored.\",\n studio_sql_ran_as_other_role: \"These rows were read as {{ranAs}}, not as {{role}}: role switching is turned off on this server (DISABLE_DB_ROLE_SWITCHING), so every statement runs as the connection owner.\",\n studio_sql_result_truncated: \"Showing the first {{shown}} of {{total}} rows: the console keeps at most 10,000 rows, or 32 MB of values, of one result. Narrow the query, or page through it with LIMIT and OFFSET, to see the rest. Copy and export include only the rows shown.\",\n studio_sql_download_full_csv: \"Download full result as CSV\",\n studio_sql_downloading_full_csv: \"Downloading…\",\n studio_sql_download_full_failed: \"Could not download the full result: {{message}}\",\n studio_sql_role_switching_disabled: \"Role switching is turned off on this server: every statement runs as {{role}}, whichever role is picked here.\",\n studio_sql_execution_not_supported: \"SQL execution is not supported by the current data source.\",\n studio_sql_error_executing: \"An error occurred while executing the query.\",\n studio_sql_error_explaining: \"An error occurred while explaining the query.\",\n studio_sql_explain_single_statement: \"Explain works on one statement at a time. Select the statement to explain and try again.\",\n studio_sql_save_first_to_favorite: \"Please save the snippet first before favoriting.\",\n studio_sql_collections_label: \"Collections:\",\n studio_sql_admin_collections_tooltip: \"Tables in this query that are mapped to collections\",\n studio_sql_edit_entity: \"Open {{name}} #{{id}}\",\n studio_sql_sql_not_supported: \"SQL execution not supported by this data source\",\n studio_sql_fetch_error: \"Failed to fetch connection options: {{message}}\",\n studio_sql_unexpected_format: \"Unexpected data format: {{type}}\",\n studio_sql_no_tables: \"No tables found in this database.\",\n studio_sql_schema_fetch_error: \"Failed to fetch schema: {{message}}\",\n\n // ─── Studio: SQL Editor Sidebar ──────────────────────────────\n studio_sql_sidebar_snippets: \"Snippets\",\n studio_sql_sidebar_history: \"History\",\n studio_sql_sidebar_schema: \"Schema\",\n studio_sql_sidebar_no_snippets: \"No saved snippets\",\n studio_sql_sidebar_save_snippet_hint: \"Save a query to access it here.\",\n studio_sql_sidebar_no_history: \"No history\",\n studio_sql_sidebar_history_hint: \"Executed queries will appear here.\",\n studio_sql_sidebar_delete_snippet: \"Delete snippet\",\n studio_sql_close_tab: \"Close this query tab\",\n studio_sql_new_tab: \"New query tab\",\n\n // ─── Studio: Schema Browser ──────────────────────────────────\n studio_schema_tables: \"Tables\",\n studio_schema_loading: \"Loading schema...\",\n studio_schema_no_tables: \"No tables found\",\n studio_schema_retry: \"Retry\",\n studio_schema_primary_key: \"Primary Key\",\n studio_schema_select_all: \"SELECT * FROM\",\n studio_schema_insert_into: \"INSERT INTO\",\n studio_schema_update: \"UPDATE\",\n studio_schema_delete_from: \"DELETE FROM\",\n studio_schema_columns: \"{{count}} columns\",\n\n // ─── Studio: RLS Editor ──────────────────────────────────────\n studio_rls_title: \"Row Level Security\",\n studio_rls_description: \"Manage RLS policies for your tables\",\n studio_rls_enabled: \"RLS Enabled\",\n studio_rls_disabled: \"RLS Disabled\",\n studio_rls_no_rls: \"No RLS\",\n studio_rls_enable_rls: \"Enable RLS\",\n studio_rls_disable_rls: \"Disable RLS\",\n studio_rls_create_policy: \"Create Policy\",\n studio_rls_policies: \"Policies\",\n studio_rls_no_policies: \"No policies defined\",\n studio_rls_no_policies_desc: \"This table has no RLS policies. All rows are accessible based on the RLS status.\",\n studio_rls_add_first_policy: \"Add your first policy\",\n studio_rls_force_rls: \"Force RLS\",\n studio_rls_force_rls_desc: \"When enabled, RLS policies apply to the table owner as well.\",\n studio_rls_enable_force_rls: \"Enable Force RLS\",\n studio_rls_disable_force_rls: \"Disable Force RLS\",\n studio_rls_edit: \"Edit\",\n studio_rls_edit_generated: \"{{policy}} is generated by Rebase for every collection, so there is no rule of yours to edit. Add a policy of your own instead.\",\n studio_rls_edit_not_declared: \"{{policy}} exists only in the database, so there is no rule in your code to edit. Import it to the codebase first.\",\n studio_rls_edit_several_operations: \"{{policy}} is one of the policies a single rule compiles to, one per operation. Edit that rule in the collection's source file.\",\n studio_rls_delete: \"Delete\",\n studio_rls_confirm_delete_title: \"Delete Policy\",\n studio_rls_confirm_delete_body: \"Are you sure you want to delete this policy? This action cannot be undone.\",\n studio_rls_confirm_enable_title: \"Enable Row Level Security\",\n studio_rls_confirm_enable_body: \"Enabling RLS will restrict access to rows in this table based on your policies. Make sure you have appropriate policies in place.\",\n studio_rls_confirm_disable_title: \"Disable Row Level Security\",\n studio_rls_confirm_disable_body: \"Disabling RLS will make all rows accessible to all roles. Are you sure you want to continue?\",\n studio_rls_select_table: \"Select a table\",\n studio_rls_no_tables: \"No tables available\",\n studio_rls_error: \"Error loading policies\",\n studio_rls_retry: \"Retry\",\n studio_rls_loading: \"Loading policies...\",\n\n // ─── Studio: Policy Editor ───────────────────────────────────\n studio_policy_edit: \"Edit Policy\",\n studio_policy_create: \"Create New Policy\",\n studio_policy_defining_rules: \"Defining access rules for\",\n studio_policy_cancel: \"Cancel\",\n studio_policy_save: \"Save Policy\",\n studio_policy_template: \"Start from a template (Optional)\",\n studio_policy_select_template: \"Select a template...\",\n studio_policy_name: \"Policy Name\",\n studio_policy_name_placeholder: \"Give your policy a descriptive name\",\n studio_policy_behavior: \"Policy Behavior\",\n studio_policy_permissive: \"Permissive\",\n studio_policy_permissive_desc: \"Combined using \\\"OR\\\"\",\n studio_policy_restrictive: \"Restrictive\",\n studio_policy_restrictive_desc: \"Combined using \\\"AND\\\"\",\n studio_policy_command: \"Policy Command\",\n studio_policy_target_roles: \"Target Roles\",\n studio_policy_roles_placeholder: \"Select roles (defaults to public)\",\n studio_policy_using_expr: \"USING expression\",\n studio_policy_using_expr_desc: \"Applies to existing rows (SELECT, UPDATE, DELETE)\",\n studio_policy_check_expr: \"WITH CHECK expression\",\n studio_policy_check_expr_desc: \"Applies to new or modified rows (INSERT, UPDATE)\",\n studio_policy_help_title: \"Row Level Security (RLS) Guide\",\n studio_policy_help_intro: \"Row Level Security (RLS) allows you to restrict which rows a user can access or modify based on their authentication status or roles.\",\n studio_policy_help_step1_title: \"1. Select a Template\",\n studio_policy_help_step1_desc: \"If you're new to RLS, the easiest way to start is by selecting a predefined template from the dropdown. It will automatically configure the policy for common use cases like \\\"Users can update their own rows\\\".\",\n studio_policy_help_step2_title: \"2. Target Roles\",\n studio_policy_help_step2_desc: \"Choose the database roles the policy applies to. Every API request runs as the same role, signed in or not, so who the caller is goes in the USING expression:\",\n studio_policy_help_role_public: \"Every role, so every request. What the templates and Rebase's own policies target.\",\n studio_policy_help_role_rebase_user: \"The role API requests run as. It differs from public only for connections made directly as another role.\",\n studio_policy_help_roles_not_users: \"Signed-in users, anonymous visitors and admins are not database roles here. Target public and check rebase.uid() or rebase.roles() in the expression, as the templates do.\",\n studio_policy_help_step3_title: \"3. USING Expression\",\n studio_policy_help_step3_desc: \"A SQL condition that must evaluate to true for existing rows to be visible or updatable (SELECT, UPDATE, DELETE).\",\n studio_policy_help_step3_example: \"Ensures users can only see rows where they are the owner.\",\n studio_policy_help_step4_title: \"4. WITH CHECK Expression\",\n studio_policy_help_step4_desc: \"A SQL condition that must evaluate to true for new or modified rows to be saved (INSERT, UPDATE).\",\n studio_policy_help_step4_example: \"Usually the same as the USING expression when users are only allowed to insert/edit their own data.\",\n studio_policy_help_auth_vars_title: \"Rebase Auth Variables\",\n studio_policy_help_auth_vars_desc: \"Rebase provides native helper functions that you can use in your expressions:\",\n studio_policy_help_auth_uid: \"Returns the current user's ID as text. Example:\",\n studio_policy_help_auth_jwt: \"Returns the full JWT payload as JSONB so you can check custom claims. Example:\",\n studio_policy_help_auth_roles: \"Returns the user's role IDs as a comma-separated string. Best used with:\",\n studio_policy_help_docs_cta: \"To learn more about Postgres policies, check out the official documentation.\",\n studio_policy_help_read_docs: \"Read Docs\",\n studio_policy_help_got_it: \"Got it!\",\n\n // ─── Studio: UI Actions ──────────────────────────────────────\n studio_add_kanban_column: \"Add column\",\n studio_add_kanban_column_title: \"Add Kanban Column\",\n studio_add_kanban_column_name: \"Column name\",\n studio_add_kanban_column_name_placeholder: \"New column name\",\n studio_add_kanban_column_add: \"Add\",\n studio_add_kanban_column_cancel: \"Cancel\",\n studio_collection_view_sql: \"SQL Editor\",\n studio_collection_view_admin: \"Admin View\",\n studio_editor_collection_tooltip: \"Edit collection schema\",\n studio_editor_collection_no_permission: \"You don't have permission to edit this collection\",\n studio_editor_collection_start_tooltip: \"Copy path or edit schema\",\n studio_editor_collection_start_no_permission: \"You don't have permission to modify this collection\",\n studio_editor_collection_start_copied: \"Copied!\",\n studio_editor_entity_tooltip: \"Edit entity schema\",\n studio_editor_entity_no_permission: \"You don't have permission to edit this entity\",\n studio_home_edit_collection: \"Edit collection\",\n studio_home_delete_collection: \"Delete collection\",\n studio_home_confirm_delete_title: \"Delete collection?\",\n studio_home_confirm_delete_body: \"Are you sure you want to delete the collection \\\"{{name}}\\\"? This action cannot be undone.\",\n studio_kanban_setup: \"Kanban Setup\",\n studio_missing_reference: \"Missing reference: {{path}}\",\n studio_missing_reference_create: \"Create\",\n studio_new_collection: \"New collection\",\n studio_new_collection_card: \"New collection\",\n studio_new_collection_no_permission: \"You don't have permissions to create collections\",\n studio_property_add_column: \"Add new property\",\n studio_property_add_column_no_permission: \"You don't have permission to add new properties\",\n studio_add_kanban_column_desc: \"Add a new option to the \\\"{{property}}\\\" property. This will create a new column in the Kanban board.\",\n studio_add_kanban_column_adding: \"Adding...\",\n studio_add_kanban_column_exists: \"A column named \\\"{{label}}\\\" is already on the board.\",\n studio_add_kanban_column_not_enum: \"\\\"{{property}}\\\" is not a property with options, so no column can be added to it.\",\n studio_collection_view_edit: \"Edit\",\n studio_editor_collection_disabled: \"Collection editing is disabled\",\n studio_editor_collection_edit: \"Edit collection\",\n studio_editor_entity_save_first: \"You need to save the document before changing the schema\",\n studio_editor_entity_edit_schema: \"Edit schema for this form\",\n studio_editor_collection_start_save_filter: \"Save default filter and sort\",\n studio_editor_collection_start_clear_filter: \"Clear default filter and sort\",\n studio_editor_collection_start_reset_filter: \"Reset to default filter and sort\",\n studio_editor_collection_start_saved: \"Default config saved\",\n studio_home_duplicate_collection: \"Duplicate\",\n studio_home_delete: \"Delete\",\n studio_home_confirm_delete_no_data: \"Deletes the collection's file and its entry in index.ts, and commits that. The table and its rows stay in the database. Refused while another collection links to this one.\",\n studio_home_collection_deleted: \"Collection deleted\",\n studio_kanban_configure: \"Configure Kanban\",\n studio_missing_reference_error: \"No collection for path: {{path}}\",\n studio_new_collection_add: \"Add new collection\",\n studio_tool_schema: \"Collections\",\n studio_js_collections_tab: \"Collections\",\n studio_tool_schema_description: \"Define and manage your data model and collection schemas\",\n studio_collections_editor_empty: \"No collections yet.\",\n studio_collections_editor_pick: \"Select a collection or create a new one to start editing.\",\n studio_collections_editor_read_only: \"Collections cannot be edited on this server.\",\n studio_collections_editor_unsaved: \"There are unsaved changes in this collection.\",\n\n // ─── Property field labels ──────────────────────────────────\n db_column_type: \"Database Column Type\",\n primary_key_unique_id: \"Primary Key / Unique ID\",\n spread_children_as_columns: \"Spread children as columns\",\n mode: \"Mode\",\n timezone: \"Timezone\",\n target_collection: \"Target collection\",\n\n // ─── Storage property ───────────────────────────────────────\n storage_file_name: \"File name\",\n storage_path: \"Storage path\",\n storage_max_size: \"Max size (in bytes)\",\n storage_resize_mode: \"Resize mode\",\n storage_output_format: \"Output format\",\n storage_max_width: \"Max width (px)\",\n storage_max_height: \"Max height (px)\",\n storage_quality: \"Quality (0-100)\",\n storage_file_upload_config: \"File upload config\",\n storage_image_resize_config: \"Image Resize Configuration\",\n storage_all_file_types: \"All file types allowed\",\n storage_allowed_file_types: \"Allowed file types\",\n storage_include_bucket_url: \"Include bucket URL (s3://...) in saved value\",\n storage_save_url: \"Save URL instead of storage path\",\n\n // ─── DateTime property ──────────────────────────────────────\n datetime_automatic_value: \"Automatic value\",\n\n // ─── Markdown property ──────────────────────────────────────\n markdown_paste_behavior: \"Paste behavior\",\n\n // ─── Entity identity bar and inspector ──────────────────────\n entity_saved: \"Saved\",\n more_actions: \"More actions\",\n record_history: \"History\",\n inspect_record: \"Inspect record\",\n inspect: \"Inspect\",\n close_inspector: \"Close inspector\",\n open_in_live_site: \"Open in the live site\",\n\n // ─── Revision history ───────────────────────────────────────\n history_revert: \"Revert to this version\",\n history_revert_title: \"Revert data to this version?\",\n history_reverted: \"Reverted to selected version\",\n history_revert_error: \"Error reverting entity\",\n history_revert_dirty: \"Please save or discard your changes before reverting\",\n history_empty: \"No history available\",\n history_empty_description: \"When you save a record, a new version is created and stored in the history.\",\n history_new_entity: \"History is only available for existing records\",\n history_no_more: \"No more history\",\n\n // ─── Studio: tools, groups and empty states ─────────────────\n // The admin's own three groups, read by `useNavigationGroupLabel` the same\n // way as the Studio ones below — the group *name* is an identifier the\n // ordering and the icons key off, and only the heading is translated.\n studio_group_views: \"Views\",\n studio_group_admin: \"Admin\",\n studio_group_settings: \"Settings\",\n studio_group_database: \"Database\",\n studio_group_compute: \"Compute\",\n studio_group_storage: \"Storage\",\n studio_group_api: \"API\",\n studio_group_access_control: \"Access Control\",\n studio_tool_sql: \"SQL Console\",\n studio_tool_sql_description: \"Execute SQL queries\",\n studio_tool_js: \"JS Console\",\n studio_tool_js_description: \"Execute JavaScript\",\n studio_tool_rls: \"RLS Policies\",\n studio_tool_rls_description: \"Row Level Security\",\n studio_tool_storage: \"Storage\",\n studio_tool_storage_description: \"Manage storage files\",\n studio_tool_cron: \"Cron Jobs\",\n studio_tool_cron_description: \"Manage scheduled tasks\",\n studio_tool_schema_visualizer: \"Schema Visualizer\",\n studio_tool_schema_visualizer_description: \"Entity diagram of your collections\",\n studio_tool_branches: \"Branches\",\n studio_tool_branches_description: \"Create and manage database branches\",\n studio_tool_backups: \"Backups\",\n studio_tool_backups_description: \"Download database backups\",\n studio_tool_api: \"API Explorer\",\n studio_tool_api_description: \"Interactive API documentation and testing\",\n studio_tool_logs: \"Logs Explorer\",\n studio_tool_logs_description: \"Real-time system and query logs\",\n studio_tool_api_keys: \"API Keys\",\n studio_tool_api_keys_description: \"Create and manage scoped API keys\",\n studio_backups_denied_title: \"You cannot list this project's backups\",\n studio_backups_denied_hint: \"Nothing is wrong with the project. Listing backups needs an admin connection, and the signed-in account was refused.\",\n studio_backups_read_failed: \"Could not read this project's backups\",\n studio_backups_downloading: \"Downloading…\",\n studio_backups_roles_file: \"Roles file\",\n studio_backups_roles_file_hint: \"The .globals.sql saved with this backup. It recreates the database roles that the dump's grants and row-level security refer to, and `rebase db restore` reads it from next to the .dump, so keep the two files together.\",\n studio_backups_no_roles_file: \"No roles file\",\n studio_backups_no_roles_file_hint: \"No .globals.sql was saved with this backup. Restoring it into a new Postgres stops at the first grant to a database role that does not exist there.\",\n studio_backups_empty: \"No backups yet.\",\n studio_backups_empty_hint: \"Take one with `rebase db backup`, or schedule them with a cron file that exports createBackupCron.\",\n studio_backups_last_run_failed: \"The last scheduled backup failed ({{when}})\",\n studio_backups_last_run_ok: \"Last scheduled backup: {{when}}\",\n studio_backups_never_ran: \"The scheduled backup has not run yet\",\n studio_backups_next_run: \"Next run: {{when}}\",\n studio_backups_schedule_paused: \"Scheduled backups are paused. Resume the {{job}} job in Cron Jobs.\",\n studio_backups_schedule_off_in_code: \"Scheduled backups are off: the {{job}} job is declared disabled in its cron file. With the documented backup cron file, setting BACKUP_SCHEDULE turns them on.\",\n studio_backups_manual_run_ok: \"Last run by hand: {{when}}\",\n studio_backups_manual_run_failed: \"The last run by hand failed ({{when}})\",\n studio_backups_history_unreadable: \"Could not read the scheduled backup's run history, so whether it ran is not known. The server log has the reason.\",\n studio_backups_job_refused: \"Scheduled backups never run: the scheduler refused the {{job}} job. Fix it in its cron file.\",\n studio_backups_local_disk_of_this_process: \"These are the backups on this server process's disk. Scheduled backups run in another process and write to its disk, so they are listed here only if both share this directory. An s3:// or gs:// destination reads the same from every process.\",\n studio_backups_unavailable_title: \"Backups not available\",\n studio_backups_unavailable_body: \"This backend does not expose the backups API.\",\n studio_cron_denied_title: \"You cannot list this project's cron jobs\",\n studio_cron_denied_hint: \"Nothing is wrong with the project. The cron API is admin-only, and the signed-in account was refused.\",\n studio_cron_read_failed: \"Could not read this project's cron jobs\",\n studio_cron_logs_read_failed: \"Could not read this job's executions\",\n studio_cron_logs_denied_title: \"You cannot read this job's executions\",\n studio_cron_run_succeeded: \"{{job}} ran successfully\",\n studio_cron_last_error: \"Last error\",\n studio_cron_no_executions: \"No executions yet\",\n studio_cron_manual_run: \"manual\",\n studio_cron_job_enabled: \"Job enabled\",\n studio_cron_job_paused: \"Job paused\",\n studio_cron_refresh: \"Refresh\",\n studio_cron_select_job: \"Select a cron job to view its details\",\n studio_cron_pause_job: \"Pause job\",\n studio_cron_enable_job: \"Enable job\",\n studio_cron_run_now: \"Run now\",\n studio_cron_schedule: \"Schedule\",\n studio_cron_last_run: \"Last run\",\n studio_cron_next_run: \"Next run\",\n studio_cron_paused: \"Paused\",\n studio_cron_duration: \"Duration\",\n studio_cron_status: \"Status\",\n studio_cron_total_runs: \"Total runs\",\n studio_cron_failures: \"Failures\",\n studio_cron_execution_history: \"Execution history\",\n studio_cron_refresh_logs: \"Refresh executions\",\n studio_cron_run_failed: \"{{job}} ran and failed: {{error}}\",\n studio_cron_job_refused: \"{{job}} is not scheduled: the scheduler refused it\",\n studio_cron_files_failed: \"{{count}} cron files failed to load and are not scheduled. The server log says why.\",\n studio_cron_files_failed_one: \"{{count}} cron file failed to load and is not scheduled. The server log says why.\",\n studio_api_keys_denied_title: \"You cannot list this project's API keys\",\n studio_api_keys_denied_hint: \"Nothing is wrong with the project. Listing service keys needs the keys:read scope, which the signed-in account does not hold.\",\n studio_api_keys_read_failed: \"Could not read this project's API keys\",\n studio_api_keys_empty_title: \"No API keys yet\",\n studio_api_keys_empty_hint: \"Create a key to enable machine-to-machine authentication\",\n studio_api_keys_revoke: \"Revoke\",\n studio_api_keys_select_hint: \"Select an API key to view details\",\n studio_api_keys_revoke_confirmation: \"Revoke confirmation\",\n studio_api_keys_name_label: \"Name:\",\n studio_api_keys_access_label: \"Access:\",\n studio_api_keys_admin_granted: \"Admin role granted\",\n studio_api_keys_admin_granted_hint: \"row-level security does not limit it: it can read, change and delete every row its scopes reach, and it passes the admin checks in functions and storage\",\n studio_api_keys_done: \"Done\",\n studio_api_keys_status_active: \"Active\",\n studio_api_keys_status_expired: \"Expired\",\n studio_api_keys_status_revoked: \"Revoked\",\n studio_api_keys_inactive_heading: \"Revoked / Expired\",\n studio_api_keys_stat_status: \"Status\",\n studio_api_keys_stat_last_used: \"Last used\",\n studio_api_keys_stat_expires: \"Expires\",\n studio_api_keys_never: \"Never\",\n studio_api_keys_stat_rate_limit: \"Rate limit\",\n studio_api_keys_rate_limit_default: \"Default (1000/15min)\",\n studio_api_keys_stat_created_by: \"Created by\",\n studio_api_keys_copy_failed: \"Failed to copy\",\n studio_api_keys_tab_service: \"Service keys\",\n studio_api_keys_tab_personal: \"My keys\",\n studio_api_keys_refresh: \"Refresh\",\n studio_api_keys_new: \"New\",\n studio_api_keys_personal_empty_title: \"You have no personal keys\",\n studio_api_keys_personal_empty_hint: \"A personal key acts as your account, for scripts and tools you run yourself\",\n studio_api_keys_personal_read_failed: \"Could not read your API keys\",\n studio_api_keys_personal_denied_title: \"This session cannot have personal keys\",\n studio_api_keys_personal_denied_hint: \"A personal key acts as a signed-in account. API keys, the service key and guest sessions have no account for one to act as.\",\n studio_api_keys_personal_off_title: \"Personal keys are switched off\",\n studio_api_keys_personal_off_body: \"A personal key acts as your own account and never holds more than you do. To let accounts create them, set this in the auth block of the users collection:\",\n studio_api_keys_kind_service: \"Service\",\n studio_api_keys_kind_personal: \"Personal\",\n studio_api_keys_stat_kind: \"Kind\",\n studio_api_keys_stat_owner: \"Owner\",\n studio_api_keys_rate_limit_value: \"{{limit}}/15min\",\n studio_api_keys_scopes: \"Scopes\",\n studio_api_keys_no_scopes: \"This key holds no scopes\",\n studio_api_keys_scopes_count: \"{{count}} scopes\",\n studio_api_keys_plane_data: \"Data\",\n studio_api_keys_plane_data_hint: \"Rows, files and functions; row-level security still decides which rows\",\n studio_api_keys_plane_admin: \"Admin\",\n studio_api_keys_plane_admin_hint: \"Users, schema, database, backups, cron and logs\",\n studio_api_keys_plane_app: \"App\",\n studio_api_keys_plane_app_hint: \"Declared by this app under auth.scopes\",\n studio_api_keys_target_all_collection: \"Every collection\",\n studio_api_keys_target_all_bucket: \"Every storage source\",\n studio_api_keys_target_all_function: \"Every function\",\n studio_api_keys_target_all_other: \"Any {{kind}}\",\n studio_api_keys_target_some: \"Only the ones I choose\",\n studio_api_keys_target_mode: \"Targets\",\n studio_api_keys_target_pick: \"Choose…\",\n studio_api_keys_target_typed_placeholder: \"{{kind}} ids, comma-separated\",\n studio_api_keys_target_missing: \"Choose at least one target for “{{scope}}”, or switch it to all of them.\",\n studio_api_keys_bucket_default: \"Default bucket\",\n studio_api_keys_roles: \"RLS roles\",\n studio_api_keys_roles_rows_hint: \"Which rows the key can read, change and delete\",\n studio_api_keys_roles_service_only: \"Runs as service only. Row-level security grants it nothing unless a policy names that role.\",\n studio_api_keys_roles_service_plus: \"Runs as service plus these roles; every row-level security policy that names one of them applies.\",\n studio_api_keys_admin_bypasses_rls: \"Runs as admin: row-level security does not limit it, so it can read, change and delete every row its scopes reach, and it passes the admin checks in custom functions and storage. Its scopes still decide which endpoints it may call.\",\n studio_api_keys_admin_chip_tooltip: \"Runs as the admin role: row-level security does not limit its reads, writes or deletes\",\n studio_api_keys_personal_roles: \"Runs as its owner, with the owner's roles as they are each time it is used. It never holds a scope its owner has lost.\",\n studio_api_keys_revoke_title: \"Revoke “{{name}}”?\",\n studio_api_keys_revoke_body: \"Requests authenticated with this key stop working immediately. This cannot be undone.\",\n studio_api_keys_revoked: \"API key revoked\",\n studio_api_keys_created_title: \"API key created\",\n studio_api_keys_copy_now: \"Copy your key now — it won't be shown again\",\n studio_api_keys_copy_now_hint: \"This is the only time the full key is displayed. Store it somewhere safe.\",\n studio_api_keys_copied: \"API key copied to clipboard\",\n studio_api_keys_create_title: \"Create service key\",\n studio_api_keys_create_personal_title: \"Create personal key\",\n studio_api_keys_create_intro: \"A credential for scripts, cron jobs and agents. It acts as the project's service identity, not as a person, and reaches only the scopes you grant here.\",\n studio_api_keys_create_personal_intro: \"A credential for scripts and tools you run yourself. It acts as your account and can never do more than you can.\",\n studio_api_keys_field_name: \"Name\",\n studio_api_keys_field_name_placeholder: \"e.g. Analytics pipeline\",\n studio_api_keys_section_scopes_hint: \"Which endpoints the key may call\",\n studio_api_keys_scopes_read_failed: \"Could not read the scopes this backend offers\",\n studio_api_keys_scopes_offered_note: \"Only scopes your account holds are offered. Managing keys (keys:read, keys:write) can never go on a key.\",\n studio_api_keys_roles_explainer: \"Scopes decide which endpoints the key may call; roles decide which rows it can read, change and delete. Every service key runs as service, plus the roles you add here. Leave this empty unless a row-level security policy names a role the key needs.\",\n studio_api_keys_roles_other: \"Other roles\",\n studio_api_keys_roles_other_placeholder: \"Comma-separated role names\",\n studio_api_keys_roles_unavailable: \"The project's roles could not be listed; type role names instead.\",\n studio_api_keys_roles_admin_warning: \"With admin, row-level security does not limit the key: it can read, change and delete every row its scopes reach, and it passes the admin checks in custom functions and storage. Its scopes still decide which endpoints it may call.\",\n studio_api_keys_section_limits: \"Limits\",\n studio_api_keys_expiry_7d: \"In 7 days\",\n studio_api_keys_expiry_30d: \"In 30 days\",\n studio_api_keys_expiry_90d: \"In 90 days\",\n studio_api_keys_expiry_1y: \"In 1 year\",\n studio_api_keys_rate_limit_unit: \"per 15 min\",\n studio_api_keys_rate_limit_hint: \"Leave empty for the server default of 1000 requests per 15-minute window.\",\n studio_api_keys_rate_limit_scope: \"The limit counts the key's data, file and function requests, over HTTP, the realtime socket and MCP. Admin operations are not rate limited.\",\n studio_api_keys_summary_title: \"This key will be able to\",\n studio_api_keys_summary_empty: \"Nothing yet — choose at least one scope.\",\n studio_api_keys_summary_roles: \"Row-level security treats it as {{roles}}\",\n studio_api_keys_block_name: \"Name the key first\",\n studio_api_keys_block_scopes: \"Choose at least one scope\",\n studio_api_keys_block_targets: \"Finish choosing targets\",\n studio_api_keys_creating: \"Creating…\",\n studio_api_keys_create: \"Create key\",\n studio_api_keys_unsupported: \"This client cannot create API keys.\",\n studio_api_keys_error_invalid_scopes: \"Some scopes are not valid\",\n studio_api_keys_error_scope_exceeds_creator: \"A key cannot hold more than your account\",\n studio_api_keys_error_role_exceeds_creator: \"A key cannot run as a role you do not hold\",\n studio_api_keys_error_unknown_scope_target: \"A target does not exist on this backend\",\n studio_api_keys_error_key_management_scope: \"Managing keys cannot go on a key\",\n studio_api_keys_error_generic: \"The key was not created\",\n studio_scope_data_read_label: \"Read data\",\n studio_scope_data_read_description: \"Read rows from collections, through the caller's row-level security.\",\n studio_scope_data_write_label: \"Create and update data\",\n studio_scope_data_write_description: \"Create and update rows in collections, through the caller's row-level security.\",\n studio_scope_data_delete_label: \"Delete data\",\n studio_scope_data_delete_description: \"Delete rows from collections, through the caller's row-level security.\",\n studio_scope_storage_read_label: \"Read files\",\n studio_scope_storage_read_description: \"List and download stored files.\",\n studio_scope_storage_write_label: \"Upload files\",\n studio_scope_storage_write_description: \"Upload files and create folders.\",\n studio_scope_storage_delete_label: \"Delete files\",\n studio_scope_storage_delete_description: \"Delete stored files.\",\n studio_scope_functions_invoke_label: \"Call functions\",\n studio_scope_functions_invoke_description: \"Call the backend's custom functions. A function can do anything its code does.\",\n studio_scope_users_read_label: \"See users\",\n studio_scope_users_read_description: \"List user accounts and their roles.\",\n studio_scope_users_write_label: \"Manage users\",\n studio_scope_users_write_description: \"Create, edit and delete accounts, reset passwords and second factors, and assign roles up to the holder's own.\",\n studio_scope_schema_read_label: \"See the schema\",\n studio_scope_schema_read_description: \"Read the collection schema, plan schema changes and run the RLS audit.\",\n studio_scope_schema_write_label: \"Change the schema\",\n studio_scope_schema_write_description: \"Apply schema changes: edits collection files and alters the database.\",\n studio_scope_database_read_label: \"Inspect the database\",\n studio_scope_database_read_description: \"List databases, tables, Postgres roles and branches.\",\n studio_scope_database_write_label: \"Run SQL\",\n studio_scope_database_write_description: \"Run SQL as the database owner, outside row-level security, and create or delete branches.\",\n studio_scope_backups_read_label: \"Download backups\",\n studio_scope_backups_read_description: \"List and download database backups — every row, outside row-level security.\",\n studio_scope_cron_read_label: \"See cron jobs\",\n studio_scope_cron_read_description: \"List cron jobs and read their run history.\",\n studio_scope_cron_write_label: \"Run cron jobs\",\n studio_scope_cron_write_description: \"Trigger cron jobs and switch them on or off.\",\n studio_scope_logs_read_label: \"Read server logs\",\n studio_scope_logs_read_description: \"Read the server's request and application logs.\",\n studio_scope_keys_read_label: \"See service keys\",\n studio_scope_keys_read_description: \"List the project's service keys. Never grantable to a key.\",\n studio_scope_keys_write_label: \"Manage service keys\",\n studio_scope_keys_write_description: \"Create, change and revoke the project's service keys. Never grantable to a key.\",\n studio_branches_denied_title: \"You cannot list this project's branches\",\n studio_branches_denied_hint: \"Nothing is wrong with the project. Branching runs on the admin connection, and the signed-in account was refused.\",\n studio_branches_read_failed: \"Could not read this project's branches\",\n studio_schema_no_collections: \"No collections declared\",\n studio_schema_no_collections_body: \"There is nothing to draw yet. Add a collection under config/collections/, or open Edit collections to add one here.\",\n studio_schema_introspect_hint: \"Against a database that already has tables, rebase schema introspect writes the collection files for you.\",\n studio_schema_visualizer_source: \"Drawn from your collections: tables, columns, types and relations are as they declare them. Only the RLS markers are read from the database.\",\n studio_schema_laying_out: \"Laying out the diagram…\",\n studio_schema_neighbourhood: \"Showing {{shown}} of {{total}} tables: {{table}} and the tables around it. Pick another in the list to move.\",\n studio_schema_neighbourhood_depth_1: \"1 relation away\",\n studio_schema_neighbourhood_depth_2: \"2 relations away\",\n\n\n // ─── Studio: RLS editor confirmations ───────────────────────\n studio_rls_enable_confirm_title: \"Enable Row Level Security?\",\n studio_rls_enable_confirm_body: \"Until a policy allows it, every row of {{table}} becomes unreadable. Postgres denies by default.\",\n studio_rls_disable_confirm_title: \"Disable Row Level Security?\",\n studio_rls_disable_confirm_body: \"Every policy on {{table}} stops being enforced. Anyone who can reach the table can read and write every row.\",\n studio_rls_drop_policy_title: \"Drop this policy?\",\n studio_rls_drop_policy_body: \"{{policy}} is removed from {{table}} in the database. Nothing is written to your code, so a deploy can restore it.\",\n studio_rls_unapplied: \"Unapplied\",\n studio_rls_unapplied_tooltip: \"Declared in your code, not in the database yet. Rebase applies it the next time the server starts or `rebase db push` runs; if it is still missing after that, the server log says why.\",\n studio_rls_drift: \"Differs from code\",\n studio_rls_drift_tooltip: \"The database's {{fields}} differ from what the project declares for this policy. The declared version comes back the next time the server starts or `rebase db push` runs.\",\n studio_rls_reapplied_on_start: \"Rebase manages the policies on {{table}}. Each time the server starts, and on every `rebase db push`, it switches row-level security back on for this table and re-creates every policy the project declares for it. A change made here to one of those policies, or to the RLS switch, lasts until then. A policy you add under a name of your own is kept.\",\n studio_rls_disable_reapplied: \"Rebase manages {{table}}, so row-level security is switched back on the next time the server starts or `rebase db push` runs.\",\n studio_rls_nothing_changed: \"Nothing changed, so nothing was saved.\",\n\n\n // ─── Studio: empty states that name a remedy ────────────────\n studio_branches_unavailable_title: \"Database branching is not available\",\n studio_branches_unavailable_body: \"Branching needs a Postgres backend with an admin connection. Set ADMIN_CONNECTION_STRING in the backend's environment.\",\n studio_backups_not_configured_title: \"Backups are not configured\",\n studio_backups_not_configured_body: \"Set BACKUP_DESTINATION to a local path or an s3:// or gs:// URL, then create a backup with `rebase db backup` or a scheduled cron.\",\n studio_cron_empty_title: \"No cron jobs registered\",\n studio_cron_empty_body: \"Add a file under backend/crons/ that default-exports a CronJobDefinition.\",\n studio_read_the_docs: \"Read the documentation\",\n\n\n // ─── Studio: storage browser ────────────────────────────────\n studio_storage_root: \"Root\",\n studio_storage_root_folder: \"root\",\n studio_storage_loading: \"Loading…\",\n studio_storage_denied_title: \"This project's storage rules refused this listing\",\n studio_storage_denied_hint: \"Nothing is wrong with the project. Its storageAuthorize hook decides who may read which keys, and it declined this path for the signed-in account — commonly because a listing must name a prefix the rule recognises rather than the bucket root.\",\n studio_storage_read_failed: \"Could not read this project's storage\",\n studio_storage_empty: \"This folder is empty\",\n studio_storage_new_folder: \"New folder\",\n studio_storage_upload_files: \"Upload files\",\n studio_storage_upload: \"Upload\",\n studio_storage_upload_count: \"Upload ({{count}})\",\n studio_storage_uploading: \"Uploading…\",\n studio_storage_upload_failed: \"Upload failed\",\n studio_storage_upload_dialog_title: \"Upload Files\",\n studio_storage_upload_to: \"to\",\n studio_storage_drop_or_browse: \"Drop files here or click to browse\",\n studio_storage_any_file_type: \"Any file type supported\",\n studio_storage_selected_files: \"Selected files ({{count}})\",\n studio_storage_drop_to_upload: \"Drop files to upload\",\n studio_storage_files_uploaded: \"{{count}} files uploaded successfully\",\n studio_storage_files_uploaded_one: \"{{count}} file uploaded successfully\",\n studio_storage_cancel: \"Cancel\",\n studio_storage_create: \"Create\",\n studio_storage_download: \"Download\",\n studio_storage_delete: \"Delete\",\n studio_storage_deselect: \"Deselect\",\n studio_storage_refresh: \"Refresh\",\n studio_storage_go_up: \"Go up\",\n studio_storage_grid_view: \"Grid view\",\n studio_storage_list_view: \"List view\",\n studio_storage_default_source: \"Default\",\n studio_storage_name: \"Name\",\n studio_storage_type: \"Type\",\n studio_storage_type_unknown: \"Unknown\",\n studio_storage_size: \"Size\",\n studio_storage_extension: \"Extension\",\n studio_storage_path: \"Path\",\n studio_storage_url: \"URL\",\n studio_storage_copy_url: \"Copy URL\",\n studio_storage_url_copied: \"Copied!\",\n studio_storage_url_temporary: \"Temporary link: anyone who has it can open this file for up to {{minutes}} min. Download and Copy URL make a fresh one.\",\n studio_storage_url_public: \"Public link: anyone can open this file, and the link does not expire.\",\n studio_storage_folder: \"Folder\",\n studio_storage_folders: \"Folders\",\n studio_storage_files_heading: \"Files ({{count}})\",\n studio_storage_file_count: \"{{count}} files\",\n studio_storage_file_count_one: \"{{count}} file\",\n studio_storage_folder_count: \"{{count}} folders\",\n studio_storage_folder_count_one: \"{{count}} folder\",\n studio_storage_selected_count: \"{{count}} selected\",\n studio_storage_selected_count_one: \"{{count}} selected\",\n studio_storage_items_selected: \"{{count}} items selected\",\n studio_storage_items_selected_one: \"{{count}} item selected\",\n studio_storage_selected_label: \"Selected:\",\n studio_storage_no_preview: \"No preview available\",\n studio_storage_file_info: \"File Info\",\n studio_storage_delete_file_title: \"Delete File\",\n studio_storage_delete_file_question: \"Delete File?\",\n studio_storage_delete_file_body: \"Are you sure you want to delete “{{name}}”? This action cannot be undone.\",\n studio_storage_delete_confirmation_title: \"Delete Confirmation\",\n studio_storage_delete_question: \"Delete?\",\n studio_storage_delete_items_question: \"Delete {{count}} items?\",\n studio_storage_delete_items_question_one: \"Delete {{count}} item?\",\n studio_storage_delete_folder_question: \"Delete folder “{{name}}”?\",\n studio_storage_delete_selection_body: \"This will permanently delete all selected files and folders, including their contents. This action cannot be undone.\",\n studio_storage_delete_folder_body: \"This will permanently delete the folder and all of its contents. This action cannot be undone.\",\n studio_storage_file_deleted: \"“{{name}}” deleted\",\n studio_storage_folder_deleted: \"Folder “{{name}}” deleted\",\n studio_storage_items_deleted: \"{{count}} items deleted\",\n studio_storage_items_deleted_one: \"{{count}} item deleted\",\n studio_storage_delete_incomplete: \"{{count}} items are still there after the delete: {{names}}\",\n studio_storage_delete_incomplete_one: \"“{{names}}” is still there after the delete\",\n studio_storage_replace_title: \"Replace files\",\n studio_storage_replace_question: \"Replace {{count}} files?\",\n studio_storage_replace_question_one: \"Replace {{count}} file?\",\n studio_storage_replace_body: \"{{names}} are already in this folder. Uploading replaces them, and the files there now are lost.\",\n studio_storage_replace_body_one: \"“{{names}}” is already in this folder. Uploading replaces it, and the file there now is lost.\",\n studio_storage_replace: \"Replace\",\n studio_storage_new_folder_title: \"New Folder\",\n studio_storage_folder_name: \"Folder name\",\n studio_storage_folder_name_placeholder: \"Enter folder name\",\n studio_storage_created_in: \"Will be created in\",\n studio_storage_folder_name_has_slash: \"Folder name cannot contain slashes\",\n studio_storage_folder_exists: \"Folder “{{name}}” already exists\",\n studio_storage_folder_created: \"Folder “{{name}}” created\",\n studio_storage_create_folder_failed: \"Failed to create folder\",\n\n // ─── Insights plugin ─────────────────────────────────────────\n insights_period_last_days: \"Last {{count}} days\",\n insights_period_last_days_one: \"Last day\",\n insights_previous_period_value: \"Previous {{count}} days: {{value}}\",\n insights_previous_period_value_one: \"Previous day: {{value}}\",\n insights_change_up: \"Up {{change}}\",\n insights_change_down: \"Down {{change}}\",\n insights_change_none: \"No change\",\n\n // ─── Icon button names ───────────────────────────────────────\n add_to_favourites: \"Add to favourites\",\n remove_from_favourites: \"Remove from favourites\",\n change_value_type: \"Change type\",\n refresh: \"Refresh\",\n create_branch: \"Create branch\",\n new_tab: \"New tab\",\n close_tab: \"Close tab\",\n help: \"Help\",\n copy_table_name: \"Copy table name\",\n copy_column_name: \"Copy column name\",\n generate_sql_templates: \"Generate SQL templates\",\n select_row: \"Select {{id}}\",\n select: \"Select\",\n open_view: \"Open view\"\n};\n","import React, { PropsWithChildren, useEffect, useMemo, useRef } from \"react\";\nimport i18next, { BackendModule, i18n } from \"i18next\";\nimport { I18nextProvider, initReactI18next } from \"react-i18next\";\nimport { loadChunk, UiLabelsProvider, type UiLabelsProviderProps } from \"@rebasepro/ui\";\nimport { en } from \"../locales/en\";\nimport { RebaseTranslations } from \"@rebasepro/cms-types\";\nimport { readStoredString, writeStoredString } from \"../util/local_storage\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\nconst REBASE_NS = \"rebase_core\";\n\n/**\n * The translations Rebase ships besides English, each its own chunk.\n *\n * English is bundled: it is the fallback for every key, so it is needed\n * whatever the language. The other six used to be bundled too, and every\n * admin downloaded, parsed and merged ~616 kB of languages it never showed\n * before its login screen could paint. Now one is fetched the first time its\n * language is asked for — on mount, for a stored preference or a `locale`\n * prop; later, from the language menu — and i18next switches to it only once\n * it has arrived, so nobody sees keys or a flash of English.\n *\n * Keep each `import()` a literal path: that is what makes it a chunk.\n */\nconst LOCALE_LOADERS: Record<string, () => Promise<RebaseTranslations>> = {\n es: () => import(\"../locales/es\").then(m => m.es),\n de: () => import(\"../locales/de\").then(m => m.de),\n fr: () => import(\"../locales/fr\").then(m => m.fr),\n it: () => import(\"../locales/it\").then(m => m.it),\n hi: () => import(\"../locales/hi\").then(m => m.hi),\n pt: () => import(\"../locales/pt\").then(m => m.pt)\n};\n\n/**\n * Tables already fetched, shared by every provider instance. Static strings,\n * nothing per user: keyed by language code, never invalidated (a new build is\n * a new page load). Lets a remount, or a second `<Rebase>`, resolve\n * synchronously instead of awaiting the chunk again.\n */\nconst loadedTables: Record<string, RebaseTranslations> = { en };\n\nexport const REBASE_LOCALE_STORAGE_KEY = \"rebase_locale\";\n\n/** DeepPartial helper — allows partial overrides at any nesting level */\ntype DeepPartial<T> = T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\nexport interface RebaseI18nProviderProps {\n /** BCP-47 locale tag, e.g. \"en\", \"es\", \"fr\". Defaults to \"en\". */\n locale?: string;\n /**\n * Override or extend any Rebase UI string, keyed by locale.\n *\n * @example\n * translations={{\n * en: { save: \"Publish\" },\n * es: { save: \"Publicar\", discard: \"Descartar\" }\n * }}\n */\n translations?: {\n [locale: string]: DeepPartial<RebaseTranslations>;\n };\n}\n\n/**\n * Initialises a dedicated i18next instance for Rebase's internal UI strings.\n *\n * This instance is isolated from any app-level i18next configuration the\n * consumer may have. Mount this at the top of the Rebase component tree.\n *\n * @internal\n */\nexport function RebaseI18nProvider({\n locale = \"en\",\n translations,\n children\n}: PropsWithChildren<RebaseI18nProviderProps>) {\n const i18nRef = useRef<i18n | null>(null);\n const [ready, setReady] = React.useState(false);\n // The language the `locale` prop is switching to, while it does. That\n // change is the app's, not the user's, and must not be stored as their\n // preference — once stored, the prop is ignored for good.\n const propLanguageRef = useRef<string | null>(null);\n // The overrides the backend merges into a table it loads later. A ref,\n // not a closure over the first render's prop, so a language fetched after\n // the prop changed still gets the current overrides.\n const translationsRef = useRef(translations);\n translationsRef.current = translations;\n // The overrides the instance was built with — the effect below skips them\n // rather than merging every table a second time on mount.\n const appliedTranslationsRef = useRef<string | null>(null);\n\n if (!i18nRef.current) {\n const instance = i18next.createInstance();\n\n let initialLocale = locale;\n const stored = readStoredString(REBASE_LOCALE_STORAGE_KEY);\n if (stored) initialLocale = stored;\n // The first language is the prop's (or the stored one), not a choice\n // the user made now. A language that has to be fetched announces\n // itself after the listener below is attached, and was stored as the\n // user's preference — after which the prop was ignored for good.\n else propLanguageRef.current = initialLocale;\n\n appliedTranslationsRef.current = serializeTranslations(translations);\n\n instance\n .use(createLocaleBackend(() => translationsRef.current))\n .use(initReactI18next)\n .init({\n lng: initialLocale,\n fallbackLng: \"en\",\n ns: [REBASE_NS],\n defaultNS: REBASE_NS,\n // English and any language Rebase does not ship are in from\n // the start; a shipped one is asked of the backend above.\n resources: buildInitialResources(translations),\n partialBundledLanguages: true,\n interpolation: {\n // React already escapes — don't double-escape\n escapeValue: false\n }\n }, () => {\n // Synchronous for English (nothing to fetch), so it renders\n // on the first pass as before; for another language this runs\n // once its table is in, and nothing renders until then.\n setReady(true);\n });\n\n instance.on(\"languageChanged\", (lng) => {\n const fromProp = propLanguageRef.current === lng;\n propLanguageRef.current = null;\n if (fromProp) return;\n if (typeof window !== \"undefined\") {\n writeStoredString(REBASE_LOCALE_STORAGE_KEY, lng);\n }\n });\n\n i18nRef.current = instance;\n }\n\n // When `locale` prop changes, switch language on the existing instance\n // ONLY if the user hasn't explicitly set a preference\n useEffect(() => {\n if (i18nRef.current && i18nRef.current.language !== locale) {\n const hasUserPreference = Boolean(readStoredString(REBASE_LOCALE_STORAGE_KEY));\n if (!hasUserPreference) {\n propLanguageRef.current = locale;\n i18nRef.current.changeLanguage(locale);\n }\n }\n }, [locale]);\n\n // When consumer translations prop changes, update the resource bundles.\n // Keyed on the content, not the object: an inline `translations={{…}}`\n // is a new object on every render of the app.\n const translationsKey = serializeTranslations(translations);\n useEffect(() => {\n const instance = i18nRef.current;\n if (!instance) return;\n if (translationsKey === appliedTranslationsRef.current) return;\n appliedTranslationsRef.current = translationsKey;\n const overrides = translationsRef.current ?? {};\n const languages = new Set([...Object.keys(loadedTables), ...Object.keys(overrides)]);\n for (const lang of languages) {\n const table = loadedTables[lang];\n // A shipped table not fetched yet: leave it to the backend, which\n // merges the current overrides when it loads. Adding a bundle here\n // would make i18next think it is loaded and never fetch it.\n if (!table && LOCALE_LOADERS[lang]) continue;\n if (table && lang !== \"en\" && !instance.hasResourceBundle(lang, REBASE_NS)) continue;\n instance.addResourceBundle(\n lang,\n REBASE_NS,\n { ...(table ?? en), ...overrides[lang] },\n true, // deep merge\n true // overwrite existing keys\n );\n }\n }, [translationsKey]);\n\n if (!ready || !i18nRef.current) return null;\n\n return (\n <I18nextProvider i18n={i18nRef.current}>\n <UiLabelsFromTranslations>\n {children}\n </UiLabelsFromTranslations>\n </I18nextProvider>\n );\n}\n\ntype TranslationOverrides = { [locale: string]: DeepPartial<RebaseTranslations> };\n\nfunction serializeTranslations(translations?: TranslationOverrides): string {\n return translations ? JSON.stringify(translations) : \"\";\n}\n\n/**\n * The resources i18next starts with: English, plus every language the\n * consumer adds that Rebase does not ship (it starts from English, then the\n * overrides). A shipped language is left out — the backend fetches it and\n * merges its overrides then; an override added here first would be\n * overwritten by the table, or stop the table from ever loading.\n */\nfunction buildInitialResources(translations?: TranslationOverrides): Record<string, Record<string, object>> {\n const resources: Record<string, Record<string, object>> = {\n en: { [REBASE_NS]: { ...en, ...translations?.en } }\n };\n for (const [lang, overrides] of Object.entries(translations ?? {})) {\n if (lang === \"en\" || LOCALE_LOADERS[lang]) continue;\n resources[lang] = { [REBASE_NS]: { ...en, ...overrides } };\n }\n return resources;\n}\n\n/**\n * An i18next backend over {@link LOCALE_LOADERS}. i18next asks it for a\n * language it has no bundle for, and `changeLanguage` (and `init`) wait for\n * the answer before switching — which is what keeps a half-loaded language\n * off the screen.\n *\n * A language Rebase does not ship answers with an empty table, synchronously,\n * so keys fall back to English at once. A chunk that fails to load (a deploy\n * replaced it under an open tab, say) is retried once by `loadChunk`; after\n * that i18next switches anyway and English fills in.\n */\nfunction createLocaleBackend(getOverrides: () => TranslationOverrides | undefined): BackendModule {\n return {\n type: \"backend\",\n init() {\n // nothing to configure\n },\n read(language, namespace, callback) {\n if (namespace !== REBASE_NS) {\n callback(null, {});\n return;\n }\n const cached = loadedTables[language];\n if (cached) {\n callback(null, { ...cached, ...getOverrides()?.[language] });\n return;\n }\n const loader = LOCALE_LOADERS[language];\n if (!loader) {\n callback(null, { ...getOverrides()?.[language] });\n return;\n }\n loadChunk(loader).then(\n table => {\n loadedTables[language] = table;\n callback(null, { ...table, ...getOverrides()?.[language] });\n },\n (error: unknown) => callback(error instanceof Error ? error : String(error), null)\n );\n }\n };\n}\n\n/**\n * The UI kit's own words (`@rebasepro/ui`'s list and card notices, the table's\n * error title, the search bar's names, relative dates) in the admin language.\n * The kit speaks English on its own; this fills its labels from the\n * translations, and refills them when the language changes.\n */\nfunction UiLabelsFromTranslations({ children }: PropsWithChildren) {\n // `t` changes identity with the language, so the labels follow it.\n const { t } = useTranslation();\n const labels = useMemo((): UiLabelsProviderProps[\"labels\"] => ({\n errorLoadingData: (message) => t(\"error_loading_data_message\", { message }),\n noEntriesFound: t(\"no_entries_found\"),\n allEntriesLoaded: (count) => t(\"all_entries_loaded\", { count }),\n error: t(\"error\"),\n search: t(\"search\"),\n clearSearch: t(\"clear_search\"),\n select: t(\"select\"),\n openTimePicker: t(\"open_time_picker\"),\n relativeTime: {\n justNow: t(\"relative_just_now\"),\n inAMoment: t(\"relative_in_a_moment\"),\n minutesAgo: (count) => t(\"relative_minutes_ago\", { count }),\n inMinutes: (count) => t(\"relative_in_minutes\", { count }),\n hoursAgo: (count) => t(\"relative_hours_ago\", { count }),\n inHours: (count) => t(\"relative_in_hours\", { count }),\n daysAgo: (count) => t(\"relative_days_ago\", { count }),\n inDays: (count) => t(\"relative_in_days\", { count })\n }\n }), [t]);\n return <UiLabelsProvider labels={labels}>{children}</UiLabelsProvider>;\n}\n","\"use client\";\nimport type { RebaseProps } from \"./RebaseProps\";\nimport type { CustomizationController, RebasePlugin, AnySlotContribution } from \"@rebasepro/cms-types\";\nimport type { ComponentOverrideMap } from \"@rebasepro/cms-types\";\n\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { CenteredView, TooltipProvider, Typography } from \"@rebasepro/ui\";\nimport { User, CollectionRegistryController, DataDriver, DataSourceDefinition, RebaseData, DEFAULT_DATA_SOURCE_KEY, StorageSource, StorageSourceDefinition, DEFAULT_STORAGE_SOURCE_KEY } from \"@rebasepro/types\";\nimport { RebaseContext, UNRENDERED_SLOTS } from \"@rebasepro/cms-types\";\nimport { PluginProviderStack } from \"./PluginProviderStack\";\nimport { PluginLifecycleManager } from \"./PluginLifecycleManager\";\nimport { warnDeprecatedPluginKeys } from \"./deprecated_plugin_keys\";\nimport { AuthControllerContext, CollectionResolverRegistrationContext, CollectionResolver, CollectionResolverRegistration, DataPathResolver } from \"../contexts\";\nimport { useCustomizationController, useRebaseContext, useAuthSubscription } from \"../hooks\";\nimport { ApiConfigProvider, useApiConfig } from \"../hooks/ApiConfigContext\";\nimport { ErrorView } from \"../components\";\nimport { StorageSourceContext } from \"../contexts/StorageSourceContext\";\nimport { UserConfigurationPersistenceContext } from \"../contexts/UserConfigurationPersistenceContext\";\nimport { RebaseDataContext } from \"../contexts/RebaseDataContext\";\nimport { DataSourcesContext, DataSourcesContextValue } from \"../contexts/DataSourcesContext\";\nimport { StorageSourcesContext, StorageSourcesContextValue } from \"../contexts/StorageSourcesContext\";\nimport { DatabaseAdminContext } from \"../contexts/DatabaseAdminContext\";\nimport { ModeControllerProvider, AdminModeControllerProvider, SnackbarProvider } from \"../contexts\";\nimport { RebaseI18nProvider } from \"../i18n/RebaseI18nProvider\";\nimport { RebaseRegistryProvider } from \"../hooks/useRebaseRegistry\";\nimport { SchemaDriftProvider } from \"../components/SchemaDriftBanner\";\nimport { GlobalComponentOverrideProvider } from \"../contexts/ComponentOverrideContext\";\nimport { useBuildModeController } from \"../hooks/useBuildModeController\";\nimport { useBuildAdminModeController } from \"../hooks/useBuildAdminModeController\";\nimport { useBuildLocalConfigurationPersistence } from \"../hooks/useBuildLocalConfigurationPersistence\";\nimport { RebaseClientInstanceContext } from \"../contexts/RebaseClientInstanceContext\";\nimport { DialogsProvider } from \"../contexts/DialogsProvider\";\nimport { buildRebaseData, wrapAsEntityData, CollectionRegistry } from \"@rebasepro/common\";\nimport { CustomizationControllerContext } from \"../contexts/CustomizationControllerContext\";\nimport { AnalyticsContext } from \"../contexts/AnalyticsContext\";\n\nimport { EffectiveRoleControllerContext } from \"../contexts/EffectiveRoleController\";\nimport { useBuildEffectiveRoleController } from \"../hooks/useBuildEffectiveRoleController\";\n\n/**\n * If you are using independent components of the admin\n * you need to wrap them with this main component, so the internal hooks work.\n *\n * This is the main component of Rebase. It acts as the provider of all the\n * internal contexts and hooks.\n *\n * You only need to use this component if you are building a custom app.\n *\n * @group Core\n */\n/**\n * Does this socket carry the admin surface?\n *\n * `RebaseWebSocket` declares none of `DatabaseAdmin`'s methods — the SQL console\n * is served over the same socket only when the backend enables it — so the\n * question is genuinely a runtime one. It used to be asked as\n * `typeof (ws as unknown as Record<string, unknown>).executeSql === \"function\"`\n * and then answered a second time, one line down, by asserting the whole socket\n * to `DatabaseAdmin`: a check and a claim, with nothing connecting them. A\n * predicate makes the check *be* the narrowing, so the five method reads below\n * are checked against the interface they came from.\n */\nfunction canExecuteSql(ws: object): ws is import(\"@rebasepro/types\").DatabaseAdmin {\n return typeof (ws as { executeSql?: unknown }).executeSql === \"function\";\n}\n\n/**\n * The `slots` default. A `[]` in the parameter list was a new array on every\n * render, which rebuilt the customization controller — and with it\n * `useRebaseContext()` for every consumer — each time `<Rebase>` rendered.\n */\nconst EMPTY_SLOTS: AnySlotContribution[] = [];\n\nexport function Rebase<USER extends User, DB = unknown>(props: RebaseProps<USER, DB>) {\n\n const {\n children,\n entityLinkBuilder,\n userConfigPersistence,\n dateTimeFormat,\n locale,\n client,\n authController: authControllerProp,\n storageSource: storageSourceProp,\n dataSources: dataSourcesProp,\n storageSources: storageSourcesProp,\n\n databaseAdmin,\n plugins: pluginsProp,\n slots: directSlots = EMPTY_SLOTS,\n onAnalyticsEvent,\n propertyConfigs,\n entityViews,\n collectionViews,\n entityActions,\n\n effectiveRoleController,\n modeController: modeControllerProp,\n apiUrl,\n translations,\n components: componentsProp\n } = props;\n\n const plugins = pluginsProp;\n\n // Validate plugin key uniqueness\n if (plugins) {\n const keys = plugins.map((p) => p.key);\n if (new Set(keys).size !== keys.length) {\n console.error(\"Duplicate plugin keys detected:\", keys.filter((k, i) => keys.indexOf(k) !== i));\n }\n }\n\n // A plugin key nothing calls is a plugin doing nothing, silently.\n useEffect(() => {\n if (plugins) warnDeprecatedPluginKeys(plugins);\n }, [plugins]);\n\n // Per-user table preferences — a resized column, a reordered one, the view\n // mode a collection was left in — are local by nature, so the panel keeps\n // its own localStorage-backed store unless the host app supplies one.\n // Without a default here the context was `undefined` for every app that\n // did not pass `userConfigPersistence` (which is every app the CLI\n // scaffolds), and each of those preferences was written nowhere and lost\n // on the next render.\n const localUserConfigPersistence = useBuildLocalConfigurationPersistence();\n const resolvedUserConfigPersistence = userConfigPersistence ?? localUserConfigPersistence;\n\n // Merge direct slots with plugin slots.\n const resolvedSlots: AnySlotContribution[] = useMemo(() => [\n ...directSlots,\n ...((plugins ?? []).flatMap((p) => p.slots ?? []))\n ], [directSlots, plugins]);\n\n // A declared slot that is rendered nowhere has a props interface and a row\n // in the public slot reference, so registering for one looks exactly like\n // registering for one that works — and then nothing happens, with no way to\n // tell whether the fault is the plugin's. `UNRENDERED_SLOTS` is empty today\n // and `slot-render-sites.test.ts` keeps it honest in both directions, so\n // this loop warns about nothing until a slot is declared ahead of its\n // render site again.\n useEffect(() => {\n const dead = new Set<string>(UNRENDERED_SLOTS);\n const registered = new Set(resolvedSlots.map(s => s.slot).filter(slot => dead.has(slot)));\n for (const slot of registered) {\n console.warn(\n `[Rebase] A component is registered for the \"${slot}\" slot, which this ` +\n \"build declares but renders nowhere — nothing will appear. This is a gap \" +\n \"in Rebase, not in your plugin.\"\n );\n }\n }, [resolvedSlots]);\n\n\n // Auth fallback logic\n const clientAuthController = useAuthSubscription(authControllerProp ? undefined : client?.auth);\n const authController = authControllerProp ?? clientAuthController;\n\n const normalizedDataSources = useMemo(() => {\n return dataSourcesProp ?? [];\n }, [dataSourcesProp]);\n\n // Rows arrive as columns only; their address is derived from the\n // collection's primary keys. A direct driver is handed the path a\n // collection declares for its store rather than its slug. The collections\n // live below us (in RebaseCMS), so they register both resolvers here and we\n // read them lazily, per call. Headless apps register nothing and are\n // unaffected.\n //\n // More than one layer may own collections — the CMS navigation and any\n // standalone `CollectionsProvider` — each registered under its own owner.\n const resolversRef = useRef(new Map<string, { resolveCollection?: CollectionResolver, resolveDataPath?: DataPathResolver }>());\n const registerCollectionResolver = React.useCallback<CollectionResolverRegistration>((resolver, resolveDataPath, owner = \"default\") => {\n if (!resolver && !resolveDataPath) {\n resolversRef.current.delete(owner);\n return;\n }\n resolversRef.current.set(owner, { resolveCollection: resolver, resolveDataPath });\n }, []);\n const entityDataOptions = useMemo(() => ({\n resolveCollection: (slug: string) => {\n for (const { resolveCollection } of resolversRef.current.values()) {\n const collection = resolveCollection?.(slug);\n if (collection) return collection;\n }\n return undefined;\n },\n // The owner that knows the collection decides where it is stored; with\n // none that does, the first that answers (a registry hands an unknown\n // path back unchanged).\n resolveDataPath: (path: string) => {\n const registrations = [...resolversRef.current.values()];\n const owning = registrations.find(({ resolveCollection }) => resolveCollection?.(path) !== undefined);\n if (owning?.resolveDataPath) return owning.resolveDataPath(path);\n for (const { resolveDataPath } of registrations) {\n const dataPath = resolveDataPath?.(path);\n if (dataPath !== undefined) return dataPath;\n }\n return undefined;\n }\n }), []);\n\n // Build the data-source context: the declared registry plus a RebaseData\n // per direct/custom source (those carrying a client-side driver). Server-\n // mediated sources have no entry — they ride the default client.\n //\n // Shallow-compared against the previous build (key/engine/transport +\n // driver instances) so inline `dataSources` literals don't rebuild\n // RebaseData instances every render and thrash data-fetch effects that\n // key off the data identity.\n const dataSourcesRef = useRef<{\n sig: { key: string; engine: string; transport?: string; driver?: DataDriver }[];\n value: DataSourcesContextValue;\n } | null>(null);\n const dataSourcesValue = useMemo<DataSourcesContextValue>(() => {\n const sig = normalizedDataSources.map((d) => ({ key: d.key, engine: d.engine, transport: d.transport, driver: d.driver }));\n const prev = dataSourcesRef.current;\n if (prev\n && prev.sig.length === sig.length\n && sig.every((s, i) => prev.sig[i].key === s.key\n && prev.sig[i].engine === s.engine\n && prev.sig[i].transport === s.transport\n && prev.sig[i].driver === s.driver)) {\n return prev.value;\n }\n const registry: Record<string, DataSourceDefinition> = {};\n const sources: Record<string, RebaseData> = {};\n for (const ds of normalizedDataSources) {\n const { driver, ...definition } = ds;\n // Materialize the inferred transport so downstream consumers\n // (routing, editor capabilities) always see a concrete value.\n registry[ds.key] = {\n ...definition,\n transport: ds.transport ?? (driver ? \"direct\" : \"server\")\n };\n if (driver) sources[ds.key] = buildRebaseData(driver, entityDataOptions);\n }\n const value: DataSourcesContextValue = { registry, sources };\n dataSourcesRef.current = { sig, value };\n return value;\n }, [normalizedDataSources, entityDataOptions]);\n\n // Default data source — serves every collection not routed to a\n // registered direct/custom source. Resolution:\n // 1. A \"(default)\"-keyed data source with a driver.\n // 2. `client.data`.\n // 3. The sole registered source, when it is the only candidate.\n const resolvedData = useMemo(() => {\n const registeredDefault = dataSourcesValue.sources[DEFAULT_DATA_SOURCE_KEY];\n if (registeredDefault) return registeredDefault;\n // admin boundary: the SDK client returns flat rows; wrap them into the\n // Entity view-model the admin (`useData()`) renders.\n if (client?.data) return wrapAsEntityData(client.data, entityDataOptions);\n const built = Object.values(dataSourcesValue.sources);\n if (built.length === 1) return built[0];\n if (built.length > 1) {\n throw new Error(\n \"[Rebase] Several data sources are registered but none is the default. \" +\n \"Pass a `client`, or key one `dataSources` entry \\\"(default)\\\".\"\n );\n }\n throw new Error(\"Rebase requires either `client` or a `dataSources` entry with a driver to be provided\");\n }, [client, dataSourcesValue, entityDataOptions]);\n\n // Storage fallback logic\n const resolvedStorage = storageSourceProp ?? client?.storage;\n\n // ── Storage sources (mirrors the dataSources pattern) ────────────\n // Storage-source definitions discovered from the backend via\n // `GET /api/storage/sources`. The backend is the single source of truth;\n // server-transport sources are auto-wired on the client, `direct` sources\n // are completed by the `storageSources` prop (which holds live instances).\n const [remoteStorageSources, setRemoteStorageSources] = useState<StorageSourceDefinition[]>([]);\n // Who is signed in, not the user object: a token refresh or a profile edit\n // hands over a new object for the same person, and the listing does not\n // depend on anything but being allowed to ask.\n const authUid = authController.user?.uid;\n const loginSkipped = authController.loginSkipped;\n // Not asked when `GET /auth/config` says the backend has no storage: the\n // answer is already known, and asking would cost a request on every page\n // load. While that config is still in flight (`null`), wait for it.\n const storageEnabled = authController.storageEnabled;\n useEffect(() => {\n if (!client?.fetchStorageSources) return;\n if (storageEnabled === false || storageEnabled === null) return;\n let cancelled = false;\n client.fetchStorageSources()\n .then((defs) => { if (!cancelled) setRemoteStorageSources(defs); })\n .catch((e) => {\n // A 401 before auth is expected; the effect re-runs once the\n // user logs in (authUid/loginSkipped change) and retries.\n //\n // Guarded on `cancelled` like the success path: once this\n // provider is gone (or the effect re-ran) the outcome of the\n // request describes nothing that still exists, and the request\n // outlives the provider by however long the network takes to\n // give up — so an unguarded write here lands at an arbitrary\n // later moment. In a test worker that moment is after the file\n // finished, which closes the run's console channel mid-write\n // and fails an otherwise green suite.\n if (!cancelled) console.debug(\"[Rebase] Could not load storage sources\", e);\n });\n return () => { cancelled = true; };\n }, [client, authUid, loginSkipped, storageEnabled]);\n\n // Normalize the prop + discovered definitions into a registry + sources map.\n const storageSourcesRef = useRef<{\n propList: { key: string; source?: StorageSource; transport?: string }[];\n remote: StorageSourceDefinition[];\n resolvedStorage?: StorageSource;\n client?: typeof client;\n value: StorageSourcesContextValue;\n } | null>(null);\n const storageSourcesValue = useMemo<StorageSourcesContextValue>(() => {\n const list = storageSourcesProp ?? [];\n const prev = storageSourcesRef.current;\n // Stable identity unless an input actually changed (the prop may be a\n // fresh array literal on every render; sources are compared by identity).\n if (prev\n && prev.remote === remoteStorageSources\n && prev.resolvedStorage === resolvedStorage\n && prev.client === client\n && prev.propList.length === list.length\n && list.every((s, i) => prev.propList[i].key === s.key\n && prev.propList[i].source === s.source\n && prev.propList[i].transport === s.transport)) {\n return prev.value;\n }\n const registry: Record<string, StorageSourceDefinition> = {};\n const sources: Record<string, StorageSource> = {};\n\n // 1. Definitions discovered from the backend (labels, engine, transport).\n for (const def of remoteStorageSources) {\n registry[def.key] = def;\n }\n\n // 2. Server-backed named sources wired on the client registry: the\n // default, `createRebaseClient({ storageSources })`, and any\n // server-transport sources auto-registered by `fetchStorageSources`.\n if (client?.storageRegistry) {\n for (const key of client.storageRegistry.list()) {\n const source = client.storageRegistry.get(key);\n if (source) sources[key] = source;\n }\n }\n\n // 3. App-provided definitions: `direct` live sources and overrides.\n for (const ss of list) {\n const { source, ...definition } = ss;\n registry[ss.key] = definition;\n if (source) {\n // `direct` transport: app-provided live source (e.g. Firebase).\n sources[ss.key] = source;\n } else if (!sources[ss.key]\n && ss.transport === \"server\"\n && ss.key !== DEFAULT_STORAGE_SOURCE_KEY\n && client?.createStorageSource) {\n // `server` transport declared only on the prop: build a\n // backend-routed source so requests carry `?storageId=key`.\n sources[ss.key] = client.createStorageSource(ss.key);\n }\n }\n // 4. Default/server storage from the client.\n if (resolvedStorage && !sources[DEFAULT_STORAGE_SOURCE_KEY]) {\n sources[DEFAULT_STORAGE_SOURCE_KEY] = resolvedStorage;\n }\n // A key no source above answers — `/storage/sources` has not loaded,\n // or failed — is still routed to the server under its own name, never\n // to the default source. One instance per key.\n const buildSource = client?.createStorageSource;\n const built = new Map<string, StorageSource>();\n const createSource = buildSource\n ? (key: string): StorageSource => {\n const existing = built.get(key);\n if (existing) return existing;\n const source = buildSource(key);\n built.set(key, source);\n return source;\n }\n : undefined;\n const value: StorageSourcesContextValue = { registry, sources, createSource };\n storageSourcesRef.current = {\n propList: list.map((s) => ({ key: s.key, source: s.source, transport: s.transport })),\n remote: remoteStorageSources,\n resolvedStorage,\n client,\n value\n };\n return value;\n }, [storageSourcesProp, remoteStorageSources, resolvedStorage, client]);\n\n // Database admin — use explicit prop, or derive from client.ws / driver when available.\n const resolvedDatabaseAdmin = useMemo(() => {\n if (databaseAdmin) return databaseAdmin;\n\n // 1. The default source's DataDriver exposes `.admin` capability object\n const defaultDriver = normalizedDataSources.find((d) => d.key === DEFAULT_DATA_SOURCE_KEY && d.driver)?.driver\n ?? (!client && normalizedDataSources.length === 1 ? normalizedDataSources[0].driver : undefined);\n if (defaultDriver?.admin) {\n return defaultDriver.admin;\n }\n\n // 2. Auto-derive from the client's WebSocket connection (Rebase backend)\n const ws = client?.ws;\n if (ws && canExecuteSql(ws)) {\n const wsAdmin = ws;\n return {\n executeSql: wsAdmin.executeSql!.bind(wsAdmin),\n runSqlScript: wsAdmin.runSqlScript?.bind(wsAdmin),\n fetchAvailableDatabases: wsAdmin.fetchAvailableDatabases?.bind(wsAdmin),\n fetchAvailableRoles: wsAdmin.fetchAvailableRoles?.bind(wsAdmin),\n fetchApplicationRoles: wsAdmin.fetchApplicationRoles?.bind(wsAdmin),\n fetchCurrentDatabase: wsAdmin.fetchCurrentDatabase?.bind(wsAdmin),\n fetchUnmappedTables: wsAdmin.fetchUnmappedTables?.bind(wsAdmin),\n fetchTableMetadata: wsAdmin.fetchTableMetadata?.bind(wsAdmin),\n // Branch admin capabilities\n ...(typeof wsAdmin.createBranch === \"function\" ? {\n createBranch: wsAdmin.createBranch.bind(wsAdmin),\n deleteBranch: wsAdmin.deleteBranch!.bind(wsAdmin),\n listBranches: wsAdmin.listBranches!.bind(wsAdmin)\n } : {})\n };\n }\n\n return undefined;\n }, [databaseAdmin, client, normalizedDataSources]);\n\n if (!resolvedStorage && typeof console !== \"undefined\") {\n console.warn(\n \"[Rebase] No storageSource provided. File upload features will not work. \" +\n \"Provide storageSource via props or through a RebaseClient.\"\n );\n }\n\n const pluginsLoading = plugins?.some((p) => p.loading) ?? false;\n\n const loading = authController.initialLoading || pluginsLoading;\n\n const customizationController: CustomizationController = useMemo(() => ({\n dateTimeFormat,\n locale,\n entityLinkBuilder,\n plugins,\n resolvedSlots,\n entityViews: entityViews ?? [],\n collectionViews: collectionViews ?? [],\n entityActions: entityActions ?? [],\n propertyConfigs: propertyConfigs ?? {},\n components: componentsProp\n }), [dateTimeFormat, locale, entityLinkBuilder, plugins, resolvedSlots, entityViews, collectionViews, entityActions, propertyConfigs, componentsProp]);\n\n // Keyed on the handler: an inline one — gated on consent, say — closes over\n // that render's state, and the first one frozen kept its consent forever.\n const analyticsController = useMemo(() => ({\n onAnalyticsEvent\n }), [onAnalyticsEvent]);\n\n const fallbackEffectiveRoleController = useBuildEffectiveRoleController();\n const activeEffectiveRoleController = effectiveRoleController ?? fallbackEffectiveRoleController;\n\n // Built either way (a hook cannot be skipped), but switched off — no class\n // on <html>, no media query, no storage — when the host owns the theme.\n const ownModeController = useBuildModeController({ enabled: !modeControllerProp });\n const modeController = modeControllerProp ?? ownModeController;\n const adminModeController = useBuildAdminModeController();\n\n if (authController.authError) {\n return (\n <CenteredView maxWidth={\"md\"}>\n <ErrorView\n title={\"Error loading auth\"}\n error={authController.authError as Error | string}/>\n </CenteredView>\n );\n }\n\n // One tooltip provider for the whole admin: a tooltip under it uses it\n // instead of mounting its own, and neighbouring tooltips share the skip\n // delay (moving along a row of icons does not wait on each).\n const content = (\n <TooltipProvider>\n <RebaseI18nProvider locale={locale} translations={translations}>\n <GlobalComponentOverrideProvider overrides={componentsProp}>\n <SnackbarProvider>\n <ModeControllerProvider value={modeController}>\n <AdminModeControllerProvider value={adminModeController}>\n <RebaseClientInstanceContext.Provider value={client}>\n <AnalyticsContext.Provider value={analyticsController}>\n <CustomizationControllerContext.Provider value={customizationController}>\n <UserConfigurationPersistenceContext.Provider\n value={resolvedUserConfigPersistence}>\n <StorageSourcesContext.Provider\n value={storageSourcesValue}>\n <StorageSourceContext.Provider\n value={resolvedStorage}>\n <CollectionResolverRegistrationContext.Provider\n value={registerCollectionResolver}>\n <DataSourcesContext.Provider\n value={dataSourcesValue}>\n <RebaseDataContext.Provider\n value={resolvedData}>\n <DatabaseAdminContext.Provider\n value={resolvedDatabaseAdmin}>\n <AuthControllerContext.Provider\n value={authController}>\n <EffectiveRoleControllerContext.Provider value={activeEffectiveRoleController}>\n <DialogsProvider>\n <SchemaDriftProvider>\n <RebaseRegistryProvider>\n <RebaseInternal\n loading={loading}>\n {children}\n </RebaseInternal>\n </RebaseRegistryProvider>\n </SchemaDriftProvider>\n </DialogsProvider>\n </EffectiveRoleControllerContext.Provider>\n </AuthControllerContext.Provider>\n </DatabaseAdminContext.Provider>\n </RebaseDataContext.Provider>\n </DataSourcesContext.Provider>\n </CollectionResolverRegistrationContext.Provider>\n </StorageSourceContext.Provider>\n </StorageSourcesContext.Provider>\n </UserConfigurationPersistenceContext.Provider>\n </CustomizationControllerContext.Provider>\n </AnalyticsContext.Provider>\n </RebaseClientInstanceContext.Provider>\n </AdminModeControllerProvider>\n </ModeControllerProvider>\n </SnackbarProvider>\n </GlobalComponentOverrideProvider>\n </RebaseI18nProvider>\n </TooltipProvider>\n );\n\n const resolvedApiUrl = apiUrl || client?.baseUrl || (typeof window !== \"undefined\" ? window.location.origin : \"\");\n\n if (resolvedApiUrl) {\n return (\n <ApiConfigProvider\n apiUrl={resolvedApiUrl}\n apiPath={client?.apiPath}\n getAuthToken={authController.getAuthToken}\n >\n {content}\n </ApiConfigProvider>\n );\n }\n\n return content;\n\n}\n\nfunction RebaseInternal({\n loading,\n children\n}: {\n loading: boolean;\n children: React.ReactNode | ((props: { context: RebaseContext; loading: boolean; }) => React.ReactNode);\n}) {\n\n const context = useRebaseContext();\n const customizationController = useCustomizationController();\n\n const childrenResult = typeof children === \"function\" ? children({\n context,\n loading\n }) : children;\n\n const plugins = customizationController.plugins;\n const authController = context.authController;\n const authReady = !loading\n && !authController.authLoading\n && (Boolean(authController.user) || authController.loginSkipped);\n\n if (plugins && plugins.length > 0) {\n return (\n <PluginProviderStack\n plugins={plugins}\n scope=\"root\"\n scopeProps={{ context }}>\n <PluginLifecycleManager plugins={plugins} context={context} authReady={authReady}/>\n {childrenResult}\n </PluginProviderStack>\n );\n }\n\n return childrenResult;\n}\n\n","import { createBrowserRouter } from \"react-router\"\nimport { RouterProvider } from \"react-router/dom\"\nimport { removeInitialAndTrailingSlashes } from \"@rebasepro/app\";\n\nexport function RebaseRouter({\n children,\n basePath\n}: {\n children: React.ReactNode,\n basePath?: string;\n}) {\n return <RouterProvider router={createBrowserRouter([\n {\n path: basePath ? `${removeInitialAndTrailingSlashes(basePath)}/*` : \"/*\",\n element: children\n }\n ])}/>;\n}\n","import React from \"react\";\nimport { Route, Routes, useLocation } from \"react-router\";\n\n\n/**\n * A drop-in replacement for react-router's `<Routes>` that preserves the\n * underlying view when a side dialog navigates the URL to a different path.\n *\n * When opening a side dialog from e.g. `/posts` to `authors/123#side`,\n * the `base_location` stored in router state is used so the route tree\n * keeps rendering the original `/posts` view underneath the dialog overlay.\n *\n * Additionally, registered views from `useNavigationStateController()` are\n * automatically routed — no need to manually map them to `<Route>` elements.\n * Views with `nestedRoutes: true` get a wildcard route (slug/*) as well.\n * Explicitly declared `children` routes take priority.\n */\nexport function RebaseRoutes({ children }: { children?: React.ReactNode }) {\n const location = useLocation();\n const state = location.state as Record<string, unknown> | null;\n const baseLocation = state?.base_location ?? location;\n\n return <Routes location={baseLocation}>{children}</Routes>;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { deepEqual } from \"fast-equals\";\nimport { RebaseClientError } from \"@rebasepro/types\";\nimport type { User, AuthChangeEvent, RebaseSession } from \"@rebasepro/types\";\nimport type { AuthConfigResponse } from \"./api\";\nimport { RebaseAuthController, RebaseAuthControllerProps } from \"./types\";\nimport { bindSessionCachesToUser, clearSessionCaches } from \"./session_caches\";\n\n/**\n * Auth controller hook for JWT-based authentication.\n *\n * This is a thin React binding over the headless SDK `client.auth`.\n * It synchronizes React state with the SDK's internal state and delegates\n * all operations to the SDK to ensure a single source of truth for\n * authentication sessions across the entire application.\n *\n * @param props Configuration options\n * @returns RebaseAuthController instance\n */\nexport function useRebaseAuthController(\n props: RebaseAuthControllerProps = {}\n): RebaseAuthController {\n const { client, onSignOut, defineRolesFor } = props;\n const auth = client?.auth;\n\n const [user, setUser] = useState<User | null>(null);\n const [authLoading, setAuthLoading] = useState(false);\n const [initialLoading, setInitialLoading] = useState(true);\n const [authError, setAuthError] = useState<Error | null>(null);\n const [authProviderError, setAuthProviderError] = useState<Error | null>(null);\n const [loginSkipped, setLoginSkipped] = useState(false);\n const [extra, setExtra] = useState<unknown>(null);\n const [authConfig, setAuthConfig] = useState<AuthConfigResponse | null>(null);\n const [authConfigFailed, setAuthConfigFailed] = useState(false);\n const [heldScopes, setHeldScopes] = useState<string[] | undefined>(undefined);\n\n const isMountedRef = useRef(true);\n // Keep a stable ref to onSignOut so the listener never goes stale.\n const onSignOutRef = useRef(onSignOut);\n onSignOutRef.current = onSignOut;\n // Keep a stable ref to defineRolesFor too, so an inline (non-memoized)\n // function from the consumer does not re-run the sync effect on every\n // render — which would re-subscribe to auth events and re-fetch the\n // (uncached) auth config each time.\n const defineRolesForRef = useRef(defineRolesFor);\n defineRolesForRef.current = defineRolesFor;\n\n const clearError = useCallback(() => {\n setAuthProviderError(null);\n }, []);\n\n // Sync state with client.auth\n useEffect(() => {\n if (!auth) {\n setInitialLoading(false);\n return;\n }\n\n isMountedRef.current = true;\n\n // `defineRolesFor` is usually a fetch, so updates can finish out of\n // order. Only the latest one may set the user: an earlier call that\n // resolves last would otherwise bring back a user who has since signed\n // out, or overwrite the one who signed in after them.\n let latestUpdate = 0;\n\n const updateState = async (session: RebaseSession | null) => {\n if (!isMountedRef.current) return;\n const update = ++latestUpdate;\n\n let userToSet = session?.user ?? null;\n const defineRolesFor = defineRolesForRef.current;\n if (userToSet && defineRolesFor) {\n try {\n const roles = await defineRolesFor(userToSet);\n if (roles && isMountedRef.current) {\n userToSet = { ...userToSet, roles };\n }\n } catch (e) {\n console.error(\"Error defining roles:\", e);\n }\n }\n\n if (update !== latestUpdate) return;\n if (isMountedRef.current) {\n const nextUser = userToSet;\n if (nextUser) bindSessionCachesToUser(nextUser.uid);\n // A token refresh (hourly, and a few times at boot) hands over a\n // freshly mapped user every time. The same user, field for field,\n // keeps the object the app already holds: as a new one it changed\n // the controller, and with it every context consumer, and re-ran\n // every effect keyed on the user.\n setUser(previous => (previous && nextUser && deepEqual(previous, nextUser)) ? previous : nextUser);\n }\n };\n\n // Fetched at mount and again on every sign-in and sign-out. The config\n // is not fixed for the life of the tab: `needsSetup` turns false the\n // moment the first admin is created, and a stale `true` showed only\n // the bootstrap form to the next person to sign out — no way to sign\n // in until a reload. Only the latest answer is applied.\n let latestConfigRequest = 0;\n function loadAuthConfig() {\n if (!auth) return;\n const request = ++latestConfigRequest;\n auth.getAuthConfig().then((config: AuthConfigResponse) => {\n if (isMountedRef.current && request === latestConfigRequest) setAuthConfig(config);\n }).catch((e: unknown) => {\n // Swallowed entirely before. This is what tells the login view which\n // providers exist, so losing it renders a login form that is wrong\n // rather than one that is broken — the hardest kind to report. Not\n // promoted to `authError`, which blanks the whole app: a signed-in\n // user is unaffected by this failing.\n console.warn(\"[Rebase] Could not load the backend auth configuration; \" +\n \"the login view will fall back to defaults.\", e);\n if (isMountedRef.current && request === latestConfigRequest) setAuthConfigFailed(true);\n });\n }\n\n const syncState = async (event: AuthChangeEvent, session: RebaseSession | null) => {\n if (event === \"SIGNED_IN\" || event === \"SIGNED_OUT\") {\n loadAuthConfig();\n }\n if (event === \"SIGNED_OUT\") {\n // What the session that just ended read. The caches are\n // module-level and keyed by path only, so without this the next\n // user in the same tab is shown rows they may not be allowed to\n // read — tables and previews render straight out of them.\n clearSessionCaches();\n }\n await updateState(session);\n if (event === \"SIGNED_OUT\") {\n if (isMountedRef.current) {\n setLoginSkipped(false);\n }\n onSignOutRef.current?.();\n }\n };\n\n // Initial sync with whatever is currently in the SDK\n updateState(auth.getSession());\n\n // Wait for SDK initialization (restoring session from storage or silent refresh)\n auth.isInitialized().then(() => {\n if (isMountedRef.current) {\n updateState(auth.getSession());\n setInitialLoading(false);\n }\n }).catch(() => {\n if (isMountedRef.current) setInitialLoading(false);\n });\n\n // Fetch backend auth configuration\n loadAuthConfig();\n\n const unsubscribe = auth.onAuthStateChange(syncState);\n\n return () => {\n isMountedRef.current = false;\n unsubscribe();\n };\n }, [auth]);\n\n // The scopes the signed-in user holds, read again whenever who that is, or\n // which roles they have, changes. A screen offers an admin action only to\n // those its route admits; `undefined` — not yet known — admits nobody.\n const scopeListing = client?.personalKeys;\n const signedInAs = user ? `${user.uid}|${(user.roles ?? []).join(\",\")}` : undefined;\n useEffect(() => {\n setHeldScopes(undefined);\n if (!signedInAs || !scopeListing) return;\n let current = true;\n scopeListing.listScopes()\n .then(({ held }) => { if (current) setHeldScopes(held); })\n .catch((e: unknown) => console.warn(\"[Rebase] Could not read the scopes this user holds.\", e));\n return () => { current = false; };\n }, [signedInAs, scopeListing]);\n\n const getAuthToken = useCallback(async (): Promise<string> => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n let session = auth.getSession();\n\n // On load the session may still be being restored (in cookie mode it\n // always is, until the server answers): what that finds is the answer.\n if (!session) {\n await auth.isInitialized().catch(() => undefined);\n session = auth.getSession();\n }\n\n // Nobody is signed in, so there is nothing to refresh. Asking anyway\n // sent a `POST /auth/refresh` the server could only refuse, an error in\n // the console for every anonymous caller.\n if (!session) {\n throw new RebaseClientError(\"Not signed in: there is no session to read a token from.\", { code: \"NOT_SIGNED_IN\" });\n }\n\n // If we have a valid token, return it\n if (session.accessToken && session.expiresAt > Date.now() + 10000) {\n return session.accessToken;\n }\n\n // Otherwise, refresh\n const newSession = await auth.refreshSession();\n return newSession.accessToken;\n }, [auth]);\n\n const signOut = useCallback(async () => {\n if (!auth) return;\n setAuthLoading(true);\n try {\n await auth.signOut();\n // signOut emits SIGNED_OUT → syncState calls onSignOutRef.current\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const emailPasswordLogin = useCallback(async (email: string, password: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.signInWithEmail(email, password);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const register = useCallback(async (email: string, password: string, displayName?: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n const result = await auth.signUp(email, password, displayName);\n const confirmationRequired = typeof result === \"object\" && result !== null\n && \"confirmationRequired\" in result && result.confirmationRequired === true;\n return { confirmationRequired };\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const googleLogin = useCallback(async (\n payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }\n ) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.signInWithGoogle(payload);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const oauthLogin = useCallback(async (providerId: string, payload: Record<string, unknown>) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.signInWithOAuth(providerId, payload);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n /**\n * Open the challenge that finishes a sign-in refused with `MFA_REQUIRED`.\n *\n * `mfaToken` is that refusal's `details.mfaToken`, sent on this request\n * only. Every sign-in method above lands such a refusal in\n * `authProviderError`, which is where the login view reads it from.\n */\n const startMfaChallenge = useCallback(async (mfaToken: string, factorId: string) => {\n if (!auth?.mfa) throw new Error(\"Rebase client with MFA is required\");\n const { challengeId } = await auth.mfa.challenge(factorId, { mfaToken });\n return challengeId;\n }, [auth]);\n\n /**\n * Answer that challenge. On success the SDK adopts the session and emits\n * SIGNED_IN, which sets the user like any other sign-in.\n *\n * A refused code is rethrown and NOT recorded in `authProviderError`: the\n * code step reports it itself, and the refusal it would replace is the\n * `MFA_REQUIRED` that says a sign-in is still waiting for its second\n * factor.\n */\n const verifyMfaChallenge = useCallback(async (mfaToken: string, challengeId: string, code: string) => {\n if (!auth?.mfa) throw new Error(\"Rebase client with MFA is required\");\n setAuthLoading(true);\n try {\n await auth.mfa.verifyChallenge(challengeId, code, { mfaToken });\n // Answered. Left in place, the refusal would reopen the code step\n // — for a token long expired — the next time the login screen is\n // shown, after a sign-out.\n setAuthProviderError(null);\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const skipLogin = useCallback(() => {\n setLoginSkipped(true);\n setUser(null);\n }, []);\n\n const forgotPassword = useCallback(async (email: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.resetPasswordForEmail(email);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const resetPassword = useCallback(async (token: string, password: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.resetPassword(token, password);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const verifyEmail = useCallback(async (token: string, options?: { password?: string; removeUnproven?: boolean }) => {\n if (!auth?.verifyEmail) throw new Error(\"Rebase client with email verification is required\");\n const result = await auth.verifyEmail(token, options);\n const isObject = typeof result === \"object\" && result !== null;\n return {\n passwordRemoved: isObject && \"passwordRemoved\" in result && result.passwordRemoved === true,\n signedIn: isObject && \"session\" in result && Boolean(result.session)\n };\n }, [auth]);\n\n const changePassword = useCallback(async (oldPassword: string, newPassword: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n // The SDK adopts the fresh session the server answers with: this\n // device stays signed in, every other one is signed out.\n await auth.changePassword(oldPassword, newPassword);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n /**\n * Sign in with a magic link's token. The SDK adopts the session and emits\n * SIGNED_IN; a refusal lands in `authProviderError` like every other\n * sign-in's, which is how an `MFA_REQUIRED` reaches the code step.\n */\n const magicLinkLogin = useCallback(async (token: string) => {\n if (!auth?.verifyMagicLink) throw new Error(\"Rebase client with magic links is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.verifyMagicLink(token);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n\n const changeEmail = useCallback(async (newEmail: string) => {\n if (!auth?.changeEmail) throw new Error(\"Rebase client with email change is required\");\n return await auth.changeEmail(newEmail);\n }, [auth]);\n\n const confirmEmailChange = useCallback(async (token: string) => {\n if (!auth?.confirmEmailChange) throw new Error(\"Rebase client with email change is required\");\n const { email, removedProviders } = await auth.confirmEmailChange(token);\n return { email, removedProviders };\n }, [auth]);\n\n const updateProfile = useCallback(async (displayName?: string, photoURL?: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n const updatedUser = await auth.updateUser({ displayName, photoURL });\n return updatedUser;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const fetchSessions = useCallback(async () => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n return await auth.getSessions();\n }, [auth]);\n\n const revokeSession = useCallback(async (sessionId: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n await auth.revokeSession(sessionId);\n }, [auth]);\n\n const revokeAllSessions = useCallback(async () => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n await auth.revokeAllSessions();\n }, [auth]);\n\n const baseUrl = client?.baseUrl;\n const getApiUrl = useCallback(() => baseUrl, [baseUrl]);\n const googleClientId = props.googleClientId;\n\n // One object per state, not per render: the controller is the auth\n // context's value, and `useRebaseContext()` is rebuilt — for every consumer\n // in the app — whenever it changes. Every field it carries is in the deps.\n return useMemo<RebaseAuthController>(() => ({\n user,\n authLoading,\n initialLoading,\n authError,\n authProviderError,\n loginSkipped,\n needsSetup: authConfig?.needsSetup ?? false,\n registrationEnabled: authConfig?.registrationEnabled ?? false,\n getAuthToken,\n getApiUrl,\n signOut,\n emailPasswordLogin,\n register,\n googleLogin,\n oauthLogin,\n skipLogin,\n forgotPassword,\n resetPassword,\n verifyEmail,\n changePassword,\n // Offered only when the client can, so the settings view and the\n // link's screen can tell a missing feature from a failed request.\n changeEmail: auth?.changeEmail ? changeEmail : undefined,\n magicLinkLogin: auth?.verifyMagicLink ? magicLinkLogin : undefined,\n confirmEmailChange: auth?.confirmEmailChange ? confirmEmailChange : undefined,\n updateProfile,\n fetchSessions,\n revokeSession,\n revokeAllSessions,\n clearError,\n setAuthProviderError,\n // Offered only when the client can answer a challenge, so a login\n // view can tell a second step it can take from one it cannot.\n startMfaChallenge: auth?.mfa ? startMfaChallenge : undefined,\n verifyMfaChallenge: auth?.mfa ? verifyMfaChallenge : undefined,\n heldScopes,\n // `null` until the config has been read, so the panel waits for it\n // rather than asking for storage sources the backend may not have.\n // `undefined` when it cannot be read, or says nothing: ask then.\n storageEnabled: authConfig\n ? authConfig.storage\n : (auth && !authConfigFailed ? null : undefined),\n extra,\n setExtra,\n // `authConfig` is null until `GET /auth/config` lands, so each fallback\n // is what to assume *while it is still in flight* — not a stand-in for a\n // backend that might omit the field. The backend always sends all of them.\n capabilities: {\n emailPasswordLogin: true,\n googleLogin: !!(googleClientId),\n registrationEnabled: authConfig?.registrationEnabled ?? false,\n passwordReset: authConfig?.passwordReset ?? false,\n // True while loading: the admin UI's \"Reset Password\" action is worth\n // showing optimistically and hiding once a backend says it cannot.\n adminPasswordReset: authConfig?.adminPasswordReset ?? true,\n sessionManagement: true,\n profileUpdate: true,\n emailVerification: authConfig?.emailVerification ?? false,\n enabledProviders: authConfig?.enabledProviders ?? []\n }\n }), [\n user, authLoading, initialLoading, authError, authProviderError, loginSkipped,\n authConfig, authConfigFailed, heldScopes, extra, auth, googleClientId,\n getAuthToken, getApiUrl, signOut, emailPasswordLogin, register, googleLogin, oauthLogin,\n skipLogin, forgotPassword, resetPassword, verifyEmail, changePassword, changeEmail,\n magicLinkLogin, confirmEmailChange, updateProfile, fetchSessions, revokeSession,\n revokeAllSessions, clearError, startMfaChallenge, verifyMfaChallenge\n ]);\n}\n","/**\n * Auth-config fetch helper for the Rebase React frontend.\n *\n * The former per-endpoint auth client (login, register, refresh, OAuth,\n * sessions, …) has been removed: `useRebaseAuthController` now delegates to\n * the headless SDK's `client.auth` (from `@rebasepro/client`), which is the\n * single source of truth for the auth session. The only piece that remains\n * here is the unauthenticated `/api/auth/config` probe used to detect\n * bootstrap mode and enabled providers before a session exists.\n */\n\nimport { RebaseApiError } from \"@rebasepro/types\";\nimport type { AuthConfigDocument } from \"@rebasepro/types\";\nimport { DEFAULT_API_PATH } from \"../hooks/ApiConfigContext\";\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n let data: Record<string, unknown>;\n try {\n data = await response.json();\n } catch (parseError) {\n // Response wasn't JSON - could be network error or server issue\n throw new RebaseApiError(\n `Server returned non-JSON response (status: ${response.status})`,\n { status: response.status, code: \"PARSE_ERROR\" }\n );\n }\n\n if (!response.ok) {\n throw new RebaseApiError(\n (data as Record<string, Record<string, string>>).error?.message || \"Request failed\",\n {\n status: response.status,\n code: (data as Record<string, Record<string, string>>).error?.code || \"UNKNOWN_ERROR\"\n }\n );\n }\n\n return data as T;\n}\n\n/**\n * Wrapper for fetch that catches generic network failures (like server down)\n * and translates them to a {@link RebaseApiError} with code `NETWORK_ERROR`.\n */\nasync function fetchWithHandling(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n try {\n return await fetch(input, init);\n } catch (error: unknown) {\n if (error instanceof TypeError && error.message.includes(\"Failed to fetch\")) {\n throw new RebaseApiError(\n \"Failed to connect to the backend server. The backend might be down or failed to initialize (e.g., database connection timeout).\",\n { code: \"NETWORK_ERROR\", cause: error }\n );\n }\n throw new RebaseApiError(\n \"Network error: \" + (error instanceof Error ? error.message : String(error)),\n { code: \"NETWORK_ERROR\", cause: error }\n );\n }\n}\n\n/**\n * What `GET /api/auth/config` answers.\n *\n * The wire contract is declared once, in `@rebasepro/types`, and re-exported\n * here under the name this module uses. Three near-copies of it used to exist —\n * this one listed an `emailServiceEnabled` flag no backend sends, and marked as\n * optional fields every backend always returns.\n */\nexport type AuthConfigResponse = AuthConfigDocument;\n\n/**\n * Cache container for `fetchAuthConfig` — holds both the inflight promise\n * (to deduplicate concurrent calls) and the cached result.\n */\nexport interface AuthConfigCache {\n cached: AuthConfigResponse | null;\n inflight: Promise<AuthConfigResponse> | null;\n}\n\n/**\n * Create a fresh `AuthConfigCache` instance.\n * Callers own the cache object and pass it into `fetchAuthConfig` / `clearAuthConfigCache`.\n */\nexport function createAuthConfigCache(): AuthConfigCache {\n return { cached: null, inflight: null };\n}\n\n/**\n * Fetch auth configuration / status from the backend\n * This is an unauthenticated endpoint used to detect bootstrap mode.\n *\n * Results are cached for the session lifetime.\n * Concurrent calls are deduplicated: only one network request is made\n * and all callers share the same promise.\n */\nexport async function fetchAuthConfig(\n apiUrl: string,\n cache: AuthConfigCache,\n /** The backend's `basePath`; only needed if it is not the default. */\n apiPath: string = DEFAULT_API_PATH\n): Promise<AuthConfigResponse> {\n if (cache.cached) {\n return cache.cached;\n }\n\n if (cache.inflight) {\n return cache.inflight;\n }\n\n cache.inflight = (async () => {\n const response = await fetchWithHandling(`${apiUrl.replace(/\\/+$/, \"\")}${apiPath}/auth/config`, {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" }\n });\n return handleResponse<AuthConfigResponse>(response);\n })();\n\n try {\n const result = await cache.inflight;\n cache.cached = result;\n return result;\n } finally {\n cache.inflight = null;\n }\n}\n\n/**\n * Clear the cached auth config (e.g. on logout or for testing).\n */\nexport function clearAuthConfigCache(cache: AuthConfigCache): void {\n cache.cached = null;\n cache.inflight = null;\n}\n","const iconSynonyms: Record<string, string> = {};\nimport { iconKeys } from \"@rebasepro/ui\";\nimport Fuse from \"fuse.js\";\n\n\nconst map = iconKeys\n .map((importName) => {\n const iconSynonym = importName in iconSynonyms ? iconSynonyms[importName] : \"\";\n return {\n key: importName,\n synonyms: iconSynonym\n }\n });\nexport const iconsSearch = new Fuse(map, {\n isCaseSensitive: false,\n shouldSort: true,\n ignoreLocation: true,\n distance: 0,\n keys: [\"key\", \"synonyms\"]\n})\n\n\n","import React from \"react\";\nimport {\n cls,\n colorClassesMapping,\n coolIconKeys,\n IconColor,\n iconKeys,\n iconSize,\n LucideIconByName\n} from \"@rebasepro/ui\";\nimport { deepEqual as equal } from \"fast-equals\"\nimport { hashString, slugify } from \"@rebasepro/utils\";\n\n// iconKeys are now PascalCase strings (e.g. \"ShoppingCart\", \"Users\")\nconst iconKeysMap: Record<string, string> = iconKeys.reduce((acc: Record<string, string>, key) => {\n // Also add lowercase versions and snake_case versions to support legacy lookups\n const lower = key.toLowerCase();\n const snake = key.replace(/([A-Z])/g, \"_$1\").toLowerCase().replace(/^_/, \"\");\n acc[lower] = key;\n acc[snake] = key;\n acc[key] = key;\n return acc;\n}, {});\n\n/**\n * Render an icon element from a string key or existing React element.\n *\n * Whether a key names an icon is decided here, against `iconKeys` — an array\n * of strings. The component behind the key is fetched by `LucideIconByName` on\n * first use: this used to index lucide's full `icons` map, which is the whole\n * library and cannot be tree-shaken.\n */\nexport function getIcon(iconKey?: string | React.ReactNode,\n className?: string,\n color?: IconColor,\n size?: \"smallest\" | \"small\" | \"medium\" | \"large\" | number): React.ReactElement | undefined {\n\n if (React.isValidElement(iconKey)) {\n return iconKey;\n }\n\n if (!iconKey) return undefined;\n if (typeof iconKey === \"string\") {\n const lowerKey = iconKey.toLowerCase();\n const slugifiedKey = slugify(iconKey).replace(/-/g, \"_\");\n\n const mappedKey = iconKeysMap[iconKey] || iconKeysMap[lowerKey] || iconKeysMap[slugifiedKey];\n\n if (!mappedKey) {\n return undefined;\n }\n\n const sizeInPx = typeof size === \"number\" ? size : iconSize[size ?? \"medium\"];\n return <LucideIconByName\n name={mappedKey}\n size={sizeInPx}\n className={cls(\n color ? colorClassesMapping[color] : \"\",\n \"select-none shrink-0\",\n className\n )}\n />;\n }\n\n console.warn(\"Invalid icon key provided:\", iconKey);\n return undefined;\n}\n\nexport type IconViewProps = {\n slug: string;\n name: string;\n singularName?: string;\n group?: string;\n icon?: string | React.ReactNode;\n}\n\nexport const IconForView = React.memo(\n function IconForView({\n collectionOrView,\n className,\n color,\n size = \"medium\"\n }: {\n collectionOrView?: IconViewProps,\n color?: IconColor,\n className?: string,\n size?: \"smallest\" | \"small\" | \"medium\" | \"large\" | number,\n }): React.ReactElement {\n if (!collectionOrView) return <></>;\n const icon = getIcon(collectionOrView.icon, className, color, size);\n if (collectionOrView?.icon && icon)\n return icon;\n\n let pathname = slugify((\"singularName\" in collectionOrView ? collectionOrView.singularName : undefined) ?? collectionOrView.name).replace(/-/g, \"_\");\n\n let key: string | undefined;\n if (pathname in iconKeysMap)\n key = iconKeysMap[pathname];\n\n if (!key) {\n pathname = slugify(collectionOrView.slug).replace(/-/g, \"_\");\n if (pathname in iconKeysMap)\n key = iconKeysMap[pathname];\n }\n\n const iconsCount = coolIconKeys.length;\n\n if (!key)\n key = coolIconKeys[hashString(collectionOrView.slug) % iconsCount];\n\n const sizeInPx = typeof size === \"number\" ? size : iconSize[size];\n return <LucideIconByName\n name={key}\n size={sizeInPx}\n className={cls(\n color ? colorClassesMapping[color] : \"\",\n \"select-none shrink-0\",\n className\n )}\n />;\n }, (prevProps, nextProps) => {\n return equal(prevProps.collectionOrView?.icon, nextProps.collectionOrView?.icon) &&\n prevProps.collectionOrView?.name === nextProps.collectionOrView?.name &&\n prevProps.collectionOrView?.slug === nextProps.collectionOrView?.slug &&\n prevProps.collectionOrView?.singularName === nextProps.collectionOrView?.singularName &&\n equal(prevProps.color, nextProps.color) &&\n prevProps.className === nextProps.className &&\n prevProps.size === nextProps.size;\n });\n","import { FormexController } from \"@rebasepro/forms\";\n\nexport function createFormexStub<T extends object>(values: T): FormexController<T> {\n const errorMessage = \"You are in a read-only context. You cannot modify the formex controller.\";\n\n return {\n debugId: \"\",\n values,\n initialValues: values,\n touched: {} as Record<string, boolean>,\n dirty: false,\n errors: {} as Record<string, string>,\n submitCount: 0,\n isSubmitting: false,\n isValidating: false,\n version: 0,\n canUndo: false,\n canRedo: false,\n\n setValues: () => {\n throw new Error(errorMessage);\n },\n setTouched(touched: Record<string, boolean>): void {\n throw new Error(errorMessage);\n },\n setFieldValue: () => {\n throw new Error(errorMessage);\n },\n setFieldTouched: () => {\n throw new Error(errorMessage);\n },\n setDirty: () => {\n throw new Error(errorMessage);\n },\n setSubmitCount: () => {\n throw new Error(errorMessage);\n },\n setFieldError: () => {\n throw new Error(errorMessage);\n },\n handleChange: () => {\n throw new Error(errorMessage);\n },\n handleBlur: () => {\n throw new Error(errorMessage);\n },\n handleSubmit: () => {\n throw new Error(errorMessage);\n },\n validate: () => {\n throw new Error(errorMessage);\n },\n resetForm: () => {\n throw new Error(errorMessage);\n },\n setSubmitting: () => {\n throw new Error(errorMessage);\n },\n undo: () => {\n throw new Error(errorMessage);\n },\n redo: () => {\n throw new Error(errorMessage);\n }\n };\n}\n","\nimport type { ArrayProperty, Property, StringProperty } from \"@rebasepro/types\";\nimport Compressor from \"compressorjs\";\nimport { deepEqual as equal } from \"fast-equals\";\n\nimport { resourceKeyOf } from \"@rebasepro/types\";\nimport { EntityValues, StorageConfig, StorageSource, StorageSourceRegistry, UploadFileProps } from \"@rebasepro/types\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { resolveStorageFilenameString, resolveStoragePathString, resolveStorageSource } from \"@rebasepro/common\";\nimport { useAuthController } from \"../hooks\";\nimport { useStorageSources } from \"../contexts/StorageSourcesContext\";\nimport { randomString } from \"@rebasepro/utils\";\n\nexport type StorageFieldSize = \"smallest\" | \"small\" | \"medium\" | \"large\" | number;\n\n/**\n * Internal representation of an item in the storage\n * It can have two states, having a storagePathOrDownloadUrl set,\n * which means the file has been uploaded, and it is rendered as a preview\n * Or have a pending file being uploaded.\n */\nexport interface StorageFieldItem {\n id: number; // generated on the fly for internal use only\n storagePathOrDownloadUrl?: string;\n file?: File;\n fileName?: string;\n metadata?: Record<string, unknown>,\n size: StorageFieldSize\n}\n\nexport function useStorageUploadController<M extends Record<string, unknown>>({\n entityId,\n entityValues,\n path,\n value,\n property,\n propertyKey,\n storageSource,\n storageSourceRegistry,\n collectionSlug,\n disabled,\n onChange\n}:\n {\n entityId?: string | number,\n entityValues: EntityValues<M>,\n value: string | string[] | null;\n path?: string,\n propertyKey: string,\n property: StringProperty | ArrayProperty | StringProperty | ArrayProperty,\n storageSource: StorageSource,\n /** Optional explicit registry. When omitted, the hook reads from the\n * `StorageSourcesContext` provided by `<Rebase storageSources={...}>`. */\n storageSourceRegistry?: StorageSourceRegistry,\n /** The slug of the collection the property belongs to, so the server\n * can hold the upload to the property's own `maxSize`/`acceptedFiles`. */\n collectionSlug?: string,\n disabled: boolean,\n onChange: (value: string | string[] | null) => void\n }) {\n\n const authController = useAuthController();\n const storageSources = useStorageSources();\n const storage: StorageConfig | undefined = property.type === \"string\"\n ? property.storage\n : property.type === \"array\" &&\n (property.of as Property).type === \"string\"\n ? (property.of as StringProperty).storage\n : undefined;\n\n // Resolve the correct storage source for this property.\n // Priority: explicit registry prop → StorageSourcesContext → default.\n const propertySource = useMemo(() => resolveStorageSource({\n sourceKey: storage?.storageSource === undefined ? undefined : resourceKeyOf(storage.storageSource),\n registry: storageSourceRegistry,\n sources: storageSources.sources,\n defaultSource: storageSource,\n createSource: storageSources.createSource\n }), [storage?.storageSource, storageSourceRegistry, storageSources.sources, storageSources.createSource, storageSource]);\n\n const multipleFilesSupported = property.type === \"array\";\n\n // What every upload of this property tells the storage source beyond the\n // file: `storage.public` (stored under the public prefix, served by a\n // stable token-less URL) and which property it is for. Neither used to be\n // sent, so a `public: true` field stored private files with expiring URLs,\n // and the server could not hold the upload to the property's own limits.\n //\n // Carried by the source this hook hands out — the one the field provides\n // to its upload components — so every upload of the property sends them,\n // whichever component calls `putObject`.\n const isPublic = storage?.public === true;\n const resolvedStorageSource = useMemo(() => withUploadOptions(propertySource, {\n ...(isPublic ? { public: true } : {}),\n ...(collectionSlug ? { context: { collection: collectionSlug, property: propertyKey } } : {})\n }), [propertySource, isPublic, collectionSlug, propertyKey]);\n\n if (!storage)\n throw Error(\"Storage meta must be specified\");\n\n const processFile = storage?.processFile;\n\n const metadata: Record<string, unknown> | undefined = storage?.metadata;\n // One preview size. A single-file field asked for \"large\" (a 220px\n // thumbnail) while a multi-file field asked for \"medium\" (118px), so two\n // upload fields in the same form reserved wildly different heights and\n // neither matched its own empty state.\n const size = \"medium\";\n\n const imageResize = storage?.imageResize;\n\n const internalInitialValue: StorageFieldItem[] =\n getInternalInitialValue(multipleFilesSupported, value, metadata, size);\n\n const [initialValue, setInitialValue] = useState<string | string[] | null>(value);\n const [internalValue, setInternalValue] = useState<StorageFieldItem[]>(internalInitialValue);\n\n useEffect(() => {\n if (!equal(initialValue, value)) {\n setInitialValue(value);\n setInternalValue(internalInitialValue);\n }\n }, [internalInitialValue, value, initialValue]);\n\n const fileNameBuilder = useCallback(async (file: File) => {\n if (storage.fileName) {\n const fileName = await resolveStorageFilenameString({\n input: storage.fileName,\n storage,\n values: entityValues,\n entityId,\n path,\n property: property,\n file,\n propertyKey\n });\n if (!fileName || fileName.length === 0) {\n throw Error(\"You need to return a valid filename\");\n }\n return fileName;\n }\n return randomString() + \"_\" + file.name;\n }, [entityId, entityValues, path, property, propertyKey, storage]);\n\n const storagePathBuilder = useCallback((file: File) => {\n return resolveStoragePathString({\n input: storage.storagePath,\n storage,\n values: entityValues,\n entityId,\n path,\n property: property,\n file,\n propertyKey\n }) ?? \"/\";\n }, [entityId, entityValues, path, property, propertyKey, storage]);\n\n const onFileUploadComplete = useCallback(async (uploadedPath: string,\n entry: StorageFieldItem,\n metadata?: Record<string, unknown>,\n uploadedUrl?: string) => {\n\n console.debug(\"onFileUploadComplete\", uploadedPath, entry);\n\n let uploadPathOrDownloadUrl: string | null = uploadedPath;\n\n if (storage.includeBucketUrl) {\n if (!uploadedUrl) {\n console.warn(\"includeBucketUrl is set but no fully-qualified storage URL was returned by the StorageSource. Falling back to the storage path.\");\n } else {\n uploadPathOrDownloadUrl = uploadedUrl;\n }\n }\n\n if (storage.storeUrl) {\n uploadPathOrDownloadUrl = (await resolvedStorageSource.getSignedUrl(uploadedPath)).url;\n }\n if (storage.postProcess && uploadPathOrDownloadUrl) {\n uploadPathOrDownloadUrl = await storage.postProcess(uploadPathOrDownloadUrl);\n }\n\n if (!uploadPathOrDownloadUrl) {\n console.warn(\"uploadPathOrDownloadUrl is null\")\n return;\n }\n\n let newValue: StorageFieldItem[];\n\n entry.storagePathOrDownloadUrl = uploadPathOrDownloadUrl;\n entry.metadata = metadata;\n newValue = [...internalValue];\n\n newValue = removeDuplicates(newValue);\n setInternalValue(newValue);\n\n const fieldValue = newValue\n .filter(e => !!e.storagePathOrDownloadUrl)\n .map(e => e.storagePathOrDownloadUrl as string);\n\n if (multipleFilesSupported) {\n onChange(fieldValue);\n } else {\n onChange(fieldValue ? fieldValue[0] : null);\n }\n }, [internalValue, multipleFilesSupported, onChange, storage, resolvedStorageSource]);\n\n const onFileUploadError = useCallback((entry: StorageFieldItem) => {\n console.debug(\"onFileUploadError\", entry);\n\n // Remove the failed entry from internalValue\n const newValue = internalValue.filter(item => item.id !== entry.id);\n setInternalValue(newValue);\n }, [internalValue]);\n\n const onFilesAdded = useCallback(async (acceptedFiles: File[]) => {\n\n if (!acceptedFiles.length || disabled)\n return;\n\n if (processFile) {\n try {\n acceptedFiles = await Promise.all(acceptedFiles.map(async file => {\n const processedFile = await processFile(file);\n if (!processedFile) {\n return file;\n }\n return processedFile;\n }));\n } catch (e) {\n console.error(\"Error processing file with custom code. Attempting to continue uploading.\", e);\n }\n }\n\n let newInternalValue: StorageFieldItem[];\n\n if (multipleFilesSupported) {\n newInternalValue = [...internalValue,\n ...(await Promise.all(acceptedFiles.map(async file => {\n if (imageResize && isImageFile(file)) {\n file = await resizeImage(file, imageResize);\n }\n\n return {\n id: getRandomId(),\n file,\n fileName: await fileNameBuilder(file),\n metadata,\n size\n } as StorageFieldItem;\n })))];\n } else {\n let file = acceptedFiles[0];\n if (imageResize && isImageFile(file)) {\n file = await resizeImage(file, imageResize);\n }\n\n newInternalValue = [{\n id: getRandomId(),\n file,\n fileName: await fileNameBuilder(file),\n metadata,\n size\n }];\n }\n\n // Remove either storage path or file duplicates\n newInternalValue = removeDuplicates(newInternalValue);\n setInternalValue(newInternalValue);\n }, [disabled, fileNameBuilder, internalValue, metadata, multipleFilesSupported, size, imageResize]);\n\n return {\n internalValue,\n setInternalValue,\n storage,\n fileNameBuilder,\n storagePathBuilder,\n onFileUploadComplete,\n onFileUploadError,\n onFilesAdded,\n multipleFilesSupported,\n /** The resolved StorageSource for this property — may differ from the\n * default context source when `StorageConfig.storageSource` is set —\n * whose uploads carry the property's `public` flag and `context`. */\n resolvedStorageSource\n }\n}\n\nfunction getInternalInitialValue(multipleFilesSupported: boolean,\n value: string | string[] | null,\n metadata: Record<string, unknown> | undefined,\n size: StorageFieldSize): StorageFieldItem[] {\n let strings: string[] = [];\n if (multipleFilesSupported) {\n if (Array.isArray(value) && value.every((v) => typeof v === \"string\")) {\n strings = (value ?? []) as string[];\n }\n } else {\n if (typeof value === \"string\") {\n strings = value ? [value as string] : [];\n }\n }\n\n return strings\n .map(entry => (\n {\n id: getRandomId(),\n storagePathOrDownloadUrl: entry,\n metadata,\n size\n }\n ));\n}\n\nfunction removeDuplicates(items: StorageFieldItem[]) {\n return items.filter(\n (item, i) => {\n return ((items.map((v) => v.storagePathOrDownloadUrl).indexOf(item.storagePathOrDownloadUrl) === i) || !item.storagePathOrDownloadUrl) &&\n ((items.map((v) => v.file).indexOf(item.file) === i) || !item.file);\n }\n );\n}\n\nfunction getRandomId() {\n return Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER));\n}\n\n/**\n * Check if a file is an image type supported for resizing\n */\nfunction isImageFile(file: File): boolean {\n return file.type === \"image/jpeg\" ||\n file.type === \"image/png\" ||\n file.type === \"image/webp\";\n}\n\n/**\n * Resize and compress an image using compressorjs.\n */\nasync function resizeImage(\n file: File,\n imageResize?: StorageConfig[\"imageResize\"]\n): Promise<File> {\n const maxWidth = imageResize?.maxWidth;\n const maxHeight = imageResize?.maxHeight;\n const quality = (imageResize?.quality ?? 80) / 100;\n const mode = imageResize?.mode ?? \"contain\";\n\n // Determine output format\n let mimeType = file.type;\n if (imageResize?.format && imageResize.format !== \"original\") {\n mimeType = `image/${imageResize.format}`;\n }\n\n return new Promise<File>((resolve, reject) => {\n new Compressor(file, {\n quality,\n maxWidth,\n maxHeight,\n mimeType,\n // Use cover mode if specified (crops to fit)\n // Otherwise use contain mode (scales to fit)\n ...(mode === \"cover\" || mode === undefined ? {\n width: maxWidth,\n height: maxHeight,\n resize: \"cover\" as const\n } : {}),\n success: (result) => {\n const compressedFile = new File([result], file.name, {\n type: result.type,\n lastModified: Date.now()\n });\n resolve(compressedFile);\n },\n error: reject\n });\n });\n}\n\n/**\n * `source`, with `options` sent on every `putObject` (a call's own values win).\n * Delegates method by method rather than spreading, so a class-based source\n * keeps its `this`.\n */\nfunction withUploadOptions(\n source: StorageSource,\n options: Pick<UploadFileProps, \"public\" | \"context\">\n): StorageSource {\n if (options.public === undefined && options.context === undefined) return source;\n return {\n putObject: (props) => source.putObject({ ...options, ...props }),\n getSignedUrl: (keyOrUrl, bucket) => source.getSignedUrl(keyOrUrl, bucket),\n getObject: (key, bucket) => source.getObject(key, bucket),\n deleteObject: (key, bucket) => source.deleteObject(key, bucket),\n listObjects: (prefix, options) => source.listObjects(prefix, options)\n };\n}\n","import { EnumValueConfig } from \"@rebasepro/types\";\nimport { ChipColorScheme, getColorSchemeForKey, getColorSchemeForSeed } from \"@rebasepro/ui\";\nimport { getLabelOrConfigFrom } from \"@rebasepro/common\";\n\nexport function getColorScheme(enumValues: EnumValueConfig[], key: string | number): ChipColorScheme | undefined {\n const labelOrConfig = getLabelOrConfigFrom(enumValues, key);\n if (!labelOrConfig?.color)\n return getColorSchemeForSeed(key.toString());\n if (typeof labelOrConfig === \"object\" && \"color\" in labelOrConfig) {\n if (typeof labelOrConfig.color === \"string\")\n // Not a raw table lookup: a config naming a colour this build does\n // not have still deserves a colour rather than `undefined`.\n return getColorSchemeForKey(labelOrConfig.color);\n if (typeof labelOrConfig.color === \"object\")\n return labelOrConfig.color;\n }\n return undefined;\n}\n\nexport function isEnumValueDisabled(labelOrConfig?: string | EnumValueConfig) {\n return typeof labelOrConfig === \"object\" && (labelOrConfig as EnumValueConfig).disabled;\n}\n\nexport function buildEnumLabel(\n labelOrConfig?: string | EnumValueConfig\n): string | undefined {\n if (labelOrConfig === undefined)\n return undefined;\n if (typeof labelOrConfig === \"object\") {\n return labelOrConfig.label;\n } else {\n return labelOrConfig;\n }\n}\n","export const STUDIO_NAVIGATION_GROUPS = [\n \"Database\",\n \"Compute\",\n \"API\",\n \"Storage\",\n \"Access Control\"\n];\n","/**\n * Layout width primitives used by the framework's own side-panel and form\n * dialog sizing logic.\n *\n * @internal Not part of the stable public API — exported only because\n * `@rebasepro/cms` and `@rebasepro/studio` need them to compute the same\n * dialog widths as the framework. Do not depend on these for app code; they\n * may change shape or be removed without a major version bump.\n */\nexport const CONTAINER_FULL_WIDTH = \"100vw\";\n\n/** @internal See {@link CONTAINER_FULL_WIDTH}. */\nexport const FORM_CONTAINER_WIDTH = \"768px\";\n\n/**\n * How wide the side panel opens when neither the caller nor the collection\n * says otherwise.\n *\n * Sized from what it has to hold rather than from a round number: the form's\n * content column plus its metadata rail plus gutters, which is also the width\n * at which the form stops being a single stack and picks up the same\n * two-column layout it has in full screen. Capped against the viewport so a\n * panel never becomes the whole window on a laptop — at that point you want\n * full screen, and there is a button for it.\n *\n * @internal See {@link CONTAINER_FULL_WIDTH}.\n */\nexport const SIDE_PANEL_DEFAULT_WIDTH = \"min(1160px, 88vw)\";\n","import React, { useCallback, useEffect, useRef } from \"react\";\nimport { useLocation } from \"react-router\";\n\nconst scrollsMap: Record<string, number> = {};\n\n/**\n * Restores per-route scroll position on a scrollable container, keyed by\n * router location. Used by the framework's own home page implementations.\n *\n * @internal Not part of the stable public API — exported only because\n * `@rebasepro/cms` and `@rebasepro/studio` reuse it in their home page\n * components. Its behavior (module-level scroll cache, router coupling) is\n * an implementation detail and may change without a major version bump.\n */\nexport function useRestoreScroll() {\n\n const location = useLocation();\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [scroll, setScroll] = React.useState(0);\n const [direction, setDirection] = React.useState<\"up\" | \"down\">(\"down\");\n\n // Use ref to track previous scroll for direction calculation\n // This avoids recreating handleScroll on every scroll\n const prevScrollRef = useRef(0);\n\n const handleScroll = useCallback(() => {\n if (!containerRef.current || !location.key) return;\n const scrollTop = containerRef.current.scrollTop;\n scrollsMap[location.key] = scrollTop;\n setScroll(scrollTop);\n setDirection(scrollTop > prevScrollRef.current ? \"down\" : \"up\");\n prevScrollRef.current = scrollTop;\n }, [location.key]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n container.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n return () => {\n if (container)\n container.removeEventListener(\"scroll\", handleScroll);\n };\n }, [handleScroll]);\n\n // Defer scroll restoration to next tick to allow async content to render\n // This is necessary because DefaultHomePage content loads asynchronously\n useEffect(() => {\n const savedScroll = scrollsMap[location.key];\n if (!containerRef.current || !savedScroll) return;\n\n const timeoutId = setTimeout(() => {\n if (!containerRef.current) return;\n containerRef.current.scrollTo({\n top: savedScroll,\n behavior: \"auto\"\n });\n }, 0);\n\n return () => clearTimeout(timeoutId);\n }, [location.key]);\n\n return {\n containerRef,\n scroll,\n direction\n };\n}\n","import React from \"react\";\nimport { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\nexport interface UnsavedChangesDialogProps {\n open: boolean;\n body?: React.ReactNode;\n title?: string;\n handleOk: () => void;\n handleCancel: () => void;\n}\n\nexport function UnsavedChangesDialog({\n open,\n handleOk,\n handleCancel,\n body,\n title\n}: UnsavedChangesDialogProps) {\n\n const { t } = useTranslation();\n\n return (\n <Dialog\n onEscapeKeyDown={() => {\n handleCancel();\n }}\n open={open}\n >\n <DialogTitle variant={\"h6\"}>{title}</DialogTitle>\n <DialogContent>\n\n <Typography>\n {body ?? t(\"unsaved_changes\")}\n </Typography>\n\n </DialogContent>\n <DialogActions>\n <Button variant=\"text\"\n onClick={handleCancel} autoFocus> {t(\"cancel\")} </Button>\n <Button\n onClick={handleOk}> {t(\"ok\")} </Button>\n </DialogActions>\n </Dialog>\n );\n}\n","import React, { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport type {\n CollectionRegistryController\n} from \"@rebasepro/types\";\nimport type {\n SidePanelController,\n UrlController,\n NavigationStateController,\n BreadcrumbEntry,\n BreadcrumbsController\n} from \"@rebasepro/cms-types\";\n\nexport type { BreadcrumbEntry, BreadcrumbsController };\n\n// ─── Breadcrumbs ──────────────────────────────────────────────────\n\n\n// ─── Bridge interface ───────────────────────────────────────────────\n\n/**\n * StudioBridge provides optional admin capabilities to Studio components.\n * When the admin is present, a bridge provider injects real implementations.\n * When the admin is absent, noop defaults ensure Studio works standalone.\n */\n/**\n * Editing a collection's source through the admin's plan/apply flow.\n *\n * Studio has its own writers — the RLS editor saves a policy, the collection\n * editor saves a property — and until this existed they did not go to the same\n * place. Saving a policy on a mapped table POSTed the rules straight to\n * `/schema-editor/collection/save`: no plan, no dialog, no record of what SQL\n * the change would produce, while the identical edit made two tabs away in the\n * collection editor showed all three.\n *\n * `available` is false when there is no collection editor above this Studio —\n * the hosted console against somebody else's container, or a panel that never\n * enabled it — and the caller falls back to whatever it did before.\n */\nexport interface StudioSchemaEditing {\n available: boolean;\n /**\n * Merge `patch` into the collection and take it through plan → confirm →\n * apply: the same dialog `useLiveSchemaEditing` shows the collection\n * editor.\n *\n * Resolves once the change has been applied, or written source-only if\n * that is what was chosen. Rejects with `SchemaChangeCancelled` when the\n * dialog was closed — which is not an error to report, it is an answer.\n */\n updateCollection: (collectionId: string, patch: Record<string, unknown>) => Promise<void>;\n}\n\nexport interface StudioBridge {\n collectionRegistry: CollectionRegistryController;\n schemaEditing: StudioSchemaEditing;\n sidePanelController: SidePanelController;\n urlController: UrlController;\n navigationState: NavigationStateController;\n breadcrumbs: BreadcrumbsController;\n capabilities: StudioCapabilities;\n}\n\n/**\n * What the *host* of these tools can do, as opposed to what the backend can.\n *\n * Studio is mounted in two very different places. In a project's own admin\n * panel it runs next to the collection source files and can edit them through\n * the schema-editor routes. In the hosted console it runs against somebody\n * else's deployed container: there is no source to edit — the container is\n * rebuilt from the customer's repository on every deploy — and the routes that\n * would edit it are not mounted at all, because the framework switches the\n * schema editor off under `NODE_ENV=production`.\n *\n * Tools that would otherwise offer a write into the codebase read this to\n * decide whether that write is even meaningful.\n */\nexport interface StudioCapabilities {\n /**\n * Whether the host has the project's collection source at hand and can\n * write to it.\n *\n * Defaults to `true`, which is what an admin panel running beside its own\n * `collectionsDir` has always assumed.\n */\n codebase: boolean;\n}\n\n// ─── Noop defaults ──────────────────────────────────────────────────\n\nconst NOOP_COLLECTION_REGISTRY: CollectionRegistryController = {\n getCollection: () => undefined,\n getRawCollection: () => undefined,\n resolveDataPath: (path) => path,\n resolveCollectionPath: (path) => path,\n getParentReferencesFromPath: () => [],\n getParentCollectionSlugs: () => [],\n getParentEntityIds: () => [],\n convertIdsToPaths: () => [],\n initialised: false\n};\n\nconst NOOP_SCHEMA_EDITING: StudioSchemaEditing = {\n available: false,\n updateCollection: async () => {\n throw new Error(\"No collection editor is mounted — check `available` before calling this.\");\n }\n};\n\nconst NOOP_SIDE_PANEL: SidePanelController = {\n open: () => {},\n replace: () => {},\n close: () => {}\n};\n\nconst NOOP_URL_CONTROLLER: UrlController = {\n basePath: \"/\",\n baseCollectionPath: \"/c\",\n urlPathToDataPath: () => \"\",\n homeUrl: \"/\",\n isUrlCollectionPath: () => false,\n buildUrlCollectionPath: () => \"\",\n buildAppUrlPath: () => \"\",\n resolveDatabasePathsFrom: () => \"\",\n navigate: () => {}\n};\n\nconst NOOP_NAVIGATION_STATE: NavigationStateController = {\n loading: false,\n refreshNavigation: () => {}\n};\n\nconst NOOP_BREADCRUMBS: BreadcrumbsController = {\n breadcrumbs: [],\n set: () => {}\n};\n\nconst DEFAULT_CAPABILITIES: StudioCapabilities = {\n codebase: true\n};\n\nconst NOOP_BRIDGE: StudioBridge = {\n collectionRegistry: NOOP_COLLECTION_REGISTRY,\n schemaEditing: NOOP_SCHEMA_EDITING,\n sidePanelController: NOOP_SIDE_PANEL,\n urlController: NOOP_URL_CONTROLLER,\n navigationState: NOOP_NAVIGATION_STATE,\n breadcrumbs: NOOP_BREADCRUMBS,\n capabilities: DEFAULT_CAPABILITIES\n};\n\n// ─── Context & Provider ─────────────────────────────────────────────\n\nexport const StudioBridgeContext = createContext<StudioBridge>(NOOP_BRIDGE);\n\n/**\n * Provider that injects admin capabilities into Studio.\n * Accepts partial overrides — any field not provided falls back to noop.\n *\n * Usage (in app wiring, when the admin is present):\n * ```tsx\n * <StudioBridgeProvider value={{\n * collectionRegistry: useCollectionRegistryController(),\n * sidePanelController: useSidePanel(),\n * urlController: useUrlController(),\n * navigationState: useNavigationStateController(),\n * breadcrumbs: useBreadcrumbsController(),\n * }}>\n * <RebaseStudio ... />\n * </StudioBridgeProvider>\n * ```\n */\nexport function StudioBridgeProvider({\n value,\n children\n}: {\n value: Partial<StudioBridge>;\n children: React.ReactNode;\n}) {\n // Keyed on the slices rather than on `value`: callers write the object\n // inline (`value={{ collectionRegistry }}`), so a `[value]` dependency\n // rebuilt the context on every render of the host and re-rendered every\n // Studio consumer with it.\n const merged = React.useMemo(\n () => ({ ...NOOP_BRIDGE,\n...value }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n value.collectionRegistry,\n value.sidePanelController,\n value.urlController,\n value.navigationState,\n value.breadcrumbs,\n value.capabilities\n ]\n );\n return (\n <StudioBridgeContext.Provider value={merged}>\n {children}\n </StudioBridgeContext.Provider>\n );\n}\n\n// ─── Convenience hooks ──────────────────────────────────────────────\n\n/**\n * Source editing through the admin's plan/apply dialog. `available` is false\n * when no collection editor is mounted.\n */\nexport function useStudioSchemaEditing(): StudioSchemaEditing {\n return useContext(StudioBridgeContext).schemaEditing;\n}\n\n/** Collection registry — returns noop if the admin is not present. */\nexport function useStudioCollectionRegistry(): CollectionRegistryController {\n return useContext(StudioBridgeContext).collectionRegistry;\n}\n\n/** Side panel controller — returns noop if the admin is not present. */\nexport function useStudioSidePanelController(): SidePanelController {\n return useContext(StudioBridgeContext).sidePanelController;\n}\n\n/** URL controller — returns noop if the admin is not present. */\nexport function useStudioUrlController(): UrlController {\n return useContext(StudioBridgeContext).urlController;\n}\n\n/** Navigation state — returns noop if the admin is not present. */\nexport function useStudioNavigationState(): NavigationStateController {\n return useContext(StudioBridgeContext).navigationState;\n}\n\n/** Breadcrumbs controller — returns noop if the admin is not present. */\nexport function useStudioBreadcrumbs(): BreadcrumbsController {\n return useContext(StudioBridgeContext).breadcrumbs;\n}\n\n/** What the host can do — see {@link StudioCapabilities}. */\nexport function useStudioCapabilities(): StudioCapabilities {\n return useContext(StudioBridgeContext).capabilities;\n}\n\n// ─── Self-Assembling Bridge Registry ────────────────────────────────\n\n/**\n * Registry that controllers use to self-register their implementations\n * into the Studio bridge. Each controller calls `register(key, value)`\n * on mount and `unregister(key)` on unmount.\n */\nexport interface StudioBridgeRegistry {\n register: <K extends keyof StudioBridge>(key: K, value: StudioBridge[K]) => void;\n unregister: (key: keyof StudioBridge) => void;\n}\n\nexport const StudioBridgeRegistryContext = createContext<StudioBridgeRegistry | null>(null);\n\n/**\n * Provider that creates a self-assembling bridge.\n *\n * Mount this above the controller providers. Each controller calls\n * `useBridgeRegistration(key, value)` to inject its implementation.\n * The bridge context value is automatically kept in sync.\n *\n * ```tsx\n * <StudioBridgeRegistryProvider>\n * <CollectionRegistryProvider> // auto-registers\n * <SidePanelProvider> // auto-registers\n * <UrlProvider> // auto-registers\n * <RebaseStudio /> // consumes bridge\n * </UrlProvider>\n * </SidePanelProvider>\n * </CollectionRegistryProvider>\n * </StudioBridgeRegistryProvider>\n * ```\n */\nexport function StudioBridgeRegistryProvider({ children }: { children: React.ReactNode }) {\n const [version, setVersion] = useState(0);\n const slicesRef = useRef<Partial<StudioBridge>>({});\n\n const register = useCallback(<K extends keyof StudioBridge>(key: K, value: StudioBridge[K]) => {\n slicesRef.current[key] = value;\n setVersion(v => v + 1);\n }, []);\n\n const unregister = useCallback((key: keyof StudioBridge) => {\n delete slicesRef.current[key];\n setVersion(v => v + 1);\n }, []);\n\n const registry = useMemo<StudioBridgeRegistry>(() => ({ register,\nunregister }), [register, unregister]);\n\n const bridgeValue = useMemo<StudioBridge>(() => ({\n ...NOOP_BRIDGE,\n ...slicesRef.current\n }), [version]);\n\n return (\n <StudioBridgeRegistryContext.Provider value={registry}>\n <StudioBridgeContext.Provider value={bridgeValue}>\n {children}\n </StudioBridgeContext.Provider>\n </StudioBridgeRegistryContext.Provider>\n );\n}\n","import { useContext, useEffect } from \"react\";\nimport type { StudioBridge } from \"./useStudioBridge\";\nimport { StudioBridgeRegistryContext } from \"./useStudioBridge\";\n\n/**\n * Registers a value into the self-assembling Studio bridge.\n *\n * Each controller (collectionRegistry, sidePanel, url, navigation, breadcrumbs)\n * calls this hook on mount to inject its real implementation into the bridge.\n * On unmount the slice is automatically removed, reverting to the noop default.\n *\n * Usage:\n * ```tsx\n * function SomeProvider({ children }) {\n * const controller = useBuildSomeController();\n * useBridgeRegistration(\"sidePanelController\", controller);\n * return <SomeContext.Provider value={controller}>{children}</SomeContext.Provider>;\n * }\n * ```\n */\nexport function useBridgeRegistration<K extends keyof StudioBridge>(\n key: K,\n value: StudioBridge[K]\n): void {\n const registry = useContext(StudioBridgeRegistryContext);\n\n useEffect(() => {\n if (!registry) return;\n registry.register(key, value);\n return () => registry.unregister(key);\n }, [registry, key, value]);\n}\n","/**\n * Collection helpers that only the admin panel needs.\n *\n * These lived in `@rebasepro/common`, which is on the backend's dependency path,\n * and they read presentation fields — `defaultSelectedView`, `localChangesBackup`\n * — that now live under a collection's `admin` block. A server has no use for\n * either, and `resolveDefaultSelectedView` was the *only* thing making\n * `@rebasepro/common` name an admin view-model type\n * (`DefaultSelectedViewBuilder`), which was the last UI symbol any core package\n * imported.\n */\nimport type { ChildViewSource, CollectionConfig } from \"@rebasepro/types\";\nimport { type AdminCollection, type DefaultSelectedViewBuilder, type DefaultSelectedViewParams, resolveAdminCollection } from \"@rebasepro/cms-types\";\nimport { getEntityChildViews } from \"@rebasepro/common\";\n\nexport function resolveDefaultSelectedView(\n defaultSelectedView: string | DefaultSelectedViewBuilder | undefined,\n params: DefaultSelectedViewParams\n) {\n if (!defaultSelectedView) {\n return undefined;\n } else if (typeof defaultSelectedView === \"string\") {\n return defaultSelectedView;\n } else {\n return defaultSelectedView(params);\n }\n}\n\nexport function getLocalChangesBackup(collection: AdminCollection) {\n if (!collection.localChangesBackup) {\n return \"manual_apply\";\n }\n\n return collection.localChangesBackup;\n}\n\n/**\n * Returns the primary keys for a entity collection by inspecting the properties\n * and finding any properties with `isId`.\n * Fallbacks to `[\"id\"]` if no properties are marked as `isId: true`.\n * @param collection\n */\n/**\n * A collection's child collections, as the panel's view model.\n *\n * `getSubcollections` in `@rebasepro/common` returns the contract type, so the\n * children of a resolved collection arrived un-flattened and reading\n * `child.icon` or `child.hideFromNavigation` failed. Resolving is not recursive\n * on purpose — children are fetched lazily through a thunk\n * (`childCollections`/`subcollections`), so walking the whole tree eagerly to\n * flatten it would defeat that.\n */\nexport function getAdminSubcollections(\n collection: AdminCollection | CollectionConfig\n): AdminCollection[] {\n return getAdminEntityChildViews(collection).map(view => view.collection);\n}\n\n/**\n * A collection's child views as the panel's view model, keeping the `source`\n * that says what kind of list each one is.\n *\n * The tabs need it: on a junction-backed relation the parent owns the *link*,\n * so the destructive action is a removal from this record, not a delete. Every\n * caller that renders a tab should prefer this over\n * {@link getAdminSubcollections}, which flattens that distinction away.\n */\nexport function getAdminEntityChildViews(\n collection: AdminCollection | CollectionConfig\n): { key: string; collection: AdminCollection; source: ChildViewSource }[] {\n return (getEntityChildViews(collection as CollectionConfig) ?? []).map(view => ({\n key: view.key,\n collection: resolveAdminCollection(view.collection),\n source: view.source\n }));\n}\n","/**\n * Reading a collection's `display` block.\n *\n * Two questions, kept apart because they are answered at different times: which\n * *property* fills a role (readable from values already in hand) and which\n * *resolver* fills it (may have to go to the network). A caller that cannot\n * await — a sort comparator, an export column, a server render — uses the key\n * and is documented to ignore resolvers.\n */\nimport type {\n AdminCollection,\n EntityDisplayResolver,\n EntityDisplayRole\n} from \"@rebasepro/cms-types\";\n\n/**\n * What the collection declares for a role, before deciding which form it is.\n *\n * One field states it: `display[role]`. `admin.titleProperty` used to be a\n * second way to say `display.title` and is gone — a role with two spellings is\n * a role with two readers, and this one had grown seven.\n */\nfunction getDeclaredSource<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): string | EntityDisplayResolver<M, unknown> | undefined {\n const display = collection.display as Record<string, unknown> | undefined;\n const declared = display?.[role];\n return declared === undefined\n ? undefined\n : declared as string | EntityDisplayResolver<M, unknown>;\n}\n\n/**\n * The property path a role is declared to read, when it is declared as a path.\n *\n * Returns `undefined` for a role filled by a resolver — a resolver has no key —\n * and for a role the collection says nothing about, which is then derived.\n *\n * @group Collections\n */\nexport function getDisplayPropertyKey<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): string | undefined {\n const declared = getDeclaredSource(collection, role);\n return typeof declared === \"string\" ? declared : undefined;\n}\n\n/**\n * The resolver a role is declared to use, when it is declared as one.\n *\n * @group Collections\n */\nexport function getDisplayResolver<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): EntityDisplayResolver<M, unknown> | undefined {\n const declared = getDeclaredSource(collection, role);\n return typeof declared === \"function\" ? declared : undefined;\n}\n\n/**\n * True when the collection states this role at all, in either form.\n *\n * The derivation is a guess about what a collection probably means; a statement\n * outranks it, and the heuristics that look for \"the first enum\" or \"the leading\n * relation\" have to stand down when one exists.\n *\n * @group Collections\n */\nexport function hasDeclaredDisplay<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): boolean {\n return getDeclaredSource(collection, role) !== undefined;\n}\n","import { CollectionConfig } from \"@rebasepro/types\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { getDisplayPropertyKey } from \"./entity-display\";\n\n/**\n * The property that fills a record's image slot.\n *\n * `admin.display.image` first, then six fallbacks in descending confidence —\n * the first image-typed storage property, an array of them, a URL rendered as an\n * image, and so on. The ladder stays for collections that say nothing; a\n * collection that names its picture is not guessed at.\n */\nexport function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: CollectionConfig<M>): string | undefined {\n\n const declared = getDisplayPropertyKey(collection as AdminCollection<M>, \"image\");\n if (declared) return declared;\n\n // find first storage property of type image\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // alternatively, look for the first array of images\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // also check for URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.admin?.urlPreview === \"image\") {\n return key;\n }\n }\n // and arrays of URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && property.of && !Array.isArray(property.of) && property.of.type === \"string\" && property.of.admin?.urlPreview === \"image\") {\n return key;\n }\n }\n // fallback: any storage property without explicit acceptedFiles (e.g. a generic \"picture\" field)\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage && !property.storage.acceptedFiles) {\n return key;\n }\n }\n // fallback: any array of storage properties without explicit acceptedFiles\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage && !property.of.storage.acceptedFiles) {\n return key;\n }\n }\n return undefined;\n}\n","import {\n ALL_WHERE_FILTER_OPS,\n DataType,\n DEFAULT_FILTERABLE_RELATION_KINDS,\n getDataSourceCapabilities,\n Property,\n RelationProperty,\n WhereFilterOp\n} from \"@rebasepro/types\";\n\n/**\n * Default operators offered per property type, before engine capabilities and\n * per-property narrowing are applied. These mirror what the built-in filter\n * fields can render.\n */\nconst COMPARISON_OPS: readonly WhereFilterOp[] = [\"==\", \"!=\", \">\", \">=\", \"<\", \"<=\"];\nconst NULL_CHECK_OPS: readonly WhereFilterOp[] = [\"is-null\", \"is-not-null\"];\nconst MEMBERSHIP_OPS: readonly WhereFilterOp[] = [\"in\", \"not-in\"];\nconst PATTERN_OPS: readonly WhereFilterOp[] = [\"like\", \"ilike\", \"not-like\", \"not-ilike\"];\n\nconst DEFAULT_OPS_BY_TYPE: Partial<Record<DataType, readonly WhereFilterOp[]>> = {\n string: [...COMPARISON_OPS, ...MEMBERSHIP_OPS, ...PATTERN_OPS, ...NULL_CHECK_OPS],\n number: [...COMPARISON_OPS, ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS],\n date: [...COMPARISON_OPS, ...NULL_CHECK_OPS],\n boolean: [\"==\", \"!=\", ...NULL_CHECK_OPS],\n reference: [\"==\", \"!=\", ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS],\n relation: [\"==\", \"!=\", ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS]\n // geopoint, map, vector, binary, array (as a container): not filterable\n // through the generic filter UI.\n};\n\n/** Operators offered when the property is an *array of* a filterable type. */\nconst ARRAY_OPS: readonly WhereFilterOp[] = [\"array-contains\", \"array-contains-any\"];\n\n/**\n * Item types an array can be filtered by — the ones a filter field can take a\n * single item value for. An array of booleans, maps or geopoints is not: the\n * dialog used to offer `array-contains` for every item type, so an array of\n * maps listed a row with nothing to fill in.\n */\nconst ARRAY_ITEM_FILTERABLE_TYPES: readonly DataType[] = [\"string\", \"number\", \"date\", \"reference\", \"relation\"];\n\n/**\n * Whether a relation is one the collection's engine can compile into a\n * `WHERE`.\n *\n * Which kinds those are is the *driver's* answer, not this function's, so it\n * comes from {@link DataSourceCapabilities.filterableRelationKinds}. The admin\n * is one UI over Postgres, MongoDB, Firestore and whatever a developer\n * registers, and \"a many-to-many compiles to an `EXISTS` over the junction\" is\n * a fact about the Postgres driver — true today, and not the sort of thing to\n * assert on an engine's behalf.\n *\n * Offering an uncompilable filter is not a cosmetic bug. The Postgres driver\n * used to drop a filter key it could not resolve, which *widened* the result\n * set — filtering a many-to-many column returned every row instead of none.\n * That now fails closed with a 400, which is correct for a real schema drift\n * and wrong as the answer to a control the admin itself put on screen.\n *\n * A relation whose kind cannot be determined at all — no inline `relation`\n * block and no stamped `resolvedRelation` — stays filterable. The server\n * resolves relations before the config reaches the admin, so this is the\n * hand-built-property case, and silently dropping a working filter there would\n * be its own regression.\n */\nexport function isFilterableRelation(property: Property, engine?: string): boolean {\n if (property.type !== \"relation\") return true;\n const relationProperty = property as RelationProperty;\n const kind = relationProperty.relation?.kind ?? relationProperty.resolvedRelation?.kind;\n if (!kind) return true;\n const kinds = getDataSourceCapabilities(engine).filterableRelationKinds\n ?? DEFAULT_FILTERABLE_RELATION_KINDS;\n return kinds.includes(kind);\n}\n\nexport interface ResolveFilterOperatorsParams {\n /**\n * The property to filter on. For array properties, pass the **item**\n * property (`property.of`) together with `isArray: true` — the same\n * convention the filter field dispatchers use.\n */\n property: Property;\n /** True when filtering an array of `property`. */\n isArray?: boolean;\n /**\n * The engine backing the collection (`collection.engine`, e.g.\n * `\"postgres\"`, `\"firestore\"`). Falls back to the default engine's\n * capabilities when omitted.\n */\n engine?: string;\n}\n\n/**\n * Resolve which filter operators the UI should offer for a property.\n *\n * The result is the **intersection** of three sets:\n * 1. what the engine can execute — {@link DataSourceCapabilities.filterOperators}\n * (e.g. Firestore cannot run the LIKE family);\n * 2. what makes sense for the property type (e.g. no `>` on booleans);\n * 3. the developer's optional narrowing — `property.admin.filterOperators`.\n *\n * Returns an empty array when the property is not filterable — by type, by\n * developer narrowing (`filterOperators: []`), or because it is a relation the\n * query layer has no column for (see {@link isFilterableRelation}).\n *\n * @group Models\n */\nexport function resolveFilterOperators({\n property,\n isArray,\n engine\n}: ResolveFilterOperatorsParams): WhereFilterOp[] {\n if (!isFilterableRelation(property, engine)) return [];\n\n const typeDefaults: readonly WhereFilterOp[] = isArray\n ? (ARRAY_ITEM_FILTERABLE_TYPES.includes(property.type) ? ARRAY_OPS : [])\n : DEFAULT_OPS_BY_TYPE[property.type] ?? [];\n if (typeDefaults.length === 0) return [];\n\n const engineOps = new Set(getDataSourceCapabilities(engine).filterOperators ?? ALL_WHERE_FILTER_OPS);\n\n const narrowing = property.admin?.filterOperators;\n const narrowingSet = narrowing !== undefined ? new Set(narrowing) : undefined;\n\n return typeDefaults.filter(op =>\n engineOps.has(op) && (narrowingSet === undefined || narrowingSet.has(op)));\n}\n\n/**\n * Whether a property can be filtered at all — the one answer the table header\n * and the filters dialog both give.\n *\n * They used to answer it with a predicate each, and disagreed: the header\n * allowed an array only of strings, numbers, dates, references and relations;\n * the dialog allowed an array of anything, and listed an array of maps with an\n * empty control. The header, for its part, ignored both the developer's\n * `filterOperators: []` and a custom `admin.Filter`.\n *\n * A property with a custom filter field is filterable: the developer owns that\n * field. Otherwise it is filterable when at least one operator survives\n * {@link resolveFilterOperators} — for an array, on its item type. A tuple\n * array (`of: [a, b]`) has no single item type to filter by.\n *\n * @group Models\n */\nexport function isPropertyFilterable(property: Property, engine?: string): boolean {\n const isArray = property.type === \"array\";\n const base = isArray\n ? (property.of && !Array.isArray(property.of) ? property.of : undefined)\n : property;\n if (!base) return false;\n if (base.admin?.Filter) return true;\n return resolveFilterOperators({ property: base, isArray, engine }).length > 0;\n}\n","/**\n * Form layout resolution.\n *\n * Turns a collection into the shape the entity form renders: an ordered list of\n * sections holding grid-spanned fields, plus the metadata rail beside them.\n *\n * The reason this is a pure function rather than logic inside the form is that\n * the *defaults* are the interesting part. A collection that never writes an\n * `admin.form` block still has to get a two-column layout out of this once it is\n * long enough to need one — the flat run of full-width fields it produced before\n * was the single biggest cost in the form, and no amount of config would have fixed it for collections nobody\n * hand-tunes. Deriving it here means it is testable in isolation, which matters\n * because \"what span does a date get\" is exactly the kind of rule that rots.\n */\nimport type {\n AdminCollection,\n FormSection,\n PropertySpan\n} from \"@rebasepro/cms-types\";\nimport type { Property } from \"@rebasepro/types\";\nimport { getDisplayPropertyKey } from \"./entity-display\";\nimport { isHidden } from \"./property_presentation\";\n\n/**\n * Columns in the form grid.\n *\n * A local literal rather than an import of `FORM_GRID_COLUMNS`: everything else\n * this module takes from `@rebasepro/cms-types` is a *type*, erased at build\n * time, and a runtime value would make this pure function depend on that\n * package's built output — which is exactly what broke the dev server, since\n * `@rebasepro/app` resolves that package to its dist. `satisfies PropertySpan`\n * keeps the two honest: a full-width field and the column count are the same\n * number by definition.\n */\nconst GRID_COLUMNS = 4 satisfies PropertySpan;\n\n/**\n * The most fields a form can hold and still be laid out as one column.\n *\n * Columns are a density tool: they buy back height on a form long enough to\n * scroll. A form this short fits on any surface without scrolling, so pairing\n * its fields buys nothing and costs the reading order — the eye zig-zags across\n * values that are next to each other only because of their types. The users\n * form was the case that showed it: Email beside Name, then Roles alone on the\n * row below, in a dialog with room to spare.\n */\nconst SINGLE_COLUMN_MAX_FIELDS = 4;\n\n/** A field placed on the grid. */\nexport interface ResolvedFormField {\n key: string;\n /** Columns occupied, out of `GRID_COLUMNS`. Ignored in the rail. */\n span: PropertySpan;\n /** True for an `additionalFields` entry rather than a property. */\n additional: boolean;\n /**\n * The span was written on the property rather than derived from its type.\n * Row filling leaves these alone: an author who wrote a width meant it.\n */\n spanExplicit?: boolean;\n}\n\nexport interface ResolvedFormSection {\n key: string;\n title?: string;\n collapsible: boolean;\n /** Initial state only; the form owns it after first interaction. */\n collapsed: boolean;\n fields: ResolvedFormField[];\n /**\n * Declared arrangement for the read-only view. Carried through untouched —\n * the resolver decides *which* fields a section holds, not how the surface\n * that renders it stacks them, and only the read view honours this.\n */\n readVariant?: \"grid\" | \"summary\";\n}\n\nexport interface ResolvedFormLayout {\n sections: ResolvedFormSection[];\n /** Fields shown in the rail. Empty means no rail fields. */\n sidebar: ResolvedFormField[];\n /** Show the read-only id/created/updated block at the foot of the rail. */\n showRecordMeta: boolean;\n /** True when there is anything at all to put in the rail. */\n hasRail: boolean;\n}\n\nexport interface ResolveFormLayoutParams<M extends Record<string, unknown>> {\n collection: AdminCollection<M>;\n /**\n * Field keys in render order, already filtered by `propertiesOrder` — i.e.\n * the output of `getFormFieldKeys`. Passed in rather than recomputed so the\n * form and the layout can never disagree about which fields exist.\n */\n fieldKeys: string[];\n /**\n * Which fields the user may edit right now. A manual id is editable while\n * creating and frozen afterwards, and that decides whether it belongs in the\n * form at all or only in the record block.\n */\n status: \"new\" | \"existing\" | \"copy\";\n}\n\n/* -------------------------------------------------------------------------- */\n/* span derivation */\n/* -------------------------------------------------------------------------- */\n\n/** Does this property's editor need the full width of the column? */\nfunction needsFullWidth(property: Property): boolean {\n switch (property.type) {\n case \"map\":\n case \"binary\":\n case \"vector\":\n return true;\n case \"array\": {\n // A tag-style array of plain short strings reads fine at half width.\n // Anything else — files, nested maps, `oneOf` blocks — does not.\n if (property.oneOf) return true;\n const of = Array.isArray(property.of) ? undefined : property.of;\n if (!of) return true;\n if (of.type !== \"string\" && of.type !== \"number\") return true;\n if (of.type === \"string\" && (of.storage || of.admin?.markdown || of.admin?.multiline)) return true;\n return false;\n }\n case \"string\":\n return Boolean(property.storage || property.admin?.markdown || property.admin?.multiline);\n default:\n return false;\n }\n}\n\n/**\n * The span a property gets when nothing is declared.\n *\n * Deliberately coarse: three buckets, chosen by how much room the *editor*\n * needs, not by how important the field is. Importance is what `admin.form`\n * sections are for.\n */\nexport function deriveSpan(property: Property, isTitleProperty: boolean): PropertySpan {\n if (needsFullWidth(property)) return 4;\n // The record's name carries the row on its own; it is the first thing read.\n if (isTitleProperty) return 4;\n switch (property.type) {\n case \"number\":\n case \"boolean\":\n return 1;\n case \"date\":\n case \"geopoint\":\n case \"reference\":\n case \"relation\":\n return 2;\n case \"array\":\n return 2; // short primitive arrays only — the rest returned 4 above\n case \"string\":\n return 2;\n default:\n return 2;\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* id handling */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Can the user still type this id?\n *\n * A `manual` id is a real field while creating and frozen once the row exists.\n * Every generated strategy (`uuid`, `cuid`, a raw SQL default) is never typed.\n * Getting this wrong in the \"frozen\" direction would make manual-id collections\n * uncreatable, so it fails towards showing the field.\n */\nexport function isIdPropertyEditable(property: Property, status: \"new\" | \"existing\" | \"copy\"): boolean {\n if (!(\"isId\" in property) || !property.isId) return true;\n if (status === \"existing\") return false;\n return property.isId === \"manual\";\n}\n\nfunction isIdProperty(property: Property | undefined): boolean {\n return Boolean(property && \"isId\" in property && property.isId);\n}\n\n/**\n * An audit timestamp the database maintains — `created_at`, `updated_at`.\n *\n * Not a guess from the name: `autoValue` says the column is written by the\n * system on create or update, so the field is never typed. Rendering it as an\n * input in the middle of the form promised an edit that cannot happen, and the\n * record block already shows both values — the same two dates twice on one\n * screen.\n */\nexport function isAuditTimestamp(property: Property | undefined): boolean {\n return Boolean(\n property\n && property.type === \"date\"\n && property.autoValue\n );\n}\n\n/**\n * Close the trailing gap in each row.\n *\n * Without this a section of half-width fields with an odd count leaves a hole —\n * `name | sku` then `brand | ␣␣` — a field stranded beside half a row of\n * nothing, which reads as a mistake rather than a layout. The remainder is\n * spread across the row's derived fields rather than dumped on the last one, so\n * a lone half-width field becomes full width and a pair grows evenly. Fields\n * with an explicit span are never resized.\n */\nexport function fillRows(fields: ResolvedFormField[]): ResolvedFormField[] {\n const rows: ResolvedFormField[][] = [];\n let row: ResolvedFormField[] = [];\n let used = 0;\n\n for (const field of fields) {\n if (used + field.span > GRID_COLUMNS && row.length) {\n rows.push(row);\n row = [];\n used = 0;\n }\n row.push(field);\n used += field.span;\n }\n if (row.length) rows.push(row);\n\n return rows.flatMap(entries => {\n const total = entries.reduce((sum, f) => sum + f.span, 0);\n let gap = GRID_COLUMNS - total;\n if (gap <= 0) return entries;\n\n // Spread the remainder across the row's derived fields rather than\n // dumping it all on the last one: two half-width fields beside a gap\n // become two three-quarter fields, not one full-width and one half.\n // Fields with an explicit span keep it — the author picked that width.\n const growable = entries\n .map((f, i) => [f, i] as const)\n .filter(([f]) => !f.spanExplicit);\n\n if (!growable.length) return entries;\n\n const next = [...entries];\n let cursor = 0;\n while (gap > 0) {\n const [, index] = growable[cursor % growable.length];\n next[index] = { ...next[index], span: (next[index].span + 1) as PropertySpan };\n gap -= 1;\n cursor += 1;\n }\n return next;\n });\n}\n\n/* -------------------------------------------------------------------------- */\n/* resolution */\n/* -------------------------------------------------------------------------- */\n\nfunction buildField<M extends Record<string, unknown>>(\n key: string,\n collection: AdminCollection<M>,\n titlePropertyKey: string | undefined\n): ResolvedFormField | undefined {\n const property = collection.properties?.[key] as Property | undefined;\n\n if (!property) {\n // An additionalFields entry: a rendered card, not an input. Full width,\n // because we have no idea what the Builder puts inside it.\n const additional = collection.additionalFields?.some(f => f.key === key);\n return additional ? { key, span: 4, additional: true } : undefined;\n }\n\n if (isHidden(property)) return undefined;\n\n const admin = property.admin;\n const explicit = admin?.span !== undefined;\n const span: PropertySpan = admin?.span ?? deriveSpan(property, key === titlePropertyKey);\n\n return { key, span, additional: false, spanExplicit: explicit };\n}\n\n/**\n * Resolve the layout for a collection's generated form.\n *\n * Never drops a field: anything not named by a section lands in a trailing\n * group, so adding a column to the database cannot make it silently invisible\n * in the panel.\n */\nexport function resolveFormLayout<M extends Record<string, unknown>>({\n collection,\n fieldKeys,\n status\n}: ResolveFormLayoutParams<M>): ResolvedFormLayout {\n\n const config = collection.form;\n const titlePropertyKey = getDisplayPropertyKey(collection, \"title\");\n\n const available = new Map<string, ResolvedFormField>();\n for (const key of fieldKeys) {\n const field = buildField(key, collection, titlePropertyKey);\n if (field) available.set(key, field);\n }\n\n /* ---- the id ---------------------------------------------------------- */\n // A single surrogate key is routed out of the form and into the record\n // block, unless it is still typeable. This is what `hideIdFromForm` used to\n // be for; that flag now only decides whether the record block shows it.\n //\n // A COMPOSITE key is not. Postgres has no `id` — a row is addressed by one\n // or more real columns, and `entity.id` is a token we synthesise on top\n // (`a:::b`, see `buildCompositeId`). When the key spans several columns\n // those columns are data: on a junction row, `order_id` and `product_id`\n // are *which order* and *which product*. Hiding them behind an address\n // nobody can read would remove the only meaningful thing on the form.\n const idKeys = [...available.keys()].filter(key =>\n isIdProperty(collection.properties?.[key] as Property | undefined));\n\n if (idKeys.length === 1) {\n const property = collection.properties?.[idKeys[0]] as Property;\n if (!isIdPropertyEditable(property, status)) {\n available.delete(idKeys[0]);\n }\n }\n\n /* ---- audit timestamps ------------------------------------------------ */\n // Same treatment as the id, and for the same reason: the record block shows\n // them, so leaving them in the column renders each date twice — once as a\n // disabled input the user cannot change, once as metadata.\n const showRecordMetaResolved = config?.showRecordMeta ?? !collection.hideIdFromForm;\n if (showRecordMetaResolved) {\n for (const key of [...available.keys()]) {\n const property = collection.properties?.[key] as Property | undefined;\n // An explicit `sidebar` entry wins — the author asked for it there.\n if (config?.sidebar?.includes(key as never)) continue;\n if (isAuditTimestamp(property)) available.delete(key);\n }\n }\n\n /* ---- the rail -------------------------------------------------------- */\n const sidebar: ResolvedFormField[] = [];\n if (config?.sidebar) {\n for (const key of config.sidebar as string[]) {\n const field = available.get(key);\n if (!field) continue; // unknown, hidden, or already the id\n sidebar.push(field);\n available.delete(key);\n }\n }\n\n const showRecordMeta = showRecordMetaResolved;\n\n /* ---- sections -------------------------------------------------------- */\n const sections: ResolvedFormSection[] = [];\n\n if (config?.sections?.length) {\n for (const section of config.sections as FormSection<M>[]) {\n const fields: ResolvedFormField[] = [];\n for (const key of section.properties as string[]) {\n const field = available.get(key);\n if (!field) continue;\n fields.push(field);\n available.delete(key);\n }\n const titled = Boolean(section.title);\n sections.push({\n key: section.key,\n title: section.title,\n collapsible: section.collapsible ?? titled,\n collapsed: titled ? Boolean(section.collapsed) : false,\n fields,\n readVariant: section.readVariant\n });\n }\n }\n\n // Whatever no section claimed. Appended rather than dropped — a new column\n // showing up unstyled is recoverable, a new column vanishing is not.\n const leftovers = fieldKeys\n .map(key => available.get(key))\n .filter((f): f is ResolvedFormField => Boolean(f));\n\n if (leftovers.length) {\n // Always a trailing group, never merged into an existing section. Folding\n // them into the first untitled section put `created_at`/`updated_at`\n // between the product's images and its pricing — the reader cannot tell\n // \"we grouped this here\" from \"nobody placed this yet\", and the second is\n // what actually happened.\n sections.push({\n key: sections.length ? \"__other\" : \"__main\",\n collapsible: false,\n collapsed: false,\n fields: leftovers\n });\n }\n\n // A short form is one column. Only the derived widths change: a span the\n // author wrote is kept, because they meant it. Counted across the whole\n // form rather than per section, so one form never mixes the two rules.\n const fieldCount = sections.reduce((sum, section) => sum + section.fields.length, 0);\n const singleColumn = fieldCount <= SINGLE_COLUMN_MAX_FIELDS;\n\n // A configured section that ended up empty (every key hidden, unknown, or\n // claimed by the rail) would render as a heading over nothing.\n const nonEmpty = sections\n .filter(s => s.fields.length > 0)\n .map(s => ({\n ...s,\n fields: fillRows(singleColumn\n ? s.fields.map(f => f.spanExplicit ? f : { ...f, span: GRID_COLUMNS })\n : s.fields)\n }));\n\n return {\n sections: nonEmpty,\n sidebar,\n showRecordMeta,\n hasRail: sidebar.length > 0 || showRecordMeta\n };\n}\n","\n\nimport { getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n\nexport function addInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s;\n else return `/${s}`;\n}\n\nexport function getLastSegment(path: string) {\n const cleanPath = removeInitialAndTrailingSlashes(path);\n if (cleanPath.includes(\"/\")) {\n const segments = cleanPath.split(\"/\");\n return segments[segments.length - 1];\n }\n return cleanPath;\n}\n\nexport function resolveCollectionPathIds(path: string, allCollections: AdminCollection[]): string {\n let remainingPath = removeInitialAndTrailingSlashes(path);\n if (!remainingPath) {\n return \"\";\n }\n\n let currentCollections: AdminCollection[] | undefined = allCollections;\n const resolvedPathParts: string[] = [];\n\n while (remainingPath.length > 0) {\n if (!currentCollections || currentCollections.length === 0) {\n // We have remaining path segments but no more collections to match against\n console.warn(`resolveCollectionPathIds: Path structure implies subcollections, but none found before segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath);\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n let foundMatch = false;\n // Sort potential matches by length descending to prioritize longer matches (e.g., \"a/b\" over \"a\")\n const potentialMatches: { col: AdminCollection; match: string; }[] = currentCollections\n .flatMap(col => [{\n col,\n match: col.slug\n }])\n // Whole segments only: a bare `startsWith` read `users/abc123` as the\n // collection `user` followed by the id `s`.\n .filter(p => p.match && (remainingPath === p.match || remainingPath.startsWith(`${p.match}/`)))\n .sort((a, b) => b.match.length - a.match.length);\n\n if (potentialMatches.length > 0) {\n const {\n col: foundCollection,\n match: matchString\n } = potentialMatches[0];\n\n resolvedPathParts.push(foundCollection.slug); // Use the defined path\n remainingPath = removeInitialSlash(remainingPath.substring(matchString.length));\n\n // Check if we are at the end of the path\n if (remainingPath.length === 0) {\n foundMatch = true;\n break; // Path ends with a collection segment\n }\n\n // The next segment must be a entity ID\n const idSeparatorIndex = remainingPath.indexOf(\"/\");\n let entityId: string | number;\n if (idSeparatorIndex > -1) {\n entityId = remainingPath.substring(0, idSeparatorIndex);\n remainingPath = remainingPath.substring(idSeparatorIndex + 1);\n } else {\n // This should not happen if the original path is valid (odd segments)\n // but handle it defensively: assume the rest is the ID\n entityId = remainingPath;\n remainingPath = \"\";\n console.warn(`resolveCollectionPathIds: Path seems to end with a entity ID \"${entityId}\" instead of a collection segment in original path \"${path}\". This might indicate an invalid input path.`);\n // Even if it ends here, we still need to push the ID\n }\n\n resolvedPathParts.push(entityId); // Append entity ID\n currentCollections = getSubcollections(foundCollection); // Move to subcollections\n foundMatch = true;\n\n if (!currentCollections && remainingPath.length > 0) {\n // Warn if the path continues but no subcollections were defined\n console.warn(`resolveCollectionPathIds: Path continues after entity ID \"${entityId}\", but no subcollections are defined for the preceding collection \"${foundCollection.slug}\" in path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n }\n\n if (!foundMatch) {\n // Collection definition not found for the start of the remaining path\n console.warn(`resolveCollectionPathIds: Collection definition not found for segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n }\n\n return resolvedPathParts.join(\"/\");\n}\n\n/**\n * Find the corresponding view at any depth for a given path.\n * Note that path or segments of the paths can be collection aliases.\n * @param slugOrPath\n * @param collections\n */\nexport function getCollectionBySlugWithin(slugOrPath: string, collections: AdminCollection[]): AdminCollection | undefined {\n\n const path = removeInitialAndTrailingSlashes(slugOrPath);\n const subpathCombinations = getCollectionPathsCombinations(path.split(\"/\"));\n let result: AdminCollection | undefined;\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n const navigationEntry = collections && collections\n .sort((a, b) => (a.slug ?? \"\").localeCompare(b.slug ?? \"\"))\n .find((entry) => entry.slug === subpathCombination);\n\n if (navigationEntry) {\n // Counted from where the slug ends, not over the whole path, whose\n // count the slug's own slashes would decide. What follows a\n // collection pairs up as (entity id, subcollection), so an odd\n // remainder ends at a record.\n const rest = path.split(\"/\").slice(subpathCombination.split(\"/\").length);\n if (rest.length % 2 !== 0) {\n throw Error(`getCollectionBySlug: Collection paths must end at a collection, not at a record: ${slugOrPath}`);\n }\n if (rest.length === 0) {\n result = navigationEntry;\n } else if (getSubcollections(navigationEntry).length > 0) {\n result = getCollectionBySlugWithin(rest.slice(1).join(\"/\"), getSubcollections(navigationEntry));\n }\n }\n if (result) break;\n }\n return result;\n}\n\n/**\n * Every leading run of whole segments of a path, longest first: the\n * candidates for the collection the path starts with.\n * \"sites/es/locales\" => [\"sites/es/locales\", \"sites/es\", \"sites\"]\n *\n * Every length, not only the odd ones. A slug may contain slashes, so\n * `content/podcasts/abc123/episodes` starts with the two-segment collection\n * `content/podcasts`, and a path's own segment count says nothing about where\n * its first collection ends.\n * @param subpaths\n */\nexport function getCollectionPathsCombinations(subpaths: string[]): string[] {\n const result: string[] = [];\n for (let i = subpaths.length; i > 0; i--) {\n result.push(subpaths.slice(0, i).join(\"/\"));\n }\n return result;\n}\n","\ntype EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = { key: string; [key: string]: unknown };\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\nexport type NavigationViewInternal<M extends Record<string, unknown> = Record<string, unknown>> =\n | NavigationViewEntityInternal<M>\n | NavigationViewCollectionInternal<M>\n | NavigationViewEntityCustomInternal<M>;\n\nexport interface NavigationViewEntityInternal<M extends Record<string, unknown>> {\n type: \"entity\";\n entityId: string | number;\n slug: string;\n path: string;\n parentCollection: AdminCollection<M>;\n}\n\nexport interface NavigationViewCollectionInternal<M extends Record<string, unknown>> {\n type: \"collection\";\n id: string;\n slug: string;\n path: string;\n collection: AdminCollection<M>;\n}\n\nexport interface NavigationViewEntityCustomInternal<M extends Record<string, unknown>> {\n type: \"custom_view\";\n slug: string;\n path: string;\n entityId: string | number;\n view: EntityCustomView<M>;\n}\n\nexport function getNavigationEntriesFromPath(props: {\n path: string,\n collections: AdminCollection[] | undefined,\n currentFullPath?: string,\n contextEntityViews?: EntityCustomView[]\n}): NavigationViewInternal[] {\n\n const {\n path,\n collections = [],\n currentFullPath\n } = props;\n\n const subpaths = removeInitialAndTrailingSlashes(path).split(\"/\");\n const subpathCombinations = getCollectionPathsCombinations(subpaths);\n\n const result: NavigationViewInternal[] = [];\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n\n const collection = collections && collections.find((entry) => entry.slug === subpathCombination);\n\n if (collection) {\n const collectionPath = currentFullPath && currentFullPath.length > 0\n ? (currentFullPath + \"/\" + collection.slug)\n : collection.slug;\n result.push({\n type: \"collection\",\n id: collection.slug,\n slug: collectionPath,\n path: collectionPath,\n collection\n });\n const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, \"\"));\n const nextSegments = restOfThePath.length > 0 ? restOfThePath.split(\"/\") : [];\n if (nextSegments.length > 0) {\n const entityId = nextSegments[0];\n const path = collectionPath + \"/\" + entityId;\n result.push({\n type: \"entity\",\n entityId,\n slug: collectionPath,\n path,\n parentCollection: collection\n });\n if (nextSegments.length > 1) {\n const newPath = nextSegments.slice(1).join(\"/\");\n if (!collection) {\n throw Error(\"collection not found resolving path: \" + collection);\n }\n const entityViews = collection.entityViews;\n const customView = entityViews && entityViews\n .map((entry) => resolveEntityView(entry, props.contextEntityViews))\n .filter((v): v is EntityCustomView => v != null)\n .find((entry) => entry.key === newPath);\n const subcollections = getSubcollections(collection);\n if (customView) {\n result.push({\n type: \"custom_view\",\n slug: collectionPath,\n entityId: entityId,\n path: path + \"/\" + customView.key,\n view: customView\n });\n } else if (subcollections) {\n result.push(...getNavigationEntriesFromPath({\n path: newPath,\n collections: subcollections,\n currentFullPath: path,\n contextEntityViews: props.contextEntityViews\n }));\n }\n }\n }\n break;\n }\n\n }\n return result;\n}\n\nfunction resolveEntityView(entityView: string | EntityCustomView, contextEntityViews?: EntityCustomView[]): EntityCustomView | undefined {\n if (typeof entityView === \"string\") {\n return contextEntityViews?.find((entry) => entry.key === entityView);\n } else {\n return entityView;\n }\n}\n","import { EntityReference } from \"@rebasepro/types\";\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\nexport function getParentReferencesFromPath(props: {\n path: string,\n collections: AdminCollection[] | undefined,\n currentFullPath?: string,\n}): EntityReference[] {\n\n const {\n path,\n collections = [],\n currentFullPath\n } = props;\n\n const subpaths = removeInitialAndTrailingSlashes(path).split(\"/\");\n const subpathCombinations = getCollectionPathsCombinations(subpaths);\n\n const result: EntityReference[] = [];\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n\n const collection: AdminCollection | undefined = collections && collections.find((entry) => entry.slug === subpathCombination);\n\n // If we find a collection, we add the reference and continue\n if (collection) {\n const collectionPath = currentFullPath && currentFullPath.length > 0\n ? (currentFullPath + \"/\" + collection.slug) // Use the current full path if provided\n : collection.slug;\n\n const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, \"\"));\n const nextSegments = restOfThePath.length > 0 ? restOfThePath.split(\"/\") : [];\n if (nextSegments.length > 0) {\n const entityId = nextSegments[0];\n const path = collectionPath + \"/\" + entityId;\n result.push(new EntityReference({ id: entityId,\npath: collectionPath }));\n if (nextSegments.length > 1) {\n const newPath = nextSegments.slice(1).join(\"/\");\n if (!collection) {\n throw Error(\"collection not found resolving path: \" + collection);\n }\n if (getSubcollections(collection).length > 0) {\n result.push(...getParentReferencesFromPath({\n path: newPath,\n collections: getSubcollections(collection),\n currentFullPath: path\n }));\n }\n }\n }\n break;\n }\n\n }\n return result;\n}\n","import { isRelationalCollectionConfig, type Property, type Relation } from \"@rebasepro/types\";\nimport { generateForeignKeyName } from \"@rebasepro/utils\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { getPrimaryKeys, isPropertyBuilder } from \"@rebasepro/common\";\nimport { getPropertyInPath } from \"./property-path\";\nimport { getDisplayPropertyKey, hasDeclaredDisplay } from \"./entity-display\";\nimport { isStorageProperty } from \"./summary-property\";\n\n/**\n * How good a property is as the human-readable title of an entity.\n * Higher wins; ties are broken by declaration order.\n * `DISQUALIFIED` means the property can never be a title.\n */\nconst SCORE = {\n DISQUALIFIED: -1,\n /**\n * Points at another entity. Only readable once the target resolves, and it\n * renders as the raw key until then — last resort, for collections (like\n * junction tables) that hold no text of their own.\n */\n REFERENCE: 5,\n RELATION: 10,\n /** A user picker: resolves to a person's name, like a relation does */\n USER: 10,\n /** Long form text — readable, but a description, not a name */\n LONG_TEXT: 20,\n /** A closed set of values: shared by many rows, so it identifies nothing */\n ENUM: 30,\n /** Identifying, but PII and usually secondary to a name */\n EMAIL: 45,\n /** Any plain, short, free text field */\n PLAIN_TEXT: 60,\n /** Free text whose name says it holds the entity's label */\n NAMED: 100\n} as const;\n\n/**\n * Keys whose name states outright that the property is the entity label.\n * This is a *bonus* on top of the structural rules — never a requirement, and\n * never the mechanism that keeps identifiers out of the title slot.\n */\nconst TITLE_LIKE_KEYS = new Set([\n \"name\",\n \"fullname\",\n \"displayname\",\n \"title\",\n \"label\",\n \"heading\",\n \"subject\",\n \"username\",\n \"nickname\"\n]);\n\nfunction normalizeKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nfunction isHidden(property: Property): boolean {\n return Boolean(property.admin?.hideFromCollection);\n}\n\n/**\n * Every column on this collection that stores a foreign key: the `localKey` of\n * each owning relation (declared inline on a property or in `relations[]`), the\n * source column of a junction, and the key a many-to-many joins on.\n *\n * These hold another entity's id, so they must never fill the title slot even\n * though they are declared as plain strings.\n */\nfunction getForeignKeyColumns<M extends Record<string, unknown>>(collection: AdminCollection<M>): Set<string> {\n const keys = new Set<string>();\n\n const addRelationKeys = (relation: Relation) => {\n switch (relation.kind) {\n case \"belongsTo\":\n // Left to be inferred, the column still takes the conventional\n // `<relation>_id` name.\n keys.add(relation.localKey ?? generateForeignKeyName(relation.relationName ?? \"\"));\n break;\n case \"manyToMany\":\n if (relation.through?.sourceColumn) keys.add(relation.through.sourceColumn);\n break;\n case \"via\": {\n // Only the first hop starts on this collection's table.\n const from = relation.joinPath?.[0]?.on?.from;\n for (const column of Array.isArray(from) ? from : [from]) {\n if (column) keys.add(column);\n }\n break;\n }\n default:\n // hasOne / hasMany put their column on the *target*.\n break;\n }\n };\n\n for (const relation of (isRelationalCollectionConfig(collection) ? collection.relations : undefined) ?? []) {\n addRelationKeys(relation);\n }\n\n for (const [key, propertyRaw] of Object.entries(collection.properties ?? {})) {\n const property = propertyRaw as Property | undefined;\n if (!property || isPropertyBuilder(property) || property.type !== \"relation\") continue;\n if (property.relation) {\n addRelationKeys({ ...property.relation,\nrelationName: property.relation.relationName ?? key });\n }\n }\n\n return keys;\n}\n\n/**\n * True when the property is declared to hold an opaque identifier rather than\n * something a person reads: a primary key, a foreign key, a UUID column, or a\n * picker bound to an auth user id. Decided from the property *schema*, never\n * from the key name.\n */\nfunction isIdentifierProperty(property: Property, key: string, idKeys: Set<string>, foreignKeys: Set<string>): boolean {\n if (idKeys.has(key)) return true;\n if (foreignKeys.has(key)) return true;\n if (\"isId\" in property && property.isId) return true;\n if (property.type === \"string\" && property.columnType === \"uuid\") return true;\n return false;\n}\n\nfunction scoreTitleCandidate(property: Property, key: string, idKeys: Set<string>, foreignKeys: Set<string>): number {\n if (isHidden(property)) return SCORE.DISQUALIFIED;\n if (isIdentifierProperty(property, key, idKeys, foreignKeys)) return SCORE.DISQUALIFIED;\n if (isStorageProperty(property)) return SCORE.DISQUALIFIED;\n\n if (property.type === \"relation\") {\n const isMany = property.resolvedRelation\n ? property.resolvedRelation.cardinality === \"many\"\n : property.relation?.kind === \"hasMany\" || property.relation?.kind === \"manyToMany\";\n return isMany ? SCORE.DISQUALIFIED : SCORE.RELATION;\n }\n if (property.type === \"reference\") {\n return SCORE.REFERENCE;\n }\n if (property.type !== \"string\") {\n // Numbers, dates, booleans, maps and arrays never read as a title.\n return SCORE.DISQUALIFIED;\n }\n\n // A user picker stores an auth user id but renders the person behind it, so\n // it ranks with relations: usable as a title, but only as a last resort.\n if (property.userSelect) return SCORE.USER;\n if (property.enum) return SCORE.ENUM;\n if (property.admin?.multiline || property.admin?.markdown) return SCORE.LONG_TEXT;\n if (property.email) return SCORE.EMAIL;\n if (TITLE_LIKE_KEYS.has(normalizeKey(key))) return SCORE.NAMED;\n return SCORE.PLAIN_TEXT;\n}\n\n/**\n * All properties that could serve as the entity title, best first.\n *\n * Candidates are ranked from the property *schema* — identifiers (primary\n * keys, foreign keys, UUID columns, user pickers), images and hidden fields are\n * excluded structurally, so a collection whose id column is called something\n * other than `id` is handled the same as one where it isn't.\n *\n * When the collection declares `propertiesOrder` the developer has already\n * stated what comes first, so qualifying candidates keep that order; otherwise\n * they are ranked (a name beats a description beats a relation).\n *\n * @group Collections\n */\nexport function getTitlePropertyCandidates<M extends Record<string, unknown>>(\n collection: AdminCollection<M>\n): string[] {\n if (!collection.properties) return [];\n\n // `getPropertyInPath`, not `properties[key]`: a declared title on a nested\n // field — `profile.display_name` — was looked up flat, found nothing, and\n // silently fell through to the derived ranking. The dotted form has been\n // documented as valid the whole time.\n const declared = getDisplayPropertyKey(collection, \"title\");\n if (declared && getPropertyInPath(collection.properties, declared)) {\n return [declared];\n }\n\n const idKeys = new Set<string>(getPrimaryKeys(collection) as string[]);\n const foreignKeys = getForeignKeyColumns(collection);\n const explicitOrder = collection.propertiesOrder as string[] | undefined;\n const order = explicitOrder ?? Object.keys(collection.properties);\n\n const scored: { key: string; score: number; index: number }[] = [];\n order.forEach((key, index) => {\n const property = collection.properties[key];\n if (!property || isPropertyBuilder(property)) return;\n const score = scoreTitleCandidate(property as Property, key, idKeys, foreignKeys);\n if (score === SCORE.DISQUALIFIED) return;\n scored.push({ key,\nscore,\nindex });\n });\n\n // An explicit `propertiesOrder` is a statement of what matters first, so it\n // wins over the ranking — the ranking only decides between properties the\n // developer never ordered.\n if (!explicitOrder) {\n scored.sort((a, b) => (b.score - a.score) || (a.index - b.index));\n }\n\n return scored.map(candidate => candidate.key);\n}\n\n/**\n * The relation a collection *leads* with, if it leads with one.\n *\n * A junction-shaped collection — a pipeline entry, a membership, a booking —\n * holds no label of its own: it is \"this candidate, for that vacancy\". The\n * general ranking puts relations last (they only read once the target\n * resolves), so the title slot would otherwise fall to whatever free text\n * happens to follow: a note, a comment. Preview surfaces that render one row\n * per entity (list, cards, board) prefer the leading relation instead.\n *\n * The decision is structural — the first property that could be a title, in the\n * order the developer declared (or ordered) them. Declaration order is a\n * statement about what the collection is about; property *names* are not\n * consulted here.\n *\n * Returns `undefined` when that first property is anything but a\n * single-cardinality relation, or when the collection states its own\n * `display.title`.\n *\n * @group Collections\n */\nexport function getLeadingRelationTitleKey<M extends Record<string, unknown>>(\n collection: AdminCollection<M>\n): string | undefined {\n if (!collection.properties) return undefined;\n // The collection states what it is called, in one form or the other; either\n // way it is not asking for the leading-relation heuristic.\n if (hasDeclaredDisplay(collection, \"title\")) return undefined;\n\n const idKeys = new Set<string>(getPrimaryKeys(collection) as string[]);\n const foreignKeys = getForeignKeyColumns(collection);\n const order = (collection.propertiesOrder as string[] | undefined) ?? Object.keys(collection.properties);\n\n for (const key of order) {\n const property = collection.properties[key];\n if (!property || isPropertyBuilder(property)) continue;\n if (scoreTitleCandidate(property as Property, key, idKeys, foreignKeys) === SCORE.DISQUALIFIED) continue;\n return (property as Property).type === \"relation\" ? key : undefined;\n }\n\n return undefined;\n}\n\n/**\n * The property that should fill the title slot for a collection, ignoring any\n * concrete values. Prefer {@link getTitlePropertyKeyForValues} when an entity\n * is at hand — it can skip candidates that happen to be empty or to hold an id.\n *\n * @group Collections\n */\nexport function getTitlePropertyKey<M extends Record<string, unknown>>(\n collection: AdminCollection<M>\n): string | undefined {\n return getTitlePropertyCandidates(collection)[0];\n}\n\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst LONG_HEX_REGEX = /^[0-9a-f]{24,}$/i;\nconst CUID_REGEX = /^c[a-z0-9]{20,}$/i;\n\n/**\n * True when a value reads as a machine identifier (UUID, ObjectId/long hex,\n * cuid) rather than as something worth showing to a person.\n *\n * @group Collections\n */\nexport function looksLikeIdentifierValue(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n return UUID_REGEX.test(trimmed) || LONG_HEX_REGEX.test(trimmed) || CUID_REGEX.test(trimmed);\n}\n\n/**\n * The title property for a concrete entity: the best-ranked candidate that\n * actually carries a readable value. Candidates that are empty, that repeat the\n * entity id, or that hold an opaque identifier are skipped, so a free-text\n * column that happens to store UUIDs never ends up as the title.\n *\n * Returns the top-ranked candidate when none of them has a usable value, so\n * callers can still render a placeholder for that property.\n *\n * @group Collections\n */\nexport function getTitlePropertyKeyForValues<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n values: Record<string, unknown> | undefined,\n entityId?: string | number\n): string | undefined {\n const candidates = getTitlePropertyCandidates(collection);\n if (!values || candidates.length === 0) return candidates[0];\n\n for (const key of candidates) {\n const value = values[key];\n if (value === undefined || value === null || value === \"\") continue;\n if (typeof value === \"string\") {\n if (looksLikeIdentifierValue(value)) continue;\n if (entityId !== undefined && value === String(entityId)) continue;\n }\n return key;\n }\n\n return candidates[0];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","names":[],"sources":["../src/core/PluginProviderStack.tsx","../src/core/PluginLifecycleManager.tsx","../src/core/deprecated_plugin_keys.ts","../src/contexts/SnackbarProvider.tsx","../src/contexts/ModeController.tsx","../src/contexts/AdminModeController.tsx","../src/contexts/EffectiveRoleController.tsx","../src/contexts/AuthControllerContext.tsx","../src/contexts/DataDriverContext.tsx","../src/contexts/DataSourcesContext.tsx","../src/contexts/RebaseDataContext.tsx","../src/contexts/AnalyticsContext.tsx","../src/contexts/StorageSourceContext.tsx","../src/contexts/StorageSourcesContext.tsx","../src/contexts/UserConfigurationPersistenceContext.tsx","../src/contexts/DialogsProvider.tsx","../src/contexts/RebaseClientInstanceContext.tsx","../src/contexts/CustomizationControllerContext.tsx","../src/contexts/ComponentOverrideContext.tsx","../src/contexts/CollectionScopeContext.tsx","../src/contexts/CollectionResolverContext.tsx","../src/contexts/RlsSimulationContext.tsx","../src/hooks/data/useData.tsx","../src/components/SchemaDriftBanner.tsx","../src/hooks/data/collectionQuery.ts","../src/collections/summary-property.ts","../src/util/previews.ts","../src/util/realtime.ts","../src/hooks/data/useStableFilterValues.ts","../src/hooks/data/useCollection.tsx","../src/hooks/data/collectionWindow.ts","../src/hooks/useAuthController.tsx","../src/hooks/useRebaseClient.tsx","../src/hooks/useStorageSource.tsx","../src/hooks/useSnackbarController.tsx","../src/hooks/useUserConfigurationPersistence.tsx","../src/hooks/useDialogsController.tsx","../src/hooks/useCustomizationController.tsx","../src/hooks/useAnalyticsController.tsx","../src/hooks/useEffectiveRoleController.tsx","../src/contexts/DatabaseAdminContext.tsx","../src/hooks/useRebaseContext.tsx","../src/hooks/data/useFetch.tsx","../src/hooks/data/useBatchedFetch.tsx","../src/hooks/data/useRelationSelector.tsx","../src/hooks/data/save.ts","../src/hooks/data/delete.ts","../src/hooks/useNavigationBlocker.tsx","../src/hooks/useUnsavedChangesDialog.tsx","../src/components/common/useScrollRestoration.tsx","../src/util/entity_cache.ts","../src/collections/entity-display-cache.ts","../src/auth/session_caches.ts","../src/hooks/useAuthSubscription.ts","../src/hooks/useAdminModeController.tsx","../src/util/local_storage.ts","../src/hooks/useBuildAdminModeController.tsx","../src/core/effective_role_state.ts","../src/hooks/useBuildEffectiveRoleController.tsx","../src/hooks/useModeController.tsx","../src/hooks/useClipboard.tsx","../src/hooks/useLargeLayout.tsx","../src/hooks/useCollapsedGroups.ts","../src/hooks/useBrowserTitleAndIcon.tsx","../src/hooks/useSlot.tsx","../src/hooks/useBuildLocalConfigurationPersistence.tsx","../src/hooks/useBuildModeController.tsx","../src/hooks/useRebaseRegistry.tsx","../src/hooks/usePermissions.ts","../src/hooks/ApiConfigContext.tsx","../src/hooks/useTranslation.ts","../src/hooks/useNavigationGroupLabel.ts","../src/hooks/useResolvedComponent.tsx","../src/hooks/useComponentOverride.tsx","../src/components/ErrorTooltip.tsx","../src/components/ErrorView.tsx","../src/components/common/useDebouncedData.ts","../src/collections/property-path.ts","../src/collections/property_presentation.ts","../src/components/common/useColumnsIds.tsx","../src/hooks/data/useDataOrder.ts","../src/components/common/useDataTableController.tsx","../src/components/common/table_height.tsx","../src/components/NotFoundPage.tsx","../src/components/ConfirmationDialog.tsx","../src/components/RebaseLogo.tsx","../src/components/AIIcon.tsx","../src/components/email-change-message.ts","../src/components/UserSettingsView.tsx","../src/locales/en.ts","../src/i18n/RebaseI18nProvider.tsx","../src/components/LanguageToggle.tsx","../src/components/UserSelectPopover.tsx","../src/components/UserDisplay.tsx","../src/components/LoginView/oauth-redirect-flow.ts","../src/components/LoginView/auth-error-message.ts","../src/components/LoginView/email-link.ts","../src/components/LoginView/mfa-required.ts","../src/components/LoginView/LoginView.tsx","../src/components/RebaseAuth.tsx","../src/components/ConnectionLostBanner.tsx","../src/components/studio/RlsSimulatorBar.tsx","../src/core/Rebase.tsx","../src/core/RebaseRouter.tsx","../src/core/RebaseRoutes.tsx","../src/auth/useRebaseAuthController.ts","../src/auth/api.ts","../src/util/icon_list.ts","../src/util/icons.tsx","../src/util/createFormexStub.tsx","../src/util/useStorageUploadController.tsx","../src/util/enums.ts","../src/util/constants.ts","../src/internal/common.tsx","../src/internal/useRestoreScroll.tsx","../src/components/UnsavedChangesDialog.tsx","../src/hooks/useStudioBridge.tsx","../src/hooks/useBridgeRegistration.tsx","../src/collections/collection_view_config.ts","../src/collections/entity-display.ts","../src/collections/entity_image_preview.ts","../src/collections/filter-operator-resolution.ts","../src/collections/form-layout.ts","../src/collections/navigation_utils.ts","../src/collections/navigation_from_path.ts","../src/collections/parent_references_from_path.ts","../src/collections/title-property.ts"],"sourcesContent":["import type { RebasePlugin } from \"@rebasepro/cms-types\";\nimport React from \"react\";\n;\n\n/**\n * Wraps children with all provider components from plugins that match the given scope.\n *\n * Replaces the 3 copy-pasted `plugins.forEach(plugin => { if (plugin.form?.provider) ... })` patterns\n * in Rebase.tsx, EditViewBinding.tsx, and PopupFormField.tsx.\n *\n * @param plugins - Array of plugins to extract providers from.\n * @param scope - `\"root\"` or `\"form\"` — which providers to apply.\n * @param scopeProps - Additional props passed to each provider component.\n * @param children - The content to wrap.\n *\n * @group Core\n */\nexport function PluginProviderStack({\n plugins,\n scope,\n scopeProps,\n children\n}: {\n plugins: RebasePlugin[];\n scope: \"root\" | \"form\";\n scopeProps?: Record<string, unknown>;\n children: React.ReactNode;\n}) {\n const providers = plugins.flatMap(p => p.providers ?? [])\n .filter(p => p.scope === scope);\n\n return providers.reduceRight<React.ReactNode>(\n (acc, provider) => (\n <provider.Component {...provider.props} {...scopeProps}>\n {acc}\n </provider.Component>\n ),\n children\n );\n}\n","\nimport { useEffect, useRef } from \"react\";\nimport type { RebasePlugin, RebaseContext } from \"@rebasepro/cms-types\";\n\n/**\n * Render-less component that manages plugin lifecycle hooks.\n *\n * - Calls `lifecycle.onMount(context)` once, the first time auth is ready.\n * - Calls `lifecycle.onAuthStateChange(user)` on every change of user after\n * that — `null` on sign-out, the new user on the next sign-in.\n * - Calls `lifecycle.onUnmount()` when the Rebase tree unmounts.\n *\n * Mounted for as long as there are plugins, signed in or not. It used to be\n * mounted only while a user was signed in, so a sign-out unmounted it and the\n * next sign-in mounted a fresh one — `onAuthStateChange` could never see the\n * user change, and never fired.\n *\n * Mount this component inside the Rebase tree, below PluginProviderStack,\n * so that the RebaseContext is fully available.\n *\n * @internal\n */\nexport function PluginLifecycleManager({\n plugins,\n context,\n authReady\n}: {\n plugins: RebasePlugin[];\n context: RebaseContext;\n /** Signed in, or sign-in skipped: what `onMount` waits for. */\n authReady: boolean;\n}) {\n const mountedRef = useRef(false);\n const prevUidRef = useRef<string | null>(null);\n const currentUser = context.authController?.user ?? null;\n\n // ── Mount ────────────────────────────────────────────────────────\n useEffect(() => {\n if (!authReady || mountedRef.current) return;\n mountedRef.current = true;\n prevUidRef.current = currentUser?.uid ?? null;\n\n for (const plugin of plugins) {\n if (plugin.lifecycle?.onMount) {\n try {\n const result = plugin.lifecycle.onMount(context);\n if (result instanceof Promise) {\n result.catch((err) =>\n console.error(`[Rebase] Plugin \"${plugin.key}\" onMount error:`, err)\n );\n }\n } catch (err) {\n console.error(`[Rebase] Plugin \"${plugin.key}\" onMount error:`, err);\n }\n }\n }\n // Once: later changes of user are `onAuthStateChange`'s.\n }, [authReady]);\n\n // ── Unmount ──────────────────────────────────────────────────────\n useEffect(() => {\n return () => {\n if (!mountedRef.current) return;\n mountedRef.current = false;\n for (const plugin of plugins) {\n if (plugin.lifecycle?.onUnmount) {\n try {\n plugin.lifecycle.onUnmount();\n } catch (err) {\n console.error(`[Rebase] Plugin \"${plugin.key}\" onUnmount error:`, err);\n }\n }\n }\n };\n // Only on unmount — plugins array identity should be stable\n }, []);\n\n // ── Auth state change ────────────────────────────────────────────\n useEffect(() => {\n // Before `onMount` there is nobody to tell.\n if (!mountedRef.current) return;\n\n // Only fire when the user identity actually changes\n const currUid = currentUser?.uid ?? null;\n if (prevUidRef.current === currUid) return;\n prevUidRef.current = currUid;\n\n for (const plugin of plugins) {\n if (plugin.lifecycle?.onAuthStateChange) {\n try {\n plugin.lifecycle.onAuthStateChange(currentUser);\n } catch (err) {\n console.error(\n `[Rebase] Plugin \"${plugin.key}\" onAuthStateChange error:`,\n err\n );\n }\n }\n }\n }, [currentUser, plugins]);\n\n return null;\n}\n","import type { RebasePlugin } from \"@rebasepro/cms-types\";\nimport { warnDeprecated } from \"@rebasepro/common\";\n\n/**\n * Warn, once per plugin and key, about plugin keys that are declared on\n * `RebasePlugin` but that nothing has ever called.\n *\n * A plugin that set one of these did nothing and said nothing about it. The\n * types mark them deprecated; this names them at runtime too, which also\n * reaches a plugin written in JavaScript.\n */\nexport function warnDeprecatedPluginKeys(plugins: readonly RebasePlugin[]): void {\n for (const plugin of plugins) {\n if (plugin.hooks?.modifyCollectionAsync !== undefined) {\n warnDeprecated(\n `plugin:${plugin.key}:hooks.modifyCollectionAsync`,\n `Plugin \"${plugin.key}\" sets \\`hooks.modifyCollectionAsync\\`, which is deprecated: ` +\n \"nothing has ever called it. Remove it: fetch what the change needs before rendering \" +\n \"`<Rebase>`, then build the plugin from that data and apply it in `hooks.modifyCollection`.\"\n );\n }\n if (plugin.lifecycle?.onCollectionChange !== undefined) {\n warnDeprecated(\n `plugin:${plugin.key}:lifecycle.onCollectionChange`,\n `Plugin \"${plugin.key}\" sets \\`lifecycle.onCollectionChange\\`, which is deprecated: ` +\n \"nothing has ever called it. Remove it and subscribe to the rows yourself instead — \" +\n \"`context.data.collection(slug).listen(...)` from `lifecycle.onMount`, unsubscribing in \" +\n \"`lifecycle.onUnmount`.\"\n );\n }\n }\n}\n","\"use client\";\n\nimport React, { PropsWithChildren } from \"react\";\nimport { SnackbarProvider as NotistackSnackbarProvider } from \"notistack\";\n\nexport const SnackbarProvider: React.FC<PropsWithChildren> = ({ children }) => {\n\n return (\n <NotistackSnackbarProvider maxSnack={3}\n preventDuplicate={true}\n autoHideDuration={3500}>\n {children}\n </NotistackSnackbarProvider>\n );\n};\n","import React from \"react\";\nimport type { ModeController } from \"../hooks/useModeController\";\n\nconst DEFAULT_MODE_STATE: ModeController = {\n mode: \"light\",\n setMode: (mode: \"light\" | \"dark\" | \"system\") => {\n }\n};\nexport const ModeControllerContext = React.createContext<ModeController>(DEFAULT_MODE_STATE);\n\nexport const ModeControllerProvider = ModeControllerContext.Provider;\n","import React from \"react\";\nimport type { AdminModeController } from \"../hooks/useAdminModeController\";\n\nconst DEFAULT_ADMIN_MODE_STATE: AdminModeController = {\n mode: \"cms\",\n setMode: (mode: \"cms\" | \"studio\") => {\n }\n};\nexport const AdminModeControllerContext = React.createContext<AdminModeController>(DEFAULT_ADMIN_MODE_STATE);\n\nexport const AdminModeControllerProvider = AdminModeControllerContext.Provider;\n","import type { EffectiveRoleController } from \"@rebasepro/types\";\nimport React from \"react\";\n;\n\nconst DEFAULT_EFFECTIVE_ROLE_STATE: EffectiveRoleController = {\n effectiveRole: null,\n setEffectiveRole: (_role: string | null) => {\n }\n};\nexport const EffectiveRoleControllerContext = React.createContext<EffectiveRoleController>(DEFAULT_EFFECTIVE_ROLE_STATE);\n\nexport const EffectiveRoleControllerProvider = EffectiveRoleControllerContext.Provider;\n","import React from \"react\";\nimport { AuthController } from \"@rebasepro/cms-types\";\n\n/** `null` outside `<Rebase>` — see {@link RebaseDataContext}. */\nexport const AuthControllerContext = React.createContext<AuthController<any, any> | null>(null);\n","import React from \"react\";\nimport { DataDriver } from \"@rebasepro/types\";\n\nexport const DataDriverContext = React.createContext<DataDriver>({} as DataDriver);\n","import React from \"react\";\nimport { DataSourceDefinition, RebaseData } from \"@rebasepro/types\";\n\n/**\n * The data-source configuration provided to `<Rebase>`: the declared\n * definitions plus the built {@link RebaseData} instances for direct/custom\n * transports.\n *\n * The actual path-based routing is assembled by the navigation layer (which\n * has the collection registry) via `resolveDataSource` + `buildRoutedRebaseData`\n * and re-provided through `RebaseDataContext`.\n *\n * @internal\n */\nexport interface DataSourcesContextValue {\n /** All declared data sources, keyed by data-source key. */\n registry: Record<string, DataSourceDefinition>;\n /**\n * Built {@link RebaseData} for direct/custom data sources, keyed by\n * data-source key. Server-mediated sources are absent (they ride the\n * default client).\n */\n sources: Record<string, RebaseData>;\n}\n\nconst EMPTY: DataSourcesContextValue = { registry: {}, sources: {} };\n\n/** @internal */\nexport const DataSourcesContext = React.createContext<DataSourcesContextValue>(EMPTY);\n\n/**\n * Access the data-source configuration provided to `<Rebase>` via the\n * `dataSources` prop.\n * @internal\n */\nexport const useDataSources = (): DataSourcesContextValue => React.useContext(DataSourcesContext);\n","import React from \"react\";\nimport { RebaseData } from \"@rebasepro/types\";\n\n/**\n * `null` outside `<Rebase>`, so {@link useData} can say so.\n *\n * The default used to be `{} as RebaseData` — a lie the type system agreed\n * with. A hook called outside the tree handed back an empty object, and the\n * first thing anyone does with it is `data.collection(\"posts\")`, which fails as\n * \"data.collection is not a function\" somewhere in a component's render. That\n * names neither the hook nor the missing provider.\n */\nexport const RebaseDataContext = React.createContext<RebaseData | null>(null);\n","import React from \"react\";\nimport { AnalyticsController } from \"@rebasepro/cms-types\";\n\nexport const AnalyticsContext = React.createContext<AnalyticsController>({} as AnalyticsController);\n","import React from \"react\";\nimport { StorageSource } from \"@rebasepro/types\";\n\n/**\n * Three states, and they mean different things:\n *\n * - `null` — outside `<Rebase>`.\n * - `undefined` — inside it, but the project configured no storage. `<Rebase>`\n * already warns about this on the console.\n * - a source — the resolved default storage.\n *\n * See {@link RebaseDataContext} for why the default is not `{}`.\n */\nexport const StorageSourceContext = React.createContext<StorageSource | null | undefined>(null);\n","import React from \"react\";\nimport type { StorageSource, StorageSourceDefinition, StorageSourceRegistry } from \"@rebasepro/types\";\n\n/**\n * The storage-source configuration provided to `<Rebase>`: the declared\n * definitions and the built {@link StorageSource} instances, wrapped in a\n * {@link StorageSourceRegistry} for fast key-based lookup.\n *\n * Mirrors the {@link DataSourcesContext} pattern used for databases.\n *\n * @internal\n */\nexport interface StorageSourcesContextValue {\n /** All declared storage sources, keyed by storage-source key. */\n registry: Record<string, StorageSourceDefinition>;\n /** Built {@link StorageSource} for direct sources, keyed by key. */\n sources: Record<string, StorageSource>;\n /**\n * A server-routed source for a key not (yet) in `sources` — requests carry\n * `?storageId=<key>`, so the server serves it or refuses naming it, rather\n * than the panel guessing the default. Absent without a client.\n */\n createSource?: (key: string) => StorageSource;\n}\n\nconst EMPTY: StorageSourcesContextValue = { registry: {}, sources: {} };\n\n/** @internal */\nexport const StorageSourcesContext = React.createContext<StorageSourcesContextValue>(EMPTY);\n\n/**\n * Access the storage-source configuration provided to `<Rebase>` via the\n * `storageSources` prop.\n * @internal\n */\nexport const useStorageSources = (): StorageSourcesContextValue => React.useContext(StorageSourcesContext);\n","import React from \"react\";\nimport { UserConfigurationPersistence } from \"@rebasepro/cms-types\";\n\nexport const UserConfigurationPersistenceContext = React.createContext<UserConfigurationPersistence | undefined>(undefined);\n","import type { DialogControllerEntryProps, DialogsController } from \"@rebasepro/cms-types\";\nimport React, { PropsWithChildren, useCallback, useRef, useState, useMemo } from \"react\";\n;\n\n/** `null` outside `<Rebase>` — see `RebaseDataContext`. */\nexport const DialogsControllerContext = React.createContext<DialogsController | null>(null);\n\nexport const DialogsProvider: React.FC<PropsWithChildren> = ({ children }) => {\n\n const [dialogEntries, setDialogEntries] = useState<DialogControllerEntryProps[]>([]);\n const dialogEntriesRef = useRef<DialogControllerEntryProps[]>(dialogEntries);\n\n const updateDialogEntries = (newPanels: DialogControllerEntryProps<any>[]) => {\n dialogEntriesRef.current = newPanels;\n setDialogEntries(newPanels);\n };\n\n const close = useCallback(() => {\n\n if (dialogEntries.length === 0)\n return;\n\n const updatedPanels = [...dialogEntriesRef.current.slice(0, -1)];\n updateDialogEntries(updatedPanels);\n\n }, [dialogEntries]);\n\n const open = useCallback(<T extends object = object>(dialogEntry: DialogControllerEntryProps<T>) => {\n\n const updatedPanels = [...dialogEntriesRef.current, dialogEntry];\n updateDialogEntries(updatedPanels);\n\n return {\n closeDialog: () => {\n const updatedPanels = dialogEntriesRef.current.filter(e => e.key !== dialogEntry.key);\n updateDialogEntries(updatedPanels);\n }\n }\n }, [dialogEntries]);\n\n const dialogsController = useMemo(() => ({\n open,\n close\n }), [open, close]);\n\n return (\n <DialogsControllerContext.Provider value={dialogsController}>\n {children}\n {dialogEntries.map((entry, i) => <entry.Component\n key={`dialog_${i}`}\n open={true}\n closeDialog={close}\n {...entry.props}\n />)}\n </DialogsControllerContext.Provider>\n );\n};\n","import React from \"react\";\n\n/**\n * Context that exposes the full RebaseClient instance.\n * Used by the JS Editor to give developer scripts access to `client.data`, `client.auth`, etc.\n */\nexport const RebaseClientInstanceContext = React.createContext<any>(undefined);\n","import type { CustomizationController } from \"@rebasepro/cms-types\";\nimport React from \"react\";\n\n/** `null` outside `<Rebase>` — see {@link RebaseDataContext}. */\nexport const CustomizationControllerContext = React.createContext<CustomizationController | null>(null);\n","import React, { createContext, useContext, useMemo } from \"react\";\nimport type { ComponentOverrideMap } from \"@rebasepro/cms-types\";\n\n/** Stable empty reference to avoid re-creating context values on every render. */\nconst EMPTY_OVERRIDES: ComponentOverrideMap = {};\n\n/**\n * Internal state for the component override resolution chain.\n * Holds both global overrides (set on `<Rebase>`) and collection-scoped\n * overrides (set on individual collections).\n *\n * Resolution priority: collection > global > default.\n *\n * @internal\n */\ninterface ComponentOverrideState {\n globalOverrides: ComponentOverrideMap;\n collectionOverrides: ComponentOverrideMap;\n}\n\nexport const ComponentOverrideContext = createContext<ComponentOverrideState>({\n globalOverrides: EMPTY_OVERRIDES,\n collectionOverrides: EMPTY_OVERRIDES\n});\n\n/**\n * Provider set at the `<Rebase>` root level to supply global component overrides.\n *\n * @internal — Used by the Rebase component. End users set overrides via\n * the `components` prop on `<Rebase>`.\n */\nexport function GlobalComponentOverrideProvider({\n overrides,\n children\n}: {\n overrides?: ComponentOverrideMap;\n children: React.ReactNode;\n}) {\n const value = useMemo<ComponentOverrideState>(() => ({\n globalOverrides: overrides ?? EMPTY_OVERRIDES,\n collectionOverrides: EMPTY_OVERRIDES\n }), [overrides]);\n\n return (\n <ComponentOverrideContext.Provider value={value}>\n {children}\n </ComponentOverrideContext.Provider>\n );\n}\n\n/**\n * Provider set at the collection level to layer collection-scoped overrides\n * on top of global overrides.\n *\n * When a collection defines `components`, this provider is mounted\n * around the collection's view subtree. Components within the subtree\n * will resolve overrides in order: collection → global → default.\n *\n * @internal — Used by DataCollectionView when a collection has\n * `components` defined.\n */\nexport function CollectionComponentOverrideProvider({\n overrides,\n children\n}: {\n overrides?: ComponentOverrideMap;\n children: React.ReactNode;\n}) {\n const parent = useContext(ComponentOverrideContext);\n\n const value = useMemo<ComponentOverrideState>(() => ({\n globalOverrides: parent.globalOverrides,\n collectionOverrides: overrides ?? EMPTY_OVERRIDES\n }), [parent.globalOverrides, overrides]);\n\n return (\n <ComponentOverrideContext.Provider value={value}>\n {children}\n </ComponentOverrideContext.Provider>\n );\n}\n","import React, { createContext, useContext } from \"react\";\n\nimport { CollectionComponentOverrideProvider } from \"./ComponentOverrideContext\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\n/**\n * Carries the collection a UI subtree is currently bound to.\n *\n * Mounted by every collection binding (main collection views, entity\n * edit/detail views, side panels, reference-selection dialogs, import\n * previews) via {@link CollectionScopeProvider}. Leaf components read it with\n * {@link useCollectionScope} to derive collection-dependent behavior — e.g.\n * filter fields resolve the engine's supported operators from\n * `collection.engine` — without every intermediate component threading\n * collection props.\n *\n * @internal\n */\nexport const CollectionScopeContext = createContext<AdminCollection | undefined>(undefined);\n\n/**\n * Read the collection the current subtree is bound to, or `undefined` when\n * rendered outside any collection scope (e.g. a fully standalone table).\n *\n * @group Hooks\n */\nexport function useCollectionScope(): AdminCollection | undefined {\n return useContext(CollectionScopeContext);\n}\n\n/**\n * Scopes a UI subtree to a collection.\n *\n * Provides two things at once:\n * 1. The collection itself — readable via {@link useCollectionScope} —\n * so leaf components (filter fields, previews, …) can derive\n * collection-dependent behavior such as engine capabilities.\n * 2. The collection's component overrides (`collection.components`),\n * by mounting {@link CollectionComponentOverrideProvider}.\n *\n * Mount this wherever a subtree is bound to a specific collection. If you\n * build a custom view around `SelectableTable` / `CollectionTableBinding`,\n * wrap it in this provider to get engine-aware filters and collection-scoped\n * component overrides for free:\n *\n * ```tsx\n * <CollectionScopeProvider collection={myCollection}>\n * <CollectionTableBinding ... />\n * </CollectionScopeProvider>\n * ```\n *\n * @group Components\n */\nexport function CollectionScopeProvider({\n collection,\n children\n}: {\n collection: AdminCollection<any> | undefined;\n children: React.ReactNode;\n}) {\n return (\n <CollectionScopeContext.Provider value={collection as AdminCollection | undefined}>\n <CollectionComponentOverrideProvider overrides={collection?.components}>\n {children}\n </CollectionComponentOverrideProvider>\n </CollectionScopeContext.Provider>\n );\n}\n","import React from \"react\";\n\n/**\n * Look up a collection's config by slug.\n */\nexport type CollectionResolver = (slug: string) => { properties?: Record<string, unknown> } | undefined;\n\n/**\n * Translate the path a collection is addressed by into the path its driver\n * stores it under — `fs_diagnosis` into `diagnosis`, for a Firestore collection\n * that declares `path: \"diagnosis\"`. See `EntityDataOptions.resolveDataPath`.\n */\nexport type DataPathResolver = (path: string) => string | undefined;\n\n/**\n * Lets the layer that owns the collections hand a resolver *up* to the data\n * layer, which needs a collection's primary keys to give its rows an address.\n *\n * The inversion is forced by the composition: `<Rebase client>` builds the data\n * layer, and `<RebaseCMS collections>` sits inside it — so the collections are\n * not in scope where the data is created, and `Rebase` cannot take them as a\n * prop without giving every headless BaaS app a collections argument it has no\n * use for.\n *\n * The same layer knows where each collection is stored, so it hands up the\n * data-path translation alongside: a direct driver has to be given a\n * collection's declared `path`, and only the registry knows it.\n *\n * Registration is a ref write, so it is safe to call during render — and it has\n * to be. The views that fetch rows are *below* the registrar, and child effects\n * run before parent effects, so registering in an effect would bind after the\n * first page of rows had already been converted.\n *\n * Several layers may own collections at once — the CMS navigation, and each\n * standalone `CollectionsProvider` on a page — so each registers under its own\n * `owner` (`\"default\"` when omitted). A lookup asks every owner and takes the\n * first that knows the collection. Registering nothing (`undefined` for both)\n * removes that owner's registration.\n */\nexport type CollectionResolverRegistration = (\n resolver: CollectionResolver | undefined,\n resolveDataPath?: DataPathResolver,\n owner?: string\n) => void;\n\nexport const CollectionResolverRegistrationContext =\n React.createContext<CollectionResolverRegistration>(() => undefined);\n","import React, { useContext } from \"react\";\nimport type { AccessSimulation } from \"@rebasepro/types\";\n\n/**\n * How the banner names what is simulated — a key's name, a user's email —\n * which the headers alone do not carry.\n *\n * @group Models\n */\nexport type RlsSimulationLabel =\n | { kind: \"role\"; role: string; userId?: string }\n | { kind: \"user\"; user: string }\n | { kind: \"apiKey\"; name: string; keyPrefix: string };\n\n/**\n * The RLS simulator's state: what the admin panel's data views run as.\n *\n * While `simulation` is set, every data view reads through a client derived\n * with `client.simulate()`, so a grid shows exactly the rows and fields that\n * role, user or key can read. `null` is the signed-in administrator.\n *\n * @group Models\n */\nexport interface RlsSimulationController {\n /**\n * Whether simulation is possible here: the client can derive a simulated\n * one, and the default data source is that client (not a direct driver).\n */\n available: boolean;\n simulation: AccessSimulation | null;\n label: RlsSimulationLabel | null;\n setSimulation(simulation: AccessSimulation | null, label?: RlsSimulationLabel | null): void;\n}\n\nconst DEFAULT_CONTROLLER: RlsSimulationController = {\n available: false,\n simulation: null,\n label: null,\n setSimulation: () => undefined\n};\n\nexport const RlsSimulationContext = React.createContext<RlsSimulationController>(DEFAULT_CONTROLLER);\n\n/**\n * The RLS simulator's state, for the bar that sets it and the banner that\n * shows it.\n *\n * @group Hooks and utilities\n */\nexport function useRlsSimulation(): RlsSimulationController {\n return useContext(RlsSimulationContext);\n}\n","import { useContext } from \"react\";\nimport { RebaseData } from \"@rebasepro/types\";\nimport { RebaseDataContext } from \"../../contexts/RebaseDataContext\";\n\n/**\n * Use this hook to access the unified data API.\n *\n * ```ts\n * const data = useData();\n * const { data: products } = await data.products.find({ where: { status: [\"==\", \"published\"] } });\n * await data.products.create({ name: \"Camera\", price: 299 });\n * ```\n *\n * @group Hooks and utilities\n */\nexport const useData = (): RebaseData => {\n const data = useContext(RebaseDataContext);\n if (!data) throw new Error(\"useData must be used inside <Rebase>\");\n return data;\n};\n","import React, { createContext, useCallback, useContext, useMemo, useState } from \"react\";\nimport { Alert, Typography } from \"@rebasepro/ui\";\n\n// ── Schema Drift Context ────────────────────────────────────────────────\n\ninterface SchemaDriftContextValue {\n /** Report a schema drift error (call from any data-loading hook). */\n reportSchemaDrift: (message: string) => void;\n /** The most recent schema drift message, or null. */\n schemaDriftMessage: string | null;\n /** Dismiss the banner for this session. */\n dismiss: () => void;\n}\n\nconst SchemaDriftContext = createContext<SchemaDriftContextValue>({\n reportSchemaDrift: () => {},\n schemaDriftMessage: null,\n dismiss: () => {}\n});\n\nexport function useSchemaDriftContext(): SchemaDriftContextValue {\n return useContext(SchemaDriftContext);\n}\n\n/**\n * Detects schema drift from an error object.\n * Checks both the error code (from `RebaseApiError`) and the message\n * for schema drift indicators.\n */\nexport function isSchemaDriftError(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n // RebaseApiError from the SDK has a `code` property\n if (\"code\" in error && (error as { code?: string }).code === \"SCHEMA_DRIFT\") {\n return true;\n }\n // Fallback: check the message for the telltale phrase\n if (error instanceof Error && error.message.includes(\"Schema drift:\")) {\n return true;\n }\n return false;\n}\n\n// ── Provider ─────────────────────────────────────────────────────────────\n\nexport function SchemaDriftProvider({ children }: { children: React.ReactNode }) {\n const [schemaDriftMessage, setSchemaDriftMessage] = useState<string | null>(null);\n const [dismissed, setDismissed] = useState(false);\n\n const reportSchemaDrift = useCallback((message: string) => {\n setSchemaDriftMessage(prev => prev ?? message);\n }, []);\n\n const dismiss = useCallback(() => {\n setDismissed(true);\n }, []);\n\n const value = useMemo<SchemaDriftContextValue>(() => ({\n reportSchemaDrift,\n schemaDriftMessage: dismissed ? null : schemaDriftMessage,\n dismiss\n }), [reportSchemaDrift, schemaDriftMessage, dismissed, dismiss]);\n\n return (\n <SchemaDriftContext.Provider value={value}>\n {children}\n </SchemaDriftContext.Provider>\n );\n}\n\n// ── Banner Component ─────────────────────────────────────────────────────\n\nexport interface SchemaDriftBannerProps {\n className?: string;\n}\n\n/**\n * Persistent banner shown when a schema drift error is detected.\n */\nexport function SchemaDriftBanner({ className }: SchemaDriftBannerProps) {\n const { schemaDriftMessage, dismiss } = useSchemaDriftContext();\n\n if (!schemaDriftMessage) return null;\n\n return (\n <Alert\n color=\"warning\"\n size=\"small\"\n onDismiss={dismiss}\n className={className}\n >\n <div className=\"flex flex-col gap-1\">\n <Typography variant=\"label\" className=\"text-amber-800 dark:text-amber-200\">\n Schema drift detected\n </Typography>\n <Typography variant=\"body2\" className=\"text-amber-700 dark:text-amber-300\">\n {schemaDriftMessage}\n </Typography>\n </div>\n </Alert>\n );\n}\n","import type { FindParams, FilterValues, LogicalCondition, OrderBySpec } from \"@rebasepro/types\";\n\n/**\n * The one place a collection read's parameters are assembled.\n *\n * ## Why this exists\n *\n * Four call sites used to build this object by hand — `useCollection` and\n * `useDataTableController`, each in both their `listen` and `find` branches.\n * Every one of them listed the fields it forwarded, so adding an option to\n * `FindParams` meant remembering four places, and forgetting one failed\n * silently: the option simply never reached the server, and the feature it\n * enabled looked broken for reasons nowhere near the code that dropped it.\n *\n * That is not hypothetical. `searchExplain` was added to three of the four and\n * the miss was found by intercepting a WebSocket frame, because nothing else\n * could see it.\n *\n * A field added here reaches every read. `toFindParams` returns `FindParams`\n * itself, so the compiler checks the shape rather than a hand-copied list.\n */\nexport interface CollectionQueryInput<M extends Record<string, unknown>> {\n where?: FilterValues<Extract<keyof M, string>>;\n logical?: LogicalCondition;\n /**\n * Loosened from `FindParams[\"orderBy\"]` on purpose: callers hold the sort\n * as plain `[string, direction]` pairs read off user config or a URL, where\n * the columns are not statically known. Narrowing it here would push a cast\n * onto every call site, which is the kind of friction that sends people back\n * to hand-building the object this exists to replace.\n */\n orderBy?: OrderBySpec;\n limit?: number;\n offset?: number;\n page?: number;\n searchString?: string;\n include?: string[];\n}\n\n/**\n * Build the parameters for one collection read.\n *\n * Derived options live here rather than at the call sites, so they cannot\n * disagree: `searchExplain` rides along exactly when there is a search string\n * to explain, which is also the only time it costs anything.\n */\nexport function toFindParams<M extends Record<string, unknown>>(\n input: CollectionQueryInput<M>\n): FindParams<M> {\n const { searchString, limit, ...rest } = input;\n return {\n ...rest,\n ...resolveLimit(limit),\n ...(searchString ? { searchString, searchExplain: true } : {})\n } as FindParams<M>;\n}\n\n/**\n * Keep a meaningless `limit` inside the browser.\n *\n * The API refuses a `limit` below 1 — rightly: a window nobody can be served is\n * better refused than quietly widened. But a client that computes one has a bug\n * *here*, and forwarding it turns that bug into a 400 the user reads as the\n * server being broken. That is exactly how a restored, empty scroll entry\n * presented: an `Invalid limit: 0` error where the table should have been.\n *\n * Only the meaningless end is guarded. An absent limit is a supported request —\n * every ingress defaults it (`resolveClientListLimit`), so dropping one cannot\n * produce an unbounded read — whereas a limit *above* the ceiling states an\n * intent, and silently trimming it would hand back a page the caller cannot\n * tell apart from the whole collection. That one still travels, and is still\n * refused where the ceiling lives.\n */\nfunction resolveLimit(limit: number | undefined): { limit?: number } {\n if (limit === undefined) return {};\n if (Number.isInteger(limit) && limit >= 1) return { limit };\n console.warn(`Ignoring an unusable \\`limit\\` of ${limit} — a page size must be a whole number of at least 1. ` +\n \"Reading with the server's default page size instead.\");\n return {};\n}\n","import type { Property } from \"@rebasepro/types\";\n\n/**\n * Whether a property can stand in for a record in *one line*.\n *\n * Preview surfaces — the reference card, a list row, a board card — have a\n * single line per property and no way to grow. That is a constraint on the\n * *value*, not on the property's importance: a Markdown biography is the most\n * interesting column on an author, and it is still the wrong thing to paste\n * into a 44px card. Ranking it here means the picker can skip it without\n * anyone having to configure their way out of a broken card.\n *\n * Kept beside {@link getTitlePropertyCandidates} because the two answer\n * neighbouring questions — \"what is this record called\" and \"what else can be\n * said about it in a line\" — from the same property schema.\n *\n * @group Collections\n */\nexport const SUMMARY_RANK = {\n /**\n * No single-line form exists. A map renders as a key/value table and an\n * array of maps as a stack of them; there is no first line to take.\n */\n UNUSABLE: 0,\n /**\n * Readable in one line, but only as an excerpt — the property holds a\n * document, and the line is its opening. Worth showing when nothing better\n * is available, never in preference to a value that fits whole.\n */\n EXCERPT: 1,\n /** Short and self-contained: the line *is* the value. */\n DIRECT: 2\n} as const;\n\n/** One of the three summary ranks. */\nexport type SummaryRank = typeof SUMMARY_RANK[keyof typeof SUMMARY_RANK];\n\n/**\n * File-storage backed content (single image, array of images, generic upload…).\n * Preview surfaces give these their own image slot, so they are never also a\n * text line.\n *\n * @group Collections\n */\nexport function isStorageProperty(property: Property | undefined): boolean {\n if (!property) return false;\n if (property.type === \"string\" && (property.storage || property.admin?.urlPreview === \"image\")) return true;\n if (property.type === \"array\" && property.of && !Array.isArray(property.of)) {\n const inner = property.of;\n if (inner.type === \"string\" && (inner.storage || inner.admin?.urlPreview === \"image\")) return true;\n }\n return false;\n}\n\n/**\n * True when the property holds free text long enough to be a document rather\n * than a value — Markdown, or an explicitly multi-line string.\n *\n * @group Collections\n */\nexport function isLongTextProperty(property: Property | undefined): boolean {\n if (!property || property.type !== \"string\") return false;\n return Boolean(property.admin?.markdown || property.admin?.multiline);\n}\n\n/**\n * How well a property reads as one line of a preview. See {@link SUMMARY_RANK}.\n *\n * Decided from the property *schema* only: no values are consulted, so the\n * answer is stable for a collection and can be memoised per collection rather\n * than per row.\n *\n * @group Collections\n */\nexport function rankSummaryProperty(property: Property | undefined): SummaryRank {\n if (!property) return SUMMARY_RANK.UNUSABLE;\n\n // Rendered by the image slot, not as text.\n if (isStorageProperty(property)) return SUMMARY_RANK.UNUSABLE;\n\n // A map is a table of its own, whether it declares its properties (a row\n // per sub-property) or not (a key/value dump). Neither has a first line.\n if (property.type === \"map\") return SUMMARY_RANK.UNUSABLE;\n\n if (property.type === \"array\") {\n // A tuple: several properties side by side, so there is nothing single\n // about the line it would produce.\n if (Array.isArray(property.of)) return SUMMARY_RANK.UNUSABLE;\n if (!property.of) return property.oneOf ? SUMMARY_RANK.UNUSABLE : SUMMARY_RANK.DIRECT;\n // Arrays of block-shaped things inherit the block shape.\n const innerRank = rankSummaryProperty(property.of);\n if (innerRank === SUMMARY_RANK.UNUSABLE) return SUMMARY_RANK.UNUSABLE;\n // An array of documents is a stack of excerpts — worse than one\n // excerpt, and never what a card should lead with.\n if (innerRank === SUMMARY_RANK.EXCERPT) return SUMMARY_RANK.UNUSABLE;\n // Short values render as a run of chips, which fits a line.\n return SUMMARY_RANK.DIRECT;\n }\n\n if (isLongTextProperty(property)) return SUMMARY_RANK.EXCERPT;\n\n // Numbers, dates, booleans, enums, plain strings, and single references or\n // relations (which collapse to one linked line) all fit as they are.\n return SUMMARY_RANK.DIRECT;\n}\n\n/**\n * True when the property has any single-line form at all.\n *\n * @group Collections\n */\nexport function canSummariseProperty(property: Property | undefined): boolean {\n return rankSummaryProperty(property) !== SUMMARY_RANK.UNUSABLE;\n}\n","import type { Property } from \"@rebasepro/types\";\nimport type { PropertyConfig, AdminCollection } from \"@rebasepro/cms-types\";\nimport { AuthController } from \"@rebasepro/cms-types\";\nimport { isPropertyBuilder, resolveCollectionRelations } from \"@rebasepro/common\";\nimport { getTitlePropertyKey } from \"@rebasepro/app\";\nimport { SUMMARY_RANK, isStorageProperty, rankSummaryProperty } from \"../collections/summary-property\";\n\nfunction isReferenceProperty(property: Property) {\n if (!property) return null;\n if (property.type === \"reference\") return true;\n if (property.type === \"array\") {\n if (Array.isArray(property.of)) return false;\n else return property.of?.type === \"reference\";\n }\n return false;\n}\n\nfunction isRelationProperty(property: Property) {\n if (!property) return null;\n if (property.type === \"relation\") return true;\n if (property.type === \"array\") {\n if (Array.isArray(property.of)) return false;\n else return property.of?.type === \"relation\";\n }\n return false;\n}\n\nfunction isHiddenProperty(property: Property | undefined): boolean {\n if (!property) return false;\n return Boolean(property.admin?.hideFromCollection);\n}\n\n/**\n * The properties a preview surface should render for a record, best first.\n *\n * Three things decide the answer, in this order:\n *\n * 1. `previewProperties` — passed in, or declared on the collection. A stated\n * list is returned verbatim, ranking and limit included: a developer who\n * asks for the Markdown biography gets the Markdown biography.\n * 2. Whether the value has a one-line form at all. A map renders as a\n * key/value table and a Markdown field as a document; neither fits a card\n * line, so they never take a slot from a value that does. See\n * {@link rankSummaryProperty}.\n * 3. `propertiesOrder`, which breaks ties.\n *\n * The middle step is the one that is easy to get wrong by leaving out.\n * `propertiesOrder` states the *column* order of a collection table — it is\n * not a statement that the first three columns summarise a record, and reading\n * it as one is how a card ends up rendering somebody's entire biography.\n */\nexport function getEntityPreviewKeys(\n authController: AuthController,\n targetCollection: AdminCollection<any>,\n fields: Record<string, PropertyConfig>,\n previewProperties?: string[],\n limit = 3) {\n const allProperties = Object.keys(targetCollection.properties);\n let listProperties = previewProperties?.filter(p => allProperties.includes(p as string));\n if (!listProperties && targetCollection.previewProperties) {\n listProperties = targetCollection.previewProperties?.filter(p => allProperties.includes(p as string));\n }\n if (listProperties && listProperties.length > 0) {\n return listProperties;\n }\n\n // Relations read as a link to somewhere else rather than as a value here,\n // so they are left to the dedicated relation chips — unless the collection\n // ordered its properties explicitly, which puts them back in play.\n const hasExplicitOrder = !!(targetCollection.propertiesOrder as string[] | undefined);\n const order = (targetCollection.propertiesOrder as string[]) || allProperties;\n\n const direct: string[] = [];\n const excerpt: string[] = [];\n\n for (const key of order) {\n const property = targetCollection.properties[key];\n if (!property || isPropertyBuilder(property)) continue;\n if (key === \"id\" || (\"isId\" in property && Boolean((property as { isId?: boolean }).isId))) continue;\n if (isReferenceProperty(property)) continue;\n if (!hasExplicitOrder && isRelationProperty(property)) continue;\n if (isHiddenProperty(property)) continue;\n if (isStorageProperty(property as Property)) continue;\n\n const rank = rankSummaryProperty(property as Property);\n if (rank === SUMMARY_RANK.UNUSABLE) continue;\n (rank === SUMMARY_RANK.EXCERPT ? excerpt : direct).push(key);\n\n // Every remaining slot can already be filled by a value that fits\n // whole, so nothing below can change the answer.\n if (direct.length >= limit) break;\n }\n\n // A long-text field is a poor summary but a fine last resort: better an\n // opening line than a card with nothing under the title.\n return [...direct, ...excerpt].slice(0, limit);\n}\n\n// Returned as-is rather than rebuilt per call, so the result is referentially\n// stable and safe to use as a hook dependency.\nconst INCLUDE_ALL_RELATIONS: string[] = [\"*\"];\n\n/**\n * Include lists handed out, interned by content.\n *\n * Key: the relation names, joined. A list is a pure function of its names, so\n * nothing ever invalidates an entry; the map holds one per distinct set of\n * names a session reads — one per collection shape, a handful in all. It is\n * what keeps the result referentially stable when a caller builds its\n * collection object afresh on every render: `useRelationSelector` lists the\n * include as an effect dependency, and a new array per render was a new read\n * per render.\n */\nconst INTERNED_INCLUDES = new Map<string, string[]>();\n\n/**\n * The `include` a collection view's read sends, so a relation cell renders from\n * the row it arrived with instead of fetching once per cell.\n *\n * It names the relations a **property** of the collection declares — the ones\n * a table column, a list or card chip, a picker option or a board card can\n * render, because the view model only maps relation data onto property keys\n * (`toViewModelValues`). It used to be `[\"*\"]`, which the server reads as\n * every relation the collection declares, one hop. That included the\n * relations declared only in `relations: []` for a record's tabs: no property\n * names them and no list surface shows them, yet every read embedded all of\n * their rows for every parent on the page — a `companies` table with one\n * `owner` column and a `hasMany activities` tab read 50 × 2,000 activity rows a\n * page, and again on every realtime re-read of the rows held.\n *\n * What a property renders is unchanged: each name here is exactly what `*`\n * loaded for that property, uncapped. Both transports read `include` — the\n * REST list and the realtime subscription run the same include loader on the\n * server.\n *\n * Only names the collection resolves as relations are sent: the server answers\n * an unknown one with a 400 `UNKNOWN_RELATION`. A collection whose relations\n * cannot be resolved here (a target that does not load in the browser) falls\n * back to `*` and lets the server decide, as before.\n */\nexport function getRelationIncludeParams(collection: AdminCollection<any>): string[] | undefined {\n const properties = collection.properties;\n if (!properties) return undefined;\n\n let relationNames: string[];\n try {\n relationNames = Object.keys(resolveCollectionRelations(collection));\n } catch (_e) {\n const hasRelations = Object.values(properties).some(property =>\n property && !isPropertyBuilder(property) &&\n (isRelationProperty(property as Property) || isReferenceProperty(property as Property)));\n return hasRelations ? INCLUDE_ALL_RELATIONS : undefined;\n }\n\n const names = relationNames.filter(name =>\n Object.prototype.hasOwnProperty.call(properties, name) && Boolean(properties[name]));\n if (names.length === 0) return undefined;\n\n const key = names.join(\"\\u0000\");\n const interned = INTERNED_INCLUDES.get(key);\n if (interned) return interned;\n INTERNED_INCLUDES.set(key, names);\n return names;\n}\n\n/**\n * The property that fills the title slot for a collection. Ranking lives in\n * `@rebasepro/common`, shared with the admin package so both agree on what an\n * entity is called.\n */\nexport function getEntityTitlePropertyKey<M extends Record<string, any>>(collection: AdminCollection<M>, propertyConfigs: Record<string, PropertyConfig>): string | undefined {\n return getTitlePropertyKey(collection as AdminCollection<Record<string, unknown>>);\n}\n\n","/**\n * Whether an error is the realtime client saying the connection is down —\n * not that the data is gone.\n *\n * Once the socket has been down for longer than a blip, the SDK tells every\n * live subscription `CONNECTION_LOST` through its `onError`, once, and keeps\n * the subscription: when the socket is back it is re-subscribed and its next\n * update carries what changed meanwhile. A view that already shows data should\n * keep showing it (the admin's connection banner says it may be stale) rather\n * than replace it with an error — for an open record that would unmount the\n * form and everything typed into it.\n *\n * Read by `code` rather than `instanceof RebaseApiError`: two copies of\n * `@rebasepro/types` in one tree disagree about the class, never about the code.\n *\n * @group Hooks and utilities\n */\nexport function isConnectionLostError(error: unknown): boolean {\n return typeof error === \"object\"\n && error !== null\n && \"code\" in error\n && error.code === \"CONNECTION_LOST\";\n}\n","import { useRef } from \"react\";\nimport { deepEqual } from \"fast-equals\";\n\n/**\n * The same filter object for as long as its contents stay the same.\n *\n * Callers write filters inline — the hooks guide does — so every render hands\n * a data hook a new object. Used as an effect dependency by identity, that\n * re-subscribed on every render, and every delivery rendered again: a\n * subscribe loop against the server for as long as the component was mounted.\n */\nexport function useStableFilterValues<T>(filterValues: T): T {\n const ref = useRef(filterValues);\n if (!deepEqual(ref.current, filterValues)) {\n ref.current = filterValues;\n }\n return ref.current;\n}\n","\nimport { useEffect, useState, useMemo } from \"react\";\nimport { Entity, FilterValues, User } from \"@rebasepro/types\";\nimport { useData } from \"./useData\";\nimport { isSchemaDriftError, useSchemaDriftContext } from \"../../components/SchemaDriftBanner\";\nimport { toFindParams } from \"./collectionQuery\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\nimport { isConnectionLostError } from \"../../util/realtime\";\nimport { useStableFilterValues } from \"./useStableFilterValues\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n/**\n * @group Hooks and utilities\n */\nexport interface CollectionProps<M extends Record<string, any>> {\n\n /**\n * Absolute collection path\n */\n path: string;\n\n /**\n * collection of the entity displayed by this collection\n */\n collection: AdminCollection<M>\n\n /**\n * Number of entities to fetch\n */\n itemCount?: number;\n\n /**\n * Number of items to skip\n */\n offset?: number;\n\n /**\n * Page number (1-indexed), alternative to offset\n */\n page?: number;\n\n /**\n * Filter the fetched data by the property\n */\n filterValues?: FilterValues<Extract<keyof M, string>>;\n\n /**\n * Sort the results by\n */\n sortBy?: [Extract<keyof M, string>, \"asc\" | \"desc\"];\n\n /**\n * Search string\n */\n searchString?: string;\n}\n\n/**\n * @group Hooks and utilities\n */\nexport interface CollectionResult<M extends Record<string, any>> {\n data: Entity<M>[];\n dataLoading: boolean;\n noMoreToLoad: boolean;\n dataLoadingError?: Error;\n totalCount?: number;\n}\n\n/**\n * This hook is used to fetch collections using a given collection\n * @param path\n * @param collection\n * @param filterValues\n * @param sortBy\n * @param itemCount\n * @param offset\n * @param page\n * @param searchString\n * @group Hooks and utilities\n */\nexport function useCollection<M extends Record<string, any>, USER extends User>(\n {\n path,\n collection,\n filterValues,\n sortBy,\n itemCount,\n offset,\n page,\n searchString\n }: CollectionProps<M>): CollectionResult<M> {\n const dataClient = useData();\n const { reportSchemaDrift } = useSchemaDriftContext();\n\n const sortByProperty = sortBy ? sortBy[0] : undefined;\n const currentSort = sortBy ? sortBy[1] : undefined;\n // Map to PostgREST format for orderBy\n const orderByParams: [string, \"asc\" | \"desc\"] | undefined = sortBy ? [String(sortBy[0]), sortBy[1]] : undefined;\n\n // filterValues is already FilterValues — pass directly. Held by content,\n // not identity: callers write it inline.\n const whereParams = useStableFilterValues(\n filterValues && Object.keys(filterValues).length > 0 ? filterValues : undefined);\n\n const [data, setData] = useState<Entity<M>[]>([]);\n\n const [dataLoading, setDataLoading] = useState<boolean>(false);\n const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();\n const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);\n const [totalCount, setTotalCount] = useState<number | undefined>();\n\n useEffect(() => {\n\n setDataLoading(true);\n\n // Whether this subscription has put rows on screen.\n let showingData = false;\n\n const onEntitiesUpdate = async (res: { data: Entity<M>[], meta: { hasMore: boolean; total?: number } }) => {\n showingData = true;\n const entities = res.data;\n setDataLoading(false);\n setDataLoadingError(undefined);\n // The rows as they came. A row a push did not change arrives as\n // the object it was last time (the socket and the admin boundary\n // both keep it), and a copy of every row of every frame told\n // every consumer memoised on its rows that all of them changed.\n setData(entities);\n setNoMoreToLoad(!res.meta.hasMore);\n setTotalCount(res.meta.total);\n };\n\n const onError = (error: Error) => {\n // The connection is down, not the collection: keep the rows. The\n // subscription is kept too, and its next update replaces them.\n if (showingData && isConnectionLostError(error)) return;\n console.error(\"ERROR\", error);\n setDataLoading(false);\n setData([]);\n setDataLoadingError(error);\n setTotalCount(undefined);\n // Report schema drift to the global banner context\n if (isSchemaDriftError(error)) {\n reportSchemaDrift(error.message);\n }\n };\n\n const accessor = dataClient.collection(path);\n\n // Eagerly include relations to avoid N+1 fetches.\n const includeParams = getRelationIncludeParams(collection);\n\n if (accessor.listen) {\n // Assembled in one place — see `toFindParams`.\n return accessor.listen(\n toFindParams({ where: whereParams, limit: itemCount, offset, page,\n orderBy: orderByParams, searchString, include: includeParams }),\n (res) => onEntitiesUpdate({ data: res.data as Entity<M>[],\nmeta: res.meta }), onError);\n } else {\n // The one-shot fallback, taken whenever the client has no socket.\n // `listen` above cancels on cleanup, and every dependency of this\n // effect — the search string, the filters, the sort, the page —\n // changes while a request is in flight. A promise cannot be\n // unsubscribed, so the cleanup has to disown its result instead:\n // without this, whichever response arrives last wins, and responses\n // do not arrive in request order. Typing into search would settle\n // on the results for whichever query the server happened to finish\n // last.\n let cancelled = false;\n accessor.find(\n toFindParams({ where: whereParams, limit: itemCount, offset, page,\n orderBy: orderByParams, searchString, include: includeParams }))\n .then((res) => {\n if (cancelled) return;\n onEntitiesUpdate({ data: res.data as Entity<M>[],\nmeta: res.meta });\n })\n .catch((e) => {\n if (cancelled) return;\n onError(e);\n });\n return () => {\n cancelled = true;\n };\n }\n }, [path, itemCount, offset, page, currentSort, sortByProperty, whereParams, searchString, dataClient, collection]);\n\n return useMemo(() => ({\n data,\n dataLoading,\n dataLoadingError,\n noMoreToLoad,\n totalCount\n }), [data, dataLoading, dataLoadingError, noMoreToLoad, totalCount]);\n\n}\n","import { MAX_LIST_LIMIT } from \"@rebasepro/types\";\nimport type { CollectionAccessor, Entity, FindParams } from \"@rebasepro/types\";\n\nimport { isConnectionLostError } from \"../../util/realtime\";\n\n/**\n * The part of a read that says *which* rows, without saying how many or from\n * where. The window adds `limit` and `offset` itself, page by page.\n */\nexport type CollectionWindowQuery<M extends Record<string, unknown>> =\n Omit<FindParams<M>, \"limit\" | \"offset\" | \"page\" | \"after\">;\n\n/**\n * What a {@link CollectionWindow} reports on every change.\n */\nexport interface CollectionWindowState<M extends Record<string, unknown> = Record<string, unknown>> {\n /**\n * The rows in the window, in order, without duplicates.\n *\n * `undefined` until the window first covers what it was opened for — the\n * first page, or every row a restored scroll position had on screen — so a\n * view that is still showing its previous rows keeps them instead of\n * flashing a partial list.\n */\n rows: Entity<M>[] | undefined;\n /**\n * The same rows by position, with `undefined` where a row exists but has\n * not been read — the rows above a scroll position the window was\n * restored to ({@link CollectionWindowOptions.seed}), until the view\n * scrolls to them. Absent when nothing is missing, which is always the\n * case for a window no view reports a range to: `rows` is then complete\n * from the first row.\n */\n sparse?: (Entity<M> | undefined)[];\n /** Rows not yet on screen are being read: the first page, or the next one. */\n loading: boolean;\n error: Error | undefined;\n /** A page came back short, so there is nothing past `rows`. */\n complete: boolean;\n}\n\nexport interface CollectionWindowOptions<M extends Record<string, unknown>> {\n accessor: Pick<CollectionAccessor<M>, \"find\" | \"listen\">;\n query: CollectionWindowQuery<M>;\n /** Rows in the first page, which is the one kept live. */\n pageSize: number;\n /** How many rows the window should hold. `Infinity` reads them all. */\n target: number;\n /** Subscribe to the first page when the accessor can. Defaults to `true`. */\n live?: boolean;\n /**\n * Applied to every page as it arrives, before it is merged — the panel's\n * own `afterRead`, for instance.\n */\n process?: (rows: Entity<M>[]) => Promise<Entity<M>[]> | Entity<M>[];\n /**\n * When the subscription fails, read the first page once instead of\n * reporting the failure (which is only reported if that read fails too).\n */\n fallbackToFind?: boolean;\n /**\n * Read the first page once if the subscription has not answered by then.\n * The subscription still wins whenever it does answer.\n */\n firstPaintTimeoutMs?: number;\n /**\n * The quiet time kept between the end of one re-read of the rows past the\n * first page and the start of the next. Defaults to\n * {@link REREAD_INTERVAL_MS}. A push after a quiet spell is re-read at\n * once; pushes inside this window fold into one re-read at its end.\n */\n rereadIntervalMs?: number;\n /**\n * Rows already known, from a view this window replaces (a scroll position\n * kept while a record was open full screen): `rows` sit at `offset` and\n * on. They are shown at once and read again only when a view reports\n * them in range ({@link CollectionWindow.setVisibleRange}); the rows\n * between the first page and `offset` are not read until a view scrolls\n * to them. `target` should cover them.\n */\n seed?: { offset: number; rows: Entity<M>[] };\n onChange: (state: CollectionWindowState<M>) => void;\n}\n\n/**\n * A row held past the first page, and the version of the collection it was\n * read at. The version moves on with every push that says the collection\n * changed, so a row read before the last push is stale.\n */\ntype Slot<M extends Record<string, unknown>> = { row: Entity<M>; version: number };\n\n/**\n * The quiet time between two re-reads of the rows held past the first page.\n *\n * The server pushes at most once per ~300 ms of quiet per subscription, and at\n * least once a second under a steady stream of writes; each push used to start\n * a re-read of every held row past the first page as soon as the last one\n * ended, so a table scrolled to 10,000 rows ran ten 1,000-row reads back to\n * back for as long as the writes went on. This keeps the duty cycle bounded:\n * at most one re-read per re-read time plus this.\n */\nexport const REREAD_INTERVAL_MS = 2_000;\n\n/**\n * A scrolled collection view's rows, read one page at a time.\n *\n * ## Why this exists\n *\n * The table, list, card and board views used to grow a single read: the next\n * page was the same query with `limit` raised by a page, so page *k* re-read\n * the *k − 1* pages before it, and the read that reached row 1,001 asked for a\n * `limit` the API refuses (`MAX_LIST_LIMIT`). Every row past 1,000 was out of\n * reach, behind a developer error. The board clamped at the ceiling instead,\n * and its columns then said they were finished while their own header counted\n * thousands more.\n *\n * ## How it reads\n *\n * - The **first page** is a subscription when the accessor can listen, else a\n * one-shot read. It is the only live query the window holds.\n * - Every **later page** is a one-shot read by `offset`, of only the rows past\n * the ones already held, never more than `MAX_LIST_LIMIT` at a time. Offset\n * rather than the keyset cursor because it is the one paging every sort a\n * view offers can express — a relevance-ordered search has no cursor — and\n * because the server breaks ties on the id, so pages neither repeat nor skip\n * rows under a sort with duplicates.\n * - **Realtime.** The server re-runs a subscription on every write to its\n * collection, so each push after the first says \"something changed\", and\n * every row held past the first page is stale from then on. Which of them\n * are read again depends on whether a view says what it shows:\n * - A view that reports the rows it draws ({@link setVisibleRange}) has the\n * rows on screen read again, plus a page either side — one read, however\n * far it was scrolled. Rows further out stay stale and are read when they\n * come within half a page of the screen, before they are on it.\n * - Without a report, every row held is read again, in reads of at most\n * `MAX_LIST_LIMIT`, and replaced in one step — the only way a view that\n * cannot say what it shows never shows a stale row.\n * Either way a push after a quiet spell is re-read at once; pushes that\n * arrive while a re-read runs, or within `rereadIntervalMs` of the last one\n * ending, fold into one re-read at the end of that interval — at once if the\n * view asks for more rows or scrolls to rows not read since. The first page\n * itself is applied the moment it is pushed, as always.\n *\n * Rows are de-duplicated by id, keeping the copy read last: an insert or a\n * delete above shifts every offset by one, so between a push and the re-read\n * of the rows it moved, a row can sit in two places — on the first page and in\n * the stale row below it, or in the rows just re-read and the stale ones next\n * to them.\n *\n * A window can hold **gaps**: a restored scroll position ({@link\n * CollectionWindowOptions.seed}) shows the rows that were on screen without\n * reading every row above them. A gap is read when a view scrolls to it; a\n * window no view reports a range to reads its gaps at once and shows nothing\n * until they are filled, as it would have read them all before.\n */\nexport class CollectionWindow<M extends Record<string, unknown>> {\n\n private readonly accessor: CollectionWindowOptions<M>[\"accessor\"];\n private readonly query: CollectionWindowQuery<M>;\n private readonly pageSize: number;\n private readonly options: CollectionWindowOptions<M>;\n /** Rows the window must hold before it first shows any. */\n private readonly holdUntil: number;\n\n private target: number;\n private head: Entity<M>[] | undefined;\n /** The first page came back full, so there may be more past it. */\n private headFull = false;\n /**\n * Rows past the first page: `slots[i]` is the row at offset\n * `pageSize + i`, `undefined` where it has not been read (a gap).\n */\n private slots: (Slot<M> | undefined)[] = [];\n /** The last read reaching the end of the held rows came back short. */\n private tailEnded = false;\n /** Moves on with every push after the first: rows read before it are stale. */\n private version = 0;\n /**\n * The offsets a view says it draws, end exclusive. `undefined` until one\n * says so, and again when it goes: every held row is then kept current.\n */\n private range: { start: number; end: number } | undefined;\n /** The view moved to rows not read since: read them without waiting. */\n private rangeMoved = false;\n /** Offset of each row (or gap) of the last state reported, by position. */\n private emittedOffsets: number[] | undefined;\n private pumping = false;\n private pumpQueued = false;\n private loadingMore = false;\n private headError: Error | undefined;\n private tailError: Error | undefined;\n private settled = false;\n private disposed = false;\n private headSequence = 0;\n private liveAnswered = false;\n private unsubscribe: (() => void) | undefined;\n private firstPaintTimer: ReturnType<typeof setTimeout> | undefined;\n /** When the last re-read of the rows past the first page finished. */\n private lastRereadEndedAt: number | undefined;\n /** A re-read waiting out {@link REREAD_INTERVAL_MS}. */\n private rereadTimer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(options: CollectionWindowOptions<M>) {\n this.options = options;\n this.accessor = options.accessor;\n this.query = options.query;\n // A page the API would refuse is not a page; the ceiling is the page.\n this.pageSize = Math.max(1, Math.min(Math.floor(options.pageSize), MAX_LIST_LIMIT));\n this.target = normalizeTarget(options.target);\n // A restored scroll position asks for as many rows as it had on screen,\n // and showing the first page of them first would throw that position\n // away. \"Everything\" is the exception: the first page shows at once and\n // the rest follow.\n this.holdUntil = Number.isFinite(this.target) ? this.target : this.pageSize;\n const seed = options.seed;\n if (seed && seed.rows.length > 0) {\n // Read at no version the collection has had: stale from the start.\n const start = Math.max(0, Math.floor(seed.offset) - this.pageSize);\n const skip = Math.max(0, this.pageSize - Math.floor(seed.offset));\n const rows = seed.rows.slice(skip);\n this.slots = Array.from({ length: start + rows.length },\n (_, i) => i < start ? undefined : { row: rows[i - start], version: -1 });\n }\n }\n\n start(): void {\n if (this.disposed) return;\n const live = this.options.live !== false && Boolean(this.accessor.listen);\n if (!live) {\n this.readHeadOnce(true);\n return;\n }\n this.unsubscribe = this.accessor.listen!(\n { ...this.query, limit: this.pageSize },\n (response) => {\n this.liveAnswered = true;\n void this.receiveHead(response.data);\n },\n (error) => this.receiveLiveError(error)\n );\n const timeout = this.options.firstPaintTimeoutMs;\n if (timeout !== undefined) {\n this.firstPaintTimer = setTimeout(() => {\n if (this.disposed || this.liveAnswered || this.head !== undefined) return;\n this.readHeadOnce(false);\n }, timeout);\n }\n }\n\n /** Hold this many rows. Fewer than are held drops the rows past it. */\n setTarget(target: number): void {\n if (this.disposed) return;\n const next = normalizeTarget(target);\n if (next === this.target) return;\n this.target = next;\n const keep = Math.max(0, next - this.pageSize);\n if (this.slots.length > keep) {\n this.slots = this.slots.slice(0, keep);\n this.tailEnded = false;\n }\n // Asking for more is also how a view retries a page that failed.\n this.tailError = undefined;\n this.emit();\n void this.pump();\n }\n\n /**\n * The rows a view draws, by position in the last `rows` (or `sparse`) it\n * was given, end exclusive; `undefined` when it stops drawing them. Rows\n * near the range are kept current and gaps near it are read; see the\n * class comment.\n */\n setVisibleRange(range: { start: number; end: number } | undefined): void {\n if (this.disposed) return;\n const next = range ? this.toOffsets(range) : undefined;\n if (next === undefined && this.range === undefined) return;\n if (next && this.range && next.start === this.range.start && next.end === this.range.end) return;\n this.range = next;\n this.rangeMoved = true;\n // Not at once: a view handing over to another reports `undefined`\n // and then the new range in the same breath, and reading for the\n // moment in between would read every held row.\n this.schedulePump();\n }\n\n /**\n * What to keep of this window to show it again later: the rows read\n * around the range a view last reported — or, with none reported, every\n * row from the first — the offset of the first of them, and how many\n * rows the window holds in all. See {@link CollectionWindowOptions.seed}.\n */\n snapshot(): { offset: number; rows: Entity<M>[]; held: number } {\n const held = this.head === undefined ? 0 : this.head.length + this.slots.length;\n if (!this.range) return { offset: 0, rows: this.rows().rows, held };\n const margin = this.pageSize;\n const from = Math.max(0, this.range.start - margin);\n const to = this.range.end + margin;\n const rows: Entity<M>[] = [];\n let offset: number | undefined;\n if (from < this.pageSize && this.head) {\n for (let i = from; i < Math.min(to, this.head.length); i++) rows.push(this.head[i]);\n offset = from;\n }\n for (let i = Math.max(0, from - this.pageSize); i < Math.min(this.slots.length, to - this.pageSize); i++) {\n const slot = this.slots[i];\n if (!slot) {\n // A gap ends the run: the rows kept are one block.\n if (rows.length > 0) break;\n continue;\n }\n if (offset === undefined) offset = this.pageSize + i;\n rows.push(slot.row);\n }\n return { offset: offset ?? 0, rows, held };\n }\n\n dispose(): void {\n this.disposed = true;\n if (this.firstPaintTimer !== undefined) clearTimeout(this.firstPaintTimer);\n if (this.rereadTimer !== undefined) clearTimeout(this.rereadTimer);\n this.rereadTimer = undefined;\n this.unsubscribe?.();\n this.unsubscribe = undefined;\n }\n\n private readHeadOnce(reportFailure: boolean, liveError?: Error): void {\n let request: Promise<{ data: Entity<M>[] }>;\n try {\n request = Promise.resolve(this.accessor.find(this.oneShot(this.pageSize)));\n } catch (error) {\n request = Promise.reject(error);\n }\n request\n .then((response) => {\n // The subscription answered while this was in flight: it wins.\n if (this.disposed || (!reportFailure && this.liveAnswered && !liveError)) return;\n return this.receiveHead(response.data);\n })\n .catch((error: unknown) => {\n if (this.disposed || !reportFailure) return;\n this.headError = liveError ?? toError(error);\n this.emit();\n });\n }\n\n private receiveLiveError(error: Error): void {\n if (this.disposed) return;\n // The socket is down, not the data: the SDK keeps the subscription and\n // its first push after the reconnect carries what changed meanwhile.\n // Rows already on screen stay there (the connection banner says they\n // may be stale) instead of turning into an error, as `useCollection`\n // and `useFetch` already do.\n if (this.head !== undefined && isConnectionLostError(error)) return;\n if (this.options.fallbackToFind) {\n this.readHeadOnce(true, error);\n return;\n }\n this.headError = error;\n this.emit();\n }\n\n private async receiveHead(rows: Entity<M>[] | undefined): Promise<void> {\n const sequence = ++this.headSequence;\n const raw = rows ?? [];\n let processed: Entity<M>[];\n try {\n processed = await this.process(raw);\n } catch (error) {\n if (this.disposed || sequence !== this.headSequence) return;\n this.headError = toError(error);\n this.emit();\n return;\n }\n // A newer push overtook this one while it was being processed.\n if (this.disposed || sequence !== this.headSequence) return;\n const first = this.head === undefined;\n this.head = processed;\n this.headFull = raw.length >= this.pageSize;\n this.headError = undefined;\n if (!this.headFull) {\n // The whole set fits in the first page: nothing is held past it.\n this.slots = [];\n this.tailEnded = false;\n } else if (!first) {\n this.version++;\n this.tailError = undefined;\n }\n this.emit();\n await this.pump();\n }\n\n /** Rows still wanted past the ones held. */\n private wanted(): number {\n if (this.head === undefined || !this.headFull || this.tailEnded || this.tailError) return 0;\n return Math.max(0, this.target - this.pageSize - this.slots.length);\n }\n\n private needsRead(index: number): boolean {\n const slot = this.slots[index];\n return slot === undefined || slot.version < this.version;\n }\n\n /**\n * The held rows to read again now, by slot, or `undefined` if none.\n *\n * With a range: the stale rows and gaps within a page of it, once any of\n * them is within half a page — so scrolling into stale rows reads a\n * stretch of them ahead of the screen rather than one row per frame.\n * Without: every stale row and gap, as one span.\n */\n private nextRefresh(): { start: number; end: number; urgent: boolean } | undefined {\n if (!this.headFull || this.slots.length === 0 || this.tailError) return undefined;\n let readFrom = 0;\n let readTo = this.slots.length;\n if (this.range) {\n const margin = this.pageSize;\n const half = Math.ceil(margin / 2);\n const triggerFrom = Math.max(0, this.range.start - half - this.pageSize);\n const triggerTo = Math.min(this.slots.length, this.range.end + half - this.pageSize);\n let triggered = false;\n for (let i = triggerFrom; i < triggerTo && !triggered; i++) triggered = this.needsRead(i);\n if (!triggered) return undefined;\n readFrom = Math.max(0, this.range.start - margin - this.pageSize);\n readTo = Math.min(this.slots.length, this.range.end + margin - this.pageSize);\n }\n let start = -1;\n let end = -1;\n let gap = false;\n for (let i = readFrom; i < readTo; i++) {\n if (!this.needsRead(i)) continue;\n if (start < 0) start = i;\n end = i + 1;\n if (this.slots[i] === undefined) gap = true;\n }\n if (start < 0) return undefined;\n return { start, end, urgent: gap || (this.range !== undefined && this.rangeMoved) };\n }\n\n private schedulePump(): void {\n if (this.pumpQueued) return;\n this.pumpQueued = true;\n queueMicrotask(() => {\n this.pumpQueued = false;\n void this.pump();\n });\n }\n\n /**\n * The one loop that reads past the first page, so a re-read and a next page\n * never run at the same time and interleave their offsets.\n */\n private async pump(): Promise<void> {\n if (this.pumping) return;\n this.pumping = true;\n try {\n while (!this.disposed && this.head !== undefined) {\n const refresh = this.nextRefresh();\n if (refresh) {\n // A view asking for more rows, or looking at rows not read\n // since, is not kept waiting: the re-read runs now.\n const wait = refresh.urgent || this.wanted() > 0 ? 0 : this.rereadWait();\n if (wait > 0) {\n this.armReread(wait);\n } else {\n this.rangeMoved = false;\n await this.reread(refresh.start, refresh.end);\n this.lastRereadEndedAt = Date.now();\n continue;\n }\n }\n const wanted = this.wanted();\n if (wanted > 0) {\n await this.readNext(wanted);\n continue;\n }\n break;\n }\n } finally {\n this.pumping = false;\n }\n this.emit();\n }\n\n /** How long a re-read due now still has to wait. 0 after a quiet spell. */\n private rereadWait(): number {\n if (this.lastRereadEndedAt === undefined) return 0;\n const interval = this.options.rereadIntervalMs ?? REREAD_INTERVAL_MS;\n return Math.max(0, this.lastRereadEndedAt + interval - Date.now());\n }\n\n private armReread(wait: number): void {\n if (this.rereadTimer !== undefined || this.disposed) return;\n this.rereadTimer = setTimeout(() => {\n this.rereadTimer = undefined;\n void this.pump();\n }, wait);\n }\n\n private async readNext(wanted: number): Promise<void> {\n const offset = this.pageSize + this.slots.length;\n const limit = Math.min(MAX_LIST_LIMIT, wanted);\n const version = this.version;\n this.loadingMore = true;\n this.emit();\n try {\n const response = await this.accessor.find(this.oneShot(limit, offset));\n if (this.disposed) return;\n const raw = response.data ?? [];\n const processed = await this.process(raw);\n if (this.disposed) return;\n this.slots = this.slots.concat(processed.map((row) => ({ row, version })));\n if (raw.length < limit) this.tailEnded = true;\n } catch (error) {\n if (this.disposed) return;\n this.tailError = toError(error);\n } finally {\n this.loadingMore = false;\n }\n this.emit();\n }\n\n /**\n * Read the held rows in slots `[from, to)` again, and swap them in at once.\n * A read that comes back short says where the collection ends now: the\n * rows held past that are dropped.\n */\n private async reread(from: number, to: number): Promise<void> {\n const span = to - from;\n if (span <= 0) return;\n const version = this.version;\n const fresh: Entity<M>[] = [];\n let ended = false;\n let offset = this.pageSize + from;\n try {\n while (fresh.length < span) {\n const limit = Math.min(MAX_LIST_LIMIT, span - fresh.length);\n const response = await this.accessor.find(this.oneShot(limit, offset));\n if (this.disposed) return;\n const raw = response.data ?? [];\n fresh.push(...await this.process(raw));\n if (this.disposed) return;\n offset += raw.length;\n if (raw.length < limit) {\n ended = true;\n break;\n }\n }\n } catch (error) {\n if (this.disposed) return;\n this.tailError = toError(error);\n this.emit();\n return;\n }\n // Rows held past a target that shrank while this ran stay dropped.\n const keep = Math.max(0, this.target - this.pageSize);\n const slots = this.slots.slice(0, Math.min(from, keep));\n for (const row of fresh) {\n if (slots.length >= keep) break;\n slots.push({ row, version });\n }\n if (ended) {\n this.tailEnded = slots.length <= keep;\n } else {\n for (let i = to; i < this.slots.length && slots.length < keep; i++) slots.push(this.slots[i]);\n }\n this.slots = slots;\n this.emit();\n }\n\n /**\n * Every one-shot read the window makes: its query, never counted.\n *\n * Nothing here reads `meta.total` — a page ends the window by coming back\n * short — and the `COUNT(*)` beside each page read every matching row to\n * report a number that was thrown away: scrolling a table to 10,000 rows\n * ran 199 of them. The first page's subscription is the accessor's and is\n * left as it is.\n */\n private oneShot(limit: number, offset?: number): FindParams<M> {\n return { ...this.query, limit, ...(offset !== undefined && { offset }), count: \"none\" };\n }\n\n private async process(rows: Entity<M>[]): Promise<Entity<M>[]> {\n return this.options.process ? await this.options.process(rows) : rows;\n }\n\n private complete(): boolean {\n if (this.head === undefined) return false;\n return !this.headFull || this.tailEnded;\n }\n\n private hasGaps(): boolean {\n for (const slot of this.slots) if (slot === undefined) return true;\n return false;\n }\n\n private emit(): void {\n if (this.disposed) return;\n const error = this.headError ?? this.tailError;\n if (!this.settled && this.head !== undefined) {\n const held = this.pageSize + this.slots.length;\n const enough = this.complete() || held >= Math.min(this.holdUntil, this.target) || this.tailError;\n // Gaps are only shown to a view that draws them: one that reports\n // what it shows. Any other waits until they are read.\n if (enough && (this.range !== undefined || this.tailError || !this.hasGaps())) {\n this.settled = true;\n }\n }\n let rows: Entity<M>[] | undefined;\n let sparse: (Entity<M> | undefined)[] | undefined;\n if (this.settled) {\n const built = this.rows();\n rows = built.rows;\n sparse = built.sparse;\n this.emittedOffsets = built.offsets;\n }\n this.options.onChange({\n rows,\n ...(sparse && { sparse }),\n loading: (this.head === undefined && !this.headError) || this.loadingMore || (!this.settled && !error),\n error,\n complete: this.complete()\n });\n }\n\n /**\n * The rows to show, in order, each id once — the copy read last wins, the\n * first page counting as read now — with gaps kept as positions in\n * `sparse`, and the offset each position stands for.\n */\n private rows(): { rows: Entity<M>[]; sparse?: (Entity<M> | undefined)[]; offsets: number[] } {\n const head = this.head ?? [];\n if (this.slots.length === 0) {\n return { rows: head, offsets: head.map((_, i) => i) };\n }\n // Which copy of each id to keep: the newest version, then the first.\n const keep = new Map<string, { version: number; offset: number }>();\n const consider = (row: Entity<M>, version: number, offset: number) => {\n const key = String(row.id);\n const held = keep.get(key);\n if (!held || version > held.version) keep.set(key, { version, offset });\n };\n head.forEach((row, i) => consider(row, Infinity, i));\n this.slots.forEach((slot, i) => {\n if (slot) consider(slot.row, slot.version, this.pageSize + i);\n });\n const rows: Entity<M>[] = [];\n const positions: (Entity<M> | undefined)[] = [];\n const offsets: number[] = [];\n let gaps = false;\n const place = (row: Entity<M> | undefined, offset: number) => {\n if (row && keep.get(String(row.id))?.offset !== offset) return;\n if (row) rows.push(row);\n else gaps = true;\n positions.push(row);\n offsets.push(offset);\n };\n head.forEach((row, i) => place(row, i));\n // Gaps start where the first page ends: a page that came back with\n // fewer rows than it holds now (a delete) leaves no hole of its own.\n this.slots.forEach((slot, i) => place(slot?.row, this.pageSize + i));\n return gaps ? { rows, offsets, sparse: positions } : { rows, offsets };\n }\n\n /** Positions in the last state reported, as offsets in the collection. */\n private toOffsets(range: { start: number; end: number }): { start: number; end: number } {\n const offsets = this.emittedOffsets;\n const start = Math.max(0, Math.floor(range.start));\n const end = Math.max(start, Math.ceil(range.end));\n if (!offsets || offsets.length === 0) return { start, end };\n const at = (position: number) => position < offsets.length\n ? offsets[position]\n : offsets[offsets.length - 1] + 1 + (position - offsets.length);\n return { start: at(start), end: end > start ? at(end - 1) + 1 : at(start) };\n }\n}\n\nfunction normalizeTarget(target: number): number {\n if (target === Infinity) return Infinity;\n if (!Number.isFinite(target)) return 0;\n return Math.max(0, Math.floor(target));\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n","import { User } from \"@rebasepro/types\";\nimport { AuthController } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { AuthControllerContext } from \"../contexts/AuthControllerContext\";\n\n/**\n * Hook to retrieve the AuthContext.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see AuthController\n * @group Hooks and utilities\n */\nexport const useAuthController = <USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>>(): AuthControllerType => {\n const authController = useContext(AuthControllerContext);\n if (!authController) throw new Error(\"useAuthController must be used inside <Rebase>\");\n return authController as AuthControllerType;\n};\n","import { useContext } from \"react\";\nimport { RebaseClientInstanceContext } from \"../contexts/RebaseClientInstanceContext\";\n\n/**\n * Hook to retrieve the full RebaseClient instance from context.\n * Returns `undefined` if no client was provided to `<Rebase>`.\n */\nexport function useRebaseClient<T = any>(): T | undefined {\n return useContext(RebaseClientInstanceContext) as T | undefined;\n}\n","import { StorageSource } from \"@rebasepro/types\";\nimport { StorageSourceContext } from \"../contexts/StorageSourceContext\";\nimport { useContext } from \"react\";\n\n/**\n * Use this hook to get the storage source being used\n * @group Hooks and utilities\n */\nexport const useStorageSource = (): StorageSource => {\n const storageSource = useContext(StorageSourceContext);\n if (storageSource === null) throw new Error(\"useStorageSource must be used inside <Rebase>\");\n // `undefined` is a different thing: inside the tree, but the project\n // configured no storage. `<Rebase>` warns about that on the console, and\n // every upload field then fails on its own. Throwing here instead would\n // take the whole admin down with it, because `useRebaseContext` calls this\n // unconditionally — so the return type stays a promise this hook cannot\n // keep, until the seven callers can be told the truth.\n return storageSource as StorageSource;\n};\n","import type { SnackbarAction, SnackbarMessageType } from \"@rebasepro/cms-types\";\nimport React, { useCallback, useMemo } from \"react\";\nimport { useSnackbar } from \"notistack\";\nimport { Button } from \"@rebasepro/ui\";\n\n/**\n * Hook to retrieve the SnackbarContext.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see SnackbarController\n * @group Hooks and utilities\n */\nexport const useSnackbarController = () => {\n\n const {\n enqueueSnackbar,\n closeSnackbar\n } = useSnackbar();\n\n const open = useCallback((props: {\n type: SnackbarMessageType;\n title?: string;\n message: React.ReactNode;\n autoHideDuration?: number;\n action?: SnackbarAction;\n }) => {\n const {\n type,\n message,\n autoHideDuration,\n action\n } = props;\n enqueueSnackbar({\n message: props.title ? <div className={\"flex flex-col\"}>\n <strong>{props.title}</strong>\n {message}\n </div> : message,\n variant: type,\n autoHideDuration,\n // The provider sets `preventDuplicate`, which collapses two\n // snackbars carrying the same message into one. That is right for a\n // confirmation and wrong for an action: deleting two rows in a row\n // produces the same \"Deleted\" text twice, and swallowing the second\n // would leave the second deletion with no way to undo it. A key\n // makes each one distinct.\n ...(action ? { key: nextActionKey() } : {}),\n action: action\n ? (key) => (\n <Button variant={\"text\"}\n size={\"small\"}\n className={\"text-inherit\"}\n onClick={() => {\n action.onClick();\n // The offer has been taken; leaving it up\n // invites a second click that undoes nothing,\n // or worse, undoes something else.\n closeSnackbar(key);\n }}>\n {action.label}\n </Button>\n )\n : undefined\n })\n }, [enqueueSnackbar, closeSnackbar]);\n\n const close = useCallback(() => {\n closeSnackbar();\n }, [closeSnackbar]);\n\n return useMemo(() => ({\n open,\n close\n }), [open, close]);\n\n};\n\nlet actionKeySeq = 0;\nconst nextActionKey = () => `rebase-snackbar-action-${actionKeySeq++}`;\n","import { UserConfigurationPersistence } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { UserConfigurationPersistenceContext } from \"../contexts/UserConfigurationPersistenceContext\";\n\n/**\n * Use this controller to access the configuration that is stored externally,\n * and not defined in code\n *\n * @group Hooks and utilities\n */\nexport const useUserConfigurationPersistence = (): UserConfigurationPersistence | undefined => useContext(UserConfigurationPersistenceContext);\n","import type { DialogsController } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { DialogsControllerContext } from \"../contexts/DialogsProvider\";\n;\n\n/**\n * Use this hook to open a dialog imperatively.\n * Alternatively, you can use dialogs declaratively using the `Dialog` component.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @group Hooks and utilities\n */\nexport const useDialogsController = (): DialogsController => {\n const controller = useContext(DialogsControllerContext);\n if (!controller) throw new Error(\"useDialogsController must be used inside <Rebase>\");\n return controller;\n};\n","import type { CustomizationController } from \"@rebasepro/cms-types\";\nimport { useContext } from \"react\";\nimport { CustomizationControllerContext } from \"../contexts/CustomizationControllerContext\";\n\n/**\n * Use this hook to retrieve the customization controller.\n * This hook includes all the customization options that can be used\n * to customize the admin.\n *\n * You will likely not need to use this hook directly.\n *\n * @group Hooks and utilities\n */\nexport const useCustomizationController = (): CustomizationController => {\n const controller = useContext(CustomizationControllerContext);\n if (!controller) throw new Error(\"useCustomizationController must be used inside <Rebase>\");\n return controller;\n};\n","import { useContext } from \"react\";\nimport { AnalyticsController } from \"@rebasepro/cms-types\";\nimport { AnalyticsContext } from \"../contexts/AnalyticsContext\";\n\n/**\n * @group Hooks and utilities\n */\nexport const useAnalyticsController = (): AnalyticsController => useContext(AnalyticsContext);\n","import { useContext } from \"react\";\nimport { EffectiveRoleControllerContext } from \"../contexts/EffectiveRoleController\";\n\n/**\n * Hook to retrieve the {@link EffectiveRoleController}\n *\n * @see EffectiveRoleController\n * @category Hooks and utilities\n */\nexport const useEffectiveRoleController = () => useContext(EffectiveRoleControllerContext);\n","import React from \"react\";\nimport { DatabaseAdmin } from \"@rebasepro/types\";\n\nexport const DatabaseAdminContext = React.createContext<DatabaseAdmin | undefined>(undefined);\n","import { User } from \"@rebasepro/types\";\nimport { AuthController, RebaseContext } from \"@rebasepro/cms-types\";\nimport { wrapAsSdkData } from \"@rebasepro/common\";\nimport { useAuthController } from \"./useAuthController\";\nimport { useRebaseClient } from \"./useRebaseClient\";\nimport { useData } from \"./data/useData\";\nimport { useStorageSource } from \"./useStorageSource\";\nimport { useSnackbarController } from \"./useSnackbarController\";\nimport { useUserConfigurationPersistence } from \"./useUserConfigurationPersistence\";\nimport { useDialogsController } from \"./useDialogsController\";\nimport { useCustomizationController } from \"./useCustomizationController\";\nimport { useAnalyticsController } from \"./useAnalyticsController\";\nimport { useEffectiveRoleController } from \"./useEffectiveRoleController\";\nimport React, { useContext } from \"react\";\n\n\n// DatabaseAdmin is provided by <Rebase> via DatabaseAdminContext.\nimport { DatabaseAdminContext } from \"../contexts/DatabaseAdminContext\";\n\n/**\n * Hook to retrieve the {@link RebaseContext}.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase` component.\n *\n * @see RebaseContext\n * @group Hooks and utilities\n */\nexport const useRebaseContext = <USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>>(): RebaseContext<USER, AuthControllerType> => {\n\n const client = useRebaseClient<any>();\n\n const authController = useAuthController<USER, AuthControllerType>();\n // `context.data` is the flat SDK view — identical in shape to the backend\n // `context.data` and the frontend SDK client, so callbacks behave the same\n // everywhere. The admin reads Entities via `useData()` directly.\n const entityData = useData();\n const data = React.useMemo(() => wrapAsSdkData(entityData), [entityData]);\n const storageSource = useStorageSource();\n const snackbarController = useSnackbarController();\n const userConfigPersistence = useUserConfigurationPersistence();\n const dialogsController = useDialogsController();\n const customizationController = useCustomizationController();\n const analyticsController = useAnalyticsController();\n const effectiveRoleController = useEffectiveRoleController();\n\n\n // Will get `databaseAdmin` from context\n const databaseAdmin = useContext(DatabaseAdminContext);\n\n // Built during render, so it is the context of *this* render. It used to be\n // kept in a ref and refreshed from an effect, which put every reader one\n // render behind: a sign-in or sign-out that caused no further render was\n // never seen by anything that read `context.authController`.\n return React.useMemo<RebaseContext<USER, AuthControllerType>>(() => ({\n authController,\n data,\n storageSource,\n snackbarController,\n userConfigPersistence,\n dialogsController,\n customizationController,\n analyticsController,\n effectiveRoleController,\n databaseAdmin,\n client: client! // Client should be provided\n }), [authController, data, storageSource, snackbarController, userConfigPersistence,\n dialogsController, customizationController, analyticsController,\n effectiveRoleController, databaseAdmin, client]);\n}\n","\nimport { useEffect, useState, useMemo } from \"react\";\nimport { Entity, User } from \"@rebasepro/types\";\nimport { RebaseContext, AdminCollection } from \"@rebasepro/cms-types\";\nimport { useData } from \"./useData\";\nimport { useRebaseContext } from \"../useRebaseContext\";\nimport { isConnectionLostError } from \"../../util/realtime\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\n\n/**\n * @group Hooks and utilities\n */\nexport interface FetchProps<M extends Record<string, any>, USER extends User = User> {\n path: string;\n entityId?: string | number;\n databaseId?: string;\n collection: AdminCollection<M, USER>;\n useCache?: boolean;\n /**\n * Load the collection's relation properties into the record, as a list\n * read loads them into each row. The record views ask for it: a form built\n * on a record without them shows a many-to-many field empty, and saving it\n * sets that empty membership. A preview leaves it off, since it would load\n * every related row of the record it previews.\n */\n relations?: boolean;\n}\n\n/**\n * @group Hooks and utilities\n */\nexport interface FetchResult<M extends Record<string, any>> {\n entity?: Entity<M>,\n dataLoading: boolean,\n dataLoadingError?: Error\n}\n\n/**\n * The most records {@link useFetch}'s cache holds. Past it, the record written\n * or read least recently goes first.\n *\n * The cache is what lets a record open with its values already on screen while\n * its listener catches up. It used to be fed every row a collection view held,\n * on every update of the view, and never let go of one: a table scrolled to\n * 100,000 rows kept ~260 MB alive after it was closed. A record is opened from\n * a list by clicking it, so the click is what puts it here now (see\n * `populateFetchCache`), and this bounds whatever else does.\n */\nconst FETCH_CACHE_LIMIT = 2_000;\n\n/**\n * Key: `${path}/${id}`. Holds what the signed-in user read, so it is emptied on\n * sign-out (`clearFetchCache`, from `session_caches.ts`). A `Map` for its\n * insertion order: reading or writing an entry moves it to the end, and the\n * first entry is the one to evict.\n */\nconst CACHE = new Map<string, Entity<any>>();\n\nfunction readCache<M extends Record<string, any>>(key: string): Entity<M> | undefined {\n const entity = CACHE.get(key);\n if (entity !== undefined) {\n CACHE.delete(key);\n CACHE.set(key, entity);\n }\n return entity as Entity<M> | undefined;\n}\n\nfunction writeCache(key: string, entity: Entity<any> | undefined): void {\n CACHE.delete(key);\n if (entity === undefined) return;\n CACHE.set(key, entity);\n if (CACHE.size > FETCH_CACHE_LIMIT) {\n const oldest = CACHE.keys().next().value;\n if (oldest !== undefined) CACHE.delete(oldest);\n }\n}\n\n/**\n * Put records in the entity fetch cache, so a view that opens one renders it at\n * once while the background fetch/listener brings in fresh data. The cache\n * keeps the 2,000 records written or read most recently.\n * @param path - The collection path (e.g. \"products\")\n * @param entities - Array of entities to cache\n */\nexport function populateFetchCache<M extends Record<string, any>>(path: string, entities: Entity<M>[]): void {\n for (const entity of entities) {\n writeCache(`${path}/${entity.id}`, entity);\n }\n}\n\n/**\n * Clear the entity fetch cache. Call this on auth state changes (e.g. logout)\n * to prevent stale data from a previous session leaking into the next.\n */\nexport function clearFetchCache(): void {\n CACHE.clear();\n}\n\n/**\n * `delivered`, with every relation property it does not carry taken from the\n * record already on screen.\n *\n * The record's read names the collection's relation properties (see\n * `useFetch`), so a frame normally carries them. One that does not — from a\n * server that ignores a row subscription's `include`, or a data source that\n * cannot load relations — has the key absent, not empty. The list row a click\n * opens the record on does carry it. Replaced wholesale, such a frame took\n * `tags` off the screen; the form follows an untouched field, so the field\n * emptied, and a tag added to it was saved as the whole set — which a\n * many-to-many save takes as the new membership, unlinking every other tag.\n * Absent is \"not delivered\": the value the record was opened with stands until\n * a frame carries one (an empty array included). Same record only; nothing\n * survives a deletion.\n */\nfunction keepUndeliveredRelations<M extends Record<string, any>>(\n shown: Entity<M> | undefined,\n delivered: Entity<M>,\n collection: AdminCollection<M, any>\n): Entity<M> {\n if (!shown || String(shown.id) !== String(delivered.id)) return delivered;\n const properties = collection.properties;\n if (!properties) return delivered;\n let values: M | undefined;\n for (const [name, property] of Object.entries(properties)) {\n if (property?.type !== \"relation\") continue;\n if (name in (delivered.values ?? {}) || !(name in (shown.values ?? {}))) continue;\n values ??= { ...delivered.values };\n values[name as keyof M] = shown.values[name];\n }\n return values ? { ...delivered, values } : delivered;\n}\n\n/**\n * The relations a record's read loads: the ones a list read of the same\n * collection loads into each row. Typed as `keepUndeliveredRelations` takes its\n * collection, since `useFetch`'s own `USER` reaches the export callbacks.\n */\nfunction relationsToRead<M extends Record<string, any>>(collection: AdminCollection<M, any>): { include: string[] } | undefined {\n const include = getRelationIncludeParams(collection);\n return include ? { include } : undefined;\n}\n\n/**\n * This hook is used to fetch a entity.\n * It gives real time updates if the driver supports it.\n * @param path\n * @param collection\n * @param entityId\n * @param useCache\n * @group Hooks and utilities\n */\n\nexport function useFetch<M extends Record<string, any>, USER extends User = User>(\n {\n path,\n entityId,\n collection,\n databaseId,\n useCache = false,\n relations = false\n }: FetchProps<M, USER>): FetchResult<M> {\n\n const dataClient = useData();\n\n const context: RebaseContext<USER> = useRebaseContext();\n\n // Seed initial state from the cache to avoid skeleton flashes.\n // Even when useCache is false, we show cached data instantly while\n // the background fetch/listener brings in fresh data.\n const cacheKey = entityId ? `${path}/${entityId}` : undefined;\n // Read once per mount, not per render: a read also marks the entry used.\n const [cachedEntity] = useState<Entity<M> | undefined>(() => cacheKey ? readCache<M>(cacheKey) : undefined);\n\n const [entity, setEntity] = useState<Entity<M> | undefined>(cachedEntity);\n const [dataLoading, setDataLoading] = useState<boolean>(!cachedEntity);\n const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();\n\n useEffect(() => {\n\n const key = `${path}/${entityId}`;\n const cached = readCache<M>(key);\n\n // Only show loading state if we have no cached entity to display\n if (!cached) {\n setDataLoading(true);\n }\n\n // Whether a record is on screen — the cached one counts.\n let showingEntity = Boolean(cached);\n // The record on screen, so a frame can be read against it.\n let shown: Entity<M> | undefined = cached;\n\n const onEntityUpdate = async (delivered?: Entity<M> | null) => {\n const updatedEntity = delivered ? keepUndeliveredRelations(shown, delivered, collection) : delivered;\n shown = updatedEntity ?? undefined;\n showingEntity = Boolean(updatedEntity);\n writeCache(key, updatedEntity ?? undefined);\n setEntity(updatedEntity ?? undefined);\n setDataLoading(false);\n setDataLoadingError(undefined);\n };\n\n const onError = (error: Error) => {\n // The connection is down, not the record. Dropping the entity here\n // unmounted an open edit form, and everything typed into it, over\n // an outage the client recovers from on its own: the listener is\n // kept, and its next update is the fresh record.\n if (showingEntity && isConnectionLostError(error)) return;\n console.error(\"ERROR fetching entity\", error);\n setDataLoading(false);\n setEntity(undefined);\n setDataLoadingError(error);\n };\n\n if (entityId && useCache && cached) {\n setEntity(cached);\n setDataLoading(false);\n setDataLoadingError(undefined);\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n return () => {\n };\n } else if (entityId && path && collection) {\n const accessor = dataClient.collection(path);\n // The relations the form edits, read with the record exactly as a\n // list read includes them. Without them a to-many relation was\n // absent from the record, and one opened by URL — nothing cached\n // to fall back on — showed its many-to-many field empty; a save\n // from it set that empty membership, unlinking every related row.\n const readOptions = relations ? relationsToRead(collection) : undefined;\n\n if (accessor.listenById) {\n return accessor.listenById(entityId, (entity) => onEntityUpdate(entity as Entity<M> | undefined), onError, readOptions);\n } else {\n // The one-shot fallback, taken whenever the client has no\n // socket. `listenById` above cancels on cleanup; a promise\n // cannot, so the cleanup disowns its result instead. `entityId`\n // is an effect dependency, and where this hook's caller is not\n // remounted per record — the side panel replaces its contents\n // in place — a slow response for the record just left would\n // otherwise land on top of the one now showing.\n let cancelled = false;\n accessor.findById(entityId, readOptions)\n .then((entity) => {\n if (cancelled) return;\n onEntityUpdate(entity as Entity<M> | undefined);\n })\n .catch((e) => {\n if (cancelled) return;\n onError(e);\n });\n return () => {\n cancelled = true;\n };\n }\n }\n // if no entityId is provided we do nothing\n else {\n onEntityUpdate(undefined);\n return () => {\n };\n }\n }, [entityId, path, dataClient, collection, useCache, databaseId, relations]);\n\n return useMemo(() => ({\n entity,\n dataLoading,\n dataLoadingError\n }), [entity, dataLoading, dataLoadingError]);\n\n}\n","import { useCallback, useMemo, useSyncExternalStore } from \"react\";\nimport type { CollectionAccessor, Entity, FindResponse, RebaseData } from \"@rebasepro/types\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { resolvePrimaryKeys } from \"@rebasepro/common\";\nimport { useData } from \"./useData\";\nimport { isConnectionLostError } from \"../../util/realtime\";\nimport type { FetchResult } from \"./useFetch\";\n\n/**\n * The most ids one batch reads. The same ceiling the API puts on a page.\n */\nconst MAX_BATCH = 1_000;\n\n/** What one record looks like to the previews that show it. */\ninterface Snapshot {\n entity?: Entity<any>;\n dataLoading: boolean;\n dataLoadingError?: Error;\n}\n\nconst LOADING: Snapshot = Object.freeze({ dataLoading: true });\n\ninterface Batch {\n /** Ids this batch still answers for; a slot that leaves drops out. */\n ids: Set<string>;\n stop?: () => void;\n}\n\ninterface Slot {\n snapshot: Snapshot;\n listeners: Set<() => void>;\n refs: number;\n batch?: Batch;\n}\n\n/**\n * One collection's batched record reads, for the previews of references.\n *\n * Every id a preview asks for in the same tick is read by one query — `where\n * <key> in [ids]` — and kept live by ONE subscription to that query, instead\n * of one `listenById` per id. A reference column showing 23 distinct targets\n * was 23 subscriptions, 23 single-row reads and 23 server refetches per write\n * to the target collection; it is one of each now.\n *\n * Authorization is unchanged: the read goes through the same accessor, as the\n * signed-in user, that each `listenById` did. Nothing is shared between data\n * clients — a batcher belongs to one `RebaseData`, and a sign-out replaces it.\n *\n * Kept per id: a reference counter. A slot lives while a preview shows it; the\n * batch's subscription closes when the last id it answers for is let go.\n * Releases are settled a microtask later, so a preview that remounts at once\n * (React's StrictMode, a list re-keying) keeps its record and its subscription.\n */\nclass RecordBatcher {\n private readonly slots = new Map<string, Slot>();\n private readonly pending = new Set<string>();\n private readonly released = new Set<string>();\n private flushScheduled = false;\n private settleScheduled = false;\n\n constructor(\n private readonly accessor: CollectionAccessor<any>,\n /** The one key column, and its type — `undefined` for a composite key. */\n private readonly key: { fieldName: string; type: \"string\" | \"number\" } | undefined\n ) {}\n\n peek(id: string): Snapshot {\n return this.slots.get(id)?.snapshot ?? LOADING;\n }\n\n subscribe(id: string, listener: () => void): () => void {\n let slot = this.slots.get(id);\n if (!slot) {\n slot = { snapshot: LOADING, listeners: new Set(), refs: 0 };\n this.slots.set(id, slot);\n this.pending.add(id);\n this.scheduleFlush();\n }\n slot.refs++;\n slot.listeners.add(listener);\n const owned = slot;\n return () => {\n owned.listeners.delete(listener);\n owned.refs--;\n if (owned.refs === 0) {\n this.released.add(id);\n this.scheduleSettle();\n }\n };\n }\n\n private scheduleFlush(): void {\n if (this.flushScheduled) return;\n this.flushScheduled = true;\n queueMicrotask(() => {\n this.flushScheduled = false;\n const ids = [...this.pending];\n this.pending.clear();\n for (let i = 0; i < ids.length; i += MAX_BATCH) this.start(ids.slice(i, i + MAX_BATCH));\n });\n }\n\n private scheduleSettle(): void {\n if (this.settleScheduled) return;\n this.settleScheduled = true;\n queueMicrotask(() => {\n this.settleScheduled = false;\n for (const id of this.released) {\n const slot = this.slots.get(id);\n if (!slot || slot.refs > 0) continue;\n this.slots.delete(id);\n this.pending.delete(id);\n const batch = slot.batch;\n if (!batch) continue;\n batch.ids.delete(id);\n if (batch.ids.size === 0) batch.stop?.();\n }\n this.released.clear();\n });\n }\n\n private set(id: string, batch: Batch, snapshot: Snapshot): void {\n const slot = this.slots.get(id);\n if (!slot || slot.batch !== batch) return;\n slot.snapshot = snapshot;\n for (const listener of [...slot.listeners]) listener();\n }\n\n private start(ids: string[]): void {\n const batch: Batch = { ids: new Set(ids) };\n for (const id of ids) {\n const slot = this.slots.get(id);\n if (slot) slot.batch = batch;\n }\n\n const onError = (error: Error) => {\n for (const id of batch.ids) {\n const current = this.slots.get(id)?.snapshot;\n // The connection is down, not the record: what is on screen\n // stays, and the subscription's next frame is the fresh one.\n if (current?.entity && isConnectionLostError(error)) continue;\n this.set(id, batch, { dataLoading: false, dataLoadingError: error });\n }\n };\n\n // A composite key has no single column to put an `in` on: each record\n // is read on its own, as before.\n if (!this.key) {\n const stops = ids.map(id => this.readOne(id, batch, onError));\n batch.stop = () => stops.forEach(stop => stop());\n return;\n }\n\n const values = ids.map(id => this.key!.type === \"number\" && !isNaN(Number(id)) ? Number(id) : id);\n const params = { where: { [this.key.fieldName]: [\"in\", values] }, limit: ids.length };\n const deliver = (response: FindResponse<any>) => {\n const byId = new Map(response.data.map(entity => [String(entity.id), entity]));\n for (const id of batch.ids) {\n // Absent from the answer is \"not there\" — deleted, or not\n // readable by this user — exactly as `listenById` reports it.\n this.set(id, batch, { entity: byId.get(id), dataLoading: false });\n }\n };\n\n if (this.accessor.listen) {\n batch.stop = this.accessor.listen(params as never, deliver, onError);\n return;\n }\n // The one-shot fallback, for a client with no socket.\n let stopped = false;\n batch.stop = () => { stopped = true; };\n this.accessor.find(params as never)\n .then(response => { if (!stopped) deliver(response); })\n .catch(error => { if (!stopped) onError(error instanceof Error ? error : new Error(String(error))); });\n }\n\n private readOne(id: string, batch: Batch, onError: (error: Error) => void): () => void {\n const deliver = (entity: Entity<any> | undefined | null) =>\n this.set(id, batch, { entity: entity ?? undefined, dataLoading: false });\n if (this.accessor.listenById) return this.accessor.listenById(id, deliver, onError);\n let stopped = false;\n this.accessor.findById(id)\n .then(entity => { if (!stopped) deliver(entity); })\n .catch(error => { if (!stopped) onError(error instanceof Error ? error : new Error(String(error))); });\n return () => { stopped = true; };\n }\n}\n\n/**\n * Batchers by data client, then by collection path.\n *\n * Key: the `RebaseData` instance (weakly — a client that is dropped takes its\n * batchers with it) and the path. A batcher holds only records some preview\n * still shows; nothing outlives its last subscriber.\n */\nconst BATCHERS = new WeakMap<RebaseData, Map<string, RecordBatcher>>();\n\nfunction batcherFor(data: RebaseData, path: string, collection: AdminCollection<any>): RecordBatcher {\n let byPath = BATCHERS.get(data);\n if (!byPath) {\n byPath = new Map();\n BATCHERS.set(data, byPath);\n }\n let batcher = byPath.get(path);\n if (!batcher) {\n const keys = resolvePrimaryKeys(collection as never);\n batcher = new RecordBatcher(\n data.collection(path),\n keys.length === 1 ? { fieldName: keys[0].fieldName, type: keys[0].type } : undefined\n );\n byPath.set(path, batcher);\n }\n return batcher;\n}\n\n/**\n * {@link useFetch} for a record many previews on one screen ask for at once —\n * the target of a reference in a table cell, a card, an array of references.\n *\n * The ids every preview asks for in one tick are read together: one query and\n * one live subscription per batch, not one `listenById` per record. Updates\n * reach a preview per batch — a write to any record of the batch refetches the\n * batch — which is what a preview needs.\n *\n * For one record a view edits, use {@link useFetch}: it follows that record\n * alone and seeds from the record cache.\n *\n * @group Hooks and utilities\n */\nexport function useBatchedFetch<M extends Record<string, any>>({\n path,\n entityId,\n collection\n}: {\n path: string;\n entityId?: string | number;\n collection: AdminCollection<M>;\n}): FetchResult<M> {\n const data = useData();\n const id = entityId === undefined || entityId === null || entityId === \"\" ? undefined : String(entityId);\n // The batcher depends on whether there is an id, not on which one.\n const hasId = id !== undefined;\n const batcher = useMemo(\n () => hasId ? batcherFor(data, path, collection) : undefined,\n [data, path, collection, hasId]\n );\n\n const subscribe = useCallback(\n (listener: () => void) => batcher && id !== undefined ? batcher.subscribe(id, listener) : () => undefined,\n [batcher, id]\n );\n const getSnapshot = useCallback(\n () => batcher && id !== undefined ? batcher.peek(id) : NO_RECORD,\n [batcher, id]\n );\n const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n return snapshot as FetchResult<M>;\n}\n\nconst NO_RECORD: Snapshot = Object.freeze({ dataLoading: false });\n","\nimport { useCallback, useEffect, useRef, useState, useMemo } from \"react\";\nimport { useData } from \"./useData\";\nimport { Entity, EntityRelation, FilterValues } from \"@rebasepro/types\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\nimport { CollectionWindow } from \"./collectionWindow\";\nimport { useStableFilterValues } from \"./useStableFilterValues\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nexport interface RelationItem {\n id: string | number;\n label: string;\n description?: string;\n data: Entity<any>;\n relation: EntityRelation;\n}\n\nexport interface UseRelationSelectorProps<M extends Record<string, any> = any> {\n /**\n * Full path where the relation data is located\n */\n path: string;\n /**\n * The collection that represents the relation entities\n */\n collection: AdminCollection<M>;\n /**\n * Force filter to be applied to the relation search\n */\n fixedFilter?: FilterValues<string>;\n /**\n * Page size for pagination\n */\n pageSize?: number;\n /**\n * Function to extract the label from a entity\n */\n getLabelFromEntity?: (entity: Entity<M>) => string;\n /**\n * Function to extract the description from a entity\n */\n getDescriptionFromEntity?: (entity: Entity<M>) => string | undefined;\n /**\n * Property name to use as the secondary display field\n */\n descriptionProperty?: keyof M;\n /**\n * Whether the list should be fetched at all. Defaults to `true`.\n *\n * A picker that is mounted is not a picker that is open, and the two used\n * to be the same thing here: the fetch ran on mount, so a collection table\n * with a relation column paid for one query — or one realtime subscription\n * — per rendered row before anyone clicked a cell. Pass `false` until the\n * list is actually needed and nothing is requested; flipping it to `true`\n * fetches once, and it never goes back.\n */\n enabled?: boolean;\n}\n\nexport interface RelationSelectorController {\n items: RelationItem[];\n isLoading: boolean;\n error: Error | undefined;\n search: (searchString: string) => void;\n loadMore: () => void;\n hasMore: boolean;\n entityToRelationItem: (entity: Entity<any>, relation: EntityRelation) => RelationItem;\n}\n\nconst DEFAULT_PAGE_SIZE = 10;\n\n/**\n * Hook to manage relation selection with data fetching from Rebase data source\n */\nexport function useRelationSelector<M extends Record<string, any> = any>(\n {\n path,\n collection,\n fixedFilter,\n pageSize = DEFAULT_PAGE_SIZE,\n getLabelFromEntity,\n getDescriptionFromEntity,\n descriptionProperty,\n enabled = true\n }: UseRelationSelectorProps<M>\n): RelationSelectorController {\n\n const dataClient = useData();\n // Held by content, not identity: callers write it inline.\n const stableFixedFilter = useStableFilterValues(fixedFilter);\n\n const [items, setItems] = useState<RelationItem[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const isLoadingRef = useRef(false);\n const [error, setError] = useState<Error | undefined>();\n const [hasMore, setHasMore] = useState(true);\n const [currentSearch, setCurrentSearch] = useState<string>(\"\");\n const [limit, setLimit] = useState<number>(pageSize);\n\n const unsubscribeRef = useRef<(() => void) | null>(null);\n const searchTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n // Whether a fetch has ever completed. Between `enabled` flipping and the\n // effect running there is one paint with no items and no request in\n // flight; without this the list shows \"no results\" for that frame.\n const hasLoadedRef = useRef(false);\n\n const setLoading = useCallback((loading: boolean) => {\n isLoadingRef.current = loading;\n setIsLoading(loading);\n }, []);\n\n // Function to convert entity to RelationItem\n const entityToRelationItem = useCallback((entity: Entity<M>, relation?: EntityRelation): RelationItem => {\n let label: string;\n let description: string | undefined;\n\n if (getLabelFromEntity) {\n label = getLabelFromEntity(entity);\n } else {\n // Fallback: try common label properties\n const commonLabelProps = [\"name\", \"title\", \"label\", \"displayName\"];\n let foundProp: string | undefined;\n\n if (entity.values) {\n foundProp = commonLabelProps.find(prop => entity.values[prop] != null && entity.values[prop] !== \"\");\n }\n\n if (foundProp && entity.values[foundProp]) {\n label = String(entity.values[foundProp]);\n } else {\n // Ultimate fallback: use entity ID\n label = String(entity.id);\n }\n }\n\n if (getDescriptionFromEntity) {\n description = getDescriptionFromEntity(entity);\n } else if (descriptionProperty && entity.values && entity.values[descriptionProperty]) {\n description = String(entity.values[descriptionProperty]);\n }\n\n return {\n id: entity.id,\n label,\n description,\n data: entity,\n relation: relation ? relation : new EntityRelation(entity.id, path)\n };\n }, [getLabelFromEntity, getDescriptionFromEntity, descriptionProperty]);\n\n // Clean up any existing subscription\n const cleanupSubscription = useCallback(() => {\n if (unsubscribeRef.current) {\n unsubscribeRef.current();\n unsubscribeRef.current = null;\n }\n }, []);\n\n // Eagerly include relations to avoid N+1 fetches. Referentially stable, so\n // it can be a dependency below without re-triggering the fetch.\n const includeParams = getRelationIncludeParams(collection);\n\n // How many rows the picker wants, read by the window below a page at a\n // time. A ref so that asking for more grows the window instead of\n // re-opening it.\n const limitRef = useRef(limit);\n limitRef.current = limit;\n const windowRef = useRef<CollectionWindow<Record<string, unknown>> | null>(null);\n\n const fetchData = useCallback(() => {\n cleanupSubscription();\n setError(undefined);\n setLoading(true);\n\n // fixedFilter is already FilterValues — pass directly\n const whereParams = stableFixedFilter && Object.keys(stableFixedFilter).length > 0 ? stableFixedFilter : undefined;\n\n // The first page is live when the client has a socket; every later\n // page is read by offset, past the rows already held, and never above\n // the API's read ceiling. \"Load more\" used to raise one read's\n // `limit`, which re-read every option before it and was refused once\n // it passed 1,000.\n //\n // `dispose` is what keeps this hook's results matching the query that\n // asked for them: an answer for \"ab\" that lands after the window for\n // \"abc\" opened is dropped, not painted.\n const collectionWindow = new CollectionWindow({\n accessor: dataClient.collection(path),\n query: {\n where: whereParams,\n searchString: currentSearch || undefined,\n include: includeParams\n },\n pageSize,\n target: limitRef.current,\n onChange: (state) => {\n if (state.rows) {\n hasLoadedRef.current = true;\n setItems((state.rows as Entity<M>[]).map((e) => entityToRelationItem(e)));\n setHasMore(!state.complete && !state.error);\n }\n if (state.error) {\n console.error(\"useRelationSelector: Error fetching data:\", state.error);\n hasLoadedRef.current = true;\n }\n setError(state.error);\n setLoading(state.loading);\n }\n });\n windowRef.current = collectionWindow;\n collectionWindow.start();\n\n unsubscribeRef.current = () => {\n collectionWindow.dispose();\n if (windowRef.current === collectionWindow) windowRef.current = null;\n };\n }, [dataClient, path, stableFixedFilter, pageSize, currentSearch, entityToRelationItem, cleanupSubscription, setLoading, includeParams]);\n\n // \"Load more\" asks the open window for the next page.\n useEffect(() => {\n windowRef.current?.setTarget(limit);\n }, [limit]);\n\n // Search function with debouncing\n const search = useCallback((searchString: string) => {\n // Clear existing timeout\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n\n // Debounce search\n searchTimeoutRef.current = setTimeout(() => {\n setLimit(pageSize);\n setCurrentSearch(searchString);\n }, searchString.trim() ? 300 : 0);\n }, [pageSize]);\n\n // Load more function\n const loadMore = useCallback(() => {\n if (!isLoadingRef.current && hasMore && items.length > 0) {\n setLoading(true);\n setLimit(prev => prev + pageSize);\n }\n }, [hasMore, items.length, pageSize, setLoading]);\n\n // Load initial data and update upon changes\n useEffect(() => {\n if (!enabled) return;\n fetchData();\n\n return () => {\n cleanupSubscription();\n };\n }, [fetchData, enabled, cleanupSubscription]);\n\n useEffect(() => {\n return () => {\n if (searchTimeoutRef.current) {\n clearTimeout(searchTimeoutRef.current);\n }\n };\n }, []);\n\n return useMemo(() => ({\n items,\n // Enabled but not answered yet still counts as loading, so the frame\n // between opening the picker and the request starting shows a spinner\n // rather than \"no results\".\n isLoading: isLoading || (enabled && !hasLoadedRef.current),\n error,\n search,\n loadMore,\n hasMore,\n entityToRelationItem\n }), [items, isLoading, error, search, loadMore, hasMore, entityToRelationItem, enabled]);\n}\n","\nimport { Entity, EntityStatus, EntityValues } from \"@rebasepro/types\";\nimport { RebaseContext, AdminCollection } from \"@rebasepro/cms-types\";\nimport { RebaseData } from \"@rebasepro/types\";\n\n/**\n * @group Hooks and utilities\n */\nexport type SaveEntityWithCallbacksProps<M extends Record<string, unknown>> = {\n path: string;\n values: Partial<EntityValues<M>>;\n entityId?: string | number;\n previousValues?: Partial<EntityValues<M>>;\n collection?: AdminCollection<M>;\n status: EntityStatus;\n /**\n * The version the edit was made against — the edited entity's\n * {@link Entity.etag}. An update is then refused with `412\n * PRECONDITION_FAILED` if the record has changed since, rather than\n * writing over the change. Ignored for a create.\n */\n ifMatch?: string;\n afterSave?: (updatedEntity: Entity<M>) => void,\n afterSaveError?: (e: Error) => void\n}\n\n/**\n * This function is in charge of saving a entity.\n *\n * It runs the collection's **`admin.browserCallbacks`** around the write —\n * `beforeSave`, then `afterSave` or `afterSaveError`. Not `callbacks`: that\n * block belongs to the server, which runs it inside the write it serves, and\n * its bodies are stripped from this bundle entirely.\n *\n * Which matters most for a collection on a `direct`/`custom` transport, where\n * the panel talks to the store itself and no server sees the write at all —\n * before this ran them, such a collection had no write callbacks anywhere. This\n * function has been named `saveEntityWithCallbacks` since it was written and\n * did not run any.\n *\n * A `beforeSave` that throws blocks the write, exactly as the server's does:\n * nothing is sent, and the error reaches `afterSaveError` and the caller.\n *\n * `afterSave`/`afterSaveError` below are the *caller's* UI callbacks — the\n * form's \"close the dialog\", the table's \"clear the editing state\" — and are\n * unrelated to the collection's. Both run: the collection's first. A\n * collection `afterSave` that throws does not undo the save: the write has\n * committed, so it is reported as a warning and the caller's `afterSave` runs.\n *\n * @param collection\n * @param path\n * @param entityId\n * @param values\n * @param previousValues\n * @param status\n * @param data\n * @param context\n * @param afterSave\n * @param afterSaveError\n * @group Hooks and utilities\n */\nexport async function saveEntityWithCallbacks<M extends Record<string, unknown>>({\n collection,\n path,\n entityId,\n values,\n previousValues,\n status,\n ifMatch,\n data,\n context,\n afterSave,\n afterSaveError\n}: Omit<SaveEntityWithCallbacksProps<M>, \"collection\"> & {\n collection: AdminCollection<M>,\n data: RebaseData,\n context: RebaseContext,\n}\n): Promise<Entity<M>> {\n\n if (status !== \"new\" && status !== \"copy\" && !entityId) {\n throw new Error(\"Entity id must be specified when updating an existing entity\");\n }\n\n const browserCallbacks = collection.browserCallbacks;\n\n let valuesToSave = values;\n if (browserCallbacks?.beforeSave) {\n try {\n valuesToSave = await browserCallbacks.beforeSave({\n collection,\n path,\n id: entityId,\n values,\n previousValues,\n status,\n context\n });\n } catch (e) {\n // A throw here means \"do not save\", so the write never starts. The\n // caller still needs to hear about it, and so does afterSaveError:\n // to the form this is indistinguishable from a rejected write.\n const error = e instanceof Error ? e : new Error(String(e));\n await browserCallbacks.afterSaveError?.({\n collection,\n path,\n id: entityId,\n values,\n previousValues,\n status,\n error,\n context\n });\n if (afterSaveError) afterSaveError(error);\n throw error;\n }\n }\n\n const accessor = data.collection(path);\n\n let savePromise: Promise<Entity<M>>;\n if (status === \"new\" || status === \"copy\") {\n savePromise = accessor.create(valuesToSave, entityId) as Promise<Entity<M>>;\n } else {\n savePromise = (ifMatch\n ? accessor.update(entityId!, valuesToSave, { ifMatch })\n : accessor.update(entityId!, valuesToSave)) as Promise<Entity<M>>;\n }\n\n let entity: Entity<M>;\n try {\n entity = await savePromise;\n } catch (e) {\n await browserCallbacks?.afterSaveError?.({\n collection,\n path,\n id: entityId,\n values: valuesToSave,\n previousValues,\n status,\n error: e as Error,\n context\n });\n if (afterSaveError) afterSaveError(e as Error);\n throw e;\n }\n\n // Awaited, and before the caller's: an afterSave that writes a related\n // row should have finished before the form closes over it.\n //\n // `entity.values`, not the values sent: \"after save\" means the row as\n // saved, and the two differ whenever the write path adds something. The\n // auth create response carries `temporaryPassword` / `invitationSent`\n // beside the columns, and the panel's own injected afterSave — the one\n // that shows the credentials dialog — can only read them here.\n //\n // The write has committed by now, so a throw here is not a failed save.\n // It used to be reported as one: the form stayed on \"new\", and the next\n // Save created a second row. It is said for what it is, and the save\n // completes.\n try {\n await browserCallbacks?.afterSave?.({\n collection,\n path,\n id: entity.id,\n values: entity.values,\n previousValues,\n status,\n context\n });\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e));\n console.error(`afterSave of \"${path}\" failed after the record was saved`, error);\n context.snackbarController?.open({ type: \"warning\", message: error.message });\n }\n if (afterSave)\n afterSave(entity);\n return entity;\n}\n","\nimport { Entity, User } from \"@rebasepro/types\";\nimport { RebaseContext, AdminCollection } from \"@rebasepro/cms-types\";\nimport { RebaseData } from \"@rebasepro/types\";\n\n/**\n * @group Hooks and utilities\n */\nexport type DeleteEntityWithCallbacksProps<M extends Record<string, any>, USER extends User = User> = {\n entity: Entity<M>;\n collection?: AdminCollection<M>;\n onDeleteSuccess?: (entity: Entity<M>) => void;\n onDeleteFailure?: (entity: Entity<M>, e: Error) => void;\n}\n\n/**\n * This function is in charge of deleting a entity.\n *\n * It runs the collection's **`admin.browserCallbacks`** around the delete —\n * `beforeDelete`, then `afterDelete`. Not `callbacks`: that block belongs to\n * the server, which runs it inside the delete it serves, and its bodies are\n * stripped from this bundle entirely.\n *\n * Which matters most for a collection on a `direct`/`custom` transport, where\n * the panel talks to the store itself and no server sees the delete at all —\n * before this ran them, such a collection had no delete callbacks anywhere.\n * This function has been named `deleteEntityWithCallbacks` since it was written\n * and did not run any; it even took a `callbacks` prop and ignored it.\n *\n * A `beforeDelete` that throws blocks the delete, exactly as the server's does:\n * nothing is sent, and `onDeleteFailure` hears about it.\n *\n * @param data\n * @param entity\n * @param collection\n * @param onDeleteSuccess\n * @param onDeleteFailure\n * @param context\n * @group Hooks and utilities\n */\nexport async function deleteEntityWithCallbacks<M extends Record<string, any>, USER extends User>({\n data,\n entity,\n collection,\n onDeleteSuccess,\n onDeleteFailure,\n context\n}: DeleteEntityWithCallbacksProps<M> & {\n collection: AdminCollection<M>,\n data: RebaseData,\n context: RebaseContext<USER>\n}\n): Promise<boolean> {\n\n console.debug(\"Deleting entity\", entity.path, entity.id);\n\n const browserCallbacks = collection.browserCallbacks;\n\n if (browserCallbacks?.beforeDelete) {\n try {\n await browserCallbacks.beforeDelete({\n collection,\n path: entity.path,\n id: entity.id,\n row: { id: entity.id, ...entity.values },\n context\n });\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e));\n if (onDeleteFailure) onDeleteFailure(entity, error);\n return false;\n }\n }\n\n return data.collection(entity.path).delete(entity.id).then(async () => {\n await browserCallbacks?.afterDelete?.({\n collection,\n path: entity.path,\n id: entity.id,\n row: { id: entity.id, ...entity.values },\n context\n });\n if (onDeleteSuccess) onDeleteSuccess(entity);\n return true;\n }).catch((e) => {\n if (onDeleteFailure) onDeleteFailure(entity, e);\n return false;\n });\n}\n","import React, { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport {\n Blocker,\n BlockerFunction,\n Location,\n NavigationType,\n UNSAFE_DataRouterContext,\n UNSAFE_DataRouterStateContext,\n useBlocker\n} from \"react-router\";\n\nconst IDLE_BLOCKER: Blocker = {\n state: \"unblocked\",\n proceed: undefined,\n reset: undefined,\n location: undefined\n};\n\ntype NavigationBlockerContextValue = {\n register: (id: string, predicate: BlockerFunction) => void;\n unregister: (id: string) => void;\n blocker: Blocker;\n /** Id of the registration that caused the current block, if any. */\n blockedBy: string | null;\n};\n\nconst NavigationBlockerContext = createContext<NavigationBlockerContextValue | null>(null);\n\n/**\n * Owns the single navigation guard for the whole app.\n *\n * Under a React Router **data router** (`createBrowserRouter` +\n * `<RouterProvider>`) it holds the one `useBlocker` in the tree. React Router\n * only honours one blocker at a time: `shouldBlockNavigation` picks the\n * last-registered blocker function and silently ignores every other one (it\n * only logs a dev warning). Because blockers register in a `useEffect`, the\n * winner is whichever surface mounted most recently — so an unsaved-changes\n * guard could be disabled by an unrelated component mounting after it. This\n * provider registers the only one and multiplexes it, so every surface that\n * guards navigation gets a say regardless of mount order.\n *\n * Under any **other** router (a plain `<BrowserRouter>`, a `<MemoryRouter>`)\n * there is no `useBlocker` to call — it throws outside a data router — and no\n * way to intercept an in-app navigation. The guards then degrade to the\n * browser's own: leaving the page (reload, tab close, typing a URL) asks for\n * confirmation while any registered guard would block leaving.\n *\n * Surfaces register through {@link useNavigationBlocker}.\n */\nexport function NavigationBlockerProvider({ children }: { children: React.ReactNode }) {\n // Both contexts are set by `<RouterProvider>` and by nothing else, and\n // `useBlocker` reads both. Which provider renders is fixed by where this\n // sits, so the branch never switches hooks under a mounted component.\n const dataRouter = useContext(UNSAFE_DataRouterContext);\n const dataRouterState = useContext(UNSAFE_DataRouterStateContext);\n return dataRouter && dataRouterState\n ? <DataRouterBlockerProvider>{children}</DataRouterBlockerProvider>\n : <BeforeUnloadBlockerProvider>{children}</BeforeUnloadBlockerProvider>;\n}\n\n/** The registered guards, and which of them caused the current block. */\nfunction useGuardRegistry() {\n const predicates = useRef(new Map<string, BlockerFunction>());\n\n // State, not a ref: the owning registration only renders its dialog once\n // this has propagated, so it has to go through React.\n const [blockedBy, setBlockedBy] = useState<string | null>(null);\n\n const register = useCallback((id: string, predicate: BlockerFunction) => {\n predicates.current.set(id, predicate);\n }, []);\n\n const unregister = useCallback((id: string) => {\n predicates.current.delete(id);\n setBlockedBy((current) => (current === id ? null : current));\n }, []);\n\n return { predicates, blockedBy, setBlockedBy, register, unregister };\n}\n\nfunction DataRouterBlockerProvider({ children }: { children: React.ReactNode }) {\n const { predicates, blockedBy, setBlockedBy, register, unregister } = useGuardRegistry();\n\n const shouldBlock = useCallback<BlockerFunction>((args) => {\n for (const [id, predicate] of predicates.current) {\n if (predicate(args)) {\n setBlockedBy(id);\n return true;\n }\n }\n setBlockedBy(null);\n return false;\n }, [predicates, setBlockedBy]);\n\n const blocker = useBlocker(shouldBlock);\n\n const value = useMemo<NavigationBlockerContextValue>(() => ({\n register,\n unregister,\n blocker,\n blockedBy\n }), [register, unregister, blocker, blockedBy]);\n\n return (\n <NavigationBlockerContext.Provider value={value}>\n {children}\n </NavigationBlockerContext.Provider>\n );\n}\n\n/**\n * Where a page unload goes, as a guard sees it: somewhere that is not this\n * app. No path, so it matches no record, tab or panel a guard lets through.\n */\nconst OUTSIDE_THE_APP: Location = {\n pathname: \"\",\n search: \"\",\n hash: \"\",\n state: null,\n key: \"beforeunload\"\n};\n\nfunction BeforeUnloadBlockerProvider({ children }: { children: React.ReactNode }) {\n const { predicates, register, unregister } = useGuardRegistry();\n\n useEffect(() => {\n const onBeforeUnload = (event: BeforeUnloadEvent) => {\n const here: Location = {\n pathname: window.location.pathname,\n search: window.location.search,\n hash: window.location.hash,\n state: null,\n key: \"default\"\n };\n for (const predicate of predicates.current.values()) {\n if (predicate({ currentLocation: here, nextLocation: OUTSIDE_THE_APP, historyAction: NavigationType.Pop })) {\n event.preventDefault();\n // Still what Chrome and Safari read to show the prompt.\n event.returnValue = \"\";\n return;\n }\n }\n };\n window.addEventListener(\"beforeunload\", onBeforeUnload);\n return () => window.removeEventListener(\"beforeunload\", onBeforeUnload);\n }, [predicates]);\n\n const value = useMemo<NavigationBlockerContextValue>(() => ({\n register,\n unregister,\n blocker: IDLE_BLOCKER,\n blockedBy: null\n }), [register, unregister]);\n\n return (\n <NavigationBlockerContext.Provider value={value}>\n {children}\n </NavigationBlockerContext.Provider>\n );\n}\n\n/**\n * Guard navigation with `predicate`, sharing the app-wide blocker.\n *\n * Returns a {@link Blocker} that is only ever in the `blocked` state when *this*\n * registration is what blocked the navigation — so several guards can coexist\n * without each of them popping a dialog.\n *\n * Returns an idle blocker when no {@link NavigationBlockerProvider} is mounted\n * above, rather than competing for React Router's single blocker slot.\n */\nexport function useNavigationBlocker(predicate: BlockerFunction): Blocker {\n\n const context = useContext(NavigationBlockerContext);\n const id = useId();\n\n // Keep the latest predicate without re-registering on every render.\n const predicateRef = useRef(predicate);\n predicateRef.current = predicate;\n\n const register = context?.register;\n const unregister = context?.unregister;\n\n useEffect(() => {\n if (!register || !unregister) return;\n register(id, (args) => predicateRef.current(args));\n return () => unregister(id);\n }, [register, unregister, id]);\n\n if (!context) return IDLE_BLOCKER;\n return context.blockedBy === id ? context.blocker : IDLE_BLOCKER;\n}\n","import { useCallback, useEffect, useState, useMemo } from \"react\";\nimport { UnsavedChangesDialogProps } from \"../components/UnsavedChangesDialog\";\nimport { useNavigationBlocker } from \"./useNavigationBlocker\";\n\n/**\n * A single, unified hook to prevent navigation when there are unsaved changes.\n *\n * It automatically handles:\n * 1. Internal React Router navigation using `useBlocker`.\n * 2. External browser navigation (page refresh, tab close) using `beforeunload`.\n *\n * `when` may be a function, read at the moment a navigation is attempted. Pass\n * one when the flag can be cleared in the same tick as the navigation it\n * should let through — a save that reports the form clean and then moves on.\n * A boolean is only seen once its component re-renders, which is after a\n * navigation raised in that tick has already been blocked.\n */\nexport function useUnsavedChangesDialog(\n when: boolean | (() => boolean),\n onOk: () => void\n): {\n dialogProps: UnsavedChangesDialogProps;\n triggerDialog: () => void;\n} {\n const [manualDialogOpen, setManualDialogOpen] = useState(false);\n\n const isBlocking = useCallback(\n () => typeof when === \"function\" ? when() : when,\n [when]\n );\n\n const blocker = useNavigationBlocker(\n useCallback(\n ({ currentLocation, nextLocation }) =>\n currentLocation.pathname !== nextLocation.pathname && isBlocking(),\n [isBlocking]\n )\n );\n\n useEffect(() => {\n if (!when) return;\n\n const handleBeforeUnload = (e: BeforeUnloadEvent) => {\n if (!isBlocking()) return;\n e.preventDefault();\n e.returnValue = \"\";\n };\n\n window.addEventListener(\"beforeunload\", handleBeforeUnload);\n return () => window.removeEventListener(\"beforeunload\", handleBeforeUnload);\n }, [when, isBlocking]);\n\n const handleOk = useCallback(() => {\n onOk();\n if (blocker.state === \"blocked\") {\n blocker.proceed();\n }\n setManualDialogOpen(false);\n }, [blocker, onOk]);\n\n const handleCancel = useCallback(() => {\n if (blocker.state === \"blocked\") {\n blocker.reset();\n }\n setManualDialogOpen(false);\n }, [blocker]);\n\n const triggerDialog = useCallback(() => setManualDialogOpen(true), []);\n\n return useMemo(() => ({\n dialogProps: {\n open: manualDialogOpen || blocker.state === \"blocked\",\n handleOk,\n handleCancel,\n body: \"There are unsaved changes in this collection\"\n },\n triggerDialog\n }), [manualDialogOpen, blocker.state, handleOk, handleCancel, triggerDialog]);\n}\n","import { Entity, FilterValues } from \"@rebasepro/types\";\n\n/**\n * How many (collection, filters) pairs keep a scroll position. Past it, the\n * one written least recently goes. Every combination of filters a user ever\n * applied used to keep an entry, with the rows it showed, for the rest of the\n * session.\n */\nconst SCROLL_CACHE_LIMIT = 20;\n\n/**\n * Where a collection view was, and the rows to show when it comes back.\n *\n * `data` is the rows around what was on screen — a page either side, when the\n * view reports what it draws — starting at row `dataOffset` (0 when absent:\n * `data` then starts at the first row). It used to be every row the view held,\n * which a table scrolled to 100,000 rows kept for the rest of the session and\n * read again in full on the way back.\n */\nexport type CollectionScrollEntry = {\n scrollOffset: number;\n data: Entity<any>[];\n dataOffset?: number;\n};\n\n/** Key: path plus filters (`createCacheKey`). Emptied on sign-out. */\nconst collectionScrollCache = new Map<string, CollectionScrollEntry>();\n\n/**\n * Forget every collection's scroll position and the rows kept with it.\n *\n * The rows are what the signed-in user was allowed to read, and a table seeds\n * its first render from them, so they must not outlive that user's session.\n */\nexport function clearCollectionScrollCache(): void {\n collectionScrollCache.clear();\n}\n\nexport type ScrollRestorationController = {\n\n getCollectionScroll: (path: string,\n filters?: FilterValues<any>) => CollectionScrollEntry | undefined;\n\n updateCollectionScroll: (props: CollectionScrollEntry & {\n path: string,\n filters?: FilterValues<any>;\n }) => void;\n\n}\n\nexport function useScrollRestoration(): ScrollRestorationController {\n\n const updateCollectionScroll = ({\n path,\n filters,\n scrollOffset,\n data,\n dataOffset\n }: CollectionScrollEntry & {\n path: string;\n filters?: FilterValues<any>;\n }) => {\n const key = createCacheKey(path, filters);\n // Re-inserted, so the Map's order is the order of last use.\n collectionScrollCache.delete(key);\n collectionScrollCache.set(key, {\n scrollOffset,\n data,\n ...(dataOffset !== undefined && dataOffset > 0 && { dataOffset })\n });\n if (collectionScrollCache.size > SCROLL_CACHE_LIMIT) {\n const oldest = collectionScrollCache.keys().next().value;\n if (oldest !== undefined) collectionScrollCache.delete(oldest);\n }\n }\n\n const getCollectionScroll = (path: string,\n filters?: FilterValues<any>) => {\n return collectionScrollCache.get(createCacheKey(path, filters));\n }\n\n return {\n getCollectionScroll,\n updateCollectionScroll\n }\n}\n\nfunction createCacheKey(path: string, filters?: FilterValues<any>) {\n\n if (!filters) {\n return path;\n }\n\n // codify the filters into a url friendly string\n const filtersString = filters ? Object.keys(filters).map(key => {\n const value = JSON.stringify(filters[key]);\n return `${key}=${value}`;\n }).join(\"&\") : \"\";\n\n return `${path}?${filtersString}`;\n}\n","import { EntityReference, EntityRelation, GeoPoint, Vector } from \"@rebasepro/types\";\nimport { isObject, isPlainObject } from \"@rebasepro/utils\";\n\n// Define a unique prefix for entity keys in sessionStorage to avoid key collisions\nconst LOCAL_STORAGE_PREFIX = \"entity_cache::\";\n\n/**\n * The in-session handoff channel: an edit in flight, parked here by the layout\n * that is being replaced and picked up by the one taking over — the split's\n * \"hide list\", full screen's \"show list\", the side panel's \"open full screen\".\n * A record loaded from it opens *dirty*, because that is what it is for.\n *\n * Deliberately **not** hydrated from `sessionStorage`, and it is the one thing\n * here that isn't. The persisted half of this file is the local-changes backup:\n * a draft that outlives a reload, offered back through the banner or applied on\n * open, according to the collection's `localChangesBackup`. Loading those\n * drafts into this map on startup made every one of them look like a handoff —\n * the first visit to the record after a reload silently opened dirty carrying a\n * draft the user had walked away from, and the banner that exists to ask about\n * it never appeared.\n */\nconst entityCache: Map<string, object> = new Map();\n\n// Check `sessionStorage` availability once during initialization\nconst isSessionStorageAvailable = typeof sessionStorage !== \"undefined\";\n\n// Define custom replacer for JSON.stringify\nfunction customReplacer(this: Record<string, unknown>, key: string): unknown {\n\n const value = this[key];\n\n // Handle Date objects\n if (value instanceof Date) {\n return {\n __type: \"Date\",\n value: value.toISOString()\n };\n }\n\n // Handle EntityReference\n if (value instanceof EntityReference) {\n return {\n __type: \"EntityReference\",\n id: value.id,\n path: value.path,\n driver: value.driver,\n databaseId: value.databaseId\n };\n }\n\n if (value instanceof EntityRelation) {\n return {\n __type: \"EntityRelation\",\n id: value.id,\n path: value.path,\n data: value.data\n };\n }\n\n // Handle GeoPoint\n if (value instanceof GeoPoint) {\n return {\n __type: \"GeoPoint\",\n latitude: value.latitude,\n longitude: value.longitude\n };\n }\n\n // Handle Vector\n if (value instanceof Vector) {\n return {\n __type: \"Vector\",\n value: value.value\n };\n }\n\n return value;\n}\n\n// Define custom reviver for JSON.parse\nfunction customReviver(_key: string, value: unknown): unknown {\n if (value && typeof value === \"object\" && \"__type\" in value) {\n const record = value as Record<string, unknown>;\n switch (record.__type) {\n case \"date\":\n case \"Date\":\n return new Date(record.value as string);\n case \"reference\":\n case \"EntityReference\":\n return new EntityReference({\n id: record.id as string,\n path: record.path as string,\n driver: record.driver as string | undefined,\n databaseId: record.databaseId as string | undefined\n });\n case \"relation\":\n case \"EntityRelation\":\n return new EntityRelation(record.id as string, record.path as string, record.data as Record<string, unknown> | undefined);\n case \"GeoPoint\":\n return new GeoPoint(record.latitude as number, record.longitude as number);\n case \"Vector\":\n return new Vector(record.value as number[]);\n default:\n return value;\n }\n }\n return value;\n}\n\n/**\n * Saves data to the local-changes backup in `sessionStorage`.\n *\n * The backup only — a draft that survives a reload is not an edit in flight.\n * {@link saveEntityToMemoryCache} is the other channel; see {@link entityCache}\n * for what separates them.\n * @param path - The unique path/key for the data.\n * @param data - The data to cache and persist.\n */\nexport function saveEntityToCache(path: string, data: object): void {\n // Persist the data individually in sessionStorage\n if (isSessionStorageAvailable) {\n try {\n const key = LOCAL_STORAGE_PREFIX + path;\n\n const entityString = JSON.stringify(data, customReplacer);\n sessionStorage.setItem(key, entityString);\n } catch (error) {\n console.error(\n `Failed to save entity for path \"${path}\" to sessionStorage:`,\n error\n );\n }\n }\n}\n\n/**\n * Consumes a handoff. The channel is one-shot: whoever picks an edit up owns it\n * from then on, and an edit left behind here is one that reopens a record dirty\n * long after the user stopped looking at it.\n */\nexport function removeEntityFromMemoryCache(path: string): void {\n entityCache.delete(path);\n}\n\n/**\n * Parks an edit in flight for the layout about to take over. See\n * {@link entityCache}: this is the handoff, not the backup.\n */\nexport function saveEntityToMemoryCache(path: string, data: object): void {\n entityCache.set(path, data);\n}\n\nexport function getEntityFromMemoryCache(path: string): object | undefined {\n return entityCache.get(path);\n}\n\n/**\n * Drops every edit in flight. They were parked by a user who is no longer\n * signed in, so nobody is taking them over.\n */\nexport function clearEntityMemoryCache(): void {\n entityCache.clear();\n}\n\n/**\n * Drops the whole local-changes backup: every draft in `sessionStorage`, for\n * every record. For when the drafts belong to somebody other than the user now\n * signed in.\n */\nexport function clearEntityDrafts(): void {\n if (!isSessionStorageAvailable) return;\n try {\n const keys: string[] = [];\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (key?.startsWith(LOCAL_STORAGE_PREFIX)) keys.push(key);\n }\n for (const key of keys) sessionStorage.removeItem(key);\n } catch (error) {\n console.error(\"Failed to clear the local-changes backup from sessionStorage:\", error);\n }\n}\n\n\n/**\n * Retrieves a entity from the local-changes backup in `sessionStorage`.\n *\n * The backup only — the handoff channel is read through\n * {@link getEntityFromMemoryCache}, and the two mean different things to the\n * form that receives them.\n * @param path - The unique path/key for the entity.\n * @returns The cached entity or `undefined` if not found.\n */\nexport function getEntityFromCache(path: string): object | undefined {\n\n // If not in the cache, attempt to load it from sessionStorage\n if (isSessionStorageAvailable) {\n try {\n const key = LOCAL_STORAGE_PREFIX + path;\n const entityString = sessionStorage.getItem(key);\n if (entityString) {\n const entity: object = JSON.parse(entityString, customReviver);\n return entity;\n }\n } catch (error) {\n console.error(\n `Failed to load entity for path \"${path}\" from sessionStorage:`,\n error\n );\n }\n }\n\n // Entity not found\n return undefined;\n}\n\n/**\n * Removes a entity from both the in-memory cache and `sessionStorage`.\n * @param path - The unique path/key for the entity to remove.\n */\nexport function removeEntityFromCache(path: string): void {\n\n console.debug(\"Removing entity from cache\", path);\n\n // Remove from the in-memory cache\n entityCache.delete(path);\n\n // Remove from sessionStorage\n if (isSessionStorageAvailable) {\n try {\n const key = LOCAL_STORAGE_PREFIX + path;\n sessionStorage.removeItem(key);\n } catch (error) {\n console.error(\n `Failed to remove entity for path \"${path}\" from sessionStorage:`,\n error\n );\n }\n }\n}\n\n\nexport function flattenKeys(obj: Record<string, unknown> | unknown[], prefix = \"\", result: string[] = []): string[] {\n\n if (isObject(obj) || Array.isArray(obj)) {\n const plainObject = isPlainObject(obj);\n if (!plainObject && prefix) {\n result.push(prefix);\n } else {\n const record = obj as Record<string, unknown>;\n for (const key in record) {\n if (Object.prototype.hasOwnProperty.call(record, key)) {\n const newKey = prefix\n ? Array.isArray(obj)\n ? `${prefix}[${key}]`\n : `${prefix}.${key}`\n : key;\n const val = record[key];\n if (isObject(val) || Array.isArray(val)) {\n flattenKeys(val as Record<string, unknown> | unknown[], newKey, result);\n } else {\n result.push(newKey);\n }\n }\n }\n }\n }\n return result;\n}\n","/**\n * The store behind a computed display value.\n *\n * A record's title is asked for far more often than it changes, and by many\n * components at once: a list of fifty rows, each row's relation chips, the\n * breadcrumb above them. Resolving per component is what makes an async display\n * value a bad idea — fifty rows becomes fifty reads, then fifty more on the next\n * render.\n *\n * So resolution is keyed by record *and* role, in-flight calls are shared, and\n * results are kept until something says otherwise. Deliberately not a React\n * thing: the same store answers an imperative caller (an export, a breadcrumb\n * built outside the tree), and it is testable without a renderer.\n */\nimport type { EntityDisplayRole } from \"@rebasepro/cms-types\";\n\ntype CacheEntry = {\n /** Set once resolved. `null` means \"resolved to nothing\", not \"unknown\". */\n value: unknown;\n} | {\n /** Shared by every caller that arrives while the first one is in flight. */\n promise: Promise<unknown>;\n};\n\nexport type EntityDisplayKey = string;\n\n/** The identity of one role of one record, as a cache key. */\nexport function entityDisplayKey(\n path: string,\n entityId: string | number | undefined,\n role: EntityDisplayRole\n): EntityDisplayKey {\n return `${role} ${path} ${entityId ?? \"\"}`;\n}\n\n/**\n * One shared store, so every surface agrees on a record and resolves it once.\n *\n * Module-level rather than a provider: two app instances on one page share a\n * cache keyed by collection path and record id, which *is* the same record.\n * A resolved title is what the signed-in user was allowed to read, though, so\n * the store is emptied with the rest of the session's caches when that user\n * signs out (`clearSessionCaches`).\n *\n * Built on first use rather than at module scope. Importing a module should not\n * construct anything: it runs during SSR where there is nothing to cache, and it\n * made the modules that read this store unimportable from any test that stubs\n * `@rebasepro/app`.\n */\nlet sharedCache: EntityDisplayCache | undefined;\n\nexport function getSharedEntityDisplayCache(): EntityDisplayCache {\n if (!sharedCache) sharedCache = new EntityDisplayCache();\n return sharedCache;\n}\n\nexport class EntityDisplayCache {\n\n private readonly entries = new Map<EntityDisplayKey, CacheEntry>();\n private readonly listeners = new Set<() => void>();\n\n /**\n * The resolved value, or `undefined` when this pair has not been resolved\n * yet. `null` is a resolved absence, and the two must stay distinct: a\n * caller that reads \"not yet\" as \"nothing\" flickers its fallback in on every\n * mount.\n */\n peek(key: EntityDisplayKey): unknown | undefined {\n const entry = this.entries.get(key);\n if (!entry || \"promise\" in entry) return undefined;\n return entry.value;\n }\n\n /** True while a resolution for this pair is in flight. */\n isLoading(key: EntityDisplayKey): boolean {\n const entry = this.entries.get(key);\n return Boolean(entry && \"promise\" in entry);\n }\n\n /**\n * Resolve once per record and role. Concurrent callers share the first\n * call's promise; later callers get the cached value with no promise at all.\n *\n * A resolver that throws is recorded as \"nothing\" rather than retried: the\n * alternative is every render re-running a call that just failed. And it is\n * reported here, which is a correction.\n *\n * It used to say \"the caller that saw the rejection is the one that logs\n * it\", and `useEntityDisplay` duly attached a `.catch()` that warned. But\n * both failure paths below swallow and return a *resolved* promise, so that\n * catch could never run — the two halves each did the reasonable thing and\n * between them the log was unreachable. A resolver that blew up produced a\n * blank chip and total silence, which is the failure mode\n * `EntityDisplayResolver`'s own contract (\"treated as `undefined` and logged\n * once\") exists to rule out.\n *\n * Reporting belongs here for the reason the caller could not do it: this is\n * the one place that runs exactly once per key, so \"once\" is a property of\n * the code rather than a hope about how many components mount.\n */\n resolve(key: EntityDisplayKey, resolver: () => unknown): Promise<unknown> {\n const entry = this.entries.get(key);\n if (entry) {\n return \"promise\" in entry ? entry.promise : Promise.resolve(entry.value);\n }\n\n let produced: unknown;\n try {\n produced = resolver();\n } catch (error: unknown) {\n this.fail(key, error);\n return Promise.resolve(null);\n }\n\n // A synchronous resolver never enters the loading state. Putting it\n // through one would render every caller's fallback for a frame, for\n // nothing.\n if (!isPromise(produced)) {\n const value = normalize(produced);\n this.set(key, value);\n return Promise.resolve(value);\n }\n\n const promise = produced\n .then(resolved => {\n const value = normalize(resolved);\n this.set(key, value);\n return value;\n })\n .catch((error: unknown) => {\n this.fail(key, error);\n return null;\n });\n\n this.entries.set(key, { promise });\n return promise;\n }\n\n /**\n * Drop what is known about a record, so the next ask resolves again. Called\n * after a write: the row that just saved may be called something else now.\n */\n invalidate(path: string, entityId?: string | number): void {\n const suffix = ` ${path} ${entityId ?? \"\"}`;\n let changed = false;\n for (const key of [...this.entries.keys()]) {\n // `undefined` id means the whole collection — after an import, or a\n // locale switch that changes what every title in it reads.\n const matches = entityId === undefined\n ? key.includes(` ${path} `) || key.endsWith(` ${path} `)\n : key.endsWith(suffix);\n if (matches) {\n this.entries.delete(key);\n changed = true;\n }\n }\n if (changed) this.emit();\n }\n\n /** Drop everything. The user signed out, or the app swapped datasource. */\n clear(): void {\n if (this.entries.size === 0) return;\n this.entries.clear();\n this.emit();\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private set(key: EntityDisplayKey, value: unknown): void {\n this.entries.set(key, { value });\n this.emit();\n }\n\n /**\n * Record a failed resolution as \"nothing\", and say so once.\n *\n * The key is the message: it is `<role> <path> <id>`, which is exactly what a\n * reader needs to find the resolver that blew up. A warning with no key would\n * tell them a display resolver failed somewhere in a list of fifty rows.\n *\n * `console.warn` rather than a thrown error, because this runs while a row is\n * rendering: the contract is that a title which cannot be fetched must not\n * take down the row that shows it.\n */\n private fail(key: EntityDisplayKey, error: unknown): void {\n console.warn(`[rebase] Could not resolve display value for ${key}:`, error);\n this.set(key, null);\n }\n\n private emit(): void {\n for (const listener of [...this.listeners]) listener();\n }\n}\n\n/**\n * Empty strings and empty arrays are absences, not values — a title of `\" \"`\n * would otherwise beat the derived one and render as a blank heading.\n */\nfunction normalize(value: unknown): unknown {\n if (value === undefined || value === null) return null;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n if (Array.isArray(value)) return value.length > 0 ? value : null;\n return value;\n}\n\nfunction isPromise(value: unknown): value is Promise<unknown> {\n return typeof (value as Promise<unknown> | undefined)?.then === \"function\";\n}\n","import { clearFetchCache } from \"../hooks/data/useFetch\";\nimport { clearCollectionScrollCache } from \"../components/common/useScrollRestoration\";\nimport { clearEntityDrafts, clearEntityMemoryCache } from \"../util/entity_cache\";\nimport { getSharedEntityDisplayCache } from \"../collections/entity-display-cache\";\n\n/**\n * Who the tab's cached state was read or written as. Kept in `sessionStorage`\n * as well as in memory because the local-changes backup is: a reload keeps the\n * drafts, so it has to keep the name of the user they belong to.\n */\nconst OWNER_STORAGE_KEY = \"rebase::session_cache_owner\";\nlet ownerInMemory: string | undefined;\n\nfunction readOwner(): string | undefined {\n try {\n if (typeof sessionStorage !== \"undefined\") {\n return sessionStorage.getItem(OWNER_STORAGE_KEY) ?? ownerInMemory;\n }\n } catch {\n // Storage refused (privacy mode, sandboxed frame): memory is all there is.\n }\n return ownerInMemory;\n}\n\nfunction writeOwner(userId: string): void {\n ownerInMemory = userId;\n try {\n if (typeof sessionStorage !== \"undefined\") {\n sessionStorage.setItem(OWNER_STORAGE_KEY, userId);\n }\n } catch {\n // As above.\n }\n}\n\n/**\n * Empty every module-level cache that holds data read as the signed-in user:\n * fetched records, each table's scroll position and the rows kept with it,\n * edits parked for a layout handoff, and resolved display values (the titles\n * on relation chips and breadcrumbs).\n *\n * All of them are keyed by path and id only, with no user in the key, and the\n * views seed their first render from them — so without this the next user to\n * sign in to the tab is shown what the last one could read. Called by both auth\n * controllers on `SIGNED_OUT`.\n *\n * The local-changes backup is not cleared here: a sign-out is also how a\n * rejected refresh token ends a session, and the backup exists for that user\n * coming back. {@link bindSessionCachesToUser} drops it when somebody else\n * signs in instead.\n */\nexport function clearSessionCaches(): void {\n clearFetchCache();\n clearCollectionScrollCache();\n clearEntityMemoryCache();\n getSharedEntityDisplayCache().clear();\n}\n\n/**\n * Record that the tab now acts as `userId`. When that is not who the caches\n * were filled for, everything goes — the session caches, and the drafts the\n * other user left in the local-changes backup.\n *\n * Call it before the new user is rendered: the views read these caches in\n * their first render, before any effect of the auth controller would run.\n */\nexport function bindSessionCachesToUser(userId: string): void {\n const owner = readOwner();\n if (owner !== undefined && owner !== userId) {\n clearSessionCaches();\n clearEntityDrafts();\n }\n if (owner !== userId) writeOwner(userId);\n}\n","import { useState, useEffect, useMemo, useCallback } from \"react\";\nimport { deepEqual } from \"fast-equals\";\nimport { AuthClient, User } from \"@rebasepro/types\";\nimport { AuthController } from \"@rebasepro/cms-types\";\nimport { bindSessionCachesToUser, clearSessionCaches } from \"../auth/session_caches\";\n\n/**\n * Sets the user, first making sure the tab's caches were filled for them.\n * Before the state update, not in an effect: the views read those caches in\n * the very render the new user arrives in.\n */\nfunction adoptUser(user: User | null): User | null {\n if (user) bindSessionCachesToUser(user.uid);\n return user;\n}\n\n/**\n * The state update for a user the SDK handed over. A token refresh hands over\n * a freshly mapped user every time; the same user, field for field, keeps the\n * object already held, so the controller — and every context consumer — does\n * not change with it.\n */\nfunction keepIfEqual(next: User | null) {\n return (previous: User | null) => (previous && next && deepEqual(previous, next)) ? previous : next;\n}\n\nexport function useAuthSubscription(authClient?: AuthClient): AuthController {\n\n // Check initial state\n const currentSession = authClient?.getSession();\n const [user, setUser] = useState<User | null>(() => adoptUser(currentSession?.user ?? null));\n\n const [authLoading, setAuthLoading] = useState(false);\n const [authError, setAuthError] = useState<Error>();\n const [loginSkipped, setLoginSkipped] = useState(false);\n const [extra, setExtra] = useState<any>();\n\n /**\n * Whether asking the server \"who am I?\" could possibly answer.\n *\n * A client configured with `persistSession: false` and JSON auth — the\n * shape used when one client borrows another's credential, as the hosted\n * Studio does — has no stored session and no auth cookie, so the probe\n * below is guaranteed to 401. Sending it anyway put three failing\n * `GET /auth/me` calls on the wire per mount, each one landing in the\n * *customer's* request log as an authentication failure against their own\n * backend.\n *\n * A client that does not implement the capability is treated as \"might\n * work\" — the historical behaviour.\n */\n const mayHaveRestorableSession = authClient?.canRestoreSession?.() ?? true;\n\n /**\n * `true` only while a probe is genuinely outstanding.\n *\n * It used to be seeded from `!currentSession` alone, which left a client\n * that cannot restore a session — and therefore never runs the probe that\n * clears the flag — reporting \"still loading\" forever. Anything gated on\n * `initialLoading` (a spinner, a redirect to the login view) would never\n * resolve.\n */\n const [initialLoading, setInitialLoading] = useState(!currentSession && mayHaveRestorableSession);\n\n /**\n * `true` until the client has finished restoring a session on its own.\n *\n * The first `getSession()` above is provisional while that runs: the SDK\n * holds an expired stored session during its boot refresh, and when the\n * refresh is rejected it drops the session without emitting anything. So\n * the user is read again once the restore settles, and the app does not\n * render as signed in before then.\n */\n const [restoring, setRestoring] = useState(Boolean(authClient?.isInitialized));\n\n useEffect(() => {\n if (!authClient?.isInitialized) {\n setRestoring(false);\n return;\n }\n let cancelled = false;\n setRestoring(true);\n authClient.isInitialized()\n .catch(() => {\n // A restore that failed has left no session behind; reading\n // the session below is still the answer.\n })\n .then(() => {\n if (cancelled) return;\n setUser(keepIfEqual(adoptUser(authClient.getSession()?.user ?? null)));\n setRestoring(false);\n });\n return () => {\n cancelled = true;\n };\n }, [authClient]);\n\n useEffect(() => {\n if (!authClient) return;\n // If we don't have a session initially, try to get user which restores session if a persistent token exists\n if (!currentSession && mayHaveRestorableSession) {\n setInitialLoading(true);\n authClient.getUser()\n .then(user => {\n if (user) {\n setUser(adoptUser(user));\n }\n setAuthError(undefined);\n })\n .catch((e: unknown) => {\n // A 401 or 403 is the ordinary first load of an anonymous\n // visitor: there is no session, which is not an error.\n //\n // Everything else is. This used to swallow the lot with\n // \"Ignore, user just isn't logged in\", leaving `authError`\n // — a field this controller declares and `Rebase` renders a\n // full-screen \"Error loading auth\" view for — permanently\n // undefined. So the view was unreachable, and a backend that\n // was down, misconfigured, or blocked by CORS looked exactly\n // like being signed out: the app showed the login form.\n const status = (e as { status?: number } | undefined)?.status;\n if (status === 401 || status === 403) {\n setAuthError(undefined);\n return;\n }\n setAuthError(e instanceof Error ? e : new Error(String(e)));\n })\n .finally(() => {\n setInitialLoading(false);\n });\n }\n }, [authClient, currentSession, mayHaveRestorableSession]);\n\n useEffect(() => {\n if (!authClient) return;\n const unsubscribe = authClient.onAuthStateChange((event, session) => {\n if (event === \"SIGNED_IN\" || event === \"USER_UPDATED\" || event === \"TOKEN_REFRESHED\") {\n setUser(keepIfEqual(adoptUser(session?.user ?? null)));\n } else if (event === \"SIGNED_OUT\") {\n // See `clearSessionCaches`: what this session read must not be\n // what the next user in the tab is shown first.\n clearSessionCaches();\n setUser(null);\n }\n });\n return unsubscribe;\n }, [authClient]);\n\n const signOut = useCallback(async () => {\n if (!authClient) return;\n setAuthLoading(true);\n try {\n await authClient.signOut();\n } finally {\n setAuthLoading(false);\n }\n }, [authClient]);\n\n const getAuthToken = useCallback(async () => {\n if (!authClient) return \"\";\n const session = authClient.getSession();\n if (!session) return \"\";\n if (session.expiresAt < Date.now()) {\n try {\n const refreshed = await authClient.refreshSession();\n return refreshed.accessToken;\n } catch (e) {\n return \"\";\n }\n }\n return session.accessToken;\n }, [authClient]);\n\n return useMemo(() => ({\n user,\n initialLoading: authClient ? initialLoading || restoring : false,\n authLoading,\n signOut,\n authError,\n getAuthToken,\n loginSkipped,\n extra,\n setExtra\n } as AuthController), [\n user, initialLoading, restoring, authLoading, signOut, authError,\n getAuthToken, loginSkipped, extra, setExtra, authClient\n ]);\n}\n","import { AdminModeControllerContext } from \"../contexts/AdminModeController\";\nimport { useContext } from \"react\";\n\n/**\n * Use this controller to change the admin mode: `\"cms\"` for editing data,\n * `\"studio\"` for the developer tools.\n * @group Hooks and utilities\n */\nexport interface AdminModeController {\n mode: \"cms\" | \"studio\";\n setMode: (mode: \"cms\" | \"studio\") => void;\n}\n\n/**\n * Hook to retrieve the current admin mode (`\"cms\"` | `\"studio\"`), and `setMode`\n * to change it.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see AdminModeController\n * @group Hooks and utilities\n */\nexport const useAdminModeController = () => useContext(AdminModeControllerContext);\n","/**\n * localStorage that tolerates not being there.\n *\n * `typeof window !== \"undefined\"` was the guard these call sites used, and it\n * answers the wrong question: it says \"am I in a browser\", not \"can I read\n * storage\". Three things make that distinction real rather than theoretical:\n *\n * - A browser can have storage **disabled**. Safari in private mode, a blocked\n * third-party cookie policy, and a sandboxed iframe all give you a `window`\n * whose `localStorage` property *throws on access* — a SecurityError raised\n * before any method is called, which no amount of null-checking the result\n * catches.\n * - A test environment can be **half torn down**. jsdom is disposed at the end\n * of a file while React is still finishing a concurrent render, so `window`\n * survives as a husk and `localStorage.getItem` is no longer a function.\n * That is how this was found: `TypeError: localStorage.getItem is not a\n * function`, thrown out of a render, failing a suite in which every one of\n * 709 tests passed.\n * - Server rendering has no `window` at all, which is the only case the old\n * guard actually covered.\n *\n * Reading a UI preference is never worth a crash. Every function here fails to\n * `null` / no-op, so a user with storage switched off gets the default\n * appearance instead of a blank page.\n */\n\n/** The Storage object, or null when it is absent, blocked, or not usable. */\nfunction usableStorage(): Storage | null {\n try {\n if (typeof window === \"undefined\") return null;\n const candidate = window.localStorage;\n // Not `!= null`: a torn-down jsdom leaves an object behind whose\n // methods are gone, which is exactly the shape that threw.\n return typeof candidate?.getItem === \"function\" ? candidate : null;\n } catch {\n // Access itself throws when storage is blocked by policy.\n return null;\n }\n}\n\n/** The stored string for `key`, or null if it is unset or unreadable. */\nexport function readStoredString(key: string): string | null {\n try {\n return usableStorage()?.getItem(key) ?? null;\n } catch {\n return null;\n }\n}\n\n/** Persist `value` under `key`. A no-op when storage is unavailable. */\nexport function writeStoredString(key: string, value: string): void {\n try {\n usableStorage()?.setItem(key, value);\n } catch {\n // Also the quota path: a full store throws on write but reads fine.\n }\n}\n\n/** Remove `key`. A no-op when storage is unavailable. */\nexport function removeStoredString(key: string): void {\n try {\n usableStorage()?.removeItem(key);\n } catch {\n /* nothing to undo */\n }\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport type { AdminModeController } from \"./useAdminModeController\";\nimport { readStoredString, writeStoredString } from \"../util/local_storage\";\n\n/**\n * Use this hook to build an admin mode controller that determines\n * whether the UI shows Developer or Editor tools.\n */\nexport function useBuildAdminModeController(): AdminModeController {\n\n // The content mode was renamed to \"cms\" when the panel's CMS half became a\n // product name. The value is persisted, so a browser that used the panel\n // before the rename still has \"content\" in local storage — read as-is it\n // casts to a mode nothing matches, and the drawer renders neither half.\n // Migrating on read is the exception the no-shims rule allows for stored data.\n //\n // Anything else stored under this key falls back to \"cms\" for the same\n // reason, rather than being cast to a mode: the union used to carry a third\n // value, `\"settings\"`, that nothing set and nothing read, and a cast is how\n // a value outside the union reaches state in the first place.\n const stored = readStoredString(\"rebase-admin-mode\");\n const migrated = stored === \"content\" ? \"cms\" : stored;\n const savedMode = migrated === \"cms\" || migrated === \"studio\" ? migrated : null;\n const [mode, setMode] = useState<\"cms\" | \"studio\">(savedMode ?? \"cms\");\n\n const setModeInternal = useCallback((newMode: \"cms\" | \"studio\") => {\n writeStoredString(\"rebase-admin-mode\", newMode);\n setMode(newMode);\n }, []);\n\n return useMemo(() => ({\n mode,\n setMode: setModeInternal\n }), [mode, setModeInternal]);\n}\n","import type { EffectiveRoleController } from \"@rebasepro/types\";\nimport { useCallback, useState, useMemo } from \"react\";\nimport { readStoredString, removeStoredString, writeStoredString } from \"../util/local_storage\";\n\n/**\n * The effective role controller `<Rebase>` falls back to when the host passes\n * none. Kept apart from the deprecated public hook\n * (`useBuildEffectiveRoleController`) so building it does not report a\n * deprecation the app never used, and out of the hooks barrel so it is not a\n * public export.\n */\nexport function useEffectiveRoleState(): EffectiveRoleController {\n\n const savedRole = readStoredString(\"rebase-effective-role\");\n const [effectiveRole, setEffectiveRole] = useState<string | null>(savedRole ?? null);\n\n const setRoleInternal = useCallback((newRole: string | null) => {\n if (newRole) {\n writeStoredString(\"rebase-effective-role\", newRole);\n } else {\n removeStoredString(\"rebase-effective-role\");\n }\n setEffectiveRole(newRole);\n }, []);\n\n return useMemo(() => ({\n effectiveRole,\n setEffectiveRole: setRoleInternal\n }), [effectiveRole, setRoleInternal]);\n}\n","import type { EffectiveRoleController } from \"@rebasepro/types\";\nimport { warnDeprecated } from \"@rebasepro/common\";\nimport { useEffectiveRoleState } from \"../core/effective_role_state\";\n\n/**\n * Build an effective role controller: which role Studio's navigation is\n * listed for when Dev mode is active, kept in localStorage across reloads.\n *\n * Navigation only: it changes which Studio views are listed, sends nothing to\n * the server and evaluates no row-level security policy.\n *\n * @deprecated To see what a role, a user or an API key can read and do, use\n * \"Simulate access\" (`useRlsSimulation`, `client.simulate()`), which asks the\n * server. `<Rebase>` builds its own effective role controller when none is\n * passed, so there is no need to build one.\n */\nexport function useBuildEffectiveRoleController(): EffectiveRoleController {\n warnDeprecated(\n \"useBuildEffectiveRoleController\",\n \"`useBuildEffectiveRoleController` is deprecated. It only changes which Studio views are listed and \" +\n \"tests no permission. To see what a role, user or API key can read, use Simulate access \" +\n \"(`useRlsSimulation`, `client.simulate()`). `<Rebase>` builds its own controller when none is passed.\"\n );\n return useEffectiveRoleState();\n}\n","import { ModeControllerContext } from \"../contexts/ModeController\";\nimport { useContext } from \"react\";\n\n/**\n * Use this controller to change color mode\n * @group Hooks and utilities\n */\nexport interface ModeController {\n mode: \"light\" | \"dark\";\n setMode: (mode: \"light\" | \"dark\" | \"system\") => void;\n}\n\n/**\n * Hook to retrieve the current mode (\"light\" | \"dark\"), and `setMode`\n * or `toggle` functions to change it.\n *\n * Consider that in order to use this hook you need to have a parent\n * `Rebase`\n *\n * @see ModeController\n * @group Hooks and utilities\n */\nexport const useModeController = () => useContext(ModeControllerContext);\n","// FORKED FROM https://github.com/fayeed/use-clipboard\n\nimport { MutableRefObject, useCallback, useEffect, useRef, useState, useMemo } from \"react\";\n\nexport interface UseClipboardProps {\n /**\n * It's callback function that is called after the `copy` command\n * is executed.\n *\n * @param text: The selected clipboard text.\n */\n onSuccess?: (text: string) => void;\n\n /**\n * Triggers when the hook encounters an error.\n * If passed hook won't throw an error.\n *\n * @param error: cause of the error\n */\n onError?: (error: string) => void;\n\n /**\n * Disables the new clipboard API `navigator.clipboard` even if\n * it is supported.\n */\n disableClipboardAPI?: boolean;\n\n /**\n * revert back the isCopied flag to false again if a value is set.\n */\n copiedDuration?: number;\n}\n\nexport interface useClipboardReturnType {\n /**\n * Use ref to pull the text content from.\n */\n ref: MutableRefObject<any>;\n\n /**\n * Use it to perform the copy operation\n */\n copy: (text?: string) => void;\n\n /**\n * Use it to perform the cut operation\n */\n cut: () => void;\n\n /**\n * Indicates wheater the content was successfully copied or not.\n */\n isCoppied: boolean;\n\n /**\n * Current selected clipboard content.\n */\n clipboard: string;\n\n /**\n * Clears the user clipboard.\n */\n clearClipboard: () => void;\n\n /**\n * Check to see if the browser supports the new `navigator.clipboard` API.\n */\n isSupported: () => boolean;\n}\n\nexport const useClipboard = (\n options?: UseClipboardProps\n): useClipboardReturnType => {\n const { onSuccess, onError, disableClipboardAPI = false, copiedDuration } =\n options || {};\n const ref = useRef<any>(null);\n const [isCoppied, setIsCoppied] = useState(false);\n const [clipboard, setClipbaord] = useState(\"\");\n\n useEffect(() => {\n if (copiedDuration) setTimeout(() => setIsCoppied(false), copiedDuration);\n }, [isCoppied]);\n\n const isSupported = useCallback(() => navigator.clipboard !== undefined, []);\n\n const handleError = useCallback((error: string) => {\n if (onError) onError(error);\n else throw new Error(error);\n }, [onError]);\n\n const handleSuccess = useCallback((text: string) => {\n if (onSuccess) onSuccess(text);\n setIsCoppied(true);\n setClipbaord(text);\n }, [onSuccess]);\n\n const copyToClipboard = useCallback((text: string) => {\n navigator.clipboard\n .writeText(text)\n .then(() => handleSuccess(text))\n .catch((err) => {\n handleError(err);\n setIsCoppied(false);\n });\n }, [handleError, handleSuccess]);\n\n const clearClipboard = useCallback(() => {\n if (isSupported()) {\n navigator.clipboard.writeText(\"\");\n }\n }, [isSupported]);\n\n const action = useCallback(\n (operation = \"copy\", text?: string) => {\n const element = ref.current as HTMLElement;\n\n const isInput =\n element &&\n (element.tagName === \"INPUT\" || element.tagName === \"TEXTAREA\");\n\n const input = ref.current as HTMLInputElement;\n\n if (isSupported() && !disableClipboardAPI) {\n if (text) {\n copyToClipboard(text);\n } else if (element) {\n if (isInput) {\n copyToClipboard(input.value);\n\n if (operation === \"cut\") {\n input.value = \"\";\n }\n } else {\n copyToClipboard(element.innerText);\n }\n } else {\n handleError(\"Both the ref & text were undefined\");\n }\n }\n },\n [disableClipboardAPI, copyToClipboard, handleError]\n );\n\n const copy = useCallback((text?: string) =>\n action(\"copy\", typeof text === \"object\" ? undefined : text), [action]);\n\n const cut = useCallback(() => action(\"cut\"), [action]);\n\n return useMemo(() => ({\n ref,\n isCoppied,\n clipboard,\n clearClipboard,\n isSupported,\n copy,\n cut\n }), [isCoppied, clipboard, clearClipboard, isSupported, copy, cut]);\n};\n","import { useSyncExternalStore } from \"react\";\n\nconst breakpoints = {\n xs: 0,\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n \"2xl\": 1536,\n \"3xl\": 1920\n}\n\n/**\n * Who is reading the layout, and what it was at the last `resize`.\n *\n * One `resize` listener on `window` serves every reader. It is added when the\n * first reader mounts and removed when the last one unmounts — never by\n * importing this module, which an app can do without rendering anything.\n */\nconst subscribers = new Set<() => void>();\nlet lastKnown: boolean | undefined;\n\nfunction onResize() {\n const next = checkLargeLayout(\"lg\");\n if (next === lastKnown) return;\n lastKnown = next;\n subscribers.forEach(notify => notify());\n}\n\nfunction subscribe(notify: () => void): () => void {\n if (subscribers.size === 0 && typeof window !== \"undefined\") {\n lastKnown = checkLargeLayout(\"lg\");\n window.addEventListener(\"resize\", onResize);\n }\n subscribers.add(notify);\n return () => {\n subscribers.delete(notify);\n if (subscribers.size === 0 && typeof window !== \"undefined\") {\n window.removeEventListener(\"resize\", onResize);\n lastKnown = undefined;\n }\n };\n}\n\nfunction getSnapshot(): boolean {\n // While listened to, the value the listener keeps; before the first\n // reader subscribes, the layout as it is now.\n return lastKnown ?? checkLargeLayout(\"lg\");\n}\n\nfunction getServerSnapshot(): boolean {\n return false;\n}\n\nexport const useLargeLayout = (): boolean =>\n useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n\nfunction checkLargeLayout(breakpoint: \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" = \"lg\"): boolean {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\")\n return false;\n return window.matchMedia(`(min-width: ${breakpoints[breakpoint] + 1}px)`).matches;\n}\n","import { useCallback, useEffect, useState, useMemo } from \"react\";\n\nconst STORAGE_KEY_PREFIX = \"rebase-collapsed-groups\";\n\n/**\n * Custom hook for managing collapsed/expanded state of navigation groups\n * with localStorage persistence. Automatically cleans up stale group entries\n * when groups are removed from the navigation.\n *\n * Groups that have never been toggled by the user fall back to\n * `defaults[groupName]` (driven by `collapsedByDefault` in config).\n *\n * @param groupNames - Array of group names to track\n * @param namespace - Namespace for localStorage key (e.g., \"home\", \"drawer\") to allow independent state\n * @param defaults - Optional map of group name → collapsed boolean from config\n */\nexport function useCollapsedGroups(\n groupNames: string[],\n namespace = \"default\",\n defaults?: Record<string, boolean>\n) {\n const storageKey = `${STORAGE_KEY_PREFIX}-${namespace}`;\n\n // Load collapsed groups from localStorage on mount\n const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() => {\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : {};\n } catch {\n return {};\n }\n });\n\n // Save to localStorage whenever collapsedGroups changes\n useEffect(() => {\n try {\n localStorage.setItem(storageKey, JSON.stringify(collapsedGroups));\n } catch {\n // Silently fail if localStorage is not available\n }\n }, [collapsedGroups, storageKey]);\n\n // Clean up collapsed groups state when groups change - remove entries for groups that no longer exist\n useEffect(() => {\n // Only clean up if we have actual groups loaded (avoid cleaning up during initial load)\n if (groupNames.length === 0) return;\n\n const currentGroupNames = new Set(groupNames);\n\n setCollapsedGroups(prev => {\n const cleaned = Object.fromEntries(\n Object.entries(prev).filter(([groupName]) => currentGroupNames.has(groupName))\n );\n\n // Only update if something actually changed\n const prevKeys = Object.keys(prev);\n const cleanedKeys = Object.keys(cleaned);\n\n if (prevKeys.length === cleanedKeys.length && prevKeys.every(key => cleanedKeys.includes(key))) {\n return prev;\n }\n\n return cleaned;\n });\n }, [groupNames]);\n\n const isGroupCollapsed = useCallback((name: string) => {\n // If the user has explicitly toggled this group, use that value\n if (name in collapsedGroups) {\n return collapsedGroups[name];\n }\n // Otherwise fall back to the config default\n return defaults?.[name] ?? false;\n }, [collapsedGroups, defaults]);\n\n const toggleGroupCollapsed = useCallback((name: string) => {\n setCollapsedGroups(prev => {\n // Resolve current effective state (explicit or default)\n const currentlyCollapsed = name in prev\n ? prev[name]\n : (defaults?.[name] ?? false);\n return { ...prev,\n[name]: !currentlyCollapsed };\n });\n }, [defaults]);\n\n return useMemo(() => ({\n isGroupCollapsed,\n toggleGroupCollapsed\n }), [isGroupCollapsed, toggleGroupCollapsed]);\n}\n\n/**\n * Build a defaults map from navigationGroupMappings for a given namespace.\n * Returns a Record<groupName, collapsed> that can be passed to useCollapsedGroups.\n */\nexport function buildCollapsedDefaults(\n mappings: Array<{ name: string; collapsedByDefault?: boolean | { drawer?: boolean; home?: boolean } }> | undefined,\n namespace: \"drawer\" | \"home\"\n): Record<string, boolean> {\n if (!mappings) return {};\n const result: Record<string, boolean> = {};\n for (const mapping of mappings) {\n const val = mapping.collapsedByDefault;\n if (val === undefined) continue;\n if (typeof val === \"boolean\") {\n result[mapping.name] = val;\n } else {\n const ns = val[namespace];\n if (ns !== undefined) {\n result[mapping.name] = ns;\n }\n }\n }\n return result;\n}\n","import { useEffect } from \"react\";\n\nconst rebaseLogo = \"data:image/png;base64,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\";\n\n/**\n * Internal hook to handle the browser title and icon\n * @param name\n * @param logo\n */\nexport function useBrowserTitleAndIcon(name: string, logo?: string) {\n useEffect(() => {\n if (document) {\n document.title = `${name} - Rebase`;\n let link = document.querySelector(\"link[rel~='icon']\") as HTMLLinkElement | null;\n if (!link) {\n link = document.createElement(\"link\");\n link.rel = \"icon\";\n document.getElementsByTagName(\"head\")[0].appendChild(link);\n }\n link.href = logo ?? rebaseLogo;\n }\n }, [name, logo]);\n}\n","import type { SlotName, SlotRegistry } from \"@rebasepro/cms-types\";\nimport React, { useMemo } from \"react\";\n;\nimport { useCustomizationController } from \"./useCustomizationController\";\nimport { ErrorBoundary } from \"@rebasepro/ui\";\n\n/**\n * Hook that retrieves and renders all slot contributions for a given slot name.\n *\n * @param slot - The slot name to render contributions for.\n * @param props - Props passed to each slot component.\n * @returns An array of rendered React nodes, each wrapped in an ErrorBoundary.\n *\n * @example\n * ```tsx\n * const actions = useSlot(\"home.actions\", { context });\n * return <div>{actions}</div>;\n * ```\n *\n * @group Hooks\n */\n/**\n * Are these two prop objects the same, one level down?\n *\n * Its own function so the comparison can be typed on `object` rather than on\n * the slot's props. `SlotRegistry[K]` is a union of interfaces, and an\n * interface has no implicit index signature, so reading it as\n * `Record<string, unknown>` — which the loop this replaces did, to both\n * arguments — is a conversion tsc refuses and `as unknown as` was suppressing.\n * `Object.keys` needs no such claim.\n */\nfunction shallowEqual(a: object, b: object): boolean {\n if (a === b) return true;\n const keys = Object.keys(a);\n if (keys.length !== Object.keys(b).length) return false;\n return keys.every((key) => a[key as keyof typeof a] === b[key as keyof typeof b]);\n}\n\nexport function useSlot<K extends SlotName>(\n slot: K,\n props: SlotRegistry[K]\n): React.ReactNode[] {\n const { resolvedSlots } = useCustomizationController();\n\n const propsRef = React.useRef(props);\n if (!shallowEqual(props, propsRef.current)) {\n propsRef.current = props;\n }\n\n const stableProps = propsRef.current;\n\n return useMemo(() => {\n return resolvedSlots\n .filter(s => s.slot === slot)\n .sort((a, b) => (a.order ?? 50) - (b.order ?? 50))\n .map((s, i) => {\n // `filter` cannot narrow a discriminated union through a\n // callback, so `s.Component` is still \"some slot's component\"\n // here and its props are the union of every slot's. The line\n // above is what makes this safe, and it is one line above.\n //\n // This one deliberate cast is the price of `SlotContribution`\n // declaring `ComponentType<SlotRegistry[K]>` instead of\n // `ComponentType<any>` — which is what turns a component\n // written against the wrong slot's props into an error where\n // it is registered, rather than `undefined` at render.\n const Component = s.Component as React.ComponentType<SlotRegistry[K]>;\n return (\n <ErrorBoundary key={`${slot}_${i}`}>\n <Component {...stableProps} {...(s.props ?? {})}/>\n </ErrorBoundary>\n );\n });\n }, [resolvedSlots, slot, stableProps]);\n}\n","import { useCallback, useEffect, useRef, useState, useMemo } from \"react\";\nimport { PartialCollectionConfig, UserConfigurationPersistence } from \"@rebasepro/cms-types\";\nimport { stripCollectionPath } from \"@rebasepro/common\";\nimport { isArrayValue, isRecordValue, mergeDeep, readStoredJson, writeStoredJson } from \"@rebasepro/utils\";\n\nexport function useBuildLocalConfigurationPersistence(): UserConfigurationPersistence {\n\n const configCache = useRef<Record<string, PartialCollectionConfig>>({});\n\n // Read during render by every collection view, so an unreadable value here\n // used to throw the view away rather than fall back to an unconfigured one.\n const getCollectionFromStorage = useCallback(<M extends Record<string, any>>(storageKey: string): PartialCollectionConfig<M> => {\n return readStoredJson<PartialCollectionConfig<M>>(storageKey, { fallback: {}, accept: isRecordValue });\n }, []);\n\n const getCollectionConfig = useCallback(<M extends Record<string, any>>(path: string): PartialCollectionConfig<M> => {\n const storageKey = `collection_config::${stripCollectionPath(path)}`;\n if (configCache.current[storageKey]) {\n return configCache.current[storageKey] as PartialCollectionConfig<M>;\n }\n return getCollectionFromStorage(storageKey);\n }, [getCollectionFromStorage]);\n\n // Bumped on every write. The collection views merge this store into their\n // collection while rendering, so a write that is only a ref mutation is\n // invisible to them: the new column width reaches storage, the table keeps\n // rendering the old one, and the next re-render — a row arriving, a\n // selection, a filter — rebuilds the columns from the stale config and\n // snaps the column back. Making a write a state change is what lets the\n // views re-read it.\n const [configVersion, setConfigVersion] = useState(0);\n\n const onCollectionModified = useCallback(<M extends Record<string, any>>(path: string, data: PartialCollectionConfig<M>) => {\n const storageKey = `collection_config::${stripCollectionPath(path)}`;\n // Read before writing. `data` is a partial by type and by this\n // interface's contract, so what is already stored is the other half of\n // the result — writing `data` first and merging afterwards read back\n // the value that had just been overwritten, and every key the caller\n // left out was dropped.\n const merged = mergeDeep(configCache.current[storageKey] ?? getCollectionFromStorage(storageKey), data);\n configCache.current[storageKey] = merged;\n writeStoredJson(storageKey, merged);\n setConfigVersion(version => version + 1);\n }, [getCollectionFromStorage]);\n\n const [recentlyVisitedPaths, _setRecentlyVisitedPaths] = useState<string[]>([]);\n const [favouritePaths, _setFavouritePaths] = useState<string[]>([]);\n const [collapsedGroups, _setCollapsedGroups] = useState<string[]>([]);\n\n useEffect(() => {\n const readPaths = (key: string) => readStoredJson<string[]>(key, { fallback: [], accept: isArrayValue });\n _setRecentlyVisitedPaths(readPaths(\"recently_visited_paths\"));\n _setFavouritePaths(readPaths(\"favourite_paths\"));\n _setCollapsedGroups(readPaths(\"collapsed_groups\"));\n }, []);\n\n const setRecentlyVisitedPaths = useCallback((paths: string[]) => {\n writeStoredJson(\"recently_visited_paths\", paths);\n _setRecentlyVisitedPaths(paths);\n }, []);\n\n const setFavouritePaths = useCallback((paths: string[]) => {\n writeStoredJson(\"favourite_paths\", paths);\n _setFavouritePaths(paths);\n }, []);\n\n const setCollapsedGroups = useCallback((paths: string[]) => {\n writeStoredJson(\"collapsed_groups\", paths);\n _setCollapsedGroups(paths);\n }, []);\n\n return useMemo(() => ({\n onCollectionModified,\n getCollectionConfig,\n recentlyVisitedPaths,\n setRecentlyVisitedPaths,\n favouritePaths,\n setFavouritePaths,\n collapsedGroups,\n setCollapsedGroups\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `configVersion`\n // is deliberate and the rule cannot see why: it contributes nothing to\n // the value and everything to its IDENTITY. The stored configs live in a\n // ref, so nothing else in this array changes when they do, and this is\n // the only thing telling the views that read them during render that\n // they have. Removing it as \"unnecessary\" is what would break it.\n }), [\n configVersion,\n onCollectionModified,\n getCollectionConfig,\n recentlyVisitedPaths,\n setRecentlyVisitedPaths,\n favouritePaths,\n setFavouritePaths,\n collapsedGroups,\n setCollapsedGroups\n ]);\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { ModeController } from \"./useModeController\";\nimport { readStoredString, removeStoredString, writeStoredString } from \"../util/local_storage\";\n\nconst STORAGE_KEY = \"prefers-dark-mode\";\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\n/**\n * @group Hooks and utilities\n */\nexport interface BuildModeControllerOptions {\n /**\n * `false` builds a controller that touches nothing outside React: no `dark`\n * class on `<html>`, no `prefers-color-scheme` listener, no localStorage.\n * `<Rebase>` passes it when the host app hands over its own\n * `modeController`. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\nfunction systemPrefersDark(): boolean {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return false;\n return window.matchMedia(DARK_QUERY).matches;\n}\n\n/** The stored choice, or the system's when none is stored. */\nfunction preferredMode(): \"light\" | \"dark\" {\n const stored = readStoredString(STORAGE_KEY);\n const prefersDark = stored != null ? stored === \"true\" : systemPrefersDark();\n return prefersDark ? \"dark\" : \"light\";\n}\n\n/**\n * Use this hook to build a color mode controller that determines\n * the theme of the admin.\n *\n * While enabled it owns the page's theme: it puts the `dark` class on\n * `document.documentElement`, follows `prefers-color-scheme` until the user\n * picks a mode, and remembers that pick in localStorage. When the component\n * using it unmounts, it takes away the `dark` class if it was the one that\n * added it.\n *\n * @group Hooks and utilities\n */\nexport function useBuildModeController(options: BuildModeControllerOptions = {}): ModeController {\n const enabled = options.enabled !== false;\n\n const [mode, setMode] = useState<\"light\" | \"dark\">(() => enabled ? preferredMode() : \"light\");\n\n // Whether the `dark` class on <html> is one this controller put there. A\n // class the page had before is the page's, and stays when this goes.\n const addedDarkClass = useRef(false);\n const applyToDocument = useCallback((next: \"light\" | \"dark\") => {\n const classList = document.documentElement.classList;\n if (next === \"dark\") {\n if (!classList.contains(\"dark\")) {\n classList.add(\"dark\");\n addedDarkClass.current = true;\n }\n } else {\n classList.remove(\"dark\");\n addedDarkClass.current = false;\n }\n }, []);\n\n useEffect(() => {\n if (!enabled) return;\n const initial = preferredMode();\n setMode(initial);\n applyToDocument(initial);\n\n const mediaQuery = typeof window.matchMedia === \"function\" ? window.matchMedia(DARK_QUERY) : undefined;\n const handleChange = (e: MediaQueryListEvent) => {\n if (readStoredString(STORAGE_KEY) == null) {\n const next = e.matches ? \"dark\" : \"light\";\n setMode(next);\n applyToDocument(next);\n }\n };\n mediaQuery?.addEventListener(\"change\", handleChange);\n return () => {\n mediaQuery?.removeEventListener(\"change\", handleChange);\n if (addedDarkClass.current) {\n document.documentElement.classList.remove(\"dark\");\n addedDarkClass.current = false;\n }\n };\n }, [enabled, applyToDocument]);\n\n const setModeInternal = useCallback((next: \"light\" | \"dark\" | \"system\") => {\n const resolved = next === \"system\" ? (enabled ? (systemPrefersDark() ? \"dark\" : \"light\") : \"light\") : next;\n if (enabled) {\n applyToDocument(resolved);\n if (next === \"system\") removeStoredString(STORAGE_KEY);\n else writeStoredString(STORAGE_KEY, next === \"dark\" ? \"true\" : \"false\");\n }\n setMode(resolved);\n }, [enabled, applyToDocument]);\n\n return useMemo(() => ({\n mode,\n setMode: setModeInternal\n }), [mode, setModeInternal]);\n}\n","import React, { createContext, useContext, useState, useCallback, useMemo, useRef } from \"react\";\nimport type { RebaseRegistryController, RebaseCMSConfig, RebaseStudioConfig, RebaseAuthViewConfig } from \"@rebasepro/cms-types\";\n\n/**\n * Split into two contexts to prevent infinite re-render loops:\n * - DispatchContext: stable register/unregister functions (never changes identity)\n * - StateContext: the current config values (changes when modules register)\n *\n * Feature components (RebaseAuth, RebaseCMS, RebaseStudio) only consume\n * the dispatch context, so registering does NOT cause them to re-render.\n * RebaseShell consumes state context to read the collected configs.\n */\n\ninterface RegistryDispatch {\n registerAdmin: (config: RebaseCMSConfig) => void;\n unregisterAdmin: () => void;\n registerStudio: (config: RebaseStudioConfig) => void;\n unregisterStudio: () => void;\n registerAuth: (config: RebaseAuthViewConfig) => void;\n unregisterAuth: () => void;\n}\n\ninterface RegistryState {\n cmsConfig: RebaseCMSConfig | null;\n studioConfig: RebaseStudioConfig | null;\n authConfig: RebaseAuthViewConfig | null;\n}\n\nconst RegistryDispatchContext = createContext<RegistryDispatch | undefined>(undefined);\nconst RegistryStateContext = createContext<RegistryState>({\n cmsConfig: null,\n studioConfig: null,\n authConfig: null\n});\n\nexport function RebaseRegistryProvider({ children }: { children: React.ReactNode }) {\n const [cmsConfig, setCmsConfig] = useState<RebaseCMSConfig | null>(null);\n const [studioConfig, setStudioConfig] = useState<RebaseStudioConfig | null>(null);\n const [authConfig, setAuthConfig] = useState<RebaseAuthViewConfig | null>(null);\n\n // Dispatch functions are stable — never change identity\n const dispatch = useMemo<RegistryDispatch>(() => ({\n registerAdmin: (config: RebaseCMSConfig) => setCmsConfig(config),\n unregisterAdmin: () => setCmsConfig(null),\n registerStudio: (config: RebaseStudioConfig) => setStudioConfig(config),\n unregisterStudio: () => setStudioConfig(null),\n registerAuth: (config: RebaseAuthViewConfig) => setAuthConfig(config),\n unregisterAuth: () => setAuthConfig(null)\n }), []);\n\n const state = useMemo<RegistryState>(() => ({\n cmsConfig,\nstudioConfig,\nauthConfig\n }), [cmsConfig, studioConfig, authConfig]);\n\n return (\n <RegistryDispatchContext.Provider value={dispatch}>\n <RegistryStateContext.Provider value={state}>\n {children}\n </RegistryStateContext.Provider>\n </RegistryDispatchContext.Provider>\n );\n}\n\n/**\n * Returns the full registry (state + dispatch).\n * Use this in RebaseShell where you need to read configs.\n */\nexport function useRebaseRegistry(): RebaseRegistryController {\n const dispatch = useContext(RegistryDispatchContext);\n const state = useContext(RegistryStateContext);\n if (!dispatch) {\n throw new Error(\"useRebaseRegistry must be used inside <Rebase>\");\n }\n return useMemo(() => ({ ...state,\n...dispatch }), [state, dispatch]);\n}\n\n/**\n * Returns only the stable dispatch functions.\n * Use this in feature components (RebaseAuth, RebaseCMS, RebaseStudio)\n * to avoid re-render loops.\n */\nexport function useRebaseRegistryDispatch(): RegistryDispatch {\n const dispatch = useContext(RegistryDispatchContext);\n if (!dispatch) {\n throw new Error(\"useRebaseRegistryDispatch must be used inside <Rebase>\");\n }\n return dispatch;\n}\n","\nimport { useAuthController } from \"./useAuthController\";\nimport { useRlsSimulation } from \"../contexts/RlsSimulationContext\";\nimport { Entity } from \"@rebasepro/types\";\nimport { canCreateEntity, canEditEntity, canDeleteEntity, canReadCollection } from \"@rebasepro/common\";\nimport { useCallback, useMemo } from \"react\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\n/**\n * Hook to evaluate roles and permissions for the current user.\n * It abstracts away the need to pass `authController` to permission evaluation functions.\n *\n * While access is simulated (\"Simulate access\") nothing can be created, edited\n * or deleted: the server refuses every write that carries a simulation\n * (`SIMULATION_READ_ONLY`), so the views offer none rather than failing on save.\n */\nexport function usePermissions() {\n const authController = useAuthController();\n const simulating = useRlsSimulation().simulation !== null;\n\n const canCreate = useCallback(\n (collection: AdminCollection<any>, path: string) =>\n !simulating && canCreateEntity(collection, authController, path, null),\n [authController, simulating]\n );\n\n const canEdit = useCallback(\n (collection: AdminCollection<any>, path: string, entity: Entity<any> | null) =>\n !simulating && canEditEntity(collection, authController, path, entity),\n [authController, simulating]\n );\n\n const canDelete = useCallback(\n (collection: AdminCollection<any>, path: string, entity: Entity<any> | null) =>\n !simulating && canDeleteEntity(collection, authController, path, entity),\n [authController, simulating]\n );\n\n const canRead = useCallback(\n (collection: AdminCollection<any>) =>\n canReadCollection(collection, authController),\n [authController]\n );\n\n return useMemo(() => ({\n canCreate,\n canEdit,\n canDelete,\n canRead\n }), [canCreate, canEdit, canDelete, canRead]);\n}\n","import React, { useContext } from \"react\";\n\n/**\n * Configuration for API connectivity. Passed once at the top level\n * and available to any hook that needs `apiUrl` or `getAuthToken`.\n *\n * Individual hooks can still accept explicit overrides — this context\n * serves as a fallback to eliminate repetitive threading.\n */\nexport interface ApiConfig {\n apiUrl: string;\n /**\n * The path the backend mounts its API under, appended to {@link apiUrl}.\n *\n * `\"/api\"` by default, which is the server's default `basePath`. It is\n * carried here because a good deal of UI builds request URLs by hand\n * instead of going through the client's typed methods, and every one of\n * those sites used to write `/api` as a literal — so a backend configured\n * with any other `basePath` served an admin panel whose auth-provider\n * discovery, storage browser, history panel, user picker and Studio tools\n * all requested paths that did not exist.\n */\n apiPath: string;\n getAuthToken?: () => Promise<string | null>;\n}\n\n/** What the server uses when `basePath` is not configured. */\nexport const DEFAULT_API_PATH = \"/api\";\n\nconst ApiConfigContext = React.createContext<ApiConfig | undefined>(undefined);\n\n/**\n * Read the API config from context. Returns `undefined` if no provider is present,\n * allowing hooks to fall back to their own props.\n */\nexport function useApiConfig(): ApiConfig | undefined {\n return useContext(ApiConfigContext);\n}\n\n/**\n * `apiUrl` and `apiPath` joined, with no trailing slash — the prefix to build a\n * request URL from.\n *\n * Returns `undefined` when there is no provider, so a caller can keep its own\n * fallback rather than silently requesting a relative path.\n */\nexport function useApiBase(): string | undefined {\n const config = useApiConfig();\n if (!config?.apiUrl) return undefined;\n return config.apiUrl.replace(/\\/+$/, \"\") + (config.apiPath || DEFAULT_API_PATH);\n}\n\n/**\n * The same prefix, derived from a client rather than from context.\n *\n * For the code that holds a `RebaseClient` but sits outside (or above) an\n * `ApiConfigProvider`. Returns `undefined` when the client has no base URL,\n * which is the signal every caller already treats as \"cannot build a request\".\n */\nexport function apiBaseOf(client?: { baseUrl?: string; apiPath?: string }): string | undefined {\n if (!client?.baseUrl) return undefined;\n return client.baseUrl.replace(/\\/+$/, \"\") + (client.apiPath || DEFAULT_API_PATH);\n}\n\n/**\n * Provide API configuration (apiUrl, apiPath, getAuthToken) to the entire subtree.\n * Typically rendered inside `<Rebase>` or at the app root.\n */\nexport function ApiConfigProvider({\n apiUrl,\n apiPath = DEFAULT_API_PATH,\n getAuthToken,\n children\n}: Omit<ApiConfig, \"apiPath\"> & { apiPath?: string; children: React.ReactNode }) {\n const value = React.useMemo(() => ({ apiUrl,\napiPath,\ngetAuthToken }), [apiUrl, apiPath, getAuthToken]);\n return (\n <ApiConfigContext.Provider value={value}>\n {children}\n </ApiConfigContext.Provider>\n );\n}\n","import { useTranslation as useI18nTranslation } from \"react-i18next\";\nimport { useCallback, useMemo } from \"react\";\n\nconst REBASE_NS = \"rebase_core\";\n\n/**\n * Internal hook for translating Rebase UI strings.\n *\n * Uses the `rebase_core` i18next namespace that is initialised by\n * `RebaseI18nProvider`. Do NOT use `react-i18next` directly in internal\n * components — always go through this hook so the namespace is consistent.\n *\n * @example\n * const { t } = useTranslation();\n * <Button>{t(\"save\")}</Button>\n *\n * @internal\n */\nexport function useTranslation() {\n const { t, i18n } = useI18nTranslation(REBASE_NS);\n\n /**\n * Typed translation function scoped to RebaseTranslations keys.\n * Also supports i18next interpolation variables, e.g.\n * t(\"add_to_field\", { fieldName: \"Tags\" })\n * t(\"error_deleting\", { message: err.message })\n * t(\"sort_key_position\", { position: 2 })\n *\n * Numbers are accepted as well as strings: i18next interpolates them\n * either way, and a signature that took only strings pushed a `String()`\n * onto every call site with a count in it — `{{count}}`, `{{position}}`.\n */\n const typedT = useCallback((key: string, vars?: Record<string, string | number>): string =>\n t(key, vars) as string, [t]);\n\n return useMemo(() => ({ t: typedT,\ni18n }), [typedT, i18n]);\n}\n","import { useCallback } from \"react\";\nimport { useTranslation } from \"./useTranslation\";\n\n/**\n * The display label for a navigation group.\n *\n * A group *name* is an identifier: `StudioHomePage` orders the built-in groups\n * by comparing against `[\"Database\", \"Compute\", …]`, `navigationGroupMappings`\n * keys its icons off it, and `AppView.group` sorts views into one by string\n * equality. Translating the name at the point it is declared therefore breaks\n * the ordering and drops the icons in every locale but English — which is\n * exactly what happened the first time the Studio tool list was translated.\n *\n * So the name stays English and the *label* is translated here, at the one\n * place it is drawn. A group Rebase does not ship — anything an app declares\n * itself — has no key and is rendered as written.\n *\n * @group Hooks and utilities\n */\nexport function useNavigationGroupLabel(): (group: string) => string {\n const { t } = useTranslation();\n return useCallback((group: string) => {\n const key = `studio_group_${group.toLowerCase().replace(/[^a-z0-9]+/g, \"_\")}`;\n // i18next answers a miss with the key itself.\n const label = t(key);\n return label === key ? group : label;\n }, [t]);\n}\n","import React, { useMemo } from \"react\";\nimport { lazyChunk } from \"@rebasepro/ui\";\nimport type { ComponentRef, LazyComponentRef } from \"@rebasepro/types\";\nimport { isLazyComponentRef } from \"@rebasepro/types\";\n\n/**\n * Internal cache for resolved lazy components.\n *\n * `React.lazy()` must return the SAME wrapper across renders — if we call\n * `lazy(loader)` on every render, React will treat each result as a new\n * component type and unmount/remount on each render cycle.\n *\n * This WeakMap keeps a stable mapping from a `ComponentRef` (object/function)\n * to the `React.lazy()` wrapper it produced. Strings are keyed by a separate\n * plain Map since they can't be WeakMap keys.\n */\n\nconst lazyCache = new WeakMap<object | ((...args: any[]) => any), React.ComponentType<any>>();\n\n/**\n * Resolves a `ComponentRef` into a renderable `React.ComponentType`.\n *\n * This hook handles all three forms of `ComponentRef`:\n *\n * 1. **`LazyComponentRef`** (produced by the Vite plugin from string paths):\n * Wraps the lazy loader with `React.lazy()` for automatic code-splitting.\n *\n * 2. **`() => Promise<{ default: ComponentType }>`** (manual lazy import):\n * Also wraps with `React.lazy()`. Distinguished from regular components\n * by checking that the function has no parameters and is not a known\n * React internal (no `$$typeof`).\n *\n * 3. **Direct `React.ComponentType`**:\n * Returned as-is.\n *\n * If the ref is `undefined` or a raw string (which should never happen at\n * runtime in the browser since the Vite plugin transforms strings), returns `undefined`.\n *\n * The returned component is stable across re-renders as long as the `ref`\n * is referentially stable.\n *\n * **Usage:** Wrap the rendered component in `<Suspense>` to handle the\n * loading state of lazy components.\n *\n * @example\n * ```tsx\n * const ResolvedField = useResolvedComponent(property.ui?.Field);\n * if (!ResolvedField) return null;\n * return (\n * <Suspense fallback={<CircularProgress />}>\n * <ResolvedField {...fieldProps} />\n * </Suspense>\n * );\n * ```\n * */\nexport function useResolvedComponent<P = unknown>(\n ref: ComponentRef<P> | undefined\n): React.ComponentType<P> | undefined {\n return useMemo(() => resolveComponentRef(ref), [ref]);\n}\n\n/**\n * Wraps a loader function with `React.lazy()`, caching the result so the\n * same loader always returns the same lazy component identity.\n */\nfunction getOrCreateLazy<P>(\n key: object | ((...args: any[]) => any),\n loader: () => Promise<{ default: React.ComponentType<P> }>\n): React.ComponentType<P> {\n const cached = lazyCache.get(key);\n if (cached) return cached as React.ComponentType<P>;\n\n // SAFETY: React.lazy returns LazyExoticComponent which is structurally compatible with ComponentType<P>\n // `lazyChunk`, not `lazy`: a custom view is a chunk like any other, and a\n // tab left open across a deploy cannot fetch it either.\n const LazyComponent = lazyChunk(loader) as React.ComponentType<P>;\n lazyCache.set(key, LazyComponent);\n return LazyComponent;\n}\n\n/**\n * Pure function version of the resolver, for use outside React components.\n * Same resolution logic as `useResolvedComponent`.\n *\n * Results are cached per reference identity — calling this multiple times\n * with the same `ref` object returns the same `React.ComponentType`.\n */\nexport function resolveComponentRef<P = unknown>(\n ref: ComponentRef<P> | undefined\n): React.ComponentType<P> | undefined {\n if (ref == null) return undefined;\n\n // 1. String — should not happen at runtime (Vite transforms them).\n // Log a warning and bail out.\n if (typeof ref === \"string\") {\n console.warn(\n `[Rebase] Encountered a raw string ComponentRef (\"${ref}\") at runtime. ` +\n \"This usually means the Vite transform plugin did not process this file. \" +\n \"Ensure the file is inside the configured collectionsDir.\"\n );\n return undefined;\n }\n\n // 2. LazyComponentRef — produced by the Vite plugin from string paths.\n // The object has { __rebaseLazy: true, load: () => import(...) }.\n if (isLazyComponentRef(ref)) {\n return getOrCreateLazy<P>(\n ref as object,\n // `load()` resolves to `ComponentLike<P>` — the structural stand-in\n // that lets `ComponentRef` live in the React-free core. This function\n // is the one place that boundary is crossed, so it is the one place\n // the widening is asserted: `ComponentLike` accepts a return type of\n // `unknown` where React wants `ReactNode`. What actually arrives is\n // whatever the collection file pointed at, and rendering it is\n // React's problem either way.\n () => (ref as LazyComponentRef<P>).load() as Promise<{ default: React.ComponentType<P> }>\n );\n }\n\n // 3. Function — either a React component or a lazy import loader.\n if (typeof ref === \"function\") {\n const fn = ref as (...args: any[]) => any;\n\n // Class components (React.Component / PureComponent) have this flag\n if (fn.prototype?.isReactComponent) {\n return ref as React.ComponentType<P>;\n }\n\n // React internals (forwardRef, memo, etc.) carry $$typeof\n if (\"$$typeof\" in fn) {\n return ref as React.ComponentType<P>;\n }\n\n // A function with declared parameters (fn.length > 0) is a regular\n // component that accepts props — return as-is.\n if (fn.length > 0) {\n return ref as React.ComponentType<P>;\n }\n\n // Zero-parameter function — either a React component that takes no props,\n // or a lazy loader `() => import(...)`.\n //\n // Nothing here can be decided with certainty from the outside, so the\n // signals are ordered by how much they can be trusted, and the strongest\n // one is what the function *does*, not what it is called.\n //\n // The name alone is not usable evidence, which is what this used to rely on.\n // `admin: { Preview: () => import(\"./BodyPartsPreview\") }` gives the arrow\n // the *inferred* name \"Preview\" — JS names an anonymous function after the\n // property key it is assigned to — so the \"starts with an uppercase letter,\n // therefore a component\" rule matched every lazy loader written in the\n // documented way. The thunk was then handed to React as a component, React\n // called it, got a Promise back, and rendered nothing. That is what a blank\n // custom preview column in the demo was.\n const source = (() => {\n try {\n return Function.prototype.toString.call(fn);\n } catch {\n return \"\";\n }\n })();\n\n // A dynamic module load in the body is the strongest signal, and it outranks\n // the name: a toolchain cannot rename it away without breaking the fetch,\n // whereas the name is often not the author's at all.\n //\n // Both spellings are checked because the body reaching us depends on the\n // transform. Vite and any ESM build keep `import(...)`; ts-jest and other\n // CommonJS transforms rewrite it to `require(...)`. Matching only the first\n // passes in the browser and fails in the test suite, which is precisely how\n // this went unnoticed. A zero-argument *component* containing either call is\n // not a thing — components import at module scope.\n const loadsAChunk = /\\b(?:import|require)\\s*\\(/.test(source);\n\n if (!loadsAChunk && fn.name && /^[A-Z]/.test(fn.name)) {\n // Named like a component and does not load a chunk: a component.\n return ref as React.ComponentType<P>;\n }\n\n // Treat as a lazy loader — wrap with React.lazy, cached by identity.\n return getOrCreateLazy<P>(\n fn,\n ref as () => Promise<{ default: React.ComponentType<P> }>\n );\n }\n\n // 4. React wrapper objects (React.forwardRef, React.memo) —\n // These are objects with $$typeof but are not functions.\n if (typeof ref === \"object\" && \"$$typeof\" in (ref as object)) {\n return ref as unknown as React.ComponentType<P>;\n }\n\n // 5. Unknown shape — return undefined to be safe\n return undefined;\n}\n","import React, { useContext, useMemo } from \"react\";\nimport type { ComponentOverrideMap, OverridableComponentName } from \"@rebasepro/cms-types\";\nimport { ComponentOverrideContext } from \"../contexts/ComponentOverrideContext\";\nimport { resolveComponentRef } from \"./useResolvedComponent\";\n\n/**\n * Resolves a potentially overridden component.\n *\n * The two scopes compose, innermost first:\n * 1. Default component\n * 2. Global override (`<Rebase components>`), applied to the default\n * 3. Collection-scoped override (`admin.components`), applied to the result\n * of 2\n *\n * Supports two override modes:\n * - **Eject** (default): The override component fully replaces what it is\n * applied to.\n * - **Wrap** (`wrap: true`): The override component wraps what it is applied\n * to, passed as `OriginalComponent` in props — so a collection's wrapper\n * wraps the global override when there is one, not the built-in default.\n *\n * @param name - The overridable component name (e.g. `\"Entity.Form\"`)\n * @param DefaultComponent - The built-in default component\n * @returns The resolved component — either the default, a full replacement, or a wrapper\n *\n * @example\n * ```tsx\n * import { useComponentOverride } from \"@rebasepro/app\";\n *\n * function EntityFormWrapper(props: EntityFormProps) {\n * const ResolvedForm = useComponentOverride(\"Entity.Form\", DefaultEntityForm);\n * return <ResolvedForm {...props} />;\n * }\n * ```\n *\n * @group Hooks\n */\nexport function useComponentOverride<P>(\n name: OverridableComponentName,\n DefaultComponent: React.ComponentType<P>\n): React.ComponentType<P> {\n const { globalOverrides, collectionOverrides } = useContext(ComponentOverrideContext);\n\n return useMemo(() => {\n const AfterGlobal = applyOverride(name, globalOverrides[name], DefaultComponent);\n return applyOverride(name, collectionOverrides[name], AfterGlobal);\n }, [collectionOverrides, globalOverrides, name, DefaultComponent]);\n}\n\n/**\n * One override applied to the component below it: the override itself when it\n * ejects, a wrapper handing it `Base` as `OriginalComponent` when it wraps, and\n * `Base` unchanged when there is no override or it cannot be resolved.\n */\nfunction applyOverride<P>(\n name: OverridableComponentName,\n override: ComponentOverrideMap[OverridableComponentName],\n Base: React.ComponentType<P>\n): React.ComponentType<P> {\n if (!override) return Base;\n\n // `Component` is a `ComponentRef`, so a collection may name its override\n // by module path — which is the only form a `config/collections` file\n // can use without importing React into the backend. The resolver turns\n // a path (already rewritten to a lazy ref by the Vite transform) or an\n // `import()` into a component, and hands a direct reference straight\n // back.\n //\n // Resolved at the map's own props type — `ComponentOverride` is declared\n // without a type argument there, so the override is written against\n // `Record<string, unknown>` and the single widening to `P` happens at\n // the return, exactly where it did before this was a ref.\n const UserComponent = resolveComponentRef(override.Component);\n // An override that cannot be resolved is not an override. The resolver\n // has already said why on the console; rendering what it would have\n // replaced beats rendering nothing at all.\n if (!UserComponent) return Base;\n\n if (override.wrap) {\n const Wrapper = (props: P) => (\n <UserComponent {...(props as Record<string, unknown>)} OriginalComponent={Base} />\n );\n Wrapper.displayName = `Wrapped(${name})`;\n return Wrapper as React.ComponentType<P>;\n }\n\n return UserComponent as React.ComponentType<P>;\n}\n","import React from \"react\";\nimport { Tooltip, TooltipProps } from \"@rebasepro/ui\";\n\nexport function ErrorTooltip(props: TooltipProps) {\n return (\n <Tooltip {...props}\n className={props.className}\n tooltipClassName={\"text-red-500! bg-red-50\"}>\n {props.children}\n </Tooltip>\n );\n}\n","import React from \"react\";\nimport { ErrorTooltip } from \"./ErrorTooltip\";\nimport { AlertTriangleIcon, Button, Typography, iconSize } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\n/**\n * @group Components\n */\nexport interface ErrorViewProps {\n title?: string;\n error: Error | React.ReactElement | string,\n tooltip?: string,\n onRetry?: () => void;\n}\n\n/**\n * Generic error view. Displayed for example when an unexpected value comes\n * from the driver in a collection view.\n * @param title\n * @param error\n * @param tooltip\n * @param onRetry\n\n * @group Components\n */\nexport function ErrorView({\n title,\n error,\n tooltip,\n onRetry\n}: ErrorViewProps): React.ReactElement {\n const { t } = useTranslation();\n const message = error instanceof Error ? error.message : error;\n // Extract error code from ApiError instances (e.g. PG error codes like \"42P01\")\n const errorCode = error instanceof Error && \"code\" in error\n ? (error as Error & { code?: string }).code\n : undefined;\n\n const body = (\n <div className=\"flex flex-col m-2\">\n <div className=\"flex items-start gap-2.5\">\n <AlertTriangleIcon\n size={iconSize.smallest}\n className=\"shrink-0 text-red-500 dark:text-red-400 mt-0.5\"\n />\n <div className=\"flex-1 min-w-0\">\n {title && (\n <Typography\n variant=\"body2\"\n color=\"primary\"\n className=\"font-semibold mb-0.5\"\n >\n {title}\n </Typography>\n )}\n <Typography\n variant=\"body2\"\n color=\"secondary\"\n className=\"leading-relaxed\"\n >\n {message}\n </Typography>\n {errorCode && (\n <span\n className=\"inline-block mt-1 px-1.5 py-0.5 text-[10px] font-mono rounded bg-surface-raised text-text-secondary\"\n >\n {errorCode}\n </span>\n )}\n {onRetry && (\n <div className=\"mt-3\">\n <Button\n variant=\"outlined\"\n color=\"neutral\"\n size=\"small\"\n onClick={onRetry}\n className=\"font-semibold\"\n >\n {t(\"retry\")}\n </Button>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n\n if (tooltip) {\n return (\n <ErrorTooltip title={tooltip}>\n {body}\n </ErrorTooltip>\n );\n }\n return body;\n}\n","import React from \"react\";\nimport { deepEqual as equal } from \"fast-equals\";\n\n/**\n * Hack to prevent data updates for incomplete callbacks from Firestore\n * triggers.\n * If any deps change, the update is immediate\n * @param data\n * @param deps\n * @param timeoutMs\n */\nexport function useDebouncedData<T>(data: T[], deps: unknown, timeoutMs = 5000) {\n\n const [deferredData, setDeferredData] = React.useState(data);\n const dataLength = React.useRef(deferredData.length ?? 0);\n const pendingUpdate = React.useRef(false);\n const currentDeps = React.useRef(deps);\n\n const haveDepsChanged = !equal(currentDeps.current, deps);\n const immediateUpdate = data.length >= dataLength.current || haveDepsChanged;\n\n React.useEffect(() => {\n\n const performUpdate = () => {\n if (!equal(deferredData, data)) {\n currentDeps.current = deps;\n dataLength.current = data.length;\n setDeferredData(data);\n }\n pendingUpdate.current = false;\n };\n\n pendingUpdate.current = true;\n\n let handler: ReturnType<typeof setTimeout> | undefined;\n if (immediateUpdate)\n performUpdate()\n else\n handler = setTimeout(performUpdate, timeoutMs);\n\n return () => {\n clearTimeout(handler);\n if (pendingUpdate.current && immediateUpdate)\n performUpdate();\n };\n }, [data, timeoutMs, deps, immediateUpdate]);\n\n return immediateUpdate ? data : deferredData;\n}\n","import type { Properties, Property } from \"@rebasepro/types\";\n\n/**\n * The property at a dotted path, walking `map` children — `address.street`.\n *\n * The value counterpart is `getValueInPath` in `@rebasepro/utils`; this is the\n * schema half, and the two have to be used together. Reading a dotted path off\n * an entity while looking its property up with a flat `properties[path]` gives\n * the value and `undefined` for how to render it, which is how a declared title\n * on a nested field silently fell back to a derived one.\n *\n * There were three copies of this: one private to `useColumnsIds`, one exported\n * from the admin layer, and the flat lookup in the title resolver that was not\n * this function at all. This is the one, in the lowest layer that needs it —\n * admin re-exports it under the name it already published.\n */\nexport function getPropertyInPath(properties: Properties, path: string): Property | undefined {\n if (typeof properties !== \"object\" || !properties) return undefined;\n if (path in properties) {\n return (properties as Record<string, Property>)[path];\n }\n if (path.includes(\".\")) {\n const pathSegments = path.split(\".\");\n const childProperty = (properties as Record<string, Property>)[pathSegments[0]];\n if (typeof childProperty === \"object\" && childProperty?.type === \"map\" && childProperty.properties) {\n return getPropertyInPath(childProperty.properties, pathSegments.slice(1).join(\".\"));\n }\n }\n return undefined;\n}\n","/**\n * Property presentation helpers.\n *\n * These read a property's admin block — `readOnly`, `disabled.hidden`, the\n * declarative `conditions` — and lived in `@rebasepro/common`, which is on the\n * backend's dependency path. Nothing in core ever called them: `isReadOnly`,\n * `isHidden` and `applyPropertyConditions` are the panel's alone.\n *\n * `applyPropertyConditions` is called by the record form, through\n * `resolveFormProperty`, both where a field is laid out and where the form is\n * judged on save — so a rule the collection editor writes hides, disables and\n * requires what it says it does, and a field it hides is not held against the\n * save. Until that was wired, the evaluator was reached only from its own tests.\n *\n * A condition may also be a literal: `hidden`/`readOnly`/`disabled` stated as a\n * plain boolean rather than as a rule. A literal needs no context, so\n * `isHidden`/`isReadOnly`/`isDisabled` answer it directly, and those three\n * gates are consulted everywhere a field is laid out — including places with\n * no entity to evaluate a rule against.\n */\nimport type { ConditionContext, ConditionRule, EnumValueConfig, Property, PropertyConditions, ReferenceProperty } from \"@rebasepro/types\";\nimport type { AdminArrayOptions, AdminReferenceOptions } from \"@rebasepro/cms-types\";\nimport { evaluateCondition } from \"@rebasepro/common\";\n\n/**\n * A condition stated as a literal rather than as a rule.\n *\n * `PropertyConditions` accepts either, and the two are answered in different\n * places: a rule needs a context and so can only be evaluated while rendering a\n * particular entity, but a literal is already the answer. Reading it here is\n * what makes `hidden: true` work without every gate below having to build a\n * condition context first — and without the caller reaching for\n * `{ \"==\": [1, 1] }` to say something it can say with a boolean.\n */\nfunction literalCondition(condition: ConditionRule | undefined): boolean {\n return condition === true;\n}\n\nexport function isReadOnly(property: Property): boolean {\n if (property.admin?.readOnly)\n return true;\n if (literalCondition(property.conditions?.readOnly))\n return true;\n if (property.type === \"date\") {\n if (property.autoValue)\n return true;\n }\n if (property.type === \"reference\") {\n return !property.path && !(\"Field\" in (property.admin || {}) && property.admin?.Field);\n }\n return false;\n}\n\nexport function isHidden(property: Property): boolean {\n if (literalCondition(property.conditions?.hidden)) return true;\n return typeof property.admin?.disabled === \"object\" && Boolean(property.admin?.disabled.hidden);\n}\n\n/**\n * Whether the field is disabled by its own declaration, ignoring form state.\n *\n * The `admin.disabled` block and `conditions.disabled: true` say the same thing\n * two ways, so every caller that gated on the first now asks here instead of\n * growing a second check of its own.\n */\nexport function isDisabled(property: Property): boolean {\n return Boolean(property.admin?.disabled) || literalCondition(property.conditions?.disabled);\n}\n\nexport function applyPropertyConditions(\n property: Property,\n context: ConditionContext\n): Property {\n const { conditions } = property;\n if (!conditions) return property;\n\n const result = { ...property };\n // The admin block is the collection's own object, shared by every record\n // the form opens. Written into in place, a rule that disabled one record's\n // field disabled it for every record after, whatever their values.\n if (result.admin) result.admin = { ...result.admin };\n\n // ═══════════════════════════════════════════════════════════════════════\n // FIELD STATE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Evaluate disabled condition\n if (conditions.disabled) {\n const isDisabled = evaluateCondition(conditions.disabled, context);\n if (isDisabled) {\n result.admin = result.admin || {};\n result.admin.disabled = {\n clearOnDisabled: conditions.clearOnDisabled ?? false,\n disabledMessage: conditions.disabledMessage,\n hidden: false\n };\n }\n }\n\n // Evaluate hidden condition\n if (conditions.hidden) {\n const isHidden = evaluateCondition(conditions.hidden, context);\n if (isHidden) {\n result.admin = result.admin || {};\n result.admin.disabled = {\n ...(typeof result.admin?.disabled === \"object\" ? result.admin.disabled : {}),\n hidden: true,\n clearOnDisabled: conditions.clearOnDisabled ?? false\n };\n }\n }\n\n // Evaluate readOnly condition\n if (conditions.readOnly) {\n const isReadOnly = evaluateCondition(conditions.readOnly, context);\n if (isReadOnly) {\n result.admin = result.admin || {};\n result.admin.readOnly = true;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALIDATION CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Evaluate required condition\n if (conditions.required !== undefined) {\n const isRequired = Boolean(evaluateCondition(conditions.required, context));\n result.validation = {\n ...result.validation,\n required: isRequired,\n requiredMessage: conditions.requiredMessage ?? result.validation?.requiredMessage\n };\n }\n\n // A bound for a number's value, a string's length or an array's size —\n // the same `validation.min`/`max` each of those types already reads.\n if ((conditions.min !== undefined || conditions.max !== undefined)\n && (result.type === \"number\" || result.type === \"string\" || result.type === \"array\")) {\n const bound = (rule: PropertyConditions[\"min\"]): number | undefined => {\n if (rule === undefined) return undefined;\n const value = evaluateCondition(rule, context);\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n };\n const min = bound(conditions.min);\n const max = bound(conditions.max);\n result.validation = {\n ...result.validation,\n ...(min !== undefined ? { min } : {}),\n ...(max !== undefined ? { max } : {})\n };\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALUE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Apply default value for new entities\n if (context.isNew && conditions.defaultValue !== undefined) {\n result.defaultValue = evaluateCondition(conditions.defaultValue, context) as Property[\"defaultValue\"];\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // ENUM CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (\"enum\" in result && result.enum && (conditions.enumConditions || conditions.allowedEnumValues || conditions.excludedEnumValues)) {\n (result as Record<string, unknown>).enum = applyEnumConditions(\n result.enum as EnumValueConfig[],\n conditions,\n context\n );\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFERENCE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"reference\") {\n if (conditions.referencePath) {\n (result as ReferenceProperty).path = evaluateCondition(conditions.referencePath, context) as string;\n }\n if (conditions.referenceFilter) {\n result.admin = result.admin || {};\n (result.admin as AdminReferenceOptions).fixedFilter =\n evaluateCondition(conditions.referenceFilter, context) as AdminReferenceOptions[\"fixedFilter\"];\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // ARRAY CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"array\") {\n if (conditions.canAddElements !== undefined) {\n result.admin = result.admin || {};\n (result.admin as AdminArrayOptions).canAddElements = evaluateCondition(conditions.canAddElements, context) as boolean;\n }\n if (conditions.sortable !== undefined) {\n result.admin = result.admin || {};\n (result.admin as AdminArrayOptions).sortable = evaluateCondition(conditions.sortable, context) as boolean;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // STORAGE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"string\" && result.storage && (conditions.acceptedFiles !== undefined || conditions.maxFileSize !== undefined)) {\n const storage = { ...result.storage };\n if (conditions.acceptedFiles !== undefined) {\n const accepted = objectToArray(evaluateCondition(conditions.acceptedFiles, context));\n if (accepted.length > 0) storage.acceptedFiles = accepted;\n }\n if (conditions.maxFileSize !== undefined) {\n const maxSize = evaluateCondition(conditions.maxFileSize, context);\n if (typeof maxSize === \"number\" && Number.isFinite(maxSize)) storage.maxSize = maxSize;\n }\n result.storage = storage;\n }\n\n return result;\n}\n\n/**\n * Convert an object with numeric keys back to an array.\n * Firestore stores arrays as {\"0\": \"a\", \"1\": \"b\"} to avoid nested arrays.\n */\nfunction objectToArray(obj: unknown): string[] {\n if (Array.isArray(obj)) return obj.map(String);\n if (obj && typeof obj === \"object\") {\n const keys = Object.keys(obj);\n if (keys.length > 0 && keys.every(k => !isNaN(Number(k)))) {\n return keys\n .sort((a, b) => Number(a) - Number(b))\n .map(k => (obj as Record<string, unknown>)[k])\n .filter((v): v is string => typeof v === \"string\" || typeof v === \"number\")\n .map(String);\n }\n }\n return [];\n}\n\n/**\n * Apply enum-specific conditions to filter and modify enum values.\n */\nfunction applyEnumConditions(\n enumValues: EnumValueConfig[],\n conditions: PropertyConditions,\n context: ConditionContext\n): EnumValueConfig[] {\n let result = [...enumValues];\n\n // Apply allowedEnumValues filter\n if (conditions.allowedEnumValues) {\n const allowed = evaluateCondition(conditions.allowedEnumValues, context);\n // Handle both array format and object-with-numeric-keys format (Firestore workaround)\n const allowedArray = objectToArray(allowed);\n if (allowedArray.length > 0) {\n result = result.filter(ev => allowedArray.includes(String(ev.id)));\n }\n }\n\n // Apply excludedEnumValues filter\n if (conditions.excludedEnumValues) {\n const excluded = evaluateCondition(conditions.excludedEnumValues, context);\n // Handle both array format and object-with-numeric-keys format\n const excludedArray = objectToArray(excluded);\n if (excludedArray.length > 0) {\n result = result.filter(ev => !excludedArray.includes(String(ev.id)));\n }\n }\n\n // Apply individual enum conditions\n if (conditions.enumConditions) {\n result = result\n .map(ev => {\n const evConditions = conditions.enumConditions?.[ev.id];\n if (!evConditions) return ev;\n\n // Check hidden condition first\n if (evConditions.hidden && evaluateCondition(evConditions.hidden, context)) {\n return null; // Will be filtered out\n }\n\n // Check disabled condition\n if (evConditions.disabled && evaluateCondition(evConditions.disabled, context)) {\n return {\n ...ev,\n disabled: true\n };\n }\n\n return ev;\n })\n .filter((ev): ev is EnumValueConfig => ev !== null);\n }\n\n return result;\n}\n","import type { Property, MapProperty, Properties, RelationProperty } from \"@rebasepro/types\";\nimport { useMemo } from \"react\";\n;\nimport { getChildViewDeclaringProperties, getChildViewRelationPropertyKeys, getDeclaredPrimaryKeys, getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { getPropertyInPath } from \"../../collections/property-path\";\nimport { isDisabled } from \"../../collections/property_presentation\";\n\nexport type PropertyColumnConfig = {\n key: string;\n disabled: boolean;\n};\n\nexport function getSubcollectionColumnId(collection: AdminCollection<any>) {\n return `subcollection:${collection.slug}`;\n}\n\n/**\n * The jump-to-tab columns a collection table does not need, because the relation\n * behind them already has a column of its own.\n *\n * Every child view gets a 200px button column that opens its tab. For a relation\n * declared in `relations` that button is the relation's only presence in the\n * table. For one declared as a property it is the second: the property's own\n * column is already there, hydrated by the list fetch's `include`\n * (`getRelationIncludeParams`), showing the child rows themselves — and carrying the *same heading*, because the tab\n * takes its name from the declaring property. Two columns called \"Applications\",\n * one of them a button, and nothing in the header to tell them apart.\n *\n * The property column wins: it shows what the children are, and each chip in it\n * opens one. The tab stays reachable by opening the record, which is what the\n * rest of the table's rows do anyway.\n *\n * Unless the author hid that column — `hideFromCollection` on the property, or a\n * `propertiesOrder` that omits it, is a statement about the column and not about\n * the relation, so the button comes back rather than the relation dropping out\n * of the table altogether.\n */\nexport function getRedundantChildViewColumnIds<M extends Record<string, any>>(collection: AdminCollection<M>): Set<string> {\n const redundant = new Set<string>();\n const properties = collection.properties ?? {};\n const order = collection.propertiesOrder as string[] | undefined;\n\n for (const [viewKey, propertyKey] of getChildViewDeclaringProperties(collection)) {\n const property = properties[propertyKey] as Property | undefined;\n if (!property || property.admin?.hideFromCollection) continue;\n if (order && !order.includes(propertyKey)) continue;\n redundant.add(`subcollection:${viewKey}`);\n }\n\n return redundant;\n}\n\nexport function useColumnIds<M extends Record<string, any>>(collection: AdminCollection<M>, includeSubcollections: boolean): PropertyColumnConfig[] {\n return useMemo(() => {\n const columns = collection.propertiesOrder\n ? hideAndExpandKeys(collection, collection.propertiesOrder)\n : getDefaultColumnKeys(collection, includeSubcollections);\n const keyInIdColumn = getKeyShownInIdColumn(collection);\n return keyInIdColumn ? columns.filter(column => column.key !== keyInIdColumn) : columns;\n }, [collection, includeSubcollections]);\n}\n\n/**\n * The property whose value a collection table's own ID column already shows.\n *\n * Every table opens with an ID column: the row's id, beside its checkbox and\n * menu. A single declared key *is* that id, so its property's column repeated\n * it — two columns headed \"ID\" with the same value, in the collection view and\n * in the relation picker alike. The record form treats that key the same way\n * (routed out of the fields and into the record block), and so does the CSV\n * export (its own `id` column, never the property's).\n *\n * A composite key is not the row's id — `entity.id` is a token built on top of\n * its columns, which are data — so its columns stay. Nor is an `id` property\n * no `isId` declares (see `getDeclaredPrimaryKeys`). With\n * `hideIdFromCollection` the ID column shows no id, and the property's column\n * is where it is read.\n */\nfunction getKeyShownInIdColumn<M extends Record<string, any>>(collection: AdminCollection<M>): string | undefined {\n if (collection.hideIdFromCollection) return undefined;\n const keys = getDeclaredPrimaryKeys(collection);\n return keys.length === 1 ? keys[0].fieldName : undefined;\n}\n\nfunction hideAndExpandKeys<M extends Record<string, any>>(collection: AdminCollection<M>, keys: string[]): PropertyColumnConfig[] {\n\n // First, figure out which spread map roots have individual child keys in the order\n // If so, we should NOT auto-expand them - just use the explicit child keys\n const rootsWithExplicitChildren = new Set<string>();\n for (const key of keys) {\n if (key.includes(\".\")) {\n const rootKey = key.split(\".\")[0];\n const rootProperty = collection.properties[rootKey];\n if (rootProperty && rootProperty.type === \"map\" && rootProperty.admin?.spreadChildren && rootProperty.properties) {\n rootsWithExplicitChildren.add(rootKey);\n }\n }\n }\n\n // Track processed keys to avoid duplicates\n const processedPropertyKeys = new Set<string>();\n\n // Both column paths funnel through here, including a `propertiesOrder` that\n // was saved back with the button column in it.\n const redundantChildViewColumns = getRedundantChildViewColumnIds(collection);\n\n const result = keys.flatMap((key) => {\n // Skip if already processed (handles duplicates in propertiesOrder)\n if (processedPropertyKeys.has(key)) return [null];\n if (redundantChildViewColumns.has(key)) return [null];\n\n // Check if it's a top-level property\n const property = collection.properties[key];\n if (property) {\n processedPropertyKeys.add(key);\n if (property.admin?.hideFromCollection)\n return [null];\n if (property.admin?.disabled && typeof property.admin?.disabled === \"object\" && property.admin?.disabled.hidden)\n return [null];\n\n if (property.type === \"map\" && property.admin?.spreadChildren && property.properties) {\n // Check if this spread map has explicit child keys in propertiesOrder\n if (rootsWithExplicitChildren.has(key)) {\n // DON'T auto-expand - the children are explicitly listed elsewhere\n return [null];\n }\n // Auto-expand all children\n const childConfigs = getColumnKeysForProperty(property, key);\n childConfigs.forEach(c => processedPropertyKeys.add(c.key));\n return childConfigs;\n }\n return [{\n key,\n disabled: isDisabled(property) || Boolean(property.admin?.readOnly)\n }];\n }\n\n // Check if it's a nested key like \"data.mode\" (for spread map properties)\n if (key.includes(\".\")) {\n const rootKey = key.split(\".\")[0];\n const rootProperty = collection.properties[rootKey];\n\n if (rootProperty && rootProperty.type === \"map\" && rootProperty.properties) {\n const nestedProperty = getPropertyInPath(collection.properties, key) as Property | undefined;\n if (nestedProperty) {\n processedPropertyKeys.add(key);\n // Mark root as seen\n processedPropertyKeys.add(rootKey);\n\n if (nestedProperty.admin?.hideFromCollection)\n return [null];\n if (nestedProperty.admin?.disabled && typeof nestedProperty.admin?.disabled === \"object\" && nestedProperty.admin?.disabled.hidden)\n return [null];\n\n return [{\n key,\n disabled: isDisabled(rootProperty) || Boolean(rootProperty.admin?.readOnly) ||\n isDisabled(nestedProperty) || Boolean(nestedProperty.admin?.readOnly)\n }];\n }\n }\n }\n\n // Check additional fields\n const additionalField = collection.additionalFields?.find(field => field.key === key);\n if (additionalField) {\n return [{\n key,\n disabled: true\n }];\n }\n\n // Check subcollections\n const subcollections = getSubcollections(collection);\n if (subcollections) {\n const subCollection = subcollections\n .find(subCol => getSubcollectionColumnId(subCol) === key);\n if (subCollection) {\n return [{\n key,\n disabled: true\n }];\n }\n }\n\n return [null];\n }).filter(Boolean) as PropertyColumnConfig[];\n\n // Add any missing properties that weren't in propertiesOrder\n // This ensures properties NEVER disappear\n for (const propKey of Object.keys(collection.properties)) {\n // Skip if already processed\n if (processedPropertyKeys.has(propKey)) continue;\n\n const property = collection.properties[propKey];\n if (!property) continue;\n if (property.admin?.hideFromCollection) continue;\n if (property.admin?.disabled && typeof property.admin?.disabled === \"object\" && property.admin?.disabled.hidden) continue;\n\n if (property.type === \"map\" && property.admin?.spreadChildren && property.properties) {\n // For spread maps, add all children that weren't already added\n const allChildConfigs = getColumnKeysForProperty(property as MapProperty, propKey);\n for (const childConfig of allChildConfigs) {\n if (!processedPropertyKeys.has(childConfig.key)) {\n result.push(childConfig);\n processedPropertyKeys.add(childConfig.key);\n }\n }\n } else {\n result.push({\n key: propKey,\n disabled: isDisabled(property) || Boolean(property.admin?.readOnly)\n });\n processedPropertyKeys.add(propKey);\n }\n }\n\n return result;\n}\n\nfunction getDefaultColumnKeys<M extends Record<string, any> = any>(collection: AdminCollection<M>, includeSubCollections: boolean) {\n const propertyKeys = Object.keys(collection.properties);\n\n const additionalFields = collection.additionalFields ?? [];\n const subCollections: AdminCollection[] = getSubcollections(collection) ?? [];\n\n const columnIds: string[] = [\n ...propertyKeys,\n // Filter out additional fields whose key already exists in propertyKeys to avoid duplicate column keys\n ...additionalFields.filter((field) => !propertyKeys.includes(field.key)).map((field) => field.key)\n ];\n\n if (includeSubCollections) {\n const subCollectionIds = subCollections\n .map((collection) => getSubcollectionColumnId(collection));\n columnIds.push(...subCollectionIds.filter((subColId) => !columnIds.includes(subColId)));\n }\n\n return hideAndExpandKeys(collection, columnIds);\n}\n\nexport function getColumnKeysForProperty(property: Property, key: string, disabled?: boolean): PropertyColumnConfig[] {\n // A key with no property behind it describes no column. Callers walk whole\n // property maps here to build a table's columns, so reading `.type` off a\n // hole threw away every other column with it.\n if (!property) return [];\n if (property.type === \"map\" && property.admin?.spreadChildren && property.properties) {\n return Object.entries(property.properties)\n .flatMap(([childKey, childProperty]) => getColumnKeysForProperty(\n childProperty as Readonly<Property>,\n `${key}.${childKey}`,\n disabled || isDisabled(property) || Boolean(property.admin?.readOnly))\n );\n }\n return [{\n key,\n disabled: disabled || isDisabled(property) || Boolean(property.admin?.readOnly)\n }];\n}\n\nexport function getFormFieldKeys(collection: AdminCollection): string[] {\n const properties = collection.properties ?? {};\n // A many-relation the entity view already lists as a tab is not an input:\n // the tab is the treatment, and rendering the same declaration again as a\n // picker asked the author to select a collection's own children from a\n // dropdown. `renderInForm` is how a project that wants the picker asks for\n // it back — opt in, because the tab is the default.\n const consumedByChildView = getChildViewRelationPropertyKeys(collection);\n const propertyKeys = Object.keys(properties).filter(key => {\n if (!consumedByChildView.has(key)) return true;\n return (properties[key] as RelationProperty).admin?.renderInForm === true;\n });\n const additionalFields = collection.additionalFields ?? [];\n const allKeys = [\n ...propertyKeys,\n ...additionalFields.map((field) => field.key)\n ];\n\n if (collection.propertiesOrder) {\n return collection.propertiesOrder.filter(key => allKeys.includes(key));\n }\n return allKeys;\n}\n","import { useMemo } from \"react\";\nimport { Entity } from \"@rebasepro/types\";\n\nexport interface DataOrderProps<M extends Record<string, any>> {\n data: Entity<M>[];\n entitiesDisplayedFirst?: Entity<M>[];\n}\n\n/**\n * This hook is used to have some entities at the beginning of data.\n *\n * The result is the same array until `data` or `entitiesDisplayedFirst`\n * changes. It used to be rebuilt on every call whenever rows were pinned, so\n * the table controller around it — and everything rendering from that — was\n * new on every render.\n *\n * @param path\n * @param entitiesDisplayedFirst\n * @group Hooks and utilities\n */\nexport function useDataOrder<M extends Record<string, any>>(\n {\n data,\n entitiesDisplayedFirst\n }: DataOrderProps<M>): Entity<M>[] {\n\n return useMemo(() => {\n if (!entitiesDisplayedFirst)\n return data;\n const displayedFirstId = new Set(entitiesDisplayedFirst.map((e) => e.id));\n return [...entitiesDisplayedFirst, ...data.filter((e) => !displayedFirstId.has(e.id))];\n }, [data, entitiesDisplayedFirst]);\n\n}\n","\nimport React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useLocation } from \"react-router\";\n\nimport { useData, useRebaseContext } from \"../../hooks\";\nimport { useDataOrder } from \"../../hooks/data/useDataOrder\";\nimport { toFindParams } from \"../../hooks/data/collectionQuery\";\nimport { CollectionWindow } from \"../../hooks/data/collectionWindow\";\nimport { getRelationIncludeParams } from \"../../util/previews\";\nimport { Entity, EntityReference, EntityRelation, FilterValues, OrderBySpec, OrderByTuple, User, WhereFilterOp } from \"@rebasepro/types\";\nimport { normalizeOrderBy, serializeOrderBy } from \"@rebasepro/common\";\nimport { EntityTableController, RebaseContext, SelectedCellProps, AdminCollection } from \"@rebasepro/cms-types\";\nimport { ScrollRestorationController } from \"./useScrollRestoration\";\n\nexport const DEFAULT_PAGE_SIZE = 50;\n\n/**\n * Rows held with `pagination: false` past which development builds warn. The\n * docs promise every row, so they are all loaded; but tens of thousands of\n * them sit in memory and re-render on every change, and nothing said so.\n */\nexport const UNPAGINATED_WARNING_ROWS = 10_000;\n\n/** The collections already warned about, so a warning is said once per collection. */\nconst warnedUnpaginated = new Set<string>();\n\nexport type DataTableControllerProps<M extends Record<string, any> = any> = {\n /**\n * Full path where the data of this table is located\n */\n path: string;\n /**\n * The collection that is represented by this config.\n */\n collection: AdminCollection<M>;\n /**\n * List of entities that will be displayed on top, no matter the ordering.\n * This is used for reference fields selection\n */\n entitiesDisplayedFirst?: Entity<M>[];\n\n lastDeleteTimestamp?: number;\n\n /**\n * Force filter to be applied to the table.\n */\n fixedFilter?: FilterValues<string>;\n\n scrollRestoration?: ScrollRestorationController;\n\n /**\n * When set to true the filters and sort will be updated in the URL\n */\n updateUrl?: boolean;\n\n /**\n * Read rows at all. Defaults to `true`. `false` closes the subscription and\n * reads nothing — for a view that keeps the controller for its search and\n * filters but draws its rows some other way, like the board, whose columns\n * each read their own. The rows already held stay until it is enabled\n * again, which reads afresh.\n */\n enabled?: boolean;\n\n}\n\n/**\n * Use this hook to build a controller for the {@link DataCollectionTable}.\n * This controller is bound to data in a path in your specified driver.\n *\n * Note that you can build your own hook returning a {@link EntityTableController}\n * if you would like to display different data.\n *\n * @param path\n * @param collection\n * @param scrollRestoration\n * @param entitiesDisplayedFirst\n * @param lastDeleteTimestamp\n * @param fixedFilterFromProps\n * @param updateUrl\n */\nexport function useDataTableController<M extends Record<string, any> = any, USER extends User = User>(\n {\n path,\n collection,\n scrollRestoration,\n entitiesDisplayedFirst,\n lastDeleteTimestamp,\n fixedFilter: fixedFilterFromProps,\n updateUrl,\n enabled = true\n }: DataTableControllerProps<M>)\n : EntityTableController<M> {\n\n const {\n defaultFilter,\n sort,\n fixedFilter: fixedFilterFromCollection\n } = collection;\n\n const [popupCell, setPopupCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);\n const dataClient = useData();\n\n const fixedFilter = fixedFilterFromProps ?? fixedFilterFromCollection;\n const paginationEnabled = collection.pagination === undefined || Boolean(collection.pagination);\n // `pagination: 0` says *disabled*, not \"a page of no rows\" — which is why\n // it does not reach `paginationEnabled` above. It must not reach the page\n // size either: this value is handed on to the card, board and relation\n // views as the number of rows each of them reads, and a zero there is a\n // `limit=0` the API refuses.\n const pageSize = typeof collection.pagination === \"number\" && collection.pagination > 0\n ? collection.pagination\n : DEFAULT_PAGE_SIZE;\n\n const location = useLocation();\n\n const [searchString, setSearchString] = React.useState<string | undefined>(() => {\n if (updateUrl) {\n return parseSearchString(location.search);\n }\n return undefined;\n });\n\n const checkFilterCombination = useCallback((filterValues: FilterValues<any>,\n sortBy?: OrderByTuple[]) => {\n // PostgREST/SQL can handle arbitrary filter/sort combinations natively.\n return true;\n }, []);\n\n // The collection's default, in the list form the controller works in.\n // `collection.sort` accepts either spelling so a one-key default stays the\n // one-liner it always was.\n const sortInternal = useMemo(() => {\n const keys = normalizeOrderBy(sort as OrderBySpec | undefined);\n if (keys && fixedFilter && !checkFilterCombination(fixedFilter, keys)) {\n console.warn(\"Initial sort is not compatible with the force filter. Ignoring initial sort\");\n return undefined;\n }\n return keys;\n }, [sort, fixedFilter]);\n\n const {\n filterValues: filterUrl,\n sortBy: sortUrl\n } = parseFilterAndSort(location.search);\n\n const [filterValues, setFilterValues] = React.useState<FilterValues<Extract<keyof M, string> | (string & {})> | undefined>(\n () => applyFixedFilter((updateUrl ? filterUrl : undefined) ?? defaultFilter ?? undefined, fixedFilter));\n const [sortBy, setSortBy] = React.useState<OrderByTuple<Extract<keyof M, string> | (string & {})>[] | undefined>((updateUrl ? sortUrl : undefined) ?? sortInternal);\n\n // Sync filter/sort state from URL on browser navigation (back/forward).\n //\n // Only ever on an actual *change* of the URL, which is not the same as \"not\n // the first run\". `useUpdateUrl` writes with `window.history.replaceState`,\n // which react-router does not observe, so the `location` read here keeps\n // reporting the search string this view was mounted with — normally the\n // empty one — no matter what the address bar says. The guard used to be a\n // one-shot ref that skipped the first run and armed itself for every run\n // after; the *second* run then parsed that unchanged, empty search and\n // called `setSortBy(undefined)`, throwing away the collection's `sort`\n // before anything had asked for a different one. Re-running is easy to\n // trigger — this effect depends on `fixedFilter`, a prop most callers pass\n // as a fresh object literal.\n //\n // The visible symptom was a collection that ignored its own default sort: it\n // subscribed correctly, then immediately re-subscribed with no `orderBy` at\n // all, and the second answer replaced the first.\n //\n // Nor on a URL that only repeats what this hook wrote. Opening a record\n // carries the address bar's query onto the record URL (`withListState`), so\n // react-router reports a new `location.search` that is this hook's own\n // state coming back. Parsing it into the live filter made every record\n // click a round trip through the URL format, and the URL cannot say\n // everything the state can: an absent filter param reads back as \"the\n // collection's default\", so a default the user had cleared came straight\n // back on the next click.\n const lastSyncedSearchRef = React.useRef<string>(location.search);\n const lastWrittenListStateRef = React.useRef<string | undefined>(undefined);\n useEffect(() => {\n if (!updateUrl) return;\n // Unchanged URL — including the initial mount, where the state\n // initialisers have already applied the URL params and the collection\n // defaults — carries nothing to sync.\n if (lastSyncedSearchRef.current === location.search) return;\n lastSyncedSearchRef.current = location.search;\n\n const { filterValues: urlFilterValues, sortBy: urlSortBy } = parseFilterAndSort(location.search);\n const urlSearchString = parseSearchString(location.search);\n if (encodeListState(urlFilterValues, urlSortBy, urlSearchString) === lastWrittenListStateRef.current) return;\n\n setFilterValues(applyFixedFilter<Extract<keyof M, string> | (string & {})>(urlFilterValues ?? defaultFilter, fixedFilter));\n if (urlSortBy && fixedFilter && !checkFilterCombination(fixedFilter, urlSortBy)) {\n console.warn(\"URL sort is not compatible with the force filter.\");\n } else {\n // No `__sort` is the collection's default, the same reading the\n // state initialiser gives it on mount — not \"no sort at all\".\n setSortBy((urlSortBy ?? sortInternal) as OrderByTuple<Extract<keyof M, string> | (string & {})>[] | undefined);\n }\n\n setSearchString(urlSearchString);\n }, [location.search, updateUrl, fixedFilter, checkFilterCombination, sortInternal]);\n\n useUpdateUrl(filterValues, sortBy, searchString, updateUrl, lastWrittenListStateRef);\n\n const collectionScroll = scrollRestoration?.getCollectionScroll(path, filterValues);\n /**\n * How many rows to ask for on mount: as many as were loaded last time this\n * (path, filters) pair was on screen, so returning to a view that had been\n * scrolled does not snap back to the first page.\n *\n * The floor is not cosmetic. This used to be `?? pageSize`, which falls back\n * on `null`/`undefined` but not on `0` — and a saved entry whose `data` is\n * empty is entirely ordinary: `updateCollectionScroll` records what was on\n * screen, so any filter combination matching no rows persists `data: []`\n * under its own key. Restoring that gave `itemCount === 0`, which became\n * `limit=0` on the read, which the API rejects (400 `INVALID_LIMIT`) —\n * the collection rendered an error instead of a table, and a client bug\n * read as an API failure.\n *\n * The cache is left free to record an empty view honestly: that it *was*\n * empty is a true fact, and refusing to store it would leave the previous,\n * now-wrong offset and rows in place for a view whose rows have gone. What\n * is wrong is reading \"nothing was restored\" as \"ask for nothing\".\n */\n // The rows kept sit at `dataOffset` (0 when absent): the view held every\n // row up to the last of them.\n const restoredItemCount = collectionScroll ? (collectionScroll.dataOffset ?? 0) + collectionScroll.data.length : 0;\n const initialItemCount = restoredItemCount > 0 ? restoredItemCount : pageSize;\n\n /**\n * What a restored view shows before anything is read: the rows kept for\n * it, where they sat. Kept rows that start past the first row are\n * positions only (`sparseData`, the rows above them not read); `data`\n * holds no row until the window has read the first page, so a view that\n * draws `data` never draws them at the wrong place.\n */\n const [restored] = useState(() => {\n if (!collectionScroll || collectionScroll.data.length === 0) return undefined;\n const offset = collectionScroll.dataOffset ?? 0;\n return {\n seed: { offset, rows: collectionScroll.data as Entity<M>[] },\n rows: offset === 0 ? collectionScroll.data as Entity<M>[] : [],\n sparse: offset === 0\n ? undefined\n : Array.from({ length: offset + collectionScroll.data.length },\n (_, i) => i < offset ? undefined : collectionScroll.data[i - offset] as Entity<M>)\n };\n });\n // Handed to the first window only: a later one reads a different query.\n const seedRef = React.useRef(restored?.seed);\n\n useEffect(() => {\n if (scrollRestoration) {\n // Marks the entry used, as it was restored.\n scrollRestoration.updateCollectionScroll({\n path,\n scrollOffset: collectionScroll?.scrollOffset ?? 0,\n data: collectionScroll?.data ?? [],\n ...(collectionScroll?.dataOffset !== undefined && { dataOffset: collectionScroll.dataOffset }),\n filters: filterValues\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- once, on mount: marks the entry this view was restored from as used, with the values it was restored with.\n }, []);\n\n const [itemCount, setItemCount] = React.useState<number | undefined>(paginationEnabled ? initialItemCount : undefined);\n\n // The whole sort, as one string, so the effect below re-runs when any key\n // changes — a `sortBy` array is a new reference on every render and would\n // re-subscribe on each one if used as a dependency directly.\n const sortKey = sortBy ? serializeOrderBy(sortBy) : undefined;\n\n const context: RebaseContext<USER> = useRebaseContext();\n\n const [rawData, setRawData] = useState<Entity<M>[]>(restored?.rows ?? []);\n const [sparseData, setSparseData] = useState<(Entity<M> | undefined)[] | undefined>(restored?.sparse);\n const rawDataRef = React.useRef(rawData);\n rawDataRef.current = rawData;\n\n const heldRows = rawData.length;\n const collectionKey = collection.slug ?? path;\n useEffect(() => {\n if (paginationEnabled || heldRows <= UNPAGINATED_WARNING_ROWS) return;\n if (process.env.NODE_ENV === \"production\" || warnedUnpaginated.has(collectionKey)) return;\n warnedUnpaginated.add(collectionKey);\n console.warn(`Rebase: the collection \"${collectionKey}\" holds ${heldRows} rows with \\`pagination: false\\`, ` +\n \"and loads every one of them. Set `pagination` to a page size to read them as they are scrolled to. \" +\n \"(Shown once, in development only.)\");\n }, [paginationEnabled, heldRows, collectionKey]);\n const windowRef = React.useRef<CollectionWindow<M> | undefined>(undefined);\n\n /**\n * What comes back with the view: its offset, and the rows around what it\n * showed — a page either side of the rows on screen, where a view reports\n * them, rather than every row it held. A table scrolled to 100,000 rows\n * kept all of them here, and coming back read every one again before\n * showing any.\n */\n const onScroll = useCallback(({\n scrollOffset\n }: {\n scrollOffset: number\n }) => {\n if (!scrollRestoration) return;\n const snapshot = windowRef.current?.snapshot();\n scrollRestoration.updateCollectionScroll({\n path,\n scrollOffset,\n data: snapshot ? snapshot.rows : rawDataRef.current,\n ...(snapshot && snapshot.offset > 0 && { dataOffset: snapshot.offset }),\n filters: filterValues\n });\n }, [scrollRestoration, path, filterValues]);\n\n const [dataLoading, setDataLoading] = useState<boolean>(false);\n const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();\n const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);\n\n /**\n * Clear the user's filters. `fixedFilter` survives — it is the collection\n * forcing a scope, not something the user chose — but `defaultFilter` does\n * not: a default is where the view *opens*, not a floor it can never go\n * below.\n *\n * It used to reset to `defaultFilter`, which made \"clear\" unable to clear\n * whenever a collection defined one, and every caller here wanted the\n * opposite. `ClearFilterSortButton` is labelled \"clear filter\" and left one\n * set. `EditorCollectionActionStart` calls this and then re-applies\n * `collection.defaultFilter` on the next line — redundant under the old\n * behaviour, and the clearest statement of what it expected.\n * `FilterPresetsButton` documents \"clearing all filters deactivates all\n * chips\", which was false: it derives a chip's active state from the\n * filters, so a preset whose values equalled `defaultFilter` switched\n * itself straight back on. That chip could not be turned off at all — click\n * it, the keys are removed, the filter resets to the identical default, and\n * the chip lights up again.\n */\n const clearFilter = useCallback(() => setFilterValues(fixedFilter ?? undefined), [fixedFilter]);\n\n // The user's filters combine with the collection's `fixedFilter` (AND).\n // This used to return early with a console warning whenever a fixed\n // filter was set, while the filters dialog and the header filters went on\n // offering every other field: the user applied a filter, the dialog\n // closed, and the rows did not change.\n const updateFilterValues = useCallback((updatedFilter: FilterValues<Extract<keyof M, string> | (string & {})> | undefined) => {\n setFilterValues(applyFixedFilter(updatedFilter, fixedFilter));\n }, [fixedFilter]);\n\n // Without realtime the rows are one `find` per query, so nothing tells\n // the table a row went away. `lastDeleteTimestamp` is how the collection\n // view says it did (a delete, or linking existing rows), and a re-read is\n // the only way to show it. A live subscription already delivers the\n // change, so it is left alone.\n const canListen = Boolean(dataClient.collection(path).listen);\n const oneShotReadKey = canListen ? undefined : lastDeleteTimestamp;\n\n // How many rows the view wants held. Pagination off is a request for all\n // of them — read in pages the API serves, never as one unbounded read.\n const target = itemCount ?? Infinity;\n const targetRef = React.useRef(target);\n targetRef.current = target;\n\n // The rows the view says it draws, kept for a window opened after it said\n // so (the view's effects run before this hook's).\n const rangeRef = React.useRef<{ start: number; end: number } | undefined>(undefined);\n // Rows `entitiesDisplayedFirst` puts in front of the window's.\n const displayedFirstCount = entitiesDisplayedFirst?.length ?? 0;\n const displayedFirstCountRef = React.useRef(displayedFirstCount);\n displayedFirstCountRef.current = displayedFirstCount;\n\n const onRowsRendered = useCallback((range?: { start: number; end: number }) => {\n const first = displayedFirstCountRef.current;\n const next = range && {\n start: Math.max(0, range.start - first),\n end: Math.max(0, range.end - first)\n };\n rangeRef.current = next;\n windowRef.current?.setVisibleRange(next);\n }, []);\n\n useEffect(() => {\n\n if (!enabled) {\n setDataLoading(false);\n return;\n }\n\n // Cleared by this run's cleanup. A one-shot read has nothing to\n // unsubscribe from, so without it an answer for a superseded query\n // (the \"ch\" typed before \"chair\") landed on top of the newer one.\n let cancelled = false;\n\n setDataLoading(true);\n\n // `browserCallbacks`, not `callbacks`: the server has already run its\n // own `afterRead` before these rows arrived, and running that one\n // again here applied it twice. This block is the panel's.\n const afterRead = collection.browserCallbacks?.afterRead;\n const process = afterRead\n ? async (entities: Entity<M>[]): Promise<Entity<M>[]> => {\n try {\n // afterRead operates on flat rows; unwrap the Entity view-model\n // before invoking and re-wrap the processed row after.\n return await Promise.all(\n entities.map(async (entity) => {\n const processedRow = await afterRead({\n collection,\n path,\n row: { id: entity.id, ...entity.values },\n context\n });\n return {\n ...entity,\n values: processedRow as M\n };\n }));\n } catch (_e: unknown) {\n console.error(_e);\n return entities;\n }\n }\n : undefined;\n\n // filterValues is already FilterValues — pass directly to the accessor\n const whereParams = filterValues && Object.keys(filterValues).length > 0 ? filterValues : undefined;\n const orderByParams = sortBy && sortBy.length > 0\n ? sortBy.map(([field, direction]) => [String(field), direction] as OrderByTuple)\n : undefined;\n\n // Eagerly include relations to avoid N+1 fetches.\n const includeParams = getRelationIncludeParams(collection);\n\n // One page at a time: the first page live, every later one read by\n // offset, none above the API's ceiling — see `CollectionWindow`. The\n // query is assembled in one place (`toFindParams`); listing the fields\n // here is what let `searchExplain` reach three of four read paths.\n const seed = seedRef.current;\n seedRef.current = undefined;\n const collectionWindow = new CollectionWindow<M>({\n accessor: dataClient.collection<M>(path),\n query: toFindParams({ where: whereParams, orderBy: orderByParams, searchString, include: includeParams }),\n pageSize,\n target: targetRef.current,\n process,\n seed,\n onChange: (state) => {\n if (cancelled) return;\n // The rows do not go into the record cache here. They did, all\n // of them, on every update, so that opening one showed it at\n // once — and a table scrolled to 100,000 rows kept every one of\n // them alive after it closed. Opening a record from a list is a\n // click, and the click puts that one row there\n // (`CollectionViewBinding`'s `onEntityClick`).\n if (state.rows) {\n setRawData(state.rows);\n setSparseData(state.sparse);\n }\n if (state.error) console.error(\"ERROR\", state.error);\n setDataLoading(state.loading);\n setDataLoadingError(state.error);\n setNoMoreToLoad(state.complete);\n }\n });\n windowRef.current = collectionWindow;\n if (rangeRef.current) collectionWindow.setVisibleRange(rangeRef.current);\n collectionWindow.start();\n\n return () => {\n cancelled = true;\n collectionWindow.dispose();\n if (windowRef.current === collectionWindow) windowRef.current = undefined;\n };\n }, [dataClient, path, pageSize, sortKey, filterValues, searchString, oneShotReadKey, enabled]);\n\n // Scrolling asks for more rows of the same query: only the rows past the\n // ones held are read.\n useEffect(() => {\n windowRef.current?.setTarget(target);\n }, [target]);\n\n const orderedData = useDataOrder({\n data: rawData,\n entitiesDisplayedFirst\n });\n\n // hack to fix Firestore listeners firing with incomplete data\n // const data = useDebouncedData(orderedData, {\n // filterValues,\n // sortBy,\n // searchString,\n // lastDeleteTimestamp\n // });\n const data = orderedData;\n\n return useMemo(() => ({\n data,\n ...(sparseData && { sparseData }),\n onRowsRendered,\n dataLoading,\n noMoreToLoad,\n dataLoadingError,\n filterValues,\n setFilterValues: updateFilterValues,\n sortBy,\n setSortBy,\n searchString,\n setSearchString,\n clearFilter,\n itemCount,\n setItemCount,\n initialScroll: collectionScroll?.scrollOffset,\n onScroll,\n paginationEnabled,\n pageSize,\n checkFilterCombination,\n popupCell,\n setPopupCell\n }), [\n data,\n sparseData,\n onRowsRendered,\n dataLoading,\n noMoreToLoad,\n dataLoadingError,\n filterValues,\n updateFilterValues,\n sortBy,\n searchString,\n clearFilter,\n itemCount,\n collectionScroll?.scrollOffset,\n onScroll,\n paginationEnabled,\n pageSize,\n checkFilterCombination,\n popupCell\n ]);\n}\n\n/**\n * The user's filters with the collection's fixed filter applied on top. The\n * fixed fields are the collection's, so a value the user sends for one of them\n * never replaces it; every other field is the user's. An empty result is no\n * filter at all.\n */\nfunction applyFixedFilter<K extends string>(\n filter: FilterValues<K> | undefined,\n fixedFilter: FilterValues<string> | undefined\n): FilterValues<K> | undefined {\n const combined: FilterValues<K> = { ...(filter ?? {}), ...(fixedFilter ?? {}) };\n return Object.keys(combined).length > 0 ? combined : undefined;\n}\n\nfunction useUpdateUrl<M extends Record<string, any> = any>(\n filterValues: FilterValues<Extract<keyof M, string>> | undefined,\n sortBy: OrderByTuple<Extract<keyof M, string>>[] | undefined,\n searchString: string | undefined,\n updateUrl: boolean | undefined,\n lastWrittenListStateRef: React.MutableRefObject<string | undefined>\n) {\n\n useEffect(() => {\n if (updateUrl) {\n // Parse existing URL params to preserve non-filter/sort params like __view\n const existingParams = new URLSearchParams(window.location.search);\n const preservedParams = new URLSearchParams();\n\n // Preserve params that are not filter/sort related\n existingParams.forEach((value, key) => {\n if (key.startsWith(\"__\") && key !== \"__sort\" && key !== \"__sort_order\") {\n preservedParams.set(key, value);\n }\n });\n\n const listState = encodeListState(filterValues, sortBy, searchString);\n lastWrittenListStateRef.current = listState;\n\n // Combine preserved params with filter/sort state\n const preservedString = preservedParams.toString();\n const parts = [preservedString, listState].filter(Boolean);\n const state = parts.join(\"&\");\n\n // The entry's existing state goes back in unchanged: react-router\n // keeps its `idx` and `key` there. Replacing it with `{}` left Back\n // with no index to compute a delta from, and react-router lets a\n // POP with no delta through without asking any blocker — every\n // unsaved-changes guard was skipped.\n const hash = window.location.hash;\n if (state === \"\")\n window.history.replaceState(window.history.state, \"\", `${window.location.pathname}${hash}`);\n else\n window.history.replaceState(window.history.state, \"\", `?${state}${hash}`);\n }\n }, [filterValues, sortBy, searchString, updateUrl]);\n}\n\n/**\n * The part of the query string this hook owns — filters, sort and search — in\n * the one canonical spelling, so two states can be compared by what they would\n * write.\n */\nfunction encodeListState(filterValues: FilterValues<string> | undefined,\n sortBy: OrderByTuple[] | undefined,\n searchString: string | undefined): string {\n const search = searchString ? `search=${encodeURIComponent(searchString)}` : \"\";\n return [encodeFilterAndSort(filterValues, sortBy), search].filter(Boolean).join(\"&\");\n}\n\nfunction parseSearchString(search: string): string | undefined {\n // `URLSearchParams` has already decoded the value. Decoding it a second\n // time threw on any search containing a `%` (\"50% off\").\n return new URLSearchParams(search).get(\"search\") || undefined;\n}\n\nconst OP_SUFFIX = \"_op\";\nconst VALUE_SUFFIX = \"_value\";\n\nfunction encodeFilterAndSort(filterValues?: FilterValues<string>, sortBy?: OrderByTuple[] | undefined) {\n const entries: [string, string][] = [];\n if (sortBy && sortBy.length > 0) {\n // Comma-separated, positionally paired. A single key encodes exactly as\n // it did before — `__sort=name&__sort_order=asc` — so links already out\n // in the world keep working, and a reload of a two-key sort no longer\n // silently comes back sorted by the first key alone.\n entries.push([\"__sort\", sortBy.map(([field]) => encodeURIComponent(field)).join(\",\")]);\n entries.push([\"__sort_order\", sortBy.map(([, direction]) => direction).join(\",\")]);\n }\n if (filterValues) {\n Object.entries(filterValues).forEach(([key, value]) => {\n if (value) {\n const conditions: [WhereFilterOp, unknown][] = Array.isArray(value[0])\n ? (value as [WhereFilterOp, unknown][])\n : [value as [WhereFilterOp, unknown]];\n\n // One `_op`/`_value` pair per condition, repeated for a field\n // with several (`stock >= 5 AND stock < 10`). A single condition\n // spells exactly as it always has, which is the format links\n // composed outside the admin follow.\n for (const [op, val] of conditions) {\n if (!op) continue;\n let encodedValue: unknown = val;\n try {\n if (typeof val === \"object\") {\n if (val instanceof Date) {\n encodedValue = val.toISOString();\n } else if (Array.isArray(val)) {\n encodedValue = JSON.stringify(val, (k, v) => {\n if (v instanceof EntityRelation) {\n return encodeRelation(v);\n }\n if (v instanceof EntityReference) {\n return encodeReference(v);\n }\n return v;\n });\n } else if (val instanceof EntityRelation) {\n encodedValue = encodeRelation(val);\n } else if (val instanceof EntityReference) {\n encodedValue = encodeReference(val);\n }\n }\n } catch (e) {\n encodedValue = val;\n }\n if (encodedValue !== undefined) {\n entries.push([encodeURIComponent(`${key}${OP_SUFFIX}`), encodeURIComponent(op)]);\n // Only `null` is written as `null`. `false`, `0` and the\n // empty string are values: read back as `null` they\n // became an IS NULL filter on the server.\n entries.push([encodeURIComponent(`${key}${VALUE_SUFFIX}`),\n encodedValue === null ? \"null\" : encodeURIComponent(String(encodedValue))]);\n }\n }\n }\n });\n }\n return entries.map(([key, value]) => `${key}=${value}`).join(\"&\");\n}\n\nfunction parseFilterAndSort<M>(search: string): {\n filterValues: FilterValues<string> | undefined,\n sortBy?: OrderByTuple<Extract<keyof M, string>>[]\n} {\n const entries = new URLSearchParams(search);\n const filterValues: FilterValues<string> = {};\n let sortBy: OrderByTuple[] | undefined = undefined;\n entries.forEach((value, key) => {\n if (key === \"__sort\") {\n const directions = (entries.get(\"__sort_order\") ?? \"\").split(\",\");\n const keys = value\n .split(\",\")\n .map((field) => decodeURIComponent(field).trim())\n .filter(Boolean)\n // A direction missing from the URL — a hand-written link, or the\n // one-key form of an older bookmark — is ascending, the same\n // reading `?orderBy=name` gets everywhere else.\n .map((field, index): OrderByTuple => [field, directions[index] === \"desc\" ? \"desc\" : \"asc\"]);\n sortBy = keys.length > 0 ? keys : undefined;\n } else if (key.endsWith(OP_SUFFIX) && !(key.slice(0, -OP_SUFFIX.length) in filterValues)) {\n // The suffix, not the first `_op` in the name: `shop_open_op`\n // belongs to `shop_open`.\n const field = key.slice(0, -OP_SUFFIX.length);\n const ops = entries.getAll(key);\n const values = entries.getAll(`${field}${VALUE_SUFFIX}`);\n // Paired by position. An operator with no value beside it is half a\n // pair, and guessing the rest would invent a filter.\n const conditions: [WhereFilterOp, unknown][] = ops\n .slice(0, values.length)\n .map((op, index) => [decodeURIComponent(op) as WhereFilterOp, decodeString(values[index])]);\n if (conditions.length === 1) {\n filterValues[field] = conditions[0];\n } else if (conditions.length > 1) {\n filterValues[field] = conditions;\n }\n }\n });\n\n return {\n filterValues: Object.keys(filterValues).length ? filterValues : undefined,\n sortBy\n }\n}\n\nfunction isDate(dateString: string): boolean {\n // Define a regex pattern that matches the exact date format: 2025-01-07T23:00:00.000Z\n const regexPattern = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;\n\n // Test the dateString against the regex pattern\n if (!regexPattern.test(dateString)) {\n return false;\n }\n\n // If the regex matches, further validate if it is a valid UTC date\n const date = new Date(dateString);\n return date.toISOString() === dateString;\n}\n\nfunction encodeReference(val: EntityReference) {\n return `ref::${val.path}/${val.id}`;\n}\nfunction encodeRelation(val: EntityRelation) {\n return `rel::${val.path}/${val.id}`;\n}\n\n/**\n * Read a `ref::<path>/<id>` or `rel::<path>/<id>` filter value back.\n *\n * The id is the last segment and the path is everything before it. Taking the\n * first two segments instead turned a reference to\n * `content/de-DE/podcasts/abc123` into the record `de-DE` of `content`, and\n * every reference into a subcollection the same way.\n */\nfunction splitEncodedAddress(value: string): { path: string; id: string } {\n const address = value.slice(value.indexOf(\"::\") + 2);\n const separator = address.lastIndexOf(\"/\");\n return {\n path: address.substring(0, separator),\n id: address.substring(separator + 1)\n };\n}\n\nfunction decodeString(val: string): EntityReference | EntityRelation | Date | string {\n let parsedFilterVal: EntityReference | EntityRelation | Date | string = val;\n if (isDate(val)) {\n try {\n parsedFilterVal = new Date(val);\n } catch (_e) {\n // ignore\n }\n }\n if (typeof parsedFilterVal === \"string\") {\n try {\n parsedFilterVal = JSON.parse(parsedFilterVal, (key, value) => {\n if (typeof value === \"string\") {\n if (value.startsWith(\"ref::\")) {\n const { path, id } = splitEncodedAddress(value);\n return new EntityReference({ id,\npath });\n }\n if (value.startsWith(\"rel::\")) {\n const { path, id } = splitEncodedAddress(value);\n return new EntityRelation(id, path);\n }\n }\n return value;\n });\n } catch (_e) {\n // ignore\n }\n }\n\n if (typeof parsedFilterVal === \"string\") {\n if (parsedFilterVal.startsWith(\"ref::\")) {\n const { path, id } = splitEncodedAddress(parsedFilterVal);\n return new EntityReference({ id,\npath });\n }\n if (parsedFilterVal.startsWith(\"rel::\")) {\n const { path, id } = splitEncodedAddress(parsedFilterVal);\n return new EntityRelation(id, path);\n }\n }\n return parsedFilterVal;\n}\n","/**\n * @group Components\n */\nexport type TableSize = \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\";\n\nexport function getRowHeight(size: TableSize): number {\n switch (size) {\n // Density pass (2026-09-08): the old ladder was 54 / 80 / 140 / 280 / 400,\n // sized for image thumbnails at every step, so the default \"m\" row was\n // 140px of mostly air around one line of text. Now xs..m are text rows\n // (small previews: a chip, a date, one inline reference) and only l/xl\n // make room for medium and large thumbnails.\n case \"xl\":\n return 160;\n case \"l\":\n return 96;\n case \"m\":\n return 48;\n case \"s\":\n return 42;\n case \"xs\":\n return 36;\n default:\n throw Error(\"Missing mapping for collection size -> height\");\n }\n}\n","import React from \"react\";\nimport { Link } from \"react-router\";\nimport { Button, Typography } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks\";\n\nexport function NotFoundPage() {\n const { t } = useTranslation();\n\n return (\n <div className=\"flex w-full h-full\">\n <div className=\"m-auto flex items-center flex-col\"\n >\n <Typography variant={\"h4\"} align={\"center\"}\n gutterBottom={true}>\n {t(\"page_not_found\")}\n </Typography>\n <Typography align={\"center\"} gutterBottom={true}>\n {t(\"page_not_found_body\")}\n </Typography>\n <Button\n variant={\"text\"}\n component={Link}\n to={\"/\"}>{t(\"back_to_home\")}</Button>\n </div>\n </div>\n );\n}\n","import React from \"react\";\n\nimport { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks\";\n\nexport function ConfirmationDialog({\n open,\n onAccept,\n onCancel,\n title,\n loading,\n body\n}: {\n open: boolean,\n onAccept: () => void,\n onCancel: () => void,\n loading?: boolean,\n title: React.ReactNode,\n body?: React.ReactNode,\n}) {\n const { t } = useTranslation();\n return (\n <Dialog\n open={open}\n onOpenChange={(open) => !open ? onCancel() : undefined}\n >\n <DialogTitle variant={\"h6\"} className={\"mb-2\"}>{title}</DialogTitle>\n <DialogContent>\n {body}\n </DialogContent>\n\n <DialogActions>\n <Button\n variant={\"text\"}\n onClick={onCancel}\n autoFocus>{t(\"cancel\")}</Button>\n\n <LoadingButton\n type=\"submit\"\n loading={loading}\n onClick={onAccept}\n autoFocus>\n {t(\"ok\")}\n </LoadingButton>\n </DialogActions>\n </Dialog>\n );\n}\n","import React from \"react\";\n\nexport function RebaseLogo({\n width,\n height,\n className,\n style\n}: {\n width?: string,\n height?: string,\n className?: string,\n style?: React.CSSProperties\n}) {\n return (\n <svg\n width={width ?? \"100%\"} height={height ?? \"100%\"}\n version=\"1.1\"\n style={style}\n className={className}\n viewBox=\"112.1405 1079.711 306.058 306.058\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill=\"#34b6d9\" d=\"M237.01 1087.234a56 56 0 0 1 56.07 0l83.819 48.473a56 56 0 0 1 27.965 48.477v97.108a56 56 0 0 1-27.965 48.477l-83.819 48.473a56 56 0 0 1-56.07 0l-83.818-48.473a56 56 0 0 1-27.965-48.477v-97.108a56 56 0 0 1 27.965-48.477Z\"/>\n <path fill=\"#358fd8\" d=\"M264.64 1286.718c27.352 0 49.525 22.173 49.525 49.526 0 27.352-22.173 49.525-49.525 49.525-27.353 0-49.526-22.173-49.526-49.525Z\"/>\n <path fill=\"#ff9197\" d=\"M174.941 1131.547c27.352 0 49.526 22.174 49.526 49.526s-22.174 49.526-49.526 49.526-49.526-22.174-49.526-49.526Z\"/>\n <path fill=\"#358fd8\" d=\"M355.338 1131.547c27.352 0 49.526 22.174 49.526 49.526s-22.174 49.526-49.526 49.526-49.526-22.174-49.526-49.526Z\"/>\n <path fill=\"#fe9197\" d=\"M125.227 1196.44v-14.661c0-13.35 7.55-20.303 17.99-18.168l56.424 31.13 2.72 1.572 27.643 31.545 35.193 30.52q.173 1.522.229 3.013l-54.046-11.395-28.464-26.045Z\"/>\n <path fill=\"#013afd\" d=\"M151.207 1328.696c-14.348-8.285-25.98-28.432-25.98-45v-35.214l11.299-.401c.614.866 34.062 48.973 34.606 49.656.394.495 22.156 40.224 34.409 62.328Z\"/>\n <path fill=\"#2c09d1\" d=\"m211.38 1249.996 30.436 6.417 9.53 9.1-2.926 15.797 16.939 30.08-14.049 6.672-35.072-10.288-33.83-61.32 9.09-.323Z\"/>\n <path fill=\"#2ac1cf\" d=\"M240.774 1380.37a34 34 0 0 1-1.304-.716l-16.141-9.319-49.383-74.238 29.211 7.839Z\"/>\n <path fill=\"#2c42d0\" d=\"m173.359 1219.393 9.557 4.558 28.464 26.045-19.883-3.865-12.782.453-31.643-13.936-15.11-11.819Z\"/>\n <path fill=\"#8b66ed\" d=\"M257.113 1381.863c-4.336 2.13-10.043 1.783-16.34-1.493l-37.616-76.434 13.081 3.838Z\"/>\n <path fill=\"#2c09d1\" d=\"m145.888 1247.749 7.224-.257 23.615 41.804 11.98 1.728-24.421-43.544-.014-.383 10.725-.38 28.16 57.219-29.211-7.839-7.37-11.08Z\"/>\n <path fill=\"#2ac1cf\" d=\"M265.451 1311.554v53.1q0 .255-.004.505l-.25-.26-29.148-38.794-6.308-14.37 21.57 6.328 14.048-6.672Z\"/>\n <path fill=\"#fd485f\" d=\"m223.329 1370.335-17.788-10.27c-12.253-22.104-34.015-61.833-34.41-62.328-.543-.683-33.991-48.79-34.605-49.656l9.362-.332 20.688 37.269Z\"/>\n <path fill=\"#2d42d0\" d=\"m202.362 1196.313 37.108 21.424c13.11 7.57 23.953 25.043 25.727 40.641l-35.193-30.52Z\"/>\n <path fill=\"#2b0ad1\" d=\"M265.447 1365.16c-.095 6.58-2.056 11.56-5.304 14.604l-39.936-70.826 9.534 2.797 6.308 14.37 29.148 38.794Z\"/>\n <path fill=\"#fe9196\" d=\"M125.227 1240.59v-16.4l21.845 8.458 31.643 13.936-35.367 1.255Z\"/>\n <path fill=\"#8b66ed\" d=\"m174.997 1246.716 7.411-.263 33.83 61.32-13.08-3.837Z\"/>\n <path fill=\"#2cc5d2\" d=\"m153.112 1247.492 11.16-.395.014.383 24.421 43.544-11.98-1.728Z\"/>\n <path fill=\"#fc4962\" d=\"M125.227 1224.19v-8.878l30.211-4.464 17.92 8.545-41.396 1.436 15.11 11.82Z\"/>\n <path fill=\"#fe475f\" d=\"M265.451 1292.508v18.84l-.092.043-16.939-30.08 2.927-15.799.214.206Z\"/>\n <path fill=\"#2d43cd\" d=\"M125.227 1215.312v-18.871l30.211 14.407Z\"/>\n <path fill=\"#2ac4d1\" d=\"M260.143 1379.764a12.5 12.5 0 0 1-3.03 2.099l-40.875-74.09 3.969 1.165Z\"/>\n <path fill=\"#fe475f\" d=\"M265.426 1261.391q.025.677.025 1.346v16.241l-13.89-13.26-.186-.36-.028.154-9.53-9.099Z\"/>\n <path fill=\"#40b6d9\" d=\"M265.451 1278.978v13.53c-4.95-9.535-12.604-24.31-13.89-26.79Z\"/>\n <path fill=\"#013afd\" d=\"M125.227 1248.482v-7.892l18.12 7.249Z\"/>\n <path fill=\"#fe9197\" d=\"M143.217 1163.611c2.517.515 5.203 1.558 7.99 3.168l48.434 27.963Z\"/>\n <path fill=\"#fec404\" d=\"m251.347 1265.512.028-.154.186.36Z\"/>\n <path fill=\"#ccc\" d=\"M265.451 1311.347v.207l-.092-.163Z\"/>\n <path fill=\"#2fc7d5\" d=\"M383.274 1164.17a31 31 0 0 1-3.887 2.64l-2.59 1.495-95.242 18.988-50.727-18.022 25.55-32.892 63.642 26.919-61.075-31.394Z\"/>\n <path fill=\"#320fdd\" d=\"m215.866 1112.967 18.535-16.15 5.766 32.704 16.212 6.858-25.551 32.892-57.218-19.484Z\"/>\n <path fill=\"#fd4a61\" d=\"m305.806 1094.328 73.58 42.482c7.16 4.134 10.748 9.55 10.757 14.968l-40.264-5.624-25.491-7.867-33.1-30.491-18.842-4.065Z\"/>\n <path fill=\"#fec504\" d=\"M388.516 1158.077c-1.145 2.145-2.892 4.205-5.242 6.093l-124.33-32.266 6.47-29.689 25.874 5.58 33.1 30.492Z\"/>\n <path fill=\"#320fdd\" d=\"m179.744 1183.464-26.935-15.551 18.147-15.813 55.184 23.206-15.732 20.252Z\"/>\n <path fill=\"#33b6d9\" d=\"m358.403 1178.925-52.998 30.599-44.794-17.995 89.572-18.117Z\"/>\n <path fill=\"#fd4a63\" d=\"m234.401 1096.817 12.723-11.087 19.395 11.42-7.574 34.754 61.075 31.394-79.853-33.777Z\"/>\n <path fill=\"#fe9197\" d=\"m152.809 1167.913-1.91-1.103c-10.42-6.016-13.273-14.747-8.558-22.25l56.907-27.791 15.854-3.136Z\"/>\n <path fill=\"#8b69f1\" d=\"m305.405 1209.524-14.281 8.245c-5.252 3.032-11.697 4.954-18.462 5.767l-43.574-25.631 31.523-6.376Z\"/>\n <path fill=\"#3015d8\" d=\"M252.294 1080.973c13.06-2.81 28.331-1.183 38.83 4.879l14.682 8.476-33.36 9.403-7.031-1.516 1.104-5.064-19.395-11.42Z\"/>\n <path fill=\"#2c0ace\" d=\"M239.162 1085.852c3.85-2.223 8.342-3.85 13.132-4.88l-37.192 32.66-15.854 3.137-56.907 27.791c1.777-2.828 4.63-5.482 8.559-7.75Z\"/>\n <path fill=\"#2fc7d5\" d=\"m229.088 1197.905-8.773 1.774-9.907-4.121 15.732-20.252 37.462 15.618Z\"/>\n <path fill=\"#33b6d9\" d=\"M272.662 1223.536c-11.721 1.407-24.402-.515-33.5-5.767l-28.093-16.22 18.019-3.644Z\"/>\n <path fill=\"#fe9197\" d=\"m264.078 1190.828-.476.096-37.462-15.618 4.688-6.035 50.727 18.022ZM170.956 1152.1l2.654-2.313 57.218 19.484-4.688 6.035Z\"/>\n <path fill=\"#30c3d9\" d=\"M390.143 1151.778c.01 2.125-.533 4.25-1.627 6.3l-38.637-11.924Z\"/>\n <path fill=\"#ff4c60\" d=\"m211.07 1201.55-31.326-18.086 40.57 16.215Z\"/>\n <path fill=\"#2d08d0\" d=\"m376.798 1168.305-18.395 10.62-8.22-5.513Z\"/>\n <path fill=\"#2fc7d5\" d=\"M264.887 1262.737c0-16.568 11.632-36.715 25.98-45l40.425-23.339 11.932 35.4-25.718 46.274-26.284-2.855-1.382.145-1.411-.146-23.542.675Z\"/>\n <path fill=\"#32abd6\" d=\"M383.486 1164.684c2.376-.909 4.642-1.382 6.752-1.446l-7.859 43.045-.292 5.18 8.911 13.519 5.344-41.78 4.102-15.889c2.942 3.164 4.667 8.084 4.667 14.466v91.585h-1.324c-1.104 3.308-34.555 60.887-34.486 61.007l-21.13 12.2 8.305-32.902-10.115 14.693 10.115-20.342 47.315-78.499-7.45 6.694-15.674 18.243 2.62-89.698.155-.059Z\"/>\n <path fill=\"#2eabd6\" d=\"m324.54 1360.214-33.672 19.44c-13.695 7.907-24.915 2.15-25.91-12.796l8.385-12.077 47.855-71.354 7.12-26.81 5.119-9.209.57 31.212-13.987 50.442 6.42-5.847-2.408 22.126.459 8.254Z\"/>\n <path fill=\"#8b65f0\" d=\"M264.959 1366.858a33 33 0 0 1-.072-2.204v-88.582l24.953-2.71 26.235 2.554 1.43.156 10.813-19.454-7.12 26.81-47.855 71.353Z\"/>\n <path fill=\"#fd4861\" d=\"m378.764 1192.394 3.89-5.923c-1.987-.058-4.42 64.146-4.402 65.055.019.91-5.901 22.365-5.901 22.365l-17.658 29.778-14.983 14.696 9.72-45.149.036-1.115 6.455-7.894Z\"/>\n <path fill=\"#32abd6\" d=\"m377.832 1167.529.229-.133.703 24.998-22.843 71.813-6.455 7.894.572-17.63-3.443-30.74Z\"/>\n <path fill=\"#8c66ef\" d=\"m328.775 1297.488.034-.126 20.657-25.261-.036 1.115-9.72 45.15 14.983-14.697-13.8 22.045-16.86 19.627 2.407-22.126-6.42 5.847Z\"/>\n <path fill=\"#2c08d3\" d=\"m331.292 1194.398 27.203-15.705 5.51 13.714-20.781 37.391Z\"/>\n <path fill=\"#300bd2\" d=\"m324.491 1353.595-.459-8.254 16.861-19.627 13.8-22.045 17.658-29.778 20.08-31.948 3.91-5.728 7.45-6.694-47.315 78.5-10.115 20.341-21.821 31.852Z\"/>\n <path fill=\"#2c08d3\" d=\"m333.437 1247.408 13.158-23.676 3.443 30.738-4.056 14.678-14.316 17.914 2.34-8.442Z\"/>\n <path fill=\"#8b68ef\" d=\"M405.111 1273.364v10.332c0 16.568-11.632 36.715-25.98 45l-9.83 5.675c-.07-.12 33.382-57.7 34.486-61.007Z\"/>\n <path fill=\"#fec504\" d=\"M390.238 1163.238c4.109-.125 7.625 1.3 10.206 4.075l-4.102 15.89-5.344 41.779-8.91-13.518.291-5.18Z\"/>\n <path fill=\"#300bd2\" d=\"m348.171 1346.57-23.631 13.644 31.936-46.545Z\"/>\n <path fill=\"#348fd8\" d=\"M372.35 1273.891s5.921-21.455 5.902-22.365 2.415-65.113 4.402-65.055l-1.987 67.987 15.675-18.243-3.91 5.728Z\"/>\n <path fill=\"#32abd6\" d=\"m358.495 1178.693 19.337-11.164-13.827 24.878Z\"/>\n <path fill=\"#fd4861\" d=\"m331.391 1288.05.275-.988 14.316-17.914 4.056-14.678-.572 17.63-20.657 25.262Z\"/>\n <path fill=\"#ccc\" fillOpacity=\".579\" d=\"m378.06 1167.396 1.07-.617a31 31 0 0 1 4.158-2.019l-.634 21.71-3.89 5.924Z\"/>\n <path fill=\"#2fc7d5\" d=\"M264.887 1276.072v-2.18l23.542-.676 1.411.146Z\"/>\n <path fill=\"#8b65f0\" d=\"m291.193 1273.502-1.353-.14 1.382-.145 24.853 2.7Z\"/>\n </svg>\n );\n\n}\n","import { Wand2Icon } from \"@rebasepro/ui\";\nimport React from \"react\";\n\nexport interface AIIconProps {\n size?: \"smallest\" | \"small\" | \"medium\" | \"large\";\n className?: string;\n}\n\n/**\n * AI-styled AutoAwesome icon with gradient coloring.\n * Used consistently across AI features for visual identification.\n */\nexport function AIIcon({ size = \"small\", className }: AIIconProps) {\n const sizeMap: Record<string, number> = {\n smallest: 16,\n small: 20,\n medium: 24,\n large: 28\n };\n const numericSize = typeof size === \"string\" ? sizeMap[size] || 20 : size;\n\n return (\n <Wand2Icon\n size={numericSize}\n className={className}\n style={{\n background: \"linear-gradient(to right, var(--color-primary), var(--color-secondary))\",\n WebkitBackgroundClip: \"text\",\n WebkitTextFillColor: \"transparent\",\n backgroundClip: \"text\"\n }}\n />\n );\n}\n\n/**\n * Small animated dot indicator for AI-modified elements.\n * Shows a pulsing gradient dot.\n */\nexport function AIModifiedIndicator({ className }: { className?: string }) {\n return (\n <div\n className={`w-2 h-2 rounded-full bg-gradient-to-r from-primary to-secondary animate-pulse ${className ?? \"\"}`}\n title=\"AI modified\"\n />\n );\n}\n","/**\n * What the settings screen and the link's screen say about a refused address\n * change: the codes a person can act on get the panel's own, translated words,\n * and anything else keeps the server's message.\n */\nexport function emailChangeErrorMessage(error: unknown, t: (key: string) => string): string {\n const code = error instanceof Error && \"code\" in error ? error.code : undefined;\n switch (code) {\n case \"EMAIL_EXISTS\":\n return t(\"email_change_taken\");\n case \"UNDELIVERABLE_ADDRESS\":\n return t(\"email_change_undeliverable\");\n case \"EMAIL_UNCHANGED\":\n return t(\"email_change_unchanged\");\n case \"AAL2_REQUIRED\":\n return t(\"email_change_needs_second_factor\");\n case \"INVALID_TOKEN\":\n return t(\"auth_link_invalid_or_expired\");\n default:\n return error instanceof Error ? error.message : String(error);\n }\n}\n","\nimport React, { useEffect, useRef, useState } from \"react\";\nimport {\n Alert,\n Avatar,\n Button,\n Card,\n Chip,\n CircularProgress,\n cls,\n IconButton,\n LoadingButton,\n Tab,\n Tabs,\n TextField,\n Trash2Icon,\n Typography\n} from \"@rebasepro/ui\";\nimport { useAuthController, useTranslation } from \"../hooks\";\nimport { emailChangeErrorMessage } from \"./email-change-message\";\n\ninterface SessionInfo {\n id: string;\n userAgent?: string;\n ipAddress?: string;\n createdAt: string;\n isCurrentSession?: boolean;\n}\n\ninterface ExtendedAuthController {\n user: { displayName?: string | null; photoURL?: string | null; email?: string | null; pendingEmail?: string | null } | null;\n updateProfile?: (displayName: string, photoURL: string) => Promise<void>;\n changePassword?: (oldPassword: string, newPassword: string) => Promise<void>;\n changeEmail?: (newEmail: string) => Promise<{ pendingEmail: string; expiresAt: string }>;\n fetchSessions?: () => Promise<SessionInfo[]>;\n revokeSession?: (id: string) => Promise<void>;\n revokeAllSessions?: () => Promise<void>;\n signOut: () => Promise<void>;\n}\n\ntype ActiveTab = \"profile\" | \"security\" | \"sessions\";\n\nexport function UserSettingsView() {\n const authController = useAuthController() as ExtendedAuthController;\n const user = authController.user;\n const { t } = useTranslation();\n\n const hasPasswordChange = !!authController.changePassword;\n const [activeTab, setActiveTab] = useState<ActiveTab>(\"profile\");\n\n // Profile state\n const [displayName, setDisplayName] = useState(user?.displayName || \"\");\n const [photoURL, setPhotoURL] = useState(user?.photoURL || \"\");\n const [savingProfile, setSavingProfile] = useState(false);\n const [profileError, setProfileError] = useState<string | null>(null);\n\n // Email change state. The address waiting for its link, as the server last\n // said — on load from the user, then from the request just made.\n const [newEmail, setNewEmail] = useState(user?.email || \"\");\n const [pendingEmail, setPendingEmail] = useState<string | null>(user?.pendingEmail ?? null);\n const [changingEmail, setChangingEmail] = useState(false);\n const [emailError, setEmailError] = useState<string | null>(null);\n\n // Password change state\n const [currentPassword, setCurrentPassword] = useState(\"\");\n const [newPassword, setNewPassword] = useState(\"\");\n const [confirmPassword, setConfirmPassword] = useState(\"\");\n const [changingPassword, setChangingPassword] = useState(false);\n const [passwordError, setPasswordError] = useState<string | null>(null);\n const [passwordSuccess, setPasswordSuccess] = useState<string | null>(null);\n\n // Sessions state\n const [sessions, setSessions] = useState<SessionInfo[]>([]);\n const [loadingSessions, setLoadingSessions] = useState(false);\n const [sessionsError, setSessionsError] = useState<string | null>(null);\n const [revokingSessionId, setRevokingSessionId] = useState<string | null>(null);\n const [revokingAll, setRevokingAll] = useState(false);\n\n useEffect(() => {\n setDisplayName(user?.displayName || \"\");\n setPhotoURL(user?.photoURL || \"\");\n setNewEmail(user?.email || \"\");\n setPendingEmail(user?.pendingEmail ?? null);\n if (activeTab === \"sessions\") {\n loadSessions();\n }\n }, [activeTab, user]);\n\n const handleSaveProfile = async () => {\n setSavingProfile(true);\n setProfileError(null);\n try {\n if (authController.updateProfile) {\n await authController.updateProfile(displayName, photoURL);\n } else {\n throw new Error(\"updateProfile not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setProfileError(e instanceof Error ? e.message : String(e));\n } finally {\n setSavingProfile(false);\n }\n };\n\n const handleChangeEmail = async () => {\n if (!authController.changeEmail) return;\n setChangingEmail(true);\n setEmailError(null);\n try {\n const { pendingEmail: waiting } = await authController.changeEmail(newEmail.trim());\n setPendingEmail(waiting);\n } catch (e: unknown) {\n setEmailError(emailChangeErrorMessage(e, t));\n } finally {\n setChangingEmail(false);\n }\n };\n\n const handleChangePassword = async () => {\n setPasswordError(null);\n setPasswordSuccess(null);\n\n // Validate\n if (newPassword.length < 8) {\n setPasswordError(t(\"password_too_short\"));\n return;\n }\n if (newPassword !== confirmPassword) {\n setPasswordError(t(\"passwords_dont_match\"));\n return;\n }\n\n setChangingPassword(true);\n try {\n if (authController.changePassword) {\n await authController.changePassword(currentPassword, newPassword);\n setPasswordSuccess(t(\"password_changed\"));\n setCurrentPassword(\"\");\n setNewPassword(\"\");\n setConfirmPassword(\"\");\n // The backend ends every other session and hands this device a\n // fresh one, which the controller adopts: nothing to sign out.\n }\n } catch (e: unknown) {\n setPasswordError(e instanceof Error ? e.message : String(e));\n } finally {\n setChangingPassword(false);\n }\n };\n\n const loadSessions = async () => {\n setLoadingSessions(true);\n setSessionsError(null);\n try {\n if (authController.fetchSessions) {\n const fetchedSessions = await authController.fetchSessions();\n const sortedSessions = (fetchedSessions || []).sort((a: SessionInfo, b: SessionInfo) =>\n new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n );\n setSessions(sortedSessions);\n } else {\n throw new Error(\"fetchSessions not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setSessionsError(e instanceof Error ? e.message : String(e));\n } finally {\n setLoadingSessions(false);\n }\n };\n\n const handleRevokeSession = async (id: string, isCurrentSession?: boolean) => {\n setRevokingSessionId(id);\n try {\n if (authController.revokeSession) {\n await authController.revokeSession(id);\n setSessions(sessions.filter(s => s.id !== id));\n if (isCurrentSession) {\n await authController.signOut();\n }\n } else {\n throw new Error(\"revokeSession not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setSessionsError(e instanceof Error ? e.message : String(e));\n } finally {\n setRevokingSessionId(null);\n }\n };\n\n const handleRevokeAll = async () => {\n setRevokingAll(true);\n try {\n if (authController.revokeAllSessions) {\n await authController.revokeAllSessions();\n } else {\n throw new Error(\"revokeAllSessions not implemented in this auth controller.\");\n }\n } catch (e: unknown) {\n setSessionsError(e instanceof Error ? e.message : String(e));\n } finally {\n setRevokingAll(false);\n }\n };\n\n if (!user) return null;\n\n return (\n <div className=\"flex-grow max-w-4xl w-full mx-auto p-4 sm:p-6 md:p-12\">\n <Typography variant=\"h4\" className=\"mb-8\">{t(\"account_settings\")}</Typography>\n\n <Tabs value={activeTab} onValueChange={(v) => setActiveTab(v as ActiveTab)} className=\"mb-8\">\n <Tab value=\"profile\">{t(\"profile\")}</Tab>\n {hasPasswordChange && <Tab value=\"security\">{t(\"security\")}</Tab>}\n <Tab value=\"sessions\">{t(\"sessions\")}</Tab>\n </Tabs>\n\n {activeTab === \"profile\" && (\n <div className=\"flex flex-col gap-6 max-w-xl\">\n <div className=\"flex items-center gap-6 mb-2\">\n <Avatar src={photoURL || undefined} className=\"w-24 h-24 text-3xl\">\n {displayName ? displayName[0].toUpperCase() : (user.email ? user.email[0].toUpperCase() : \"A\")}\n </Avatar>\n </div>\n <TextField\n label={t(\"display_name\")}\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n />\n <TextField\n label={t(\"photo_url\")}\n value={photoURL}\n onChange={(e) => setPhotoURL(e.target.value)}\n />\n {profileError && <Typography color=\"error\">{profileError}</Typography>}\n <div className=\"mt-4\">\n <Button variant=\"filled\" onClick={handleSaveProfile} disabled={savingProfile}>\n {savingProfile ? t(\"saving\") : t(\"save_profile\")}\n </Button>\n </div>\n\n {authController.changeEmail && (\n <div className=\"flex flex-col gap-4 mt-10\">\n <div>\n <Typography variant=\"h6\" className=\"mb-1\">{t(\"email_address\")}</Typography>\n <Typography variant=\"body2\" color=\"secondary\">{t(\"email_change_description\")}</Typography>\n </div>\n <TextField\n label={t(\"email_address\")}\n type=\"email\"\n autoComplete=\"email\"\n value={newEmail}\n onChange={(e) => {\n setNewEmail(e.target.value);\n setEmailError(null);\n }}\n />\n {pendingEmail && (\n <Alert color=\"info\">\n {t(\"email_change_pending\", { email: pendingEmail })}\n </Alert>\n )}\n {emailError && <Typography color=\"error\">{emailError}</Typography>}\n <div>\n <LoadingButton\n variant=\"filled\"\n onClick={handleChangeEmail}\n loading={changingEmail}\n disabled={changingEmail || !newEmail.trim() || newEmail.trim().toLowerCase() === (user.email ?? \"\").toLowerCase()}\n >\n {t(\"email_change_button\")}\n </LoadingButton>\n </div>\n </div>\n )}\n </div>\n )}\n\n {activeTab === \"security\" && hasPasswordChange && (\n <div className=\"flex flex-col gap-6 max-w-xl\">\n <Typography variant=\"h6\" className=\"mb-2\">{t(\"change_password\")}</Typography>\n\n <TextField\n label={t(\"current_password\")}\n type=\"password\"\n value={currentPassword}\n onChange={(e) => setCurrentPassword(e.target.value)}\n autoComplete=\"current-password\"\n />\n <TextField\n label={t(\"new_password\")}\n type=\"password\"\n value={newPassword}\n onChange={(e) => setNewPassword(e.target.value)}\n autoComplete=\"new-password\"\n />\n <TextField\n label={t(\"confirm_password\")}\n type=\"password\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n autoComplete=\"new-password\"\n />\n\n {passwordError && (\n <Typography color=\"error\">{passwordError}</Typography>\n )}\n {passwordSuccess && (\n <Alert color=\"success\">{passwordSuccess}</Alert>\n )}\n\n <div className=\"mt-4\">\n <Button\n variant=\"filled\"\n onClick={handleChangePassword}\n disabled={changingPassword || !currentPassword || !newPassword || !confirmPassword}\n >\n {changingPassword ? t(\"changing_password\") : t(\"change_password\")}\n </Button>\n </div>\n </div>\n )}\n\n\n {activeTab === \"sessions\" && (\n <div className=\"flex flex-col gap-4 max-w-3xl\">\n {loadingSessions ? (\n <div className=\"flex justify-center p-8\"><CircularProgress/></div>\n ) : sessionsError ? (\n <Typography color=\"error\">{sessionsError}</Typography>\n ) : sessions.length === 0 ? (\n <Typography>{t(\"no_active_sessions\")}</Typography>\n ) : (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex justify-end mb-2\">\n <Button\n variant=\"text\"\n color=\"error\"\n onClick={handleRevokeAll}\n disabled={revokingAll}\n >\n {revokingAll ? t(\"revoking\") : t(\"revoke_all_sessions\")}\n </Button>\n </div>\n {sessions.map(session => (\n <Card key={session.id} className=\"flex justify-between items-center p-4\">\n <div className=\"flex flex-col\">\n <div className=\"flex items-center gap-2 mb-1\">\n <Typography variant=\"body1\">\n {session.userAgent || t(\"unknown_device\")}\n </Typography>\n {session.isCurrentSession && (\n <Chip colorScheme=\"blue\" size=\"small\">\n {t(\"current\")}\n </Chip>\n )}\n </div>\n <Typography variant=\"caption\" color=\"secondary\">\n {t(\"session_details\", {\n ip: session.ipAddress || t(\"unknown_address\"),\n created: new Date(session.createdAt).toLocaleString()\n })}\n </Typography>\n </div>\n <div className=\"ml-4\">\n {revokingSessionId === session.id ? (\n <CircularProgress size=\"small\"/>\n ) : (\n <IconButton onClick={() => handleRevokeSession(session.id, session.isCurrentSession)} aria-label={t(\"revoke_session\")}>\n <Trash2Icon/>\n </IconButton>\n )}\n </div>\n </Card>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { RebaseTranslations } from \"@rebasepro/cms-types\";\n\n/**\n * English baseline translations for @rebasepro/app.\n *\n * This is the single source of truth for all default UI strings.\n * Override any key via the `translations` prop on Rebase entry-point components.\n *\n * @group Core\n */\nexport const en: RebaseTranslations = {\n // ─── Form actions ────────────────────────────────────────────\n save: \"Save\",\n create: \"Create\",\n create_copy: \"Create copy\",\n save_and_close: \"Save and close\",\n create_copy_and_close: \"Create copy and close\",\n create_and_close: \"Create and close\",\n discard: \"Discard\",\n clear: \"Clear\",\n cancel: \"Cancel\",\n\n // ─── Entity actions ──────────────────────────────────────────\n edit: \"Edit\",\n copy: \"Copy\",\n delete: \"Delete\",\n delete_not_allowed: \"You have selected at least one entity you cannot delete\",\n edit_entity: \"Edit\",\n back_to_detail: \"Back to details\",\n\n // ─── Delete dialog ───────────────────────────────────────────\n delete_confirmation_title: \"Delete?\",\n delete_confirmation_body: \"This will delete the entity. Are you sure?\",\n delete_multiple_confirmation_body: \"This will delete the selected entities. Are you sure?\",\n\n // ─── Unsaved-changes dialog ───────────────────────────────────\n unsaved_changes_title: \"Unsaved changes\",\n unsaved_changes_body: \"You have unsaved changes. Do you want to discard them?\",\n discard_changes: \"Discard changes\",\n keep_editing: \"Keep editing\",\n clear_form: \"Clear form?\",\n discard_changes_confirmation: \"All unsaved changes will be lost. This cannot be undone.\",\n clear_form_confirmation: \"All entered values will be cleared. This cannot be undone.\",\n\n // ─── Collection table / toolbar ──────────────────────────────\n search: \"Search\",\n find_by_id: \"Find by ID\",\n find_entity_by_id: \"Find entity by ID\",\n filter: \"Filter\",\n filters: \"Filters\",\n records_in_view: \"Records in this view\",\n clear_filter: \"Clear filter\",\n clear_filter_sort: \"Clear filter/sort\",\n clear_sort: \"Clear sort\",\n sort: \"Sort\",\n sort_by: \"Sort by\",\n sort_then_by: \"Then by\",\n sort_ascending: \"Sort ascending\",\n sort_descending: \"Sort descending\",\n sort_remove: \"Remove sort\",\n sort_move_up: \"Make this key more important\",\n sort_move_down: \"Make this key less important\",\n sort_remove_key: \"Remove this sort key\",\n sort_key_position: \"Sort key {{position}}\",\n sort_shift_click_hint: \"Shift-click to add a column under the current sort\",\n save_entity_before_subcollections: \"Save this record before adding related records.\",\n clear_all: \"Clear all\",\n no_items: \"No items\",\n no_entries_found: \"No entries found\",\n all_entries_loaded: \"All {{count}} entries loaded\",\n error_loading_data_message: \"Error loading data: {{message}}\",\n clear_search: \"Clear search\",\n open_time_picker: \"Open time picker\",\n relative_just_now: \"just now\",\n relative_in_a_moment: \"in a moment\",\n relative_minutes_ago: \"{{count}}m ago\",\n relative_in_minutes: \"in {{count}}m\",\n relative_hours_ago: \"{{count}}h ago\",\n relative_in_hours: \"in {{count}}h\",\n relative_days_ago: \"{{count}}d ago\",\n relative_in_days: \"in {{count}}d\",\n create_your_first_entry: \"Create your first entry\",\n no_results_filter_sort: \"No results with the applied filter/sort\",\n no_results_filter: \"No results with the applied filters\",\n no_results_search: \"No results found for \\\"{{search}}\\\"\",\n add: \"Add\",\n remove: \"Remove\",\n multiple_entities: \"Multiple entities\",\n unsaved_changes: \"You have unsaved changes in this {{collectionName}}.\",\n so_empty: \"So empty...\",\n no_results: \"No results with the applied filter/sort\",\n refresh_data: \"Refresh data\",\n dark_mode: \"Dark\",\n light_mode: \"Light\",\n system_mode: \"System\",\n join_newsletter: \"Join the newsletter, no spam\",\n ok: \"Ok\",\n save_collection_config: \"Save collection structure\",\n search_for_more_icons: \"Search for more icons…\",\n ai_modified: \"AI modified\",\n size_label: \"Size\",\n group_by: \"Group by\",\n initialize_kanban_order: \"Initialize Kanban Order\",\n copy_id: \"Copy ID\",\n add_specific: \"Add {{name}}\",\n add_named: \"Add \\\"{{name}}\\\"\",\n select_specific: \"Select {{name}}\",\n select_from: \"Select from {{name}}\",\n done: \"Done\",\n log_out: \"Log out\",\n column_cannot_be_edited: \"This column can't be edited directly\",\n close: \"Close\",\n hide_list: \"Hide list\",\n show_list: \"Show list\",\n unsaved_local_changes: \"Unsaved Local changes\",\n unsaved_local_changes_description: \"This document was edited locally and has unsaved changes. These local changes will be lost if you don't apply them.\",\n preview_changes: \"Preview Changes\",\n apply_changes: \"Apply Changes\",\n discard_local_changes: \"Discard Local Changes\",\n preview_local_changes: \"Preview Local Changes\",\n preview_local_changes_description: \"These are the local changes that will be applied to the form.\",\n type: \"Type\",\n string: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n date: \"date\",\n map: \"map\",\n array: \"array\",\n arrays_of_arrays_not_supported: \"Arrays of arrays are not supported.\",\n data_type_not_supported: \"Data type {{dataType}} not supported yet\",\n passkey_error_unsupported: \"Your device or browser doesn't support passkeys.\",\n\n // ─── Entity form feedback ─────────────────────────────────────\n saved_correctly: \"Saved successfully\",\n error_before_saving: \"Error preparing data\",\n error_after_saving: \"Error in post-save hook\",\n error_saving_entity: \"Error saving entity\",\n error_record_changed_elsewhere: \"This record changed since you opened it. Your edits are kept: review the fields marked as updated elsewhere, then save again.\",\n entity_does_not_exist: \"This entity does not exist in the database\",\n form_modified: \"This form has been modified\",\n form_in_sync: \"The current form is in sync with the database\",\n fix_errors_before_saving: \"Fix highlighted errors before saving\",\n form_predating_rule_violations: \"Some fields you did not change do not meet their current rules. They do not block saving:\",\n\n admin: \"Admin\",\n home: \"Home\",\n this_form_has_errors: \"This form has errors\",\n error_loading_navigation: \"Error loading navigation\",\n error_loading_auth: \"Error loading auth\",\n this_form_has_been_modified: \"This form has been modified\",\n current_form_in_sync: \"The current form is in sync with the database\",\n open_in_console: \"Open in the console\",\n collection_does_not_exist: \"The specified collection does not exist. Check console\",\n unexpected_value: \"Unexpected value\",\n unexpected_value_click_to_edit: \"Unexpected value. Click to edit\",\n unexpected_reference_value: \"Unexpected reference value. Click to edit\",\n copy_url_to_clipboard: \"Copy url to clipboard\",\n open_image_in_new_tab: \"Open image in new tab\",\n reference_not_set: \"Reference not set\",\n reference_does_not_exist: \"Reference does not exist\",\n entity_not_found: \"Entity not found\",\n entity_not_found_body: \"This record does not exist, or it may be hidden from you by row-level security.\",\n collection_not_found: \"Collection not found\",\n collection_not_found_body: \"Nothing is registered for \\\"{{path}}\\\".\",\n collection_not_found_hint: \"The URL names a collection the panel does not know about. It may have been renamed or removed from the collections array, or the slug may not match the path.\",\n back_to_collection: \"Back to {{name}}\",\n file_not_found: \"File not found\",\n unsaved_changes_in_entity: \"You have unsaved changes in this entity.\",\n delete_this_role: \"Delete this role\",\n no_roles_yet: \"You don't have any roles yet.\",\n create_default_roles: \"Create default roles\",\n delete_role_confirmation: \"Are you sure you want to delete this role?\",\n delete_this_user: \"Delete this user\",\n no_users_yet: \"There are no users yet\",\n add_logged_user_as_admin: \"Add the logged user as an admin\",\n add_current_user_as_admin: \"Add current user as admin\",\n create_default_roles_and_add_admin: \"Create default roles and add current user as admin\",\n delete_user_confirmation: \"Are you sure you want to delete this user?\",\n create_your_users_and_roles: \"Create your users and roles\",\n no_users_or_roles_defined: \"You have no users or roles defined. You can create default roles and add the current user as admin.\",\n save_before_changing_schema: \"You need to save the document before changing the schema\",\n edit_schema_for_this_form: \"Edit schema for this form\",\n no_permissions_to_edit_collection: \"You don't have permissions to edit this collection\",\n browser_does_not_support_audio: \"Your browser does not support the audio element.\",\n user_not_found: \"User not found: {{value}}\",\n\n // ─── Collection view actions ──────────────────────────────────\n delete_selected: \"Delete\",\n cannot_delete_selected: \"You have selected at least one entity you cannot delete\",\n\n // ─── Array / field containers ─────────────────────────────────\n add_entry: \"Add\",\n add_on_top: \"Add on top\",\n add_below: \"Add below\",\n add_to_field: \"Add to {{fieldName}}\",\n value: \"Value\",\n key: \"Key\",\n drag_drop_multiple: \"Drag 'n' drop some files here, or click to select files. Drag to reorder.\",\n drag_drop_single: \"Drag 'n' drop a file here, or click to select one\",\n\n // ─── Navigation / scaffold ────────────────────────────────────\n open_menu: \"Open menu\",\n close_drawer: \"Close drawer\",\n navigation_drawer: \"Navigation drawer\",\n collapse: \"Collapse\",\n expand: \"Expand\",\n change_language: \"Change language\",\n toggle_theme: \"Toggle theme\",\n user_menu: \"User menu\",\n resize_sidebar: \"Resize the sidebar\",\n resize_editor: \"Resize the editor\",\n resize_list: \"Resize the list\",\n panel_mode: \"Panel mode\",\n\n // ─── Error states ─────────────────────────────────────────────\n error: \"Error\",\n error_loading_data: \"Could not load data\",\n error_check_server_logs: \"Check server logs for details.\",\n error_technical_details: \"Technical details\",\n error_uploading_file: \"Error uploading file\",\n error_deleting: \"Error deleting\",\n error_before_delete: \"Error before delete\",\n error_updating_asset: \"Error updating asset\",\n error_deleting_asset: \"Error deleting asset\",\n error_firestore_index: \"A Firestore index is required for this query.\",\n realtime_connection_lost_title: \"Live updates paused\",\n realtime_connection_lost_body: \"The connection to the server was lost, so what you see may be out of date. It refreshes as soon as the connection is back.\",\n rls_simulate_access: \"Simulate access\",\n rls_simulate_access_description: \"See every collection as a role, a user or a service key would: rows and fields their row-level security hides are left out.\",\n rls_simulate_tab_role: \"Role\",\n rls_simulate_tab_user: \"User\",\n rls_simulate_tab_api_key: \"API key\",\n rls_simulate_user_id_optional: \"As user id (optional)\",\n rls_simulate_apply: \"Simulate\",\n rls_simulate_stop: \"Stop simulating\",\n rls_simulate_search_users: \"Search users\",\n rls_simulate_no_users: \"No user matches this search.\",\n rls_simulate_no_api_keys: \"No active service keys.\",\n rls_simulate_options_error: \"Could not load what can be simulated: {{message}}\",\n rls_simulate_users_error: \"Could not load users: {{message}}\",\n rls_simulation_viewing_as_role: \"Viewing as role {{role}}\",\n rls_simulation_viewing_as_role_user: \"Viewing as {{user}} with role {{role}}\",\n rls_simulation_viewing_as_user: \"Viewing as user {{user}}\",\n rls_simulation_viewing_as_api_key: \"Viewing as API key {{name}} ({{prefix}}…)\",\n rls_simulation_hidden_collections: \"{{count}} collections hidden\",\n rls_simulation_hidden_collections_one: \"1 collection hidden\",\n rls_simulation_masked_columns: \"{{count}} columns masked by RLS\",\n rls_simulation_masked_columns_one: \"1 column masked by RLS\",\n rls_simulation_counting: \"Counting what this identity can read…\",\n rls_simulation_count_failed: \"Could not count what this identity can read: {{message}}\",\n rls_simulation_note: \"Data views show only the rows and fields this identity can read. Editing is off while simulating: stop simulating to make changes. Live updates are paused.\",\n create_index: \"Create Index\",\n value_is_not_reference: \"Value is not a reference.\",\n click_to_edit: \"Click to edit\",\n data_is_not_array_of_references: \"Data is not an array of references\",\n\n // ─── Misc ─────────────────────────────────────────────────────\n loading: \"Loading\",\n local_changes_applied: \"Local changes applied to the form\",\n local_changes_discarded: \"Local changes discarded\",\n are_you_sure_leave: \"Are you sure you want to leave this page?\",\n see_console_details: \"See console for more details.\",\n drop_here_create_group: \"Drop here to create a new group\",\n filter_for_null_values: \"Filter for null values\",\n value_updated_elsewhere: \"This value has been updated elsewhere\",\n entity_deleted_elsewhere: \"This record was deleted elsewhere. What you see here has not been saved; save it as a new record to keep it.\",\n save_as_new: \"Save as new\",\n add_property: \"Add property\",\n edit_name: \"Edit {{name}}\",\n this_entity_not_exist: \"This entity does not exist in the database\",\n internal_error: \"Internal ERROR\",\n\n // ─── Rename group dialog ──────────────────────────────────────\n rename_group: \"Rename Group\",\n group_name_label: \"Group Name\",\n group_name_empty_error: \"Group name cannot be empty.\",\n group_name_exists_error: \"This group name already exists.\",\n\n // ─── Search ───────────────────────────────────────────────────\n search_collections: \"Search collections\",\n\n // ─── Navigation groups ────────────────────────────────────────\n views_group: \"Views\",\n\n // ─── Entity Edit View ─────────────────────────────────────────\n youd_need_to_save_before_additional_collections: \"Save this record before adding related records.\",\n\n // ─── Not Found Page ───────────────────────────────────────────\n page_not_found: \"Page not found\",\n page_not_found_body: \"This page does not exist or you may not have access to it\",\n back_to_home: \"Back to home\",\n\n // ─── Collection Editor ─────────────────────────────────────────\n default_collection_view: \"Default collection view\",\n table_view: \"Table\",\n cards_view: \"Cards\",\n kanban_view: \"Kanban\",\n choose_how_entities_displayed_default: \"Choose how entities should be displayed by default\",\n\n document_view: \"Document view\",\n side_panel: \"Side panel\",\n full_screen: \"Full screen\",\n should_documents_opened_full_screen: \"Should documents be opened full screen or in an inline side dialog\",\n\n select_custom_view: \"Select custom view\",\n no_custom_views_defined: \"No custom views defined. Define your custom views in the customization settings, before using this dialog.\",\n\n select_custom_action: \"Select custom action\",\n no_custom_actions_defined: \"No custom actions defined. Define your custom actions in the customization settings, before using this dialog.\",\n\n no_collections_found: \"No collections found\",\n start_building_collections: \"Start building collections in Rebase easily. Map them to your existing database data, import from files, or use our templates.\",\n create_first_collection: \"Create your first collection\",\n define_collections_programmatically: \"You can also define collections programmatically.\",\n edit_collection: \"Edit collection\",\n no_permissions_edit_collection: \"You don't have permissions to edit this collection\",\n no_permissions_create_collection: \"You don't have permissions to create collections\",\n create_collection: \"Create collection\",\n update_collection: \"Update collection\",\n\n new_collection: \"New collection\",\n add_new_collection: \"Add new collection\",\n collection_with_name: \"{{name}} collection\",\n change_icon: \"Change icon\",\n is_subcollection_of: \"This is a subcollection of\",\n name: \"Name\",\n collection_name_description: \"Name of this collection, usually a plural name (e.g. Products)\",\n path: \"Path\",\n relative_path_to_parent: \"Relative path to the parent (no need to include the parent path)\",\n path_in_database: \"Path or table name where this collection is stored in the database\",\n singular_name: \"Singular name\",\n singular_name_description: \"Optionally define a singular name for your entities\",\n description: \"Description\",\n description_of_collection: \"Description of the collection, you can use markdown\",\n collection_id: \"Collection ID\",\n collection_id_description: \"This ID identifies this collection. Typically the same as the path or table name.\",\n collection_group: \"Collection group\",\n collection_group_description: \"A collection group consists of all collections with the same path. This allows you to query over multiple collections at once.\",\n advanced_settings: \"Advanced settings\",\n doc_history_global: \"Document history revisions enabled if enabled globally\",\n doc_history_enabled: \"Document history revisions ENABLED\",\n doc_history_not_enabled: \"Document history revisions NOT enabled\",\n doc_history_description: \"When enabled, each document in this collection will have a history of changes. This is useful for auditing purposes. The data is stored in a subcollection of the document in your database, called __history.\",\n document_id_generation: \"Document IDs generation\",\n code_defined: \"Code defined\",\n users_must_define_id: \"Users must define an ID\",\n users_can_define_id: \"Users can define an ID, but it is not required\",\n doc_id_auto_generated: \"Document ID is generated automatically\",\n config_doc_id_generation: \"Configure how document IDs are generated when creating new entities.\",\n enable_text_search: \"Enable text search for this collection\",\n text_search_description: \"Allow text search for this collection. If you have not specified a text search delegate, this will use the built-in local text search. This is not recommended for large collections, as it may incur in performance and cost issues.\",\n database_id: \"Database ID\",\n default_text: \"(default)\",\n\n custom_actions: \"Custom actions\",\n more_info: \"More info\",\n define_custom_actions_cli: \"Define your own custom actions by uploading them with the CLI.\",\n action_defined_in_code: \"This action is defined in code with key\",\n add_custom_entity_action: \"Add custom entity action\",\n remove_this_action: \"Remove this action?\",\n remove_action_warning: \"This will not delete any data, only the action in the admin panel\",\n\n subcollections_of: \"Subcollections of\",\n add_subcollection: \"Add subcollection\",\n custom_views: \"Custom views\",\n define_custom_views_cli: \"Define your own custom views by uploading them with the CLI.\",\n view_defined_in_code: \"This view is defined in code with key\",\n add_custom_entity_view: \"Add custom entity view\",\n delete_this_subcollection: \"Delete this subcollection?\",\n remove_collection_warning: \"This will not delete any data, only the collection in the admin panel\",\n remove_this_view: \"Remove this view?\",\n remove_view_warning: \"This will not delete any data, only the view in the admin panel\",\n\n no_collection_selected: \"No collection selected\",\n code_for_collection: \"Code for\",\n use_config_define_json: \"Use this config to define the collection in JSON format.\",\n customise_collection_code: \"If you want to customise the collection in code, you can add this collection code to your admin app configuration.\",\n copied: \"Copied\",\n\n property_cant_be_edited: \"This property can't be edited\",\n property_not_editable_description: \"You may not have permission to edit it or it is defined in code and cannot be modified.\",\n delete_this_property: \"Delete this property?\",\n delete_property_warning: \"This will not delete any data, only modify the collection.\",\n error_must_specify_id: \"You must specify an id for the field\",\n error_id_format: \"The id can only contain letters, numbers and underscores (_), and not start with a number\",\n error_id_already_exists: \"There is another field with this ID already\",\n error_must_specify_title: \"You must specify a title for the field\",\n custom_or_other: \"Custom/Other\",\n select_property_widget: \"Select a property widget\",\n error_changing_data_type: \"This widget uses a different data type than the initially selected widget. This can cause errors with existing data.\",\n required: \"Required\",\n\n enum_form_dialog: \"Enum form dialog\",\n imported_data_preview: \"Imported data preview\",\n entities_with_same_id_overwritten: \"Entities with the same id will be overwritten\",\n collection_editor: \"Collection editor\",\n properties_in_this_group: \"Properties in this group\",\n data_property_mapping: \"Data property mapping\",\n property_edit_view: \"Property edit view\",\n all_of_these: \"All of these\",\n any_of_these: \"Any of these\",\n\n only_admins_edit_roles: \"Only admins can edit roles\",\n error_user_not_found: \"User not found\",\n all_roles: \"All Roles\",\n role: \"Role\",\n name_of_this_role: \"Name of this role\",\n id_of_this_role: \"ID of this role\",\n create_entities: \"Create entities\",\n read_entities: \"Read entities\",\n update_entities: \"Update entities\",\n delete_entities: \"Delete entities\",\n all_collections: \"All collections\",\n create_entities_in_collections: \"Create entities in collections\",\n access_all_data_in_every_collection: \"Access all data in every collection\",\n update_data_in_any_collection: \"Update data in any collection\",\n delete_data_in_any_collection: \"Delete data in any collection\",\n allow_all_permissions_in_this_collections: \"Allow all permissions in this collections\",\n all: \"All\",\n customise_permissions_description: \"You can customise the permissions that the users related to this role can perform in the entities of each collection\",\n create_collections: \"Create collections\",\n yes: \"Yes\",\n no: \"No\",\n can_user_create_collections: \"Can the user create collections\",\n edit_collections: \"Edit collections\",\n only_own_collections: \"Only his/her own\",\n own: \"Own\",\n can_user_edit_collections: \"Can the user edit collections\",\n delete_collections: \"Delete collections\",\n can_user_delete_collections: \"Can the user delete collections\",\n error_saving_role: \"There was an error saving this role\",\n create_role: \"Create role\",\n update: \"Update\",\n\n only_admins_change_roles: \"Only admins can change roles\",\n must_be_at_least_one_admin: \"There must be at least one admin\",\n logged_user_not_found: \"Logged user not found\",\n user: \"User\",\n user_id: \"User ID\",\n name_of_this_user: \"Name of this user\",\n email_of_this_user: \"Email of this user\",\n roles: \"Roles\",\n create_user: \"Create user\",\n\n users: \"Users\",\n add_user: \"Add user\",\n add_role: \"Add role\",\n is_admin: \"Is Admin\",\n default_permissions: \"Default permissions\",\n created_on: \"Created on\",\n email: \"Email\",\n id: \"ID\",\n read: \"Read\",\n\n column_in_file: \"Column in file\",\n map_to_property: \"Map to Property\",\n default_values: \"Default values\",\n default_values_description: \"You can select a default value for unmapped columns and empty values:\",\n property: \"Property\",\n default_value: \"Default value\",\n autogenerate_id: \"Autogenerate ID\",\n id_column_description: \"Column that will be used as ID for each document\",\n do_not_set_value: \"Do not set value\",\n set_value_to_true: \"Set value to true\",\n set_value_to_false: \"Set value to false\",\n drag_and_drop_file: \"Drag and drop a file here or click to upload\",\n error_saving_data: \"Error saving data\",\n retry: \"Retry\",\n saving_data: \"Saving data\",\n entities_saved: \"entities saved\",\n do_not_close_tab: \"Do not close this tab or the import will be interrupted\",\n import: \"Import\",\n import_data: \"Import data\",\n upload_file_description: \"Upload a CSV, Excel or JSON file and map it to your existing schema\",\n back: \"Back\",\n next: \"Next\",\n save_data: \"Save data\",\n use_column_as_id: \"Use this column as ID\",\n do_not_import_property: \"Do not import this property\",\n import_problems_title: \"Values that cannot be imported: {{count}}\",\n import_problems_description: \"These cells do not convert to the type of the field they map to, so they will be left empty. Go back to map the column to a text field, or correct the file and upload it again.\",\n import_problems_column: \"{{column}} → {{property}} ({{type}}): {{count}} not imported\",\n import_problems_example: \"Row {{row}}: “{{value}}”, {{reason}}\",\n import_problems_more: \"…and {{count}} more\",\n import_problem_not_a_number: \"not a number\",\n import_problem_number_leading_zero: \"a number would drop its leading zero\",\n import_problem_number_too_precise: \"more digits than a number holds exactly\",\n import_problem_not_a_boolean: \"not yes or no\",\n import_problem_not_a_date: \"not a date\",\n import_problem_ambiguous_date: \"could be day/month or month/day\",\n import_problem_not_a_vector: \"not a list of numbers\",\n import_problem_not_a_map: \"not a map (expected the JSON of an object)\",\n import_problem_not_a_geopoint: \"not a geopoint (expected {\\\"latitude\\\": …, \\\"longitude\\\": …})\",\n entities_will_be_overwritten: \"Entities with the same id will be overwritten\",\n data_imported_successfully: \"Data imported successfully\",\n export: \"Export\",\n export_data: \"Export data\",\n download_table_csv: \"Download the content of this table as a CSV\",\n csv: \"CSV\",\n json: \"JSON\",\n dates_as_timestamps: \"Dates as timestamps\",\n dates_as_strings: \"Dates as strings\",\n flatten_arrays: \"Flatten arrays\",\n download: \"Download\",\n large_number_of_documents: \"This collection has a large number of documents ({{count}}).\",\n too_many_documents_to_export: \"This collection has more documents ({{count}}) than the browser can export in a single file (limit {{limit}}). Filter it down before exporting.\",\n include_undefined_values: \"Include undefined values\",\n submit: \"Submit\",\n\n no_filterable_properties: \"No filterable properties available\",\n apply_filters: \"Apply filters\",\n\n // ─── Filter Presets ──────────────────────────────────────────\n filter_presets: \"Presets\",\n filter_preset_apply: \"Apply preset\",\n filter_preset_active: \"Active: {{label}}\",\n\n list: \"List\",\n table_view_mode: \"Table\",\n cards: \"Cards\",\n board: \"Board\",\n initialize_kanban_order_desc: \"This will assign sequential order values to all items that don't have one. Items will maintain their current order within each column.\",\n kanban_view_not_available: \"Kanban view is not available\",\n kanban_view_requires_enum: \"Kanban view requires a string property with enum values to group entities into columns. Please add an enum property to your collection schema to use this view.\",\n no_enum_values_configured: 'No enum values configured for property \"{{property}}\"',\n items_need_backfill: \"Some items don't have order values. Initialize to enable drag-and-drop reordering.\",\n kanban_order_not_configured: \"Drag-and-drop ordering is not configured. Set an order property in the collection settings to persist card positions.\",\n initialize: \"Initialize\",\n confirm_multiple_delete: \"Confirm multiple delete?\",\n delete_entity_confirm_title: \"Would you like to delete this {{entityName}}?\",\n add_existing: \"Add existing\",\n unlink_entity_confirm_title: \"Remove this {{entityName}} from this record?\",\n unlink_entity_confirm_body: \"It stays in {{collectionName}} and remains available to other records.\",\n confirm_multiple_unlink: \"remove these from this record?\",\n remove_from_record: \"Remove from this record\",\n removed_from_record: \"Removed from this record\",\n no_filter: \"No filter\",\n is_true: \"is true\",\n is_false: \"is false\",\n error_uploading_file_size: \"Error uploading file: File is larger than {{maxSize}} bytes\",\n error_uploading_file_type: \"Error uploading file: File type is not supported\",\n drag_drop_files: \"Drag 'n' drop some files here, or click here to edit\",\n drag_drop_file: \"Drag 'n' drop a file here, or click here to edit\",\n multiple_deleted: \"Multiple deleted\",\n some_entities_deleted: \"Some of the entities have been deleted, but not all\",\n error_deleting_entities: \"Error deleting entities\",\n delete_rows_failed: \"{{failed}} of {{total}} not deleted. {{reason}}\",\n deleted: \"Deleted\",\n selection_options: \"Selection options\",\n selection_menu_all_loaded: \"All on this page\",\n selection_menu_all_matching: \"All {{total}} {{collection}}\",\n selection_menu_none: \"None\",\n selection_select_all_loaded: \"Select all loaded rows\",\n selection_deselect_all: \"Deselect all\",\n selection_reading_rows: \"Reading rows… {{loaded}} of {{total}}\",\n selection_reading_rows_unknown: \"Reading rows… {{loaded}} so far\",\n selection_deleting_progress: \"Deleted {{completed}} of {{total}}\",\n confirm_delete_selection: \"Delete {{total}} {{collection}}?\",\n confirm_delete_selection_unknown: \"Delete every row matching the current filter?\",\n confirm_delete_selection_body: \"This cannot be undone. Each row is deleted individually, so this may take a while.\",\n\n export_selection_count: \"Download the {{total}} selected rows as a {{format}}\",\n export_selection_all_matching: \"Download every {{collection}} matching the current filter\",\n\n select_reference: \"Select reference\",\n select_references: \"Select references\",\n account_settings: \"Account Settings\",\n profile: \"Profile\",\n security: \"Security\",\n sessions: \"Sessions\",\n change_password: \"Change Password\",\n current_password: \"Current Password\",\n new_password: \"New Password\",\n confirm_password: \"Confirm New Password\",\n password_changed: \"Password changed. Your other devices were signed out.\",\n passwords_dont_match: \"Passwords don't match\",\n password_too_short: \"Password must be at least 8 characters\",\n password_change_not_available: \"Password change is not available for accounts using external sign-in providers.\",\n changing_password: \"Changing...\",\n display_name: \"Display Name\",\n photo_url: \"Photo URL\",\n save_profile: \"Save Profile\",\n saving: \"Saving...\",\n no_active_sessions: \"No active sessions found.\",\n revoking: \"Revoking...\",\n revoke_all_sessions: \"Revoke All Sessions\",\n unknown_device: \"Unknown Device\",\n unknown_address: \"Unknown\",\n session_details: \"IP: {{ip}} • Created: {{created}}\",\n revoke_session: \"Revoke session\",\n current: \"Current\",\n role_id: \"Role ID\",\n role_name: \"Role Name\",\n add_reference: \"Add reference\",\n add_reference_to: \"Add reference to {{name}}\",\n\n /** RolesView — table & permissions */\n role_deleted_successfully: \"Role deleted successfully\",\n error_deleting_role: \"Error deleting role\",\n collection_permissions: \"Collection permissions\",\n collection: \"Collection\",\n no_collections_configured: \"No collections configured\",\n no_security_rules_defined: \"No security rules defined — all operations unrestricted\",\n no_rules: \"no rules\",\n\n /** UsersView — snackbar */\n bootstrap_admin_success: \"You are now an admin! Refreshing...\",\n failed_to_bootstrap_admin: \"Failed to bootstrap admin\",\n user_deleted_successfully: \"User deleted successfully\",\n error_deleting_user: \"Error deleting user\",\n user_created_successfully: \"User created successfully\",\n invitation_sent: \"An invitation email has been sent to {{email}}. They can use the link to set their password.\",\n invitation_sent_title: \"Invitation Sent\",\n temporary_password: \"Temporary Password\",\n temporary_password_description: \"Email is not configured. Share this temporary password with the user securely. It will not be shown again.\",\n temporary_password_email_failed_description: \"The email could not be delivered. Share this temporary password with the user securely. It will not be shown again.\",\n copy_password: \"Copy password\",\n password_copied: \"Password copied to clipboard\",\n\n /** UsersView — pagination & search */\n search_users: \"Search users\",\n created: \"Created\",\n actions: \"Actions\",\n no_users_found: \"No users found\",\n reset_password: \"Reset Password\",\n reset_password_success: \"Password reset successfully\",\n reset_password_confirmation: \"Are you sure you want to reset this user's password?\",\n reset_password_send_email: \"Send a password reset email\",\n reset_password_set_manually: \"Set a password manually\",\n reset_password_set_manually_description: \"The password is updated immediately and no email is sent. Share it with the user securely.\",\n\n /** Permission-denied empty states */\n no_permission_to_view_users: \"You don't have permission to view users\",\n no_permission_to_view_roles: \"You don't have permission to view roles\",\n no_permission_description: \"Contact an administrator if you need access to this section.\",\n error_resetting_password: \"Error resetting password\",\n\n /** Editor table-bubble */\n add_row_before: \"Add row before\",\n add_row_after: \"Add row after\",\n delete_row: \"Delete row\",\n add_column_before: \"Add column before\",\n add_column_after: \"Add column after\",\n delete_column: \"Delete column\",\n delete_table: \"Delete table\",\n\n /** Editor image-bubble */\n alt_text: \"Alt text\",\n title: \"Title\",\n\n /** MapFieldBinding */\n a_property_of_this_map_has_error: \"A property of this map has an error\",\n\n /** AI Collection Generator Popover */\n generate_collection_with_ai: \"Generate Collection with AI\",\n modify_collection_with_ai: \"Modify Collection with AI\",\n describe_collection_to_create: \"Describe the collection you want to create.\",\n describe_changes_to_make: \"Describe the changes you want to make to this collection.\",\n ai_placeholder_create: \"e.g., Create a products collection with name, price, description, and category...\",\n ai_placeholder_modify: \"e.g., Add a thumbnail image field with storage, make price required...\",\n ai_assist: \"AI Assist\",\n generating: \"Generating...\",\n\n /** Recently extracted strings for collection editor */\n this_is_subcollection_of: \"This is a subcollection of\",\n use_existing_paths_database: \"Use one of the existing paths in your database:\",\n describe_collection_ai: \"Describe your collection to AI:\",\n generate_with_ai: \"Generate with AI\",\n create_from_json_config: \"Create from JSON configuration:\",\n paste_json_config: \"Paste JSON Configuration\",\n create_collection_from_file_formats: \"Create a collection from a file (csv, json, xls, xslx...)\",\n select_template: \"Select a template:\",\n products: \"Products\",\n collection_products_subtitle: \"A collection of products with images, prices and stock\",\n collection_users_subtitle: \"A collection of users with emails, names and roles\",\n blog_posts: \"Blog posts\",\n collection_blog_posts_subtitle: \"A collection of blog posts with images, authors and complex content\",\n pages: \"Pages\",\n collection_pages_subtitle: \"A collection of pages with images, authors and complex content\",\n continue_from_scratch: \"Continue from scratch\",\n\n /** Admin views config */\n admin_users: \"Admin Users\",\n roles_menu: \"Roles\",\n project_settings: \"Project settings\",\n\n by_signing_in_you_agree_to_our: \"By signing in you agree to our\",\n terms_and_conditions: \"Terms and Conditions\",\n and_our: \"and our\",\n privacy_policy: \"Privacy policy\",\n email_password: \"Email/password\",\n sign_in_with_google: \"Sign in with Google\",\n\n // --- Auth error messages ---\n auth_user_not_found: \"User not found\",\n auth_wrong_password: \"Wrong password. Please try again.\",\n auth_user_disabled: \"User disabled. Please contact support.\",\n auth_account_exists_with_different_credential: \"An account with this email already exists. Sign in the way you did before.\",\n auth_account_exists_sign_in_with_password: \"An account with this email already exists. Sign in with your email and password instead.\",\n auth_email_already_in_use: \"The email is already in use\",\n auth_google_permissions_required: \"You need to grant additional permissions in order to manage your Google Cloud projects\",\n auth_invalid_email_password: \"Please enter both email and password\",\n auth_enter_email_first: \"Please enter your email first\",\n auth_password_reset_sent: \"Password reset email sent\",\n auth_sign_in_account: \"Sign in to your account\",\n auth_create_new_account: \"Create a new account\",\n auth_password: \"Password\",\n auth_reset_password: \"Reset password\",\n auth_new_user: \"New user?\",\n auth_have_account: \"Have an account?\",\n auth_sign_in: \"Sign In\",\n auth_sign_up: \"Sign Up\",\n auth_new_password_title: \"Set a new password\",\n auth_new_password_subtitle: \"Choose the password you will sign in with from now on.\",\n auth_password_requirements: \"Password must be 8+ characters with uppercase, lowercase, and a number\",\n auth_set_password: \"Set password\",\n auth_password_changed_title: \"Password changed\",\n auth_password_changed_body: \"Sign in with your new password.\",\n auth_continue_to_sign_in: \"Continue to sign in\",\n auth_link_invalid_or_expired: \"This link is invalid or has expired. Request a new one from the sign-in screen.\",\n auth_password_reset_unavailable: \"Password reset is not available on this backend.\",\n auth_verifying_email: \"Confirming your email address…\",\n auth_email_verified_title: \"Email confirmed\",\n auth_email_verified_body: \"Your email address is confirmed. You can sign in now.\",\n auth_email_verification_failed_title: \"Email not confirmed\",\n auth_email_verification_unavailable: \"Email verification is not available on this backend.\",\n auth_verify_email_proof_title: \"Confirm it is your account\",\n auth_verify_email_proof_body: \"This account has a password. Enter it to keep it and sign in. If you never set one, someone else may have registered your address: confirm it without the password, and theirs is removed.\",\n auth_verify_email_password_label: \"The password you chose\",\n auth_verify_email_with_password: \"Confirm and sign in\",\n auth_verify_email_without_password: \"I didn't set a password\",\n auth_verify_email_wrong_password: \"That is not this account's password.\",\n auth_email_verified_password_removed_body: \"Your email address is confirmed. A password was set on this account before the address was confirmed, so it was removed. Sign in with a link, or set a new password with \\\"Forgot password\\\".\",\n auth_confirm_email_sent_title: \"Check your inbox\",\n auth_confirm_email_sent_body: \"We sent a link to your email address. Follow it to confirm your address, then sign in.\",\n auth_email_not_confirmed: \"Confirm your email address first. We sent a new link to it.\",\n auth_mfa_title: \"Two-step verification\",\n auth_mfa_subtitle: \"Enter the code from your authenticator app, or one of your recovery codes.\",\n auth_mfa_factor_label: \"Verify with\",\n auth_mfa_factor_totp: \"Authenticator app\",\n auth_mfa_code_label: \"Verification code\",\n auth_mfa_verify: \"Verify\",\n auth_mfa_code_invalid: \"That code is not right. Try the current code from your authenticator app, or a recovery code.\",\n auth_mfa_challenge_exhausted: \"Too many wrong codes. Enter a new code from your authenticator app to try again.\",\n auth_mfa_expired: \"This sign-in has expired. Sign in again to continue.\",\n auth_mfa_sign_in_again: \"Sign in again\",\n email_address: \"Email address\",\n email_change_description: \"We send a link to the new address. Your account moves to it when the link is followed.\",\n email_change_button: \"Change email\",\n email_change_pending: \"We sent a link to {{email}}. Your email address changes when it is followed.\",\n email_change_taken: \"Another account already uses that address.\",\n email_change_undeliverable: \"No mail can reach that address.\",\n email_change_unchanged: \"That is already your email address.\",\n email_change_needs_second_factor: \"Sign in again with your second factor before changing your email address.\",\n auth_confirming_email_change: \"Changing your email address…\",\n auth_email_change_confirmed_title: \"Email address changed\",\n auth_email_change_confirmed_body: \"Your account now uses {{email}}.\",\n auth_email_change_providers_removed: \"Signing in with {{providers}} was removed, because it was linked to your old address.\",\n auth_email_change_failed_title: \"Email address not changed\",\n auth_email_change_continue: \"Continue\",\n auth_email_change_unavailable: \"Changing an email address is not available on this backend.\",\n auth_signing_in_with_link: \"Signing you in…\",\n auth_magic_link_failed_title: \"Sign-in link not accepted\",\n auth_magic_link_unavailable: \"Sign-in links are not available on this backend.\",\n reset_mfa_title: \"Reset two-step verification\",\n reset_mfa_description: \"Removes this user's authenticator apps and recovery codes and signs them out everywhere. They sign in with their password alone and can set up two-step verification again.\",\n reset_mfa_confirm: \"Reset\",\n reset_mfa_success: \"Two-step verification reset\",\n account_access_title: \"Account access\",\n account_access_action: \"Disable or enable account\",\n account_disabled_label: \"Account disabled\",\n account_disabled_description: \"A disabled account cannot sign in, and every session and token it holds stops working at once. Its data stays; switch it back on to restore access.\",\n account_disabled_success: \"Account disabled\",\n account_enabled_success: \"Account enabled\",\n\n\n auto_setup_collections_button: \"Automatically set up collections\",\n auto_setup_collections_title: \"Automatically set up collections?\",\n auto_setup_collections_desc: \"This will automatically create collection configs for collections that are <b>NOT</b> already mapped\",\n this_can_take_a_minute: \"This can take a minute or two\",\n no_collections_found_to_setup: \"No collections found to setup.\",\n collections_have_been_setup: \"Collections have been automatically setup.\",\n error_setting_up_collections: \"Error automatically setting up collections\",\n\n // --- Home Suggestions ---\n\n admin_panel_ready_bring_data: \"Your admin panel is ready. Let's bring in your data.\",\n admin_panel_ready_get_started: \"Your admin panel is ready. Here's how to get started.\",\n auto_detect_collections: \"Auto-detect collections\",\n auto_detect_collections_desc: \"Let AI scan your database and automatically generate collection schemas.\",\n create_a_collection: \"Create a collection\",\n create_collection_desc: \"Manually define your first collection from scratch using the visual editor.\",\n read_the_docs: \"Read the docs\",\n read_the_docs_desc: \"Learn how to customize fields, views, actions and more.\",\n explore_docs: \"Explore docs\",\n want_to_customize_with_code: \"Want to customize with code? Run\",\n to_scaffold_a_local_project: \"to scaffold a local project.\",\n\n // ─── Collection Editor — Validation ──────────────────────────\n validation: \"Validation\",\n unique: \"Unique\",\n required_message: \"Required message\",\n required_tooltip: \"You won't be able to save this entity if this value is not set\",\n unique_tooltip: \"There cannot be multiple entities with the same value\",\n lowercase: \"Lowercase\",\n uppercase: \"Uppercase\",\n trim: \"Trim\",\n exact_length: \"Exact length\",\n min_length: \"Min length\",\n max_length: \"Max length\",\n varchar_narrowing_warning: \"Saving narrows this {{columnType}} column to {{max}} characters. rebase db push asks before it narrows a column, and the change fails while a stored value is longer.\",\n matches_regex: \"Matches regex\",\n not_valid_regexp: \"Not a valid regexp\",\n regex_helper: \"e.g. /^\\\\d+$/ for digits only\",\n min_value: \"Min value\",\n max_value: \"Max value\",\n less_than: \"Less than\",\n more_than: \"More than\",\n positive_value: \"Positive value\",\n negative_value: \"Negative value\",\n integer_value: \"Integer value\",\n\n // ─── Collection Editor — Property Edit ───────────────────────\n invalid_regular_expression: \"Invalid regular expression\",\n must_specify_target_collection: \"You must specify a target collection for the field\",\n need_specify_repeat_field: \"You need to specify a repeat field\",\n need_specify_block_properties: \"You need to specify the properties of this block\",\n incomplete_condition: \"Incomplete condition - please select a field\",\n field_name: \"Field name\",\n\n // ─── Collection Editor — Display & Config ────────────────────\n kanban_column_property: \"Kanban Column Property\",\n select_a_property: \"Select a property\",\n kanban_property_not_found: \"Property \\\"{{property}}\\\" does not exist or is not an enum string property. Please select a valid property or clear the selection.\",\n no_enum_string_properties: \"No enum string properties found. Add a string property with enumValues to use Kanban view.\",\n kanban_column_description: \"Select a string property with enum values to group entities into columns\",\n create_property: \"+ Create \\\"{{property}}\\\" property\",\n order_property: \"Order Property\",\n order_property_not_found: \"Property \\\"{{property}}\\\" does not exist or is not a text property. Please select a valid property or clear the selection.\",\n no_number_properties: \"No text properties found. Add a text property to enable ordering.\",\n order_property_description: \"Select a text property to persist the order of items\",\n display_settings: \"Display settings\",\n default_row_size: \"Default row size\",\n side_dialog_width: \"Side dialog width\",\n side_dialog_width_description: \"Optionally define the width (in pixels) of entities side dialog. Default is 768px\",\n inline_editing_enabled: \"Data can be edited directly in the table view\",\n inline_editing_disabled: \"Data can be edited only in the form view\",\n inline_editing_description: \"Allow editing data directly in the table view, without opening the form view.\",\n include_json_view: \"Include JSON view\",\n no_json_view: \"Do not include JSON view\",\n json_view_description: \"Include the JSON representation of the document.\",\n not_found_suffix: \"not found\",\n\n // ─── Editor ─────────────────────────────────────────────────\n editor_text: \"Text\",\n editor_text_description: \"Just start typing with plain text.\",\n editor_heading_1: \"Heading 1\",\n editor_heading_1_description: \"Big section heading.\",\n editor_heading_2: \"Heading 2\",\n editor_heading_2_description: \"Medium section heading.\",\n editor_heading_3: \"Heading 3\",\n editor_heading_3_description: \"Small section heading.\",\n editor_todo_list: \"To-do List\",\n editor_todo_list_description: \"Track tasks with a to-do list.\",\n editor_bullet_list: \"Bullet List\",\n editor_bullet_list_description: \"Create a simple bulleted list.\",\n editor_numbered_list: \"Numbered List\",\n editor_numbered_list_description: \"Create a list with numbering.\",\n editor_quote: \"Quote\",\n editor_quote_description: \"Capture a quote.\",\n editor_code: \"Code\",\n editor_code_description: \"Capture a code snippet.\",\n editor_image: \"Image\",\n editor_image_description: \"Upload an image from your computer.\",\n editor_multiple: \"Multiple\",\n editor_link: \"Link\",\n editor_save: \"Save\",\n editor_cancel: \"Cancel\",\n editor_remove_link: \"Remove link\",\n editor_paste_or_type_link: \"Paste or type link\",\n editor_invalid_url: \"That is not a link — try a full address like example.com\",\n editor_open_in_new_window: \"Open in new window\",\n editor_bold: \"Bold\",\n editor_italic: \"Italic\",\n editor_underline: \"Underline\",\n editor_strikethrough: \"Strikethrough\",\n editor_autocomplete: \"Autocomplete\",\n editor_autocomplete_description: \"Add text based on the context.\",\n\n // ─── Text Search Dialog ─────────────────────────────────────\n text_search_dialog_title: \"Enable text search\",\n text_search_local_not_recommended: \"Local text search is not recommended for large collections.\",\n text_search_local_fetch_warning: \"Note that enabling local text search will need to fetch all documents from your collection and store them in the browser. This can be inefficient for large collections. It can also incur in additional costs.\",\n text_search_external_suggestion: \"For larger collections, you are encouraged to use an external search engine such as Algolia or Elastic Search, and assign a search delegate to your config.\",\n text_search_local_description: \"Local text search is the simplest way to enable text search in your collection. It loads all documents in the collection in the browser and performs the search locally. This is the recommended option for small collections.\",\n text_search_own_implementation: \"You have implemented your own text search controller. You enable text search for your collection.\",\n text_search_enable_for_collection: \"Enable for this collection\",\n text_search_enable_for_project: \"Enable for project\",\n text_search_enabled_snackbar: \"Local text search enabled\",\n\n settings_heading: \"Settings\",\n settings_project_name: \"Project name\",\n settings_default_language: \"Default language\",\n settings_default_language_caption: \"Select the base language for this project. Users can override this preference in their personal settings.\",\n settings_enable_local_text_search: \"Enable local text search\",\n settings_local_text_search_caption: \"Enable local text search for all collections. This will allow you to search text fields in your collections using the Rebase search bar. Note that this feature can incur in higher read counts, as it will index all text fields in your collections.\",\n settings_doc_history_all_collections: \"Document history enabled for all collections\",\n settings_doc_history_caption: \"When true, all collections will have the history enabled by default. You can override this setting in each collection. History will be saved in the __history subcollection of each document.\",\n settings_theme: \"Theme\",\n settings_primary_color: \"Primary color\",\n settings_secondary_color: \"Secondary color\",\n settings_sample_theme_components: \"Sample theme components\",\n settings_drag_drop_logo: \"Drag and drop your logo here\",\n settings_security_rules: \"Security rules\",\n settings_security_rules_description: \"Rebase uses granular security rules to restrict access to data. When creating a new user through Rebase, custom claims are added to the user. By adding the following security rules to your project, you ensure Rebase users can access data securely.\",\n settings_security_rules_add_domain: \"Remember to add the domain {{domain}} to your provider allowed domains\",\n settings_security_rules_caption: \"These rules restrict access to data to Rebase users only, but do not enforce the permissions at the database level. The permissions are enforced in the frontend though, which will work fine for most projects. If you need to enforce the permissions at the database level, you can modify these security rules yourself to suit your needs. The roles assigned to a user are set as custom claims in the auth token, so you can use them in your security rules.\",\n\n // ─── Studio: SQL Editor ─────────────────────────────────────\n studio_sql_executing_query: \"EXECUTING QUERY...\",\n studio_sql_query_error: \"Query Error\",\n studio_sql_run_query_placeholder: \"Run a query to see results\",\n studio_sql_visual_execution_plan: \"Visual Execution Plan\",\n studio_sql_success: \"SUCCESS\",\n studio_sql_no_results: \"Query executed successfully but returned no results.\",\n studio_sql_rows: \"Rows:\",\n studio_sql_time: \"Time:\",\n studio_sql_copy_markdown: \"Copy Markdown\",\n studio_sql_export_json: \"Export JSON\",\n studio_sql_export_json_typed: \"Export typed JSON\",\n studio_sql_export_csv: \"Export CSV\",\n studio_sql_format_sql: \"Format SQL\",\n studio_sql_explain: \"Explain\",\n studio_sql_limit_1000: \"Limit 1000\",\n studio_sql_remove_from_favorites: \"Remove from Favorites\",\n studio_sql_add_to_favorites: \"Add to Favorites\",\n studio_sql_save: \"Save\",\n studio_sql_run: \"Run\",\n studio_sql_cancel_run: \"Cancel run\",\n studio_sql_run_cancelled: \"Run cancelled.\",\n studio_sql_database: \"Database\",\n studio_sql_role: \"Role\",\n studio_sql_admin: \"(Admin)\",\n studio_sql_select_db: \"Select DB\",\n studio_sql_query_results: \"Query Results\",\n studio_sql_save_snippet: \"Save SQL Snippet\",\n studio_sql_snippet_name: \"Snippet Name\",\n studio_sql_snippet_name_placeholder: \"e.g., Get All Users\",\n studio_sql_snippet_saved_local: \"This will be saved to your local storage.\",\n studio_sql_cancel: \"Cancel\",\n studio_sql_dangerous_operation: \"Dangerous Operation Detected\",\n studio_sql_dangerous_operation_body: \"The query you are about to run contains potentially destructive operations (DELETE, DROP, TRUNCATE, or UPDATE without WHERE). Are you sure you want to proceed?\",\n studio_sql_snippet_saved: \"Snippet \\\"{{name}}\\\" saved.\",\n studio_sql_markdown_copied: \"Results copied as Markdown!\",\n studio_sql_markdown_copy_failed: \"Failed to copy Markdown to clipboard.\",\n studio_sql_row_updated: \"Row updated successfully.\",\n studio_sql_cannot_edit_missing_query: \"Cannot edit rows: The underlying query is missing.\",\n studio_sql_edit_unreadable_query: \"The console could not read this query, so it cannot tell which row a cell came from. Cells of this result cannot be edited.\",\n studio_sql_edit_not_a_select: \"Only the rows of a single SELECT can be edited here.\",\n studio_sql_edit_duplicate_column: \"The result has more than one column named \\\"{{column}}\\\". Give each one its own alias to edit it.\",\n studio_sql_edit_computed_column: \"\\\"{{column}}\\\" is not read from a table column (it is computed, a literal or an aggregate), so there is nothing to write it back to.\",\n studio_sql_edit_not_a_table: \"\\\"{{column}}\\\" comes from {{table}}, which is not a table. Only rows of a table can be edited here.\",\n studio_sql_edit_inherited_table: \"Other tables inherit {{table}}, so its primary key can match a row in each of them. Edit the row in the table that holds it.\",\n studio_sql_edit_no_primary_key: \"{{table}} has no primary key, so a row of it cannot be found again to update it.\",\n studio_sql_edit_key_missing: \"To edit columns of {{table}}, select its primary key ({{columns}}) under a name no other column of the result has.\",\n studio_sql_edit_table_read_twice: \"The query reads {{table}} more than once, so a row's key and this cell may come from different rows of it.\",\n studio_sql_missing_pk: \"Row is missing primary key column(s): {{columns}}. Cannot safely update.\",\n studio_sql_cannot_edit_other_connection: \"These rows were read from another database or as another role. Run the query again to edit them.\",\n studio_sql_update_failed: \"Failed to update: {{message}}\",\n studio_sql_update_no_row: \"No row was updated: the row has changed or been deleted since it was read, or the selected role may not update it. Run the query again to see what is stored.\",\n studio_sql_ran_as_other_role: \"These rows were read as {{ranAs}}, not as {{role}}: role switching is turned off on this server (DISABLE_DB_ROLE_SWITCHING), so every statement runs as the connection owner.\",\n studio_sql_result_truncated: \"Showing the first {{shown}} of {{total}} rows: the console keeps at most 10,000 rows, or 32 MB of values, of one result. Narrow the query, or page through it with LIMIT and OFFSET, to see the rest. Copy and export include only the rows shown.\",\n studio_sql_download_full_csv: \"Download full result as CSV\",\n studio_sql_downloading_full_csv: \"Downloading…\",\n studio_sql_download_full_failed: \"Could not download the full result: {{message}}\",\n studio_sql_role_switching_disabled: \"Role switching is turned off on this server: every statement runs as {{role}}, whichever role is picked here.\",\n studio_sql_execution_not_supported: \"SQL execution is not supported by the current data source.\",\n studio_sql_error_executing: \"An error occurred while executing the query.\",\n studio_sql_error_explaining: \"An error occurred while explaining the query.\",\n studio_sql_explain_single_statement: \"Explain works on one statement at a time. Select the statement to explain and try again.\",\n studio_sql_save_first_to_favorite: \"Please save the snippet first before favoriting.\",\n studio_sql_collections_label: \"Collections:\",\n studio_sql_admin_collections_tooltip: \"Tables in this query that are mapped to collections\",\n studio_sql_edit_entity: \"Open {{name}} #{{id}}\",\n studio_sql_sql_not_supported: \"SQL execution not supported by this data source\",\n studio_sql_fetch_error: \"Failed to fetch connection options: {{message}}\",\n studio_sql_unexpected_format: \"Unexpected data format: {{type}}\",\n studio_sql_no_tables: \"No tables found in this database.\",\n studio_sql_schema_fetch_error: \"Failed to fetch schema: {{message}}\",\n\n // ─── Studio: SQL Editor Sidebar ──────────────────────────────\n studio_sql_sidebar_snippets: \"Snippets\",\n studio_sql_sidebar_history: \"History\",\n studio_sql_sidebar_schema: \"Schema\",\n studio_sql_sidebar_no_snippets: \"No saved snippets\",\n studio_sql_sidebar_save_snippet_hint: \"Save a query to access it here.\",\n studio_sql_sidebar_no_history: \"No history\",\n studio_sql_sidebar_history_hint: \"Executed queries will appear here.\",\n studio_sql_sidebar_delete_snippet: \"Delete snippet\",\n studio_sql_close_tab: \"Close this query tab\",\n studio_sql_new_tab: \"New query tab\",\n\n // ─── Studio: Schema Browser ──────────────────────────────────\n studio_schema_tables: \"Tables\",\n studio_schema_loading: \"Loading schema...\",\n studio_schema_no_tables: \"No tables found\",\n studio_schema_retry: \"Retry\",\n studio_schema_primary_key: \"Primary Key\",\n studio_schema_select_all: \"SELECT * FROM\",\n studio_schema_insert_into: \"INSERT INTO\",\n studio_schema_update: \"UPDATE\",\n studio_schema_delete_from: \"DELETE FROM\",\n studio_schema_columns: \"{{count}} columns\",\n\n // ─── Studio: RLS Editor ──────────────────────────────────────\n studio_rls_title: \"Row Level Security\",\n studio_rls_description: \"Manage RLS policies for your tables\",\n studio_rls_enabled: \"RLS Enabled\",\n studio_rls_disabled: \"RLS Disabled\",\n studio_rls_no_rls: \"No RLS\",\n studio_rls_enable_rls: \"Enable RLS\",\n studio_rls_disable_rls: \"Disable RLS\",\n studio_rls_create_policy: \"Create Policy\",\n studio_rls_policies: \"Policies\",\n studio_rls_no_policies: \"No policies defined\",\n studio_rls_no_policies_desc: \"This table has no RLS policies. All rows are accessible based on the RLS status.\",\n studio_rls_add_first_policy: \"Add your first policy\",\n studio_rls_force_rls: \"Force RLS\",\n studio_rls_force_rls_desc: \"When enabled, RLS policies apply to the table owner as well.\",\n studio_rls_enable_force_rls: \"Enable Force RLS\",\n studio_rls_disable_force_rls: \"Disable Force RLS\",\n studio_rls_edit: \"Edit\",\n studio_rls_edit_generated: \"{{policy}} is generated by Rebase for every collection, so there is no rule of yours to edit. Add a policy of your own instead.\",\n studio_rls_edit_not_declared: \"{{policy}} exists only in the database, so there is no rule in your code to edit. Import it to the codebase first.\",\n studio_rls_edit_several_operations: \"{{policy}} is one of the policies a single rule compiles to, one per operation. Edit that rule in the collection's source file.\",\n studio_rls_delete: \"Delete\",\n studio_rls_confirm_delete_title: \"Delete Policy\",\n studio_rls_confirm_delete_body: \"Are you sure you want to delete this policy? This action cannot be undone.\",\n studio_rls_confirm_enable_title: \"Enable Row Level Security\",\n studio_rls_confirm_enable_body: \"Enabling RLS will restrict access to rows in this table based on your policies. Make sure you have appropriate policies in place.\",\n studio_rls_confirm_disable_title: \"Disable Row Level Security\",\n studio_rls_confirm_disable_body: \"Disabling RLS will make all rows accessible to all roles. Are you sure you want to continue?\",\n studio_rls_select_table: \"Select a table\",\n studio_rls_no_tables: \"No tables available\",\n studio_rls_error: \"Error loading policies\",\n studio_rls_retry: \"Retry\",\n studio_rls_loading: \"Loading policies...\",\n\n // ─── Studio: Policy Editor ───────────────────────────────────\n studio_policy_edit: \"Edit Policy\",\n studio_policy_create: \"Create New Policy\",\n studio_policy_defining_rules: \"Defining access rules for\",\n studio_policy_cancel: \"Cancel\",\n studio_policy_save: \"Save Policy\",\n studio_policy_template: \"Start from a template (Optional)\",\n studio_policy_select_template: \"Select a template...\",\n studio_policy_name: \"Policy Name\",\n studio_policy_name_placeholder: \"Give your policy a descriptive name\",\n studio_policy_behavior: \"Policy Behavior\",\n studio_policy_permissive: \"Permissive\",\n studio_policy_permissive_desc: \"Combined using \\\"OR\\\"\",\n studio_policy_restrictive: \"Restrictive\",\n studio_policy_restrictive_desc: \"Combined using \\\"AND\\\"\",\n studio_policy_command: \"Policy Command\",\n studio_policy_target_roles: \"Target Roles\",\n studio_policy_roles_placeholder: \"Select roles (defaults to public)\",\n studio_policy_using_expr: \"USING expression\",\n studio_policy_using_expr_desc: \"Applies to existing rows (SELECT, UPDATE, DELETE)\",\n studio_policy_check_expr: \"WITH CHECK expression\",\n studio_policy_check_expr_desc: \"Applies to new or modified rows (INSERT, UPDATE)\",\n studio_policy_help_title: \"Row Level Security (RLS) Guide\",\n studio_policy_help_intro: \"Row Level Security (RLS) allows you to restrict which rows a user can access or modify based on their authentication status or roles.\",\n studio_policy_help_step1_title: \"1. Select a Template\",\n studio_policy_help_step1_desc: \"If you're new to RLS, the easiest way to start is by selecting a predefined template from the dropdown. It will automatically configure the policy for common use cases like \\\"Users can update their own rows\\\".\",\n studio_policy_help_step2_title: \"2. Target Roles\",\n studio_policy_help_step2_desc: \"Choose the database roles the policy applies to. Every API request runs as the same role, signed in or not, so who the caller is goes in the USING expression:\",\n studio_policy_help_role_public: \"Every role, so every request. What the templates and Rebase's own policies target.\",\n studio_policy_help_role_rebase_user: \"The role API requests run as. It differs from public only for connections made directly as another role.\",\n studio_policy_help_roles_not_users: \"Signed-in users, anonymous visitors and admins are not database roles here. Target public and check rebase.uid() or rebase.roles() in the expression, as the templates do.\",\n studio_policy_help_step3_title: \"3. USING Expression\",\n studio_policy_help_step3_desc: \"A SQL condition that must evaluate to true for existing rows to be visible or updatable (SELECT, UPDATE, DELETE).\",\n studio_policy_help_step3_example: \"Ensures users can only see rows where they are the owner.\",\n studio_policy_help_step4_title: \"4. WITH CHECK Expression\",\n studio_policy_help_step4_desc: \"A SQL condition that must evaluate to true for new or modified rows to be saved (INSERT, UPDATE).\",\n studio_policy_help_step4_example: \"Usually the same as the USING expression when users are only allowed to insert/edit their own data.\",\n studio_policy_help_example: \"Example:\",\n studio_policy_help_auth_vars_title: \"Rebase Auth Variables\",\n studio_policy_help_auth_vars_desc: \"Rebase provides native helper functions that you can use in your expressions:\",\n studio_policy_help_auth_uid: \"Returns the current user's ID as text. Example:\",\n studio_policy_help_auth_jwt: \"Returns the full JWT payload as JSONB so you can check custom claims. Example:\",\n studio_policy_help_auth_roles: \"Returns the user's role IDs as a comma-separated string. Best used with:\",\n studio_policy_help_docs_cta: \"To learn more about Postgres policies, check out the official documentation.\",\n studio_policy_help_read_docs: \"Read Docs\",\n studio_policy_help_got_it: \"Got it!\",\n\n // ─── Studio: UI Actions ──────────────────────────────────────\n studio_add_kanban_column: \"Add column\",\n studio_add_kanban_column_title: \"Add Kanban Column\",\n studio_add_kanban_column_name: \"Column name\",\n studio_add_kanban_column_name_placeholder: \"New column name\",\n studio_add_kanban_column_add: \"Add\",\n studio_add_kanban_column_cancel: \"Cancel\",\n studio_collection_view_sql: \"SQL Editor\",\n studio_collection_view_admin: \"Admin View\",\n studio_editor_collection_tooltip: \"Edit collection schema\",\n studio_editor_collection_no_permission: \"You don't have permission to edit this collection\",\n studio_editor_collection_start_tooltip: \"Copy path or edit schema\",\n studio_editor_collection_start_no_permission: \"You don't have permission to modify this collection\",\n studio_editor_collection_start_copied: \"Copied!\",\n studio_editor_entity_tooltip: \"Edit entity schema\",\n studio_editor_entity_no_permission: \"You don't have permission to edit this entity\",\n studio_home_edit_collection: \"Edit collection\",\n studio_home_delete_collection: \"Delete collection\",\n studio_home_confirm_delete_title: \"Delete collection?\",\n studio_home_confirm_delete_body: \"Are you sure you want to delete the collection \\\"{{name}}\\\"? This action cannot be undone.\",\n studio_kanban_setup: \"Kanban Setup\",\n studio_missing_reference: \"Missing reference: {{path}}\",\n studio_missing_reference_create: \"Create\",\n studio_new_collection: \"New collection\",\n studio_new_collection_card: \"New collection\",\n studio_new_collection_no_permission: \"You don't have permissions to create collections\",\n studio_property_add_column: \"Add new property\",\n studio_property_add_column_no_permission: \"You don't have permission to add new properties\",\n studio_add_kanban_column_desc: \"Add a new option to the \\\"{{property}}\\\" property. This will create a new column in the Kanban board.\",\n studio_add_kanban_column_adding: \"Adding...\",\n studio_add_kanban_column_exists: \"A column named \\\"{{label}}\\\" is already on the board.\",\n studio_add_kanban_column_not_enum: \"\\\"{{property}}\\\" is not a property with options, so no column can be added to it.\",\n studio_collection_view_edit: \"Edit\",\n studio_editor_collection_disabled: \"Collection editing is disabled\",\n studio_editor_collection_edit: \"Edit collection\",\n studio_editor_entity_save_first: \"You need to save the document before changing the schema\",\n studio_editor_entity_edit_schema: \"Edit schema for this form\",\n studio_editor_collection_start_save_filter: \"Save default filter and sort\",\n studio_editor_collection_start_clear_filter: \"Clear default filter and sort\",\n studio_editor_collection_start_reset_filter: \"Reset to default filter and sort\",\n studio_editor_collection_start_saved: \"Default config saved\",\n studio_home_duplicate_collection: \"Duplicate\",\n studio_home_delete: \"Delete\",\n studio_home_confirm_delete_no_data: \"Deletes the collection's file and its entry in index.ts, and commits that. The table and its rows stay in the database. Refused while another collection links to this one.\",\n studio_home_collection_deleted: \"Collection deleted\",\n studio_kanban_configure: \"Configure Kanban\",\n studio_missing_reference_error: \"No collection for path: {{path}}\",\n studio_new_collection_add: \"Add new collection\",\n studio_tool_schema: \"Collections\",\n studio_js_collections_tab: \"Collections\",\n studio_tool_schema_description: \"Define and manage your data model and collection schemas\",\n studio_collections_editor_empty: \"No collections yet.\",\n studio_collections_editor_pick: \"Select a collection or create a new one to start editing.\",\n studio_collections_editor_read_only: \"Collections cannot be edited on this server.\",\n studio_collections_editor_unsaved: \"There are unsaved changes in this collection.\",\n\n // ─── Schema change dialog ────────────────────────────────\n schema_change_title_review: \"Review schema change\",\n schema_change_title_applied: \"Schema change applied\",\n schema_change_title_committed: \"Schema change committed\",\n schema_change_verdict_safe_title: \"Ready to apply\",\n schema_change_verdict_safe_body: \"Every change here can be made against the running database.\",\n schema_change_verdict_diverges_title: \"This would leave the database out of step\",\n schema_change_verdict_diverges_body: \"The change can be written, but the database will not end up matching it. The details below say which part, and what would make it applicable.\",\n schema_change_verdict_migration_title: \"This needs a migration\",\n schema_change_verdict_migration_body: \"Some of this cannot be done to a running database at all — it drops or rewrites something, and that belongs in a migration somebody has read.\",\n schema_change_commit_only_title: \"Ready to commit\",\n schema_change_commit_only_body: \"Nothing runs against the database now. Each change below says what it does and when it takes effect.\",\n schema_change_commit_only_body_no_changes: \"This changes what your project declares. Nothing runs against the database — there is no schema change to make.\",\n schema_change_chip_safe: \"safe\",\n schema_change_chip_diverges: \"diverges\",\n schema_change_chip_migration: \"needs migration\",\n schema_change_follow_up_one: \"One thing to do afterwards\",\n schema_change_follow_up: \"To do afterwards\",\n schema_change_withheld_one: \"One constraint will not be enforced\",\n schema_change_withheld_many: \"{{count}} constraints will not be enforced\",\n schema_change_db_not_changed: \"The database was not changed\",\n schema_change_db_maybe_changed: \"The database may have been changed in part\",\n schema_change_statements_partial: \"{{ran}} of {{total}} statements ran, then one failed\",\n schema_change_commit_holds: \"The commit is on {{branch}} either way, so whatever did not run will be applied on the next boot.\",\n schema_change_committed: \"Committed\",\n schema_change_committed_on: \"{{sha}} on {{branch}}\",\n schema_change_plan_failed: \"The change could not be planned\",\n schema_change_planning: \"Working out what this change would do…\",\n schema_change_source_only_changes: \"Nothing here changes the shape of your data. Only the collection source changes, and it is committed.\",\n schema_change_source_only_title: \"Edit source only: commit the collection, leave the database\",\n schema_change_preview_only: \"You can preview this change, but not apply it\",\n schema_change_statements: \"Statements that will run\",\n schema_change_files: \"Files that will be committed\",\n schema_change_message: \"Commit message\",\n schema_change_edit_source_only: \"Edit source only\",\n schema_change_committing: \"Committing…\",\n schema_change_applying: \"Applying…\",\n schema_change_commit: \"Commit\",\n schema_change_commit_and_apply: \"Commit and apply\",\n\n // ─── API explorer ────────────────────────────────────────\n studio_api_explorer_spec_refused_title: \"This session cannot read the API specification\",\n studio_api_explorer_spec_failed_title: \"Could not load the API specification\",\n studio_api_explorer_spec_refused_body: \"The console's access to this project's API was refused. It usually means the session expired — sign in again — or that console access has been turned off for this project in Settings.\",\n studio_api_explorer_spec_failed_body: \"The project answered, but not with a specification this explorer could read. Its API is unaffected; only this page is.\",\n\n // ─── Property field labels ──────────────────────────────────\n db_column_type: \"Database Column Type\",\n primary_key_unique_id: \"Primary Key / Unique ID\",\n spread_children_as_columns: \"Spread children as columns\",\n mode: \"Mode\",\n timezone: \"Timezone\",\n target_collection: \"Target collection\",\n\n // ─── Column type and primary key selects ─────────────────\n column_type_default: \"Default ({{type}})\",\n column_type_uuid_forced: \"uuid (forced by Primary Key)\",\n column_type_varchar: \"varchar (variable length)\",\n column_type_text: \"text (unlimited)\",\n column_type_char: \"char (fixed length)\",\n column_type_timestamp: \"timestamp (with timezone)\",\n column_type_caption_string: \"Optional database override for this string field.\",\n column_type_caption_number: \"Optional database override for this number field.\",\n column_type_caption_date: \"Optional database override for this date field.\",\n primary_key_manual: \"Yes (Manual input)\",\n primary_key_generated_string: \"Yes (Auto-generated UUID/String)\",\n primary_key_identity: \"Yes (Auto-increment/identity)\",\n primary_key_increment: \"Yes (Increment)\",\n primary_key_strategy: \"Yes ({{strategy}})\",\n primary_key_caption: \"Set as Primary Key and configure ID generation strategy.\",\n\n // ─── Storage property ───────────────────────────────────────\n storage_file_name: \"File name\",\n storage_path: \"Storage path\",\n storage_max_size: \"Max size (in bytes)\",\n storage_resize_mode: \"Resize mode\",\n storage_output_format: \"Output format\",\n storage_max_width: \"Max width (px)\",\n storage_max_height: \"Max height (px)\",\n storage_quality: \"Quality (0-100)\",\n storage_file_upload_config: \"File upload config\",\n storage_image_resize_config: \"Image Resize Configuration\",\n storage_all_file_types: \"All file types allowed\",\n storage_allowed_file_types: \"Allowed file types\",\n storage_include_bucket_url: \"Include bucket URL (s3://...) in saved value\",\n storage_save_url: \"Save URL instead of storage path\",\n\n // ─── DateTime property ──────────────────────────────────────\n datetime_automatic_value: \"Automatic value\",\n\n // ─── Date property selects ───────────────────────────────\n datetime_mode_date_time: \"Date/Time\",\n datetime_mode_date: \"Date\",\n datetime_auto_value_none: \"None\",\n datetime_auto_value_on_create: \"On create\",\n datetime_auto_value_on_update: \"On any update\",\n datetime_auto_value_caption: \"Update this field automatically when creating or updating the entity\",\n datetime_timezone_local: \"Local timezone\",\n datetime_timezone_caption: \"Timezone for displaying and inputting dates. Values are always stored in UTC.\",\n\n // ─── Markdown property ──────────────────────────────────────\n markdown_paste_behavior: \"Paste behavior\",\n\n // ─── Entity identity bar and inspector ──────────────────────\n entity_saved: \"Saved\",\n more_actions: \"More actions\",\n record_history: \"History\",\n inspect_record: \"Inspect record\",\n inspect: \"Inspect\",\n close_inspector: \"Close inspector\",\n open_in_live_site: \"Open in the live site\",\n\n // ─── Revision history ───────────────────────────────────────\n history_revert: \"Revert to this version\",\n history_revert_title: \"Revert data to this version?\",\n history_reverted: \"Reverted to selected version\",\n history_revert_error: \"Error reverting entity\",\n history_revert_dirty: \"Please save or discard your changes before reverting\",\n history_empty: \"No history available\",\n history_empty_description: \"When you save a record, a new version is created and stored in the history.\",\n history_new_entity: \"History is only available for existing records\",\n history_no_more: \"No more history\",\n\n // ─── Studio: tools, groups and empty states ─────────────────\n // The admin's own three groups, read by `useNavigationGroupLabel` the same\n // way as the Studio ones below — the group *name* is an identifier the\n // ordering and the icons key off, and only the heading is translated.\n studio_group_views: \"Views\",\n studio_group_admin: \"Admin\",\n studio_group_settings: \"Settings\",\n studio_group_database: \"Database\",\n studio_group_compute: \"Compute\",\n studio_group_storage: \"Storage\",\n studio_group_api: \"API\",\n studio_group_access_control: \"Access Control\",\n studio_tool_sql: \"SQL Console\",\n studio_tool_sql_description: \"Execute SQL queries\",\n studio_tool_js: \"JS Console\",\n studio_tool_js_description: \"Execute JavaScript\",\n studio_tool_rls: \"RLS Policies\",\n studio_tool_rls_description: \"Row Level Security\",\n studio_tool_storage: \"Storage\",\n studio_tool_storage_description: \"Manage storage files\",\n studio_tool_cron: \"Cron Jobs\",\n studio_tool_cron_description: \"Manage scheduled tasks\",\n studio_tool_schema_visualizer: \"Schema Visualizer\",\n studio_tool_schema_visualizer_description: \"Entity diagram of your collections\",\n studio_tool_branches: \"Branches\",\n studio_tool_branches_description: \"Create and manage database branches\",\n studio_tool_backups: \"Backups\",\n studio_tool_backups_description: \"Download database backups\",\n studio_tool_api: \"API Explorer\",\n studio_tool_api_description: \"Interactive API documentation and testing\",\n studio_tool_logs: \"Logs Explorer\",\n studio_tool_logs_description: \"Real-time system and query logs\",\n studio_tool_api_keys: \"API Keys\",\n studio_tool_api_keys_description: \"Create and manage scoped API keys\",\n studio_backups_denied_title: \"You cannot list this project's backups\",\n studio_backups_denied_hint: \"Nothing is wrong with the project. Listing backups needs an admin connection, and the signed-in account was refused.\",\n studio_backups_read_failed: \"Could not read this project's backups\",\n studio_backups_downloading: \"Downloading…\",\n studio_backups_roles_file: \"Roles file\",\n studio_backups_roles_file_hint: \"The .globals.sql saved with this backup. It recreates the database roles that the dump's grants and row-level security refer to, and `rebase db restore` reads it from next to the .dump, so keep the two files together.\",\n studio_backups_no_roles_file: \"No roles file\",\n studio_backups_no_roles_file_hint: \"No .globals.sql was saved with this backup. Restoring it into a new Postgres stops at the first grant to a database role that does not exist there.\",\n studio_backups_empty: \"No backups yet.\",\n studio_backups_empty_hint: \"Take one with `rebase db backup`, or schedule them with a cron file that exports createBackupCron.\",\n studio_backups_last_run_failed: \"The last scheduled backup failed ({{when}})\",\n studio_backups_last_run_ok: \"Last scheduled backup: {{when}}\",\n studio_backups_never_ran: \"The scheduled backup has not run yet\",\n studio_backups_next_run: \"Next run: {{when}}\",\n studio_backups_schedule_paused: \"Scheduled backups are paused. Resume the {{job}} job in Cron Jobs.\",\n studio_backups_schedule_off_in_code: \"Scheduled backups are off: the {{job}} job is declared disabled in its cron file. With the documented backup cron file, setting BACKUP_SCHEDULE turns them on.\",\n studio_backups_manual_run_ok: \"Last run by hand: {{when}}\",\n studio_backups_manual_run_failed: \"The last run by hand failed ({{when}})\",\n studio_backups_history_unreadable: \"Could not read the scheduled backup's run history, so whether it ran is not known. The server log has the reason.\",\n studio_backups_job_refused: \"Scheduled backups never run: the scheduler refused the {{job}} job. Fix it in its cron file.\",\n studio_backups_local_disk_of_this_process: \"These are the backups on this server process's disk. Scheduled backups run in another process and write to its disk, so they are listed here only if both share this directory. An s3:// or gs:// destination reads the same from every process.\",\n studio_backups_unavailable_title: \"Backups not available\",\n studio_backups_unavailable_body: \"This backend does not expose the backups API.\",\n studio_cron_denied_title: \"You cannot list this project's cron jobs\",\n studio_cron_denied_hint: \"Nothing is wrong with the project. The cron API is admin-only, and the signed-in account was refused.\",\n studio_cron_read_failed: \"Could not read this project's cron jobs\",\n studio_cron_logs_read_failed: \"Could not read this job's executions\",\n studio_cron_logs_denied_title: \"You cannot read this job's executions\",\n studio_cron_run_succeeded: \"{{job}} ran successfully\",\n studio_cron_last_error: \"Last error\",\n studio_cron_no_executions: \"No executions yet\",\n studio_cron_manual_run: \"manual\",\n studio_cron_job_enabled: \"Job enabled\",\n studio_cron_job_paused: \"Job paused\",\n studio_cron_refresh: \"Refresh\",\n studio_cron_select_job: \"Select a cron job to view its details\",\n studio_cron_pause_job: \"Pause job\",\n studio_cron_enable_job: \"Enable job\",\n studio_cron_run_now: \"Run now\",\n studio_cron_schedule: \"Schedule\",\n studio_cron_last_run: \"Last run\",\n studio_cron_next_run: \"Next run\",\n studio_cron_paused: \"Paused\",\n studio_cron_duration: \"Duration\",\n studio_cron_status: \"Status\",\n studio_cron_total_runs: \"Total runs\",\n studio_cron_failures: \"Failures\",\n studio_cron_execution_history: \"Execution history\",\n studio_cron_refresh_logs: \"Refresh executions\",\n studio_cron_run_failed: \"{{job}} ran and failed: {{error}}\",\n studio_cron_job_refused: \"{{job}} is not scheduled: the scheduler refused it\",\n studio_cron_files_failed: \"{{count}} cron files failed to load and are not scheduled. The server log says why.\",\n studio_cron_files_failed_one: \"{{count}} cron file failed to load and is not scheduled. The server log says why.\",\n studio_api_keys_denied_title: \"You cannot list this project's API keys\",\n studio_api_keys_denied_hint: \"Nothing is wrong with the project. Listing service keys needs the keys:read scope, which the signed-in account does not hold.\",\n studio_api_keys_read_failed: \"Could not read this project's API keys\",\n studio_api_keys_empty_title: \"No API keys yet\",\n studio_api_keys_empty_hint: \"Create a key to enable machine-to-machine authentication\",\n studio_api_keys_revoke: \"Revoke\",\n studio_api_keys_select_hint: \"Select an API key to view details\",\n studio_api_keys_revoke_confirmation: \"Revoke confirmation\",\n studio_api_keys_name_label: \"Name:\",\n studio_api_keys_access_label: \"Access:\",\n studio_api_keys_admin_granted: \"Admin role granted\",\n studio_api_keys_admin_granted_hint: \"row-level security does not limit it: it can read, change and delete every row its scopes reach, and it passes the admin checks in functions and storage\",\n studio_api_keys_done: \"Done\",\n studio_api_keys_status_active: \"Active\",\n studio_api_keys_status_expired: \"Expired\",\n studio_api_keys_status_revoked: \"Revoked\",\n studio_api_keys_inactive_heading: \"Revoked / Expired\",\n studio_api_keys_stat_status: \"Status\",\n studio_api_keys_stat_last_used: \"Last used\",\n studio_api_keys_stat_expires: \"Expires\",\n studio_api_keys_never: \"Never\",\n studio_api_keys_stat_rate_limit: \"Rate limit\",\n studio_api_keys_rate_limit_default: \"Default (1000/15min)\",\n studio_api_keys_stat_created_by: \"Created by\",\n studio_api_keys_copy_failed: \"Failed to copy\",\n studio_api_keys_tab_service: \"Service keys\",\n studio_api_keys_tab_personal: \"My keys\",\n studio_api_keys_refresh: \"Refresh\",\n studio_api_keys_new: \"New\",\n studio_api_keys_personal_empty_title: \"You have no personal keys\",\n studio_api_keys_personal_empty_hint: \"A personal key acts as your account, for scripts and tools you run yourself\",\n studio_api_keys_personal_read_failed: \"Could not read your API keys\",\n studio_api_keys_personal_denied_title: \"This session cannot have personal keys\",\n studio_api_keys_personal_denied_hint: \"A personal key acts as a signed-in account. API keys, the service key and guest sessions have no account for one to act as.\",\n studio_api_keys_personal_off_title: \"Personal keys are switched off\",\n studio_api_keys_personal_off_body: \"A personal key acts as your own account and never holds more than you do. To let accounts create them, set this in the auth block of the users collection:\",\n studio_api_keys_kind_service: \"Service\",\n studio_api_keys_kind_personal: \"Personal\",\n studio_api_keys_stat_kind: \"Kind\",\n studio_api_keys_stat_owner: \"Owner\",\n studio_api_keys_rate_limit_value: \"{{limit}}/15min\",\n studio_api_keys_scopes: \"Scopes\",\n studio_api_keys_no_scopes: \"This key holds no scopes\",\n studio_api_keys_scopes_count: \"{{count}} scopes\",\n studio_api_keys_plane_data: \"Data\",\n studio_api_keys_plane_data_hint: \"Rows, files and functions; row-level security still decides which rows\",\n studio_api_keys_plane_admin: \"Admin\",\n studio_api_keys_plane_admin_hint: \"Users, schema, database, backups, cron and logs\",\n studio_api_keys_plane_app: \"App\",\n studio_api_keys_plane_app_hint: \"Declared by this app under auth.scopes\",\n studio_api_keys_target_all_collection: \"Every collection\",\n studio_api_keys_target_all_bucket: \"Every storage source\",\n studio_api_keys_target_all_function: \"Every function\",\n studio_api_keys_target_all_other: \"Any {{kind}}\",\n studio_api_keys_target_some: \"Only the ones I choose\",\n studio_api_keys_target_mode: \"Targets\",\n studio_api_keys_target_pick: \"Choose…\",\n studio_api_keys_target_typed_placeholder: \"{{kind}} ids, comma-separated\",\n studio_api_keys_target_missing: \"Choose at least one target for “{{scope}}”, or switch it to all of them.\",\n studio_api_keys_bucket_default: \"Default bucket\",\n studio_api_keys_roles: \"RLS roles\",\n studio_api_keys_roles_rows_hint: \"Which rows the key can read, change and delete\",\n studio_api_keys_roles_service_only: \"Runs as service only. Row-level security grants it nothing unless a policy names that role.\",\n studio_api_keys_roles_service_plus: \"Runs as service plus these roles; every row-level security policy that names one of them applies.\",\n studio_api_keys_admin_bypasses_rls: \"Runs as admin: row-level security does not limit it, so it can read, change and delete every row its scopes reach, and it passes the admin checks in custom functions and storage. Its scopes still decide which endpoints it may call.\",\n studio_api_keys_admin_chip_tooltip: \"Runs as the admin role: row-level security does not limit its reads, writes or deletes\",\n studio_api_keys_personal_roles: \"Runs as its owner, with the owner's roles as they are each time it is used. It never holds a scope its owner has lost.\",\n studio_api_keys_revoke_title: \"Revoke “{{name}}”?\",\n studio_api_keys_revoke_body: \"Requests authenticated with this key stop working immediately. This cannot be undone.\",\n studio_api_keys_revoked: \"API key revoked\",\n studio_api_keys_created_title: \"API key created\",\n studio_api_keys_copy_now: \"Copy your key now — it won't be shown again\",\n studio_api_keys_copy_now_hint: \"This is the only time the full key is displayed. Store it somewhere safe.\",\n studio_api_keys_copied: \"API key copied to clipboard\",\n studio_api_keys_create_title: \"Create service key\",\n studio_api_keys_create_personal_title: \"Create personal key\",\n studio_api_keys_create_intro: \"A credential for scripts, cron jobs and agents. It acts as the project's service identity, not as a person, and reaches only the scopes you grant here.\",\n studio_api_keys_create_personal_intro: \"A credential for scripts and tools you run yourself. It acts as your account and can never do more than you can.\",\n studio_api_keys_field_name: \"Name\",\n studio_api_keys_field_name_placeholder: \"e.g. Analytics pipeline\",\n studio_api_keys_section_scopes_hint: \"Which endpoints the key may call\",\n studio_api_keys_scopes_read_failed: \"Could not read the scopes this backend offers\",\n studio_api_keys_scopes_offered_note: \"Only scopes your account holds are offered. Managing keys (keys:read, keys:write) can never go on a key.\",\n studio_api_keys_roles_explainer: \"Scopes decide which endpoints the key may call; roles decide which rows it can read, change and delete. Every service key runs as service, plus the roles you add here. Leave this empty unless a row-level security policy names a role the key needs.\",\n studio_api_keys_roles_other: \"Other roles\",\n studio_api_keys_roles_other_placeholder: \"Comma-separated role names\",\n studio_api_keys_roles_unavailable: \"The project's roles could not be listed; type role names instead.\",\n studio_api_keys_roles_admin_warning: \"With admin, row-level security does not limit the key: it can read, change and delete every row its scopes reach, and it passes the admin checks in custom functions and storage. Its scopes still decide which endpoints it may call.\",\n studio_api_keys_section_limits: \"Limits\",\n studio_api_keys_expiry_7d: \"In 7 days\",\n studio_api_keys_expiry_30d: \"In 30 days\",\n studio_api_keys_expiry_90d: \"In 90 days\",\n studio_api_keys_expiry_1y: \"In 1 year\",\n studio_api_keys_rate_limit_unit: \"per 15 min\",\n studio_api_keys_rate_limit_hint: \"Leave empty for the server default of 1000 requests per 15-minute window.\",\n studio_api_keys_rate_limit_scope: \"The limit counts the key's data, file and function requests, over HTTP, the realtime socket and MCP. Admin operations are not rate limited.\",\n studio_api_keys_summary_title: \"This key will be able to\",\n studio_api_keys_summary_empty: \"Nothing yet — choose at least one scope.\",\n studio_api_keys_summary_roles: \"Row-level security treats it as {{roles}}\",\n studio_api_keys_block_name: \"Name the key first\",\n studio_api_keys_block_scopes: \"Choose at least one scope\",\n studio_api_keys_block_targets: \"Finish choosing targets\",\n studio_api_keys_creating: \"Creating…\",\n studio_api_keys_create: \"Create key\",\n studio_api_keys_unsupported: \"This client cannot create API keys.\",\n studio_api_keys_error_invalid_scopes: \"Some scopes are not valid\",\n studio_api_keys_error_scope_exceeds_creator: \"A key cannot hold more than your account\",\n studio_api_keys_error_role_exceeds_creator: \"A key cannot run as a role you do not hold\",\n studio_api_keys_error_unknown_scope_target: \"A target does not exist on this backend\",\n studio_api_keys_error_key_management_scope: \"Managing keys cannot go on a key\",\n studio_api_keys_error_generic: \"The key was not created\",\n studio_scope_data_read_label: \"Read data\",\n studio_scope_data_read_description: \"Read rows from collections, through the caller's row-level security.\",\n studio_scope_data_write_label: \"Create and update data\",\n studio_scope_data_write_description: \"Create and update rows in collections, through the caller's row-level security.\",\n studio_scope_data_delete_label: \"Delete data\",\n studio_scope_data_delete_description: \"Delete rows from collections, through the caller's row-level security.\",\n studio_scope_storage_read_label: \"Read files\",\n studio_scope_storage_read_description: \"List and download stored files.\",\n studio_scope_storage_write_label: \"Upload files\",\n studio_scope_storage_write_description: \"Upload files and create folders.\",\n studio_scope_storage_delete_label: \"Delete files\",\n studio_scope_storage_delete_description: \"Delete stored files.\",\n studio_scope_functions_invoke_label: \"Call functions\",\n studio_scope_functions_invoke_description: \"Call the backend's custom functions. A function can do anything its code does.\",\n studio_scope_users_read_label: \"See users\",\n studio_scope_users_read_description: \"List user accounts and their roles.\",\n studio_scope_users_write_label: \"Manage users\",\n studio_scope_users_write_description: \"Create, edit and delete accounts, reset passwords and second factors, and assign roles up to the holder's own.\",\n studio_scope_schema_read_label: \"See the schema\",\n studio_scope_schema_read_description: \"Read the collection schema, plan schema changes and run the RLS audit.\",\n studio_scope_schema_write_label: \"Change the schema\",\n studio_scope_schema_write_description: \"Apply schema changes: edits collection files and alters the database.\",\n studio_scope_database_read_label: \"Inspect the database\",\n studio_scope_database_read_description: \"List databases, tables, Postgres roles and branches.\",\n studio_scope_database_write_label: \"Run SQL\",\n studio_scope_database_write_description: \"Run SQL as the database owner, outside row-level security, and create or delete branches.\",\n studio_scope_backups_read_label: \"Download backups\",\n studio_scope_backups_read_description: \"List and download database backups — every row, outside row-level security.\",\n studio_scope_cron_read_label: \"See cron jobs\",\n studio_scope_cron_read_description: \"List cron jobs and read their run history.\",\n studio_scope_cron_write_label: \"Run cron jobs\",\n studio_scope_cron_write_description: \"Trigger cron jobs and switch them on or off.\",\n studio_scope_logs_read_label: \"Read server logs\",\n studio_scope_logs_read_description: \"Read the server's request and application logs.\",\n studio_scope_keys_read_label: \"See service keys\",\n studio_scope_keys_read_description: \"List the project's service keys. Never grantable to a key.\",\n studio_scope_keys_write_label: \"Manage service keys\",\n studio_scope_keys_write_description: \"Create, change and revoke the project's service keys. Never grantable to a key.\",\n studio_branches_denied_title: \"You cannot list this project's branches\",\n studio_branches_denied_hint: \"Nothing is wrong with the project. Branching runs on the admin connection, and the signed-in account was refused.\",\n studio_branches_read_failed: \"Could not read this project's branches\",\n studio_schema_no_collections: \"No collections declared\",\n studio_schema_no_collections_body: \"There is nothing to draw yet. Add a collection under config/collections/, or open Edit collections to add one here.\",\n studio_schema_introspect_hint: \"Against a database that already has tables, rebase schema introspect writes the collection files for you.\",\n studio_schema_visualizer_source: \"Drawn from your collections: tables, columns, types and relations are as they declare them. Only the RLS markers are read from the database.\",\n studio_schema_laying_out: \"Laying out the diagram…\",\n studio_schema_neighbourhood: \"Showing {{shown}} of {{total}} tables: {{table}} and the tables around it. Pick another in the list to move.\",\n studio_schema_neighbourhood_depth_1: \"1 relation away\",\n studio_schema_neighbourhood_depth_2: \"2 relations away\",\n\n\n // ─── Studio: RLS editor confirmations ───────────────────────\n studio_rls_enable_confirm_title: \"Enable Row Level Security?\",\n studio_rls_enable_confirm_body: \"Until a policy allows it, every row of {{table}} becomes unreadable. Postgres denies by default.\",\n studio_rls_disable_confirm_title: \"Disable Row Level Security?\",\n studio_rls_disable_confirm_body: \"Every policy on {{table}} stops being enforced. Anyone who can reach the table can read and write every row.\",\n studio_rls_drop_policy_title: \"Drop this policy?\",\n studio_rls_drop_policy_body: \"{{policy}} is removed from {{table}} in the database. Nothing is written to your code, so a deploy can restore it.\",\n studio_rls_unapplied: \"Unapplied\",\n studio_rls_unapplied_tooltip: \"Declared in your code, not in the database yet. Rebase applies it the next time the server starts or `rebase db push` runs; if it is still missing after that, the server log says why.\",\n studio_rls_drift: \"Differs from code\",\n studio_rls_drift_tooltip: \"The database's {{fields}} differ from what the project declares for this policy. The declared version comes back the next time the server starts or `rebase db push` runs.\",\n studio_rls_reapplied_on_start: \"Rebase manages the policies on {{table}}. Each time the server starts, and on every `rebase db push`, it switches row-level security back on for this table and re-creates every policy the project declares for it. A change made here to one of those policies, or to the RLS switch, lasts until then. A policy you add under a name of your own is kept.\",\n studio_rls_disable_reapplied: \"Rebase manages {{table}}, so row-level security is switched back on the next time the server starts or `rebase db push` runs.\",\n studio_rls_nothing_changed: \"Nothing changed, so nothing was saved.\",\n\n\n // ─── Studio: empty states that name a remedy ────────────────\n studio_branches_unavailable_title: \"Database branching is not available\",\n studio_branches_unavailable_body: \"Branching needs a Postgres backend with an admin connection. Set ADMIN_CONNECTION_STRING in the backend's environment.\",\n studio_branch_diff_tab_schema: \"Schema & RLS policies\",\n studio_branch_diff_tab_data: \"Data changes\",\n studio_branch_diff_tab_details: \"Details\",\n studio_branch_diff_merge: \"Merge into {{target}}\",\n studio_branch_diff_failed: \"Could not compare this branch\",\n studio_branch_diff_denied_title: \"You cannot review this branch\",\n studio_branch_diff_denied_hint: \"Reviewing a branch needs the database:write scope: its diff shows rows of both databases, read outside row-level security.\",\n studio_branch_diff_unreadable: \"The server answered with something that is not a branch diff.\",\n studio_branch_diff_no_api: \"This panel has no backend address to read the branch's diff from.\",\n studio_branch_diff_fork_unknown: \"The moment this branch was made could not be read, so every row that differs is counted as the branch's change. A merge would also undo what {{target}} changed since.\",\n studio_branch_diff_schema_empty: \"No schema or policy changes against {{target}}.\",\n studio_branch_diff_schema_not_merged: \"Schema and policy changes are shown for review. A merge never applies them: they belong to your collections and their migrations.\",\n studio_branch_diff_object_table: \"Table\",\n studio_branch_diff_object_column: \"Column\",\n studio_branch_diff_object_policy: \"Policy\",\n studio_branch_diff_object_rls: \"Row-level security\",\n studio_branch_diff_object_constraint: \"Constraint\",\n studio_branch_diff_object_index: \"Index\",\n studio_branch_diff_object_trigger: \"Trigger\",\n studio_branch_diff_object_enum: \"Enum type\",\n studio_branch_diff_object_view: \"View\",\n studio_branch_diff_object_function: \"Function\",\n studio_branch_diff_change_added: \"Added\",\n studio_branch_diff_change_dropped: \"Dropped\",\n studio_branch_diff_change_altered: \"Altered\",\n studio_branch_diff_data_empty: \"The branch changed no rows against {{target}}.\",\n studio_branch_diff_row_inserted: \"Inserted\",\n studio_branch_diff_row_updated: \"Updated\",\n studio_branch_diff_row_deleted: \"Deleted\",\n studio_branch_diff_row_conflict: \"Conflict\",\n studio_branch_diff_conflicts: \"{{count}} conflicts\",\n studio_branch_diff_target_changes: \"{{count}} rows changed on {{target}} only since the branch was made. A merge keeps them.\",\n studio_branch_diff_target_changes_referencing: \"{{count}} rows changed on {{target}} only since the branch was made. {{reached}} of them reference rows the branch deleted: a merge keeps them unless the branch wins that conflict.\",\n studio_branch_diff_referenced_by: \"Rows the branch deleted here are still referenced by rows {{target}} wrote since the branch was made: {{tables}}. Each one is counted as a conflict.\",\n studio_branch_diff_row_counts: \"Rows: {{targetCount}} on {{target}}, {{branchCount}} on the branch.\",\n studio_branch_diff_column_change: \"Change\",\n studio_branch_diff_column_key: \"Primary key\",\n studio_branch_diff_column_values: \"Values\",\n studio_branch_diff_samples_shown: \"Showing {{shown}} of {{total}} changed rows.\",\n studio_branch_diff_merge_title: \"Merge {{branch}} into {{target}}\",\n studio_branch_diff_merge_writes: \"This writes the branch's rows to {{target}}: {{inserted}} inserted, {{updated}} updated and {{deleted}} deleted.\",\n studio_branch_diff_merge_target_kept: \"Nothing {{target}} changed since the branch was made is touched.\",\n studio_branch_diff_merge_target_kept_count: \"The {{count}} rows {{target}} changed since the branch was made are kept as they are.\",\n studio_branch_diff_merge_schema_skipped: \"The {{count}} schema and policy changes are not merged. Apply them with your migrations (rebase db push).\",\n studio_branch_diff_merge_conflicts: \"{{count}} rows were changed on both sides. Which version wins?\",\n studio_branch_diff_merge_referenced_conflicts: \"Some of them are rows the branch deleted that {{count}} rows {{target}} wrote since still reference: {{tables}}. Keeping {{target}}'s keeps those rows and the rows that reference them.\",\n studio_branch_diff_merge_referenced_reached: \"Letting the branch win deletes rows that {{count}} rows {{target}} wrote since still reference, and the foreign keys reach those rows: {{tables}}. The other rows {{target}} changed since are kept as they are.\",\n studio_branch_diff_conflict_abort: \"Neither: merge nothing\",\n studio_branch_diff_conflict_branch: \"The branch's ({{branch}})\",\n studio_branch_diff_conflict_target: \"{{target}}'s: keep it as it is\",\n studio_branch_diff_merge_blocked: \"{{count}} tables with changed rows cannot be merged:\",\n studio_branch_diff_merge_skip_blocked: \"Merge the other tables and leave these as they are\",\n studio_branch_diff_merge_atomic: \"All of it is written in one transaction, or none of it. If either database changed since this diff was read, nothing is written and the diff reloads.\",\n studio_branch_diff_merge_confirm: \"Merge\",\n studio_branch_diff_merged: \"Merged {{count}} rows into {{target}}\",\n studio_backups_not_configured_title: \"Backups are not configured\",\n studio_backups_not_configured_body: \"Set BACKUP_DESTINATION to a local path or an s3:// or gs:// URL, then create a backup with `rebase db backup` or a scheduled cron.\",\n studio_cron_empty_title: \"No cron jobs registered\",\n studio_cron_empty_body: \"Add a file under backend/crons/ that default-exports a CronJobDefinition.\",\n studio_read_the_docs: \"Read the documentation\",\n\n\n // ─── Studio: storage browser ────────────────────────────────\n studio_storage_root: \"Root\",\n studio_storage_root_folder: \"root\",\n studio_storage_loading: \"Loading…\",\n studio_storage_denied_title: \"This project's storage rules refused this listing\",\n studio_storage_denied_hint: \"Nothing is wrong with the project. Its storageAuthorize hook decides who may read which keys, and it declined this path for the signed-in account — commonly because a listing must name a prefix the rule recognises rather than the bucket root.\",\n studio_storage_read_failed: \"Could not read this project's storage\",\n studio_storage_empty: \"This folder is empty\",\n studio_storage_new_folder: \"New folder\",\n studio_storage_upload_files: \"Upload files\",\n studio_storage_upload: \"Upload\",\n studio_storage_upload_count: \"Upload ({{count}})\",\n studio_storage_uploading: \"Uploading…\",\n studio_storage_upload_failed: \"Upload failed\",\n studio_storage_upload_dialog_title: \"Upload Files\",\n studio_storage_upload_to: \"to\",\n studio_storage_drop_or_browse: \"Drop files here or click to browse\",\n studio_storage_any_file_type: \"Any file type supported\",\n studio_storage_selected_files: \"Selected files ({{count}})\",\n studio_storage_drop_to_upload: \"Drop files to upload\",\n studio_storage_files_uploaded: \"{{count}} files uploaded successfully\",\n studio_storage_files_uploaded_one: \"{{count}} file uploaded successfully\",\n studio_storage_cancel: \"Cancel\",\n studio_storage_create: \"Create\",\n studio_storage_download: \"Download\",\n studio_storage_delete: \"Delete\",\n studio_storage_deselect: \"Deselect\",\n studio_storage_refresh: \"Refresh\",\n studio_storage_go_up: \"Go up\",\n studio_storage_grid_view: \"Grid view\",\n studio_storage_list_view: \"List view\",\n studio_storage_default_source: \"Default\",\n studio_storage_name: \"Name\",\n studio_storage_type: \"Type\",\n studio_storage_type_unknown: \"Unknown\",\n studio_storage_size: \"Size\",\n studio_storage_extension: \"Extension\",\n studio_storage_path: \"Path\",\n studio_storage_url: \"URL\",\n studio_storage_copy_url: \"Copy URL\",\n studio_storage_url_copied: \"Copied!\",\n studio_storage_url_temporary: \"Temporary link: anyone who has it can open this file for up to {{minutes}} min. Download and Copy URL make a fresh one.\",\n studio_storage_url_public: \"Public link: anyone can open this file, and the link does not expire.\",\n studio_storage_folder: \"Folder\",\n studio_storage_folders: \"Folders\",\n studio_storage_files_heading: \"Files ({{count}})\",\n studio_storage_file_count: \"{{count}} files\",\n studio_storage_file_count_one: \"{{count}} file\",\n studio_storage_folder_count: \"{{count}} folders\",\n studio_storage_folder_count_one: \"{{count}} folder\",\n studio_storage_selected_count: \"{{count}} selected\",\n studio_storage_selected_count_one: \"{{count}} selected\",\n studio_storage_items_selected: \"{{count}} items selected\",\n studio_storage_items_selected_one: \"{{count}} item selected\",\n studio_storage_selected_label: \"Selected:\",\n studio_storage_no_preview: \"No preview available\",\n studio_storage_file_info: \"File Info\",\n studio_storage_delete_file_title: \"Delete File\",\n studio_storage_delete_file_question: \"Delete File?\",\n studio_storage_delete_file_body: \"Are you sure you want to delete “{{name}}”? This action cannot be undone.\",\n studio_storage_delete_confirmation_title: \"Delete Confirmation\",\n studio_storage_delete_question: \"Delete?\",\n studio_storage_delete_items_question: \"Delete {{count}} items?\",\n studio_storage_delete_items_question_one: \"Delete {{count}} item?\",\n studio_storage_delete_folder_question: \"Delete folder “{{name}}”?\",\n studio_storage_delete_selection_body: \"This will permanently delete all selected files and folders, including their contents. This action cannot be undone.\",\n studio_storage_delete_folder_body: \"This will permanently delete the folder and all of its contents. This action cannot be undone.\",\n studio_storage_file_deleted: \"“{{name}}” deleted\",\n studio_storage_folder_deleted: \"Folder “{{name}}” deleted\",\n studio_storage_items_deleted: \"{{count}} items deleted\",\n studio_storage_items_deleted_one: \"{{count}} item deleted\",\n studio_storage_delete_incomplete: \"{{count}} items are still there after the delete: {{names}}\",\n studio_storage_delete_incomplete_one: \"“{{names}}” is still there after the delete\",\n studio_storage_replace_title: \"Replace files\",\n studio_storage_replace_question: \"Replace {{count}} files?\",\n studio_storage_replace_question_one: \"Replace {{count}} file?\",\n studio_storage_replace_body: \"{{names}} are already in this folder. Uploading replaces them, and the files there now are lost.\",\n studio_storage_replace_body_one: \"“{{names}}” is already in this folder. Uploading replaces it, and the file there now is lost.\",\n studio_storage_replace: \"Replace\",\n studio_storage_new_folder_title: \"New Folder\",\n studio_storage_folder_name: \"Folder name\",\n studio_storage_folder_name_placeholder: \"Enter folder name\",\n studio_storage_created_in: \"Will be created in\",\n studio_storage_folder_name_has_slash: \"Folder name cannot contain slashes\",\n studio_storage_folder_exists: \"Folder “{{name}}” already exists\",\n studio_storage_folder_created: \"Folder “{{name}}” created\",\n studio_storage_create_folder_failed: \"Failed to create folder\",\n\n // ─── Studio: Branches pane ───────────────────────────────────\n studio_branches_empty: \"No branches yet. Create one to start working with an isolated database copy.\",\n studio_branches_create_action: \"Create Branch\",\n studio_branches_empty_detail: \"Create a branch to get started\",\n studio_branches_select_prompt: \"Select a branch to view details\",\n studio_branches_list_from: \"from {{parent}} · {{when}}\",\n studio_branches_created_from: \"Created from\",\n studio_branches_branch_name: \"Branch Name\",\n studio_branches_source_database: \"Source Database\",\n studio_branches_created: \"Created\",\n studio_branches_size: \"Size\",\n studio_branches_usage_title: \"How to use this branch\",\n studio_branches_usage_switch: \"Point this checkout at it. Every later command uses it:\",\n studio_branches_usage_off: \"Go back to the main database with:\",\n studio_branches_usage_isolated: \"Changes made on this branch don't affect the main database.\",\n studio_branches_connection_details: \"Connection Details\",\n studio_branches_row_database: \"Database:\",\n studio_branches_row_connect: \"Connect with:\",\n studio_branches_row_branched_from: \"Branched from:\",\n studio_branches_row_created_at: \"Created at:\",\n studio_branches_create_title: \"Create New Branch\",\n studio_branches_create_body: \"Create an isolated database copy. The branch will be a full clone of the source database at this point in time.\",\n studio_branches_name_placeholder: \"e.g. feature-auth, staging, preview-pr-42\",\n studio_branches_source_main: \"Default (main database)\",\n studio_branches_creating: \"Creating…\",\n studio_branches_delete_title: \"Delete Branch\",\n studio_branches_delete_body: \"Are you sure you want to permanently delete the branch “{{name}}”? This action cannot be undone and all data in this branch will be lost.\",\n studio_branches_created_snackbar: \"Branch “{{name}}” created successfully\",\n studio_branches_deleted_snackbar: \"Branch “{{name}}” deleted\",\n\n // ─── Insights plugin ─────────────────────────────────────────\n insights_period_last_days: \"Last {{count}} days\",\n insights_period_last_days_one: \"Last day\",\n insights_previous_period_value: \"Previous {{count}} days: {{value}}\",\n insights_previous_period_value_one: \"Previous day: {{value}}\",\n insights_change_up: \"Up {{change}}\",\n insights_change_down: \"Down {{change}}\",\n insights_change_none: \"No change\",\n\n // ─── Icon button names ───────────────────────────────────────\n add_to_favourites: \"Add to favourites\",\n remove_from_favourites: \"Remove from favourites\",\n change_value_type: \"Change type\",\n refresh: \"Refresh\",\n create_branch: \"Create branch\",\n new_tab: \"New tab\",\n close_tab: \"Close tab\",\n help: \"Help\",\n copy_table_name: \"Copy table name\",\n copy_column_name: \"Copy column name\",\n generate_sql_templates: \"Generate SQL templates\",\n select_row: \"Select {{id}}\",\n relation_open_record: \"Open {{label}}\",\n select: \"Select\",\n open_view: \"Open view\"\n};\n","import React, { createContext, PropsWithChildren, useContext, useEffect, useMemo, useRef } from \"react\";\nimport i18next, { BackendModule, i18n } from \"i18next\";\nimport { I18nextProvider, initReactI18next } from \"react-i18next\";\nimport { loadChunk, UiLabelsProvider, type UiLabelsProviderProps } from \"@rebasepro/ui\";\nimport { en } from \"../locales/en\";\nimport { RebaseTranslations } from \"@rebasepro/cms-types\";\nimport { readStoredString, writeStoredString } from \"../util/local_storage\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\nconst REBASE_NS = \"rebase_core\";\n\n/**\n * The translations Rebase ships besides English, each its own chunk.\n *\n * English is bundled: it is the fallback for every key, so it is needed\n * whatever the language. The other six used to be bundled too, and every\n * admin downloaded, parsed and merged ~616 kB of languages it never showed\n * before its login screen could paint. Now one is fetched the first time its\n * language is asked for — on mount, for a stored preference or a `locale`\n * prop; later, from the language menu — and i18next switches to it only once\n * it has arrived, so nobody sees keys or a flash of English.\n *\n * Keep each `import()` a literal path: that is what makes it a chunk.\n */\nconst LOCALE_LOADERS: Record<string, () => Promise<RebaseTranslations>> = {\n es: () => import(\"../locales/es\").then(m => m.es),\n de: () => import(\"../locales/de\").then(m => m.de),\n fr: () => import(\"../locales/fr\").then(m => m.fr),\n it: () => import(\"../locales/it\").then(m => m.it),\n hi: () => import(\"../locales/hi\").then(m => m.hi),\n pt: () => import(\"../locales/pt\").then(m => m.pt)\n};\n\n/**\n * Tables already fetched, shared by every provider instance. Static strings,\n * nothing per user: keyed by language code, never invalidated (a new build is\n * a new page load). Lets a remount, or a second `<Rebase>`, resolve\n * synchronously instead of awaiting the chunk again.\n */\nconst loadedTables: Record<string, RebaseTranslations> = { en };\n\nexport const REBASE_LOCALE_STORAGE_KEY = \"rebase_locale\";\n\n/**\n * Every language the admin can be shown in: English, the ones Rebase ships,\n * and any the app adds through `translations` — a language Rebase does not\n * ship is a full table from the app, falling back to English key by key.\n */\nexport function availableRebaseLocales(translatedLocales: readonly string[] = []): string[] {\n return [...new Set([\"en\", ...Object.keys(LOCALE_LOADERS), ...translatedLocales])];\n}\n\nconst RebaseLocalesContext = createContext<string[]>(availableRebaseLocales());\n\n/**\n * The languages the admin can be switched to — what the language menu lists.\n * Outside a {@link RebaseI18nProvider}, the ones Rebase ships.\n */\nexport function useRebaseLocales(): string[] {\n return useContext(RebaseLocalesContext);\n}\n\n/** DeepPartial helper — allows partial overrides at any nesting level */\ntype DeepPartial<T> = T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\nexport interface RebaseI18nProviderProps {\n /** BCP-47 locale tag, e.g. \"en\", \"es\", \"fr\". Defaults to \"en\". */\n locale?: string;\n /**\n * Override or extend any Rebase UI string, keyed by locale.\n *\n * @example\n * translations={{\n * en: { save: \"Publish\" },\n * es: { save: \"Publicar\", discard: \"Descartar\" }\n * }}\n */\n translations?: {\n [locale: string]: DeepPartial<RebaseTranslations>;\n };\n}\n\n/**\n * Initialises a dedicated i18next instance for Rebase's internal UI strings.\n *\n * This instance is isolated from any app-level i18next configuration the\n * consumer may have. Mount this at the top of the Rebase component tree.\n *\n * @internal\n */\nexport function RebaseI18nProvider({\n locale = \"en\",\n translations,\n children\n}: PropsWithChildren<RebaseI18nProviderProps>) {\n const i18nRef = useRef<i18n | null>(null);\n const [ready, setReady] = React.useState(false);\n // The language the `locale` prop is switching to, while it does. That\n // change is the app's, not the user's, and must not be stored as their\n // preference — once stored, the prop is ignored for good.\n const propLanguageRef = useRef<string | null>(null);\n // The overrides the backend merges into a table it loads later. A ref,\n // not a closure over the first render's prop, so a language fetched after\n // the prop changed still gets the current overrides.\n const translationsRef = useRef(translations);\n translationsRef.current = translations;\n // The overrides the instance was built with — the effect below skips them\n // rather than merging every table a second time on mount.\n const appliedTranslationsRef = useRef<string | null>(null);\n\n if (!i18nRef.current) {\n const instance = i18next.createInstance();\n\n let initialLocale = locale;\n const stored = readStoredString(REBASE_LOCALE_STORAGE_KEY);\n if (stored) initialLocale = stored;\n // The first language is the prop's (or the stored one), not a choice\n // the user made now. A language that has to be fetched announces\n // itself after the listener below is attached, and was stored as the\n // user's preference — after which the prop was ignored for good.\n else propLanguageRef.current = initialLocale;\n\n appliedTranslationsRef.current = serializeTranslations(translations);\n\n instance\n .use(createLocaleBackend(() => translationsRef.current))\n .use(initReactI18next)\n .init({\n lng: initialLocale,\n fallbackLng: \"en\",\n ns: [REBASE_NS],\n defaultNS: REBASE_NS,\n // English and any language Rebase does not ship are in from\n // the start; a shipped one is asked of the backend above.\n resources: buildInitialResources(translations),\n partialBundledLanguages: true,\n interpolation: {\n // React already escapes — don't double-escape\n escapeValue: false\n }\n }, () => {\n // Synchronous for English (nothing to fetch), so it renders\n // on the first pass as before; for another language this runs\n // once its table is in, and nothing renders until then.\n setReady(true);\n });\n\n instance.on(\"languageChanged\", (lng) => {\n const fromProp = propLanguageRef.current === lng;\n propLanguageRef.current = null;\n if (fromProp) return;\n if (typeof window !== \"undefined\") {\n writeStoredString(REBASE_LOCALE_STORAGE_KEY, lng);\n }\n });\n\n i18nRef.current = instance;\n }\n\n // When `locale` prop changes, switch language on the existing instance\n // ONLY if the user hasn't explicitly set a preference\n useEffect(() => {\n if (i18nRef.current && i18nRef.current.language !== locale) {\n const hasUserPreference = Boolean(readStoredString(REBASE_LOCALE_STORAGE_KEY));\n if (!hasUserPreference) {\n propLanguageRef.current = locale;\n i18nRef.current.changeLanguage(locale);\n }\n }\n }, [locale]);\n\n // When consumer translations prop changes, update the resource bundles.\n // Keyed on the content, not the object: an inline `translations={{…}}`\n // is a new object on every render of the app.\n const translationsKey = serializeTranslations(translations);\n useEffect(() => {\n const instance = i18nRef.current;\n if (!instance) return;\n if (translationsKey === appliedTranslationsRef.current) return;\n appliedTranslationsRef.current = translationsKey;\n const overrides = translationsRef.current ?? {};\n const languages = new Set([...Object.keys(loadedTables), ...Object.keys(overrides)]);\n for (const lang of languages) {\n const table = loadedTables[lang];\n // A shipped table not fetched yet: leave it to the backend, which\n // merges the current overrides when it loads. Adding a bundle here\n // would make i18next think it is loaded and never fetch it.\n if (!table && LOCALE_LOADERS[lang]) continue;\n if (table && lang !== \"en\" && !instance.hasResourceBundle(lang, REBASE_NS)) continue;\n instance.addResourceBundle(\n lang,\n REBASE_NS,\n { ...(table ?? en), ...overrides[lang] },\n true, // deep merge\n true // overwrite existing keys\n );\n }\n }, [translationsKey]);\n\n // Keyed on the names, not the object, for the same reason as above.\n const localeNames = Object.keys(translations ?? {}).join(\",\");\n const locales = useMemo(\n () => availableRebaseLocales(localeNames ? localeNames.split(\",\") : []),\n [localeNames]\n );\n\n if (!ready || !i18nRef.current) return null;\n\n return (\n <I18nextProvider i18n={i18nRef.current}>\n <RebaseLocalesContext.Provider value={locales}>\n <UiLabelsFromTranslations>\n {children}\n </UiLabelsFromTranslations>\n </RebaseLocalesContext.Provider>\n </I18nextProvider>\n );\n}\n\ntype TranslationOverrides = { [locale: string]: DeepPartial<RebaseTranslations> };\n\nfunction serializeTranslations(translations?: TranslationOverrides): string {\n return translations ? JSON.stringify(translations) : \"\";\n}\n\n/**\n * The resources i18next starts with: English, plus every language the\n * consumer adds that Rebase does not ship (it starts from English, then the\n * overrides). A shipped language is left out — the backend fetches it and\n * merges its overrides then; an override added here first would be\n * overwritten by the table, or stop the table from ever loading.\n */\nfunction buildInitialResources(translations?: TranslationOverrides): Record<string, Record<string, object>> {\n const resources: Record<string, Record<string, object>> = {\n en: { [REBASE_NS]: { ...en, ...translations?.en } }\n };\n for (const [lang, overrides] of Object.entries(translations ?? {})) {\n if (lang === \"en\" || LOCALE_LOADERS[lang]) continue;\n resources[lang] = { [REBASE_NS]: { ...en, ...overrides } };\n }\n return resources;\n}\n\n/**\n * An i18next backend over {@link LOCALE_LOADERS}. i18next asks it for a\n * language it has no bundle for, and `changeLanguage` (and `init`) wait for\n * the answer before switching — which is what keeps a half-loaded language\n * off the screen.\n *\n * A language Rebase does not ship answers with an empty table, synchronously,\n * so keys fall back to English at once. A chunk that fails to load (a deploy\n * replaced it under an open tab, say) is retried once by `loadChunk`; after\n * that i18next switches anyway and English fills in.\n */\nfunction createLocaleBackend(getOverrides: () => TranslationOverrides | undefined): BackendModule {\n return {\n type: \"backend\",\n init() {\n // nothing to configure\n },\n read(language, namespace, callback) {\n if (namespace !== REBASE_NS) {\n callback(null, {});\n return;\n }\n const cached = loadedTables[language];\n if (cached) {\n callback(null, { ...cached, ...getOverrides()?.[language] });\n return;\n }\n const loader = LOCALE_LOADERS[language];\n if (!loader) {\n callback(null, { ...getOverrides()?.[language] });\n return;\n }\n loadChunk(loader).then(\n table => {\n loadedTables[language] = table;\n callback(null, { ...table, ...getOverrides()?.[language] });\n },\n (error: unknown) => callback(error instanceof Error ? error : String(error), null)\n );\n }\n };\n}\n\n/**\n * The UI kit's own words (`@rebasepro/ui`'s list and card notices, the table's\n * error title, the search bar's names, relative dates) in the admin language.\n * The kit speaks English on its own; this fills its labels from the\n * translations, and refills them when the language changes.\n */\nfunction UiLabelsFromTranslations({ children }: PropsWithChildren) {\n // `t` changes identity with the language, so the labels follow it.\n const { t } = useTranslation();\n const labels = useMemo((): UiLabelsProviderProps[\"labels\"] => ({\n errorLoadingData: (message) => t(\"error_loading_data_message\", { message }),\n noEntriesFound: t(\"no_entries_found\"),\n allEntriesLoaded: (count) => t(\"all_entries_loaded\", { count }),\n error: t(\"error\"),\n search: t(\"search\"),\n clearSearch: t(\"clear_search\"),\n select: t(\"select\"),\n openTimePicker: t(\"open_time_picker\"),\n relativeTime: {\n justNow: t(\"relative_just_now\"),\n inAMoment: t(\"relative_in_a_moment\"),\n minutesAgo: (count) => t(\"relative_minutes_ago\", { count }),\n inMinutes: (count) => t(\"relative_in_minutes\", { count }),\n hoursAgo: (count) => t(\"relative_hours_ago\", { count }),\n inHours: (count) => t(\"relative_in_hours\", { count }),\n daysAgo: (count) => t(\"relative_days_ago\", { count }),\n inDays: (count) => t(\"relative_in_days\", { count })\n }\n }), [t]);\n return <UiLabelsProvider labels={labels}>{children}</UiLabelsProvider>;\n}\n","import React from \"react\";\nimport { CheckIcon, IconButton, iconSize, LanguagesIcon, Menu, MenuItem, Typography } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks\";\nimport { useRebaseLocales } from \"../i18n/RebaseI18nProvider\";\n\n/** The shipped languages, each named in itself. */\nconst LANGUAGE_NAMES: Record<string, string> = {\n en: \"English\",\n es: \"Español\",\n de: \"Deutsch\",\n fr: \"Français\",\n it: \"Italiano\",\n hi: \"हिन्दी\",\n pt: \"Português\"\n};\n\n/**\n * A language's name in that language. One Rebase does not ship is named by\n * the browser (`nl` → \"Nederlands\"), and by its code when the browser cannot.\n */\nexport function languageName(locale: string): string {\n const known = LANGUAGE_NAMES[locale];\n if (known) return known;\n try {\n const name = new Intl.DisplayNames([locale], { type: \"language\" }).of(locale);\n if (name && name !== locale) return name.charAt(0).toLocaleUpperCase(locale) + name.slice(1);\n } catch {\n // not a valid language tag\n }\n return locale;\n}\n\n/**\n * The language menu: every language the admin can be shown in, which is the\n * shipped ones plus any the app adds through `<Rebase translations>`.\n */\nexport function LanguageToggle() {\n const { t, i18n } = useTranslation();\n const locales = useRebaseLocales();\n\n return (\n <Menu\n trigger={<IconButton\n aria-label={t(\"change_language\")}>\n <LanguagesIcon size={iconSize.small}/>\n </IconButton>}>\n {locales.map(locale => (\n <MenuItem key={locale} onClick={() => i18n.changeLanguage(locale)}>\n <div className=\"flex w-full items-center justify-between gap-4\">\n <Typography variant=\"body2\" className={i18n.language === locale ? \"font-semibold\" : \"\"}>\n {languageName(locale)}\n </Typography>\n {i18n.language === locale && <CheckIcon size={iconSize.small}/>}\n </div>\n </MenuItem>\n ))}\n </Menu>\n );\n}\n","\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n CircleUserIcon,\n CircularProgress,\n cls,\n defaultBorderMixin,\n IconButton,\n iconSize,\n Popover,\n SearchBar,\n SearchIcon,\n Typography,\n XIcon\n} from \"@rebasepro/ui\";\nimport { User } from \"@rebasepro/types\";\n\n/**\n * Represents a selectable user item with optional role information.\n */\nexport interface SelectableUser {\n uid: string;\n displayName?: string | null;\n email?: string | null;\n photoURL?: string | null;\n roles?: string[];\n}\n\nexport interface UserSelectPopoverProps {\n /**\n * The currently selected user, or `null` for \"self\"/default.\n */\n selectedUser: SelectableUser | null;\n /**\n * Called when the user selection changes.\n * `null` means \"reset to self/default\".\n */\n onUserSelected: (user: SelectableUser | null) => void;\n /**\n * Full list of users to display.\n * The component handles client-side search/filter internally.\n */\n users: SelectableUser[];\n /**\n * Whether users are currently loading.\n */\n loading?: boolean;\n /**\n * Called with the search text each time it changes (debounced), for a\n * parent that searches its users on a server rather than passing them all\n * in `users`. The list is still filtered here by the same text.\n */\n onSearchTextChange?: (searchText: string) => void;\n /**\n * For a parent that lists only the first page of a server search: how many\n * users that search matched in all. Leave it out when `users` holds every\n * match. When set, the header counts the listed users against it and a\n * notice says the others are not listed.\n */\n totalCount?: number;\n /**\n * The current user (displayed as the \"self\" option at the top).\n */\n currentUser?: SelectableUser | null;\n /**\n * Label to display when no user is selected.\n * @default \"Current user\"\n */\n defaultLabel?: string;\n /**\n * Maximum number of users to render at a time (for performance).\n * Users can still be found via search.\n * @default 100\n */\n renderLimit?: number;\n /**\n * Additional class name for the trigger button.\n */\n className?: string;\n /**\n * Size variant.\n * @default \"small\"\n */\n size?: \"small\" | \"medium\";\n}\n\nconst ITEM_HEIGHT = 44;\nconst MAX_VISIBLE_ITEMS = 7;\n\n/**\n * A reusable user picker popover with search support.\n * Designed to handle very large user lists (100k+) by filtering\n * client-side and limiting the rendered set.\n *\n * @group Components\n */\nexport function UserSelectPopover({\n selectedUser,\n onUserSelected,\n users,\n loading = false,\n onSearchTextChange,\n totalCount,\n currentUser,\n defaultLabel = \"Current user\",\n renderLimit = 100,\n className,\n size = \"small\"\n}: UserSelectPopoverProps) {\n const [open, setOpen] = useState(false);\n const [searchText, setSearchText] = useState(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n // Effective user label for the trigger\n const effectiveUserLabel = selectedUser\n ? (selectedUser.displayName || selectedUser.email || selectedUser.uid)\n : (currentUser?.displayName || currentUser?.email || defaultLabel);\n\n // Filter users based on search text\n const filteredUsers = useMemo(() => {\n const query = searchText.trim().toLowerCase();\n const base = users.filter(u => u.uid !== currentUser?.uid);\n\n if (!query) return base.slice(0, renderLimit);\n\n const matched = base.filter(u => {\n const name = (u.displayName || \"\").toLowerCase();\n const email = (u.email || \"\").toLowerCase();\n const uid = u.uid.toLowerCase();\n const roles = (u.roles || []).join(\" \").toLowerCase();\n return (\n name.includes(query) ||\n email.includes(query) ||\n uid.includes(query) ||\n roles.includes(query)\n );\n });\n\n return matched.slice(0, renderLimit);\n }, [users, currentUser?.uid, searchText, renderLimit]);\n\n const totalFilterable = useMemo(() => {\n const query = searchText.trim().toLowerCase();\n const base = users.filter(u => u.uid !== currentUser?.uid);\n if (!query) return base.length;\n return base.filter(u => {\n const name = (u.displayName || \"\").toLowerCase();\n const email = (u.email || \"\").toLowerCase();\n const uid = u.uid.toLowerCase();\n const roles = (u.roles || []).join(\" \").toLowerCase();\n return name.includes(query) || email.includes(query) || uid.includes(query) || roles.includes(query);\n }).length;\n }, [users, currentUser?.uid, searchText]);\n\n const handleSelect = useCallback((user: SelectableUser | null) => {\n onUserSelected(user);\n setOpen(false);\n setSearchText(\"\");\n }, [onUserSelected]);\n\n const handleOpenChange = useCallback((isOpen: boolean) => {\n setOpen(isOpen);\n if (isOpen) {\n // Auto-focus the search input when opening\n setTimeout(() => inputRef.current?.focus(), 50);\n } else {\n setSearchText(\"\");\n }\n }, []);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") {\n setOpen(false);\n setSearchText(\"\");\n }\n }, []);\n\n const listHeight = Math.min(\n (filteredUsers.length + 1) * ITEM_HEIGHT, // +1 for the \"self\" option\n MAX_VISIBLE_ITEMS * ITEM_HEIGHT\n );\n\n return (\n <Popover\n open={open}\n onOpenChange={handleOpenChange}\n side=\"bottom\"\n align=\"end\"\n sideOffset={4}\n trigger={\n <button\n className={cls(\n \"flex items-center gap-1.5 text-xs font-medium transition-colors rounded border border-transparent\",\n \"text-text-secondary dark:text-text-secondary-dark\",\n \"hover:text-text-primary dark:hover:text-text-primary-dark\",\n \"bg-surface-raised hover:bg-surface-raised-hover\",\n size === \"small\" ? \"px-2 py-1\" : \"px-3 py-1.5\",\n className\n )}\n >\n {selectedUser?.photoURL ? (\n <img\n src={selectedUser.photoURL}\n alt=\"\"\n className=\"w-4 h-4 rounded-full object-cover\"\n />\n ) : (\n <svg\n className=\"w-3.5 h-3.5 text-text-disabled dark:text-text-disabled-dark\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\"\n />\n </svg>\n )}\n <span className=\"max-w-[120px] truncate\">{effectiveUserLabel}</span>\n {selectedUser && (\n <span className=\"text-[9px] text-amber-600 dark:text-amber-400 font-semibold uppercase\">\n impersonating\n </span>\n )}\n <svg className=\"w-3 h-3 opacity-50 ml-0.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\"/>\n </svg>\n </button>\n }\n >\n <div\n className=\"flex flex-col w-[320px] max-w-[90vw] overflow-hidden\"\n onKeyDown={handleKeyDown}\n >\n {/* Header */}\n <div className={cls(\"px-3 py-2 border-b flex items-center justify-between shrink-0\", defaultBorderMixin)}>\n <Typography\n variant=\"caption\"\n className=\"font-semibold uppercase tracking-wider text-[9px] text-text-disabled dark:text-text-disabled-dark\"\n >\n Run as user\n </Typography>\n {users.length > 0 && (\n <Typography\n variant=\"caption\"\n className=\"text-[9px] text-text-disabled dark:text-text-disabled-dark tabular-nums\"\n >\n {totalCount !== undefined\n ? `${filteredUsers.length} of ${totalCount} users`\n : `${totalFilterable} user${totalFilterable !== 1 ? \"s\" : \"\"}`}\n </Typography>\n )}\n </div>\n\n {/* Search input */}\n <div className={cls(\"px-2 py-1.5 border-b shrink-0\", defaultBorderMixin)}>\n <SearchBar\n inputRef={inputRef}\n size=\"smallest\"\n placeholder=\"Search by name, email, or role…\"\n onTextSearch={(val) => {\n setSearchText(val ?? \"\");\n onSearchTextChange?.(val ?? \"\");\n }}\n />\n </div>\n\n {/* User list */}\n <div\n ref={listRef}\n className=\"overflow-y-auto overscroll-contain\"\n style={{ maxHeight: MAX_VISIBLE_ITEMS * ITEM_HEIGHT }}\n >\n {/* Self (default) option — always shown unless search hides it */}\n {currentUser && (!searchText.trim() || matchesSearch(currentUser, searchText)) && (\n <UserRow\n user={currentUser}\n isSelected={!selectedUser}\n isSelf\n onClick={() => handleSelect(null)}\n />\n )}\n\n {/* Loading state */}\n {loading && (\n <div className=\"flex items-center justify-center py-6\">\n <CircularProgress size=\"small\"/>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && filteredUsers.length === 0 && searchText.trim() && (\n <div className=\"flex flex-col items-center justify-center py-6 px-4\">\n <Typography variant=\"caption\" className=\"text-text-disabled dark:text-text-disabled-dark text-center\">\n No users matching &ldquo;{searchText}&rdquo;\n </Typography>\n </div>\n )}\n\n {/* User items */}\n {!loading && filteredUsers.map(user => (\n <UserRow\n key={user.uid}\n user={user}\n isSelected={selectedUser?.uid === user.uid}\n onClick={() => handleSelect(user)}\n />\n ))}\n\n {/* The parent listed only the first page of its server search */}\n {!loading && totalCount !== undefined && (\n <div className={cls(\"px-3 py-2 border-t text-center\", defaultBorderMixin)}>\n <Typography\n variant=\"caption\"\n className=\"text-[10px] text-text-disabled dark:text-text-disabled-dark\"\n >\n Showing the first {filteredUsers.length} of {totalCount} users. Search to find the others.\n </Typography>\n </div>\n )}\n\n {/* Truncation notice */}\n {!loading && totalCount === undefined && totalFilterable > renderLimit && (\n <div className={cls(\"px-3 py-2 border-t text-center\", defaultBorderMixin)}>\n <Typography\n variant=\"caption\"\n className=\"text-[10px] text-text-disabled dark:text-text-disabled-dark\"\n >\n Showing {renderLimit} of {totalFilterable} results. Use search to narrow down.\n </Typography>\n </div>\n )}\n </div>\n </div>\n </Popover>\n );\n}\n\n// ─── Internal Components ─────────────────────────────────────────────\n\ninterface UserRowProps {\n user: SelectableUser;\n isSelected: boolean;\n isSelf?: boolean;\n onClick: () => void;\n}\n\nfunction UserRow({ user, isSelected, isSelf, onClick }: UserRowProps) {\n return (\n <button\n onClick={onClick}\n className={cls(\n \"w-full flex items-center gap-2.5 px-3 py-2 text-left transition-colors\",\n \"hover:bg-surface-hover\",\n isSelected && \"bg-primary/5 dark:bg-primary-dark/10\"\n )}\n style={{ minHeight: ITEM_HEIGHT }}\n >\n {/* Avatar */}\n {user.photoURL ? (\n <img\n src={user.photoURL}\n alt=\"\"\n className=\"w-7 h-7 rounded-full object-cover shrink-0\"\n />\n ) : (\n <div className=\"w-7 h-7 rounded-full bg-surface-raised flex items-center justify-center shrink-0\">\n <CircleUserIcon\n size={iconSize.smallest}\n className=\"text-text-disabled dark:text-text-disabled-dark\"\n />\n </div>\n )}\n\n {/* User info */}\n <div className=\"flex flex-col min-w-0 flex-grow\">\n <div className=\"flex items-center gap-1.5\">\n <span\n className={cls(\n \"text-xs font-medium truncate\",\n isSelected\n ? \"text-primary dark:text-primary-dark\"\n : \"text-text-primary dark:text-text-primary-dark\"\n )}\n >\n {user.displayName || user.email || user.uid}\n </span>\n {isSelf && (\n <span className=\"text-[9px] text-text-disabled dark:text-text-disabled-dark font-medium shrink-0\">\n (you)\n </span>\n )}\n </div>\n {(user.email || user.roles?.length) && (\n <span className=\"text-[10px] text-text-disabled dark:text-text-disabled-dark truncate\">\n {user.email && user.displayName ? user.email : \"\"}\n {user.email && user.displayName && user.roles?.length ? \" · \" : \"\"}\n {user.roles?.length ? user.roles.join(\", \") : \"\"}\n </span>\n )}\n </div>\n\n {/* Selection indicator */}\n {isSelected && (\n <svg\n className=\"w-4 h-4 text-primary dark:text-primary-dark shrink-0\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2.5} d=\"M5 13l4 4L19 7\"/>\n </svg>\n )}\n </button>\n );\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────\n\nfunction matchesSearch(user: SelectableUser, searchText: string): boolean {\n const query = searchText.trim().toLowerCase();\n if (!query) return true;\n const name = (user.displayName || \"\").toLowerCase();\n const email = (user.email || \"\").toLowerCase();\n const uid = user.uid.toLowerCase();\n return name.includes(query) || email.includes(query) || uid.includes(query);\n}\n","import { CircleUserIcon, cls, defaultBorderMixin } from \"@rebasepro/ui\";\nimport { User } from \"@rebasepro/types\";\n\n/**\n * Component to render a single user with name and email\n */\nexport function UserDisplay({\n user\n}: { user: User | null }) {\n if (!user) {\n return <span className={cls(\"italic\", \"text-text-disabled dark:text-text-disabled-dark\", \"text-sm\")}>Not set</span>;\n }\n\n const avatarSizeClass = \"w-6 h-6\";\n\n return (\n <div className={cls(\n \"inline-flex items-center gap-4 px-2 py-1 rounded-xl text-left max-w-full overflow-hidden\",\n \"bg-surface-raised\",\n \"border\",\n defaultBorderMixin\n )}>\n {user.photoURL ? (\n <img\n src={user.photoURL}\n alt={user.displayName || user.email || \"User\"}\n className={cls(\n \"rounded-full object-cover\",\n avatarSizeClass\n )}\n />\n ) : (\n <CircleUserIcon\n className={cls(\n \"text-text-secondary dark:text-text-secondary-dark\",\n avatarSizeClass\n )}\n />\n )}\n <div className=\"flex flex-col min-w-0\">\n <span className={cls(\"font-regular truncate\", \"text-sm\")}>\n {user.displayName || user.email || \"-\"}\n </span>\n {user.displayName && user.email && (\n <span className={cls(\"text-text-secondary dark:text-text-secondary-dark truncate\",\n \"text-xs\"\n )}>\n {user.email}\n </span>\n )}\n </div>\n </div>\n );\n}\n","/**\n * The browser half of the OAuth authorization-code flow.\n *\n * The server only ever sees a `code` and a `redirectUri` taken from the\n * request body, so `state`, PKCE and the binding between \"this browser started\n * a login\" and \"this code came back\" are, by construction, the client's job.\n * In the admin login they had been nobody's job: the authorize URL carried no\n * `state`, and the return leg accepted any `?code=` as long as a localStorage\n * marker naming the *provider* was set — a marker written on button click and\n * removed only on a callback that carried a code, so abandoning the flow left\n * it set indefinitely.\n *\n * Everything here is provider-agnostic on purpose. A button that wants a new\n * provider calls {@link startOAuthRedirect} and gets state, expiry and PKCE\n * without deciding anything, which is what stops the next provider shipping\n * without them.\n */\n\n/** sessionStorage, not localStorage: a login attempt belongs to one tab. */\nconst STORAGE_KEY = \"rebase_oauth_redirect\";\n\n/** How long a started authorization stays valid. */\nconst PENDING_TTL_MS = 10 * 60 * 1000;\n\nexport interface OAuthRedirectRequest {\n /** Provider id, as mounted at `POST /auth/<id>`. */\n provider: string;\n /** The provider's authorization endpoint. */\n authorizeUrl: string;\n clientId: string;\n scope: string;\n /** Where the provider sends the browser back. Echoed to the token exchange. */\n redirectUri: string;\n /** Set when the provider implements PKCE. */\n pkce?: boolean;\n /** Extra authorize-endpoint parameters (`response_type`, and so on). */\n params?: Record<string, string>;\n}\n\n/** What the browser remembers between leaving for the provider and coming back. */\nexport interface PendingOAuthRedirect {\n provider: string;\n state: string;\n codeVerifier?: string;\n redirectUri: string;\n startedAt: number;\n}\n\nexport type OAuthCallbackResult =\n /** No OAuth callback in this URL. */\n | { status: \"none\" }\n /** The provider reported a failure, or the user declined. */\n | { status: \"error\"; error: string }\n /**\n * A code arrived that this browser cannot account for: no pending\n * authorization, an expired one, or a `state` that does not match. This is\n * what a login-CSRF / code-injection attempt looks like.\n */\n | { status: \"mismatch\" }\n | { status: \"ok\"; provider: string; code: string; codeVerifier?: string; redirectUri: string };\n\ntype Storage = Pick<globalThis.Storage, \"getItem\" | \"setItem\" | \"removeItem\">;\n\nfunction defaultStorage(): Storage | null {\n try {\n return window.sessionStorage;\n } catch {\n return null;\n }\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction randomToken(byteLength = 32): string {\n const bytes = new Uint8Array(byteLength);\n crypto.getRandomValues(bytes);\n return base64Url(bytes);\n}\n\nasync function pkceChallenge(verifier: string): Promise<string> {\n const digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(verifier));\n return base64Url(new Uint8Array(digest));\n}\n\nexport function readPendingOAuthRedirect(storage: Storage | null = defaultStorage()): PendingOAuthRedirect | null {\n if (!storage) return null;\n const raw = storage.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as PendingOAuthRedirect;\n if (!parsed?.provider || !parsed?.state) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function clearPendingOAuthRedirect(storage: Storage | null = defaultStorage()): void {\n storage?.removeItem(STORAGE_KEY);\n}\n\n/**\n * Build the authorize URL and the pending record that will validate its\n * callback. Split out from {@link startOAuthRedirect} so it can be tested\n * without navigating.\n */\nexport async function buildOAuthAuthorization(\n request: OAuthRedirectRequest,\n now: number = Date.now()\n): Promise<{ url: string; pending: PendingOAuthRedirect }> {\n const state = randomToken();\n const url = new URL(request.authorizeUrl);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", request.clientId);\n url.searchParams.set(\"redirect_uri\", request.redirectUri);\n url.searchParams.set(\"scope\", request.scope);\n url.searchParams.set(\"state\", state);\n for (const [key, value] of Object.entries(request.params ?? {})) {\n url.searchParams.set(key, value);\n }\n\n let codeVerifier: string | undefined;\n if (request.pkce) {\n codeVerifier = randomToken(32);\n url.searchParams.set(\"code_challenge\", await pkceChallenge(codeVerifier));\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n }\n\n return {\n url: url.toString(),\n pending: { provider: request.provider, state, codeVerifier, redirectUri: request.redirectUri, startedAt: now }\n };\n}\n\n/** Remember the authorization and send the browser to the provider. */\nexport async function startOAuthRedirect(\n request: OAuthRedirectRequest,\n storage: Storage | null = defaultStorage()\n): Promise<void> {\n const { url, pending } = await buildOAuthAuthorization(request);\n storage?.setItem(STORAGE_KEY, JSON.stringify(pending));\n window.location.href = url;\n}\n\n/**\n * Interpret a return from the provider.\n *\n * Clears the pending record on **every** path that saw a callback — including\n * `?error=` and a state mismatch — so a declined or abandoned consent screen\n * cannot leave the browser primed to accept somebody else's code later.\n */\nexport function consumeOAuthCallback(\n search: string,\n storage: Storage | null = defaultStorage(),\n now: number = Date.now()\n): OAuthCallbackResult {\n const params = new URLSearchParams(search);\n const code = params.get(\"code\");\n const state = params.get(\"state\");\n const error = params.get(\"error\");\n\n if (!code && !error && !state) return { status: \"none\" };\n\n const pending = readPendingOAuthRedirect(storage);\n clearPendingOAuthRedirect(storage);\n\n if (error) return { status: \"error\", error };\n if (!code) return { status: \"mismatch\" };\n if (!pending) return { status: \"mismatch\" };\n if (now - pending.startedAt > PENDING_TTL_MS) return { status: \"mismatch\" };\n if (!state || state !== pending.state) return { status: \"mismatch\" };\n\n return {\n status: \"ok\",\n provider: pending.provider,\n code,\n codeVerifier: pending.codeVerifier,\n redirectUri: pending.redirectUri\n };\n}\n","/**\n * What the login screen says about a refused sign-in.\n *\n * The server's message is written for whoever reads the API response, and some\n * of them are instructions for a developer. A Google sign-in onto an address\n * that already has an unverified password account used to put this in front of\n * the visitor:\n *\n * … Sign in with your existing method, then POST to /auth/link/google to\n * link google to your account.\n *\n * So the codes a person can act on get the screen's own, translated words, and\n * every other error keeps the server's message, which is still the most\n * specific thing there is to show.\n */\nexport function authErrorMessage(error: unknown, t: (key: string) => string): string {\n if (error instanceof Error && \"code\" in error && error.code === \"EMAIL_NOT_VERIFIED\") {\n // `local-account-unverified` is the one reason that says how the\n // existing account signs in: it holds a password.\n const reason = \"details\" in error && typeof error.details === \"object\" && error.details !== null\n && \"reason\" in error.details\n ? error.details.reason\n : undefined;\n return reason === \"local-account-unverified\"\n ? t(\"auth_account_exists_sign_in_with_password\")\n : t(\"auth_account_exists_with_different_credential\");\n }\n // Confirm-first registration: the password is right, the address is not\n // confirmed yet, and a new link is on its way.\n if (error instanceof Error && \"code\" in error && error.code === \"EMAIL_NOT_CONFIRMED\") {\n return t(\"auth_email_not_confirmed\");\n }\n return error instanceof Error ? error.message : String(error);\n}\n","/**\n * The links the backend puts in its auth emails, as the login view reads them.\n *\n * The server builds them from the configured frontend URL:\n * `<frontend>/reset-password?token=…` for a forgotten password, an admin's\n * \"send reset email\" and every invitation, `<frontend>/verify-email?token=…`\n * to confirm an address, `<frontend>/confirm-email-change?token=…` to move an\n * account to a new one, and `<frontend>/auth/magic-link?token=…` to sign in.\n * The frontend URL may carry a base path (`/admin`), so the action is read off\n * the *end* of the path, not the whole path.\n */\nexport type EmailLinkAction =\n | { kind: \"reset-password\"; token: string }\n | { kind: \"verify-email\"; token: string }\n | { kind: \"confirm-email-change\"; token: string }\n | { kind: \"magic-link\"; token: string };\n\n/** Each action, and the path it ends with. A magic link's is two segments. */\nconst ACTIONS: { kind: EmailLinkAction[\"kind\"]; path: string }[] = [\n { kind: \"reset-password\", path: \"/reset-password\" },\n { kind: \"verify-email\", path: \"/verify-email\" },\n { kind: \"confirm-email-change\", path: \"/confirm-email-change\" },\n { kind: \"magic-link\", path: \"/auth/magic-link\" }\n];\n\nexport function readEmailLinkAction(location: { pathname: string; search: string }): EmailLinkAction | null {\n const token = new URLSearchParams(location.search).get(\"token\");\n if (!token) return null;\n const pathname = location.pathname.replace(/\\/+$/, \"\");\n const action = ACTIONS.find(({ path }) => pathname.endsWith(path));\n return action ? { kind: action.kind, token } : null;\n}\n\n/**\n * Where the app lives: the link's own address without the action's path and\n * its token. `/admin/reset-password?token=…` becomes `/admin/`, and\n * `/admin/auth/magic-link?token=…` too.\n */\nexport function appAddressOfEmailLink(location: { origin: string; pathname: string }): string {\n const pathname = location.pathname.replace(/\\/+$/, \"\");\n const action = ACTIONS.find(({ path }) => pathname.endsWith(path));\n const withoutAction = action\n ? pathname.slice(0, pathname.length - action.path.length)\n : pathname.replace(/\\/[^/]*$/, \"\");\n return `${location.origin}${withoutAction}/`;\n}\n","import type { AuthControllerExtended, MfaFactorSummary } from \"@rebasepro/cms-types\";\n\n/**\n * A sign-in that is waiting for its second factor.\n *\n * The server refuses the first factor of an account with MFA enrolled with\n * `401 MFA_REQUIRED`, and puts in `details` what the second step needs: a\n * pending token, good for five minutes and for the two challenge routes only,\n * and the factors the account can answer with.\n */\nexport interface PendingMfaSignIn {\n mfaToken: string;\n factors: MfaFactorSummary[];\n}\n\nfunction isFactor(value: unknown): value is MfaFactorSummary {\n return typeof value === \"object\" && value !== null\n && \"id\" in value && typeof value.id === \"string\" && value.id.length > 0\n && \"factorType\" in value && typeof value.factorType === \"string\";\n}\n\n/**\n * The pending sign-in an `MFA_REQUIRED` refusal describes, or `null` for any\n * other error — including an `MFA_REQUIRED` without the token or a factor to\n * answer with, which no code step could finish.\n */\nexport function readMfaRequired(error: unknown): PendingMfaSignIn | null {\n if (!(error instanceof Error) || !(\"code\" in error) || error.code !== \"MFA_REQUIRED\") return null;\n const details = \"details\" in error ? error.details : undefined;\n if (typeof details !== \"object\" || details === null) return null;\n const mfaToken = \"mfaToken\" in details ? details.mfaToken : undefined;\n const factors = \"factors\" in details && Array.isArray(details.factors) ? details.factors.filter(isFactor) : [];\n if (typeof mfaToken !== \"string\" || !mfaToken || factors.length === 0) return null;\n return { mfaToken, factors };\n}\n\n/** Whether this controller can take a sign-in through its second step. */\nexport function canAnswerMfa(authController: AuthControllerExtended): boolean {\n return Boolean(authController.startMfaChallenge && authController.verifyMfaChallenge);\n}\n\n/**\n * What a refused challenge means for the code step.\n *\n * - `invalid-code`: the code was wrong; the same challenge takes another.\n * - `exhausted`: the challenge has had its five attempts; the next code needs\n * a new one.\n * - `expired`: the sign-in itself is over. The pending token lasts five\n * minutes from the password, and once it has lapsed both routes refuse the\n * caller as unauthenticated; a challenge that lapsed, or a sign-in revoked\n * meanwhile, ends the same way. Only a new sign-in gets a new token.\n */\nexport function classifyMfaRefusal(error: unknown): \"invalid-code\" | \"exhausted\" | \"expired\" | \"other\" {\n if (!(error instanceof Error)) return \"other\";\n const code = \"code\" in error && typeof error.code === \"string\" ? error.code : undefined;\n const status = \"status\" in error && typeof error.status === \"number\" ? error.status : undefined;\n if (code === \"INVALID_CODE\") return \"invalid-code\";\n if (code === \"CHALLENGE_EXHAUSTED\") return \"exhausted\";\n if (code === \"INVALID_CHALLENGE\" || code === \"SESSION_REVOKED\") return \"expired\";\n if (status === 401 && (code === undefined || code === \"UNAUTHORIZED\")) return \"expired\";\n return \"other\";\n}\n","import React, { ReactNode, useCallback, useEffect, useId, useRef, useState } from \"react\";\n\n/** Google Identity Services SDK — injected by the GIS <script> tag. */\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n oauth2: {\n initCodeClient(config: {\n client_id: string;\n scope: string;\n ux_mode: \"popup\" | \"redirect\";\n callback: (response: { code?: string; error?: string }) => void;\n }): { requestCode(): void };\n };\n };\n };\n }\n}\n\nimport {\n ArrowLeftIcon,\n Button,\n CheckCircle2Icon,\n Checkbox,\n CircularProgress,\n cls,\n IconButton,\n iconSize,\n LoadingButton,\n MailIcon,\n Menu,\n MenuItem,\n MoonIcon,\n Select,\n SelectItem,\n SunIcon,\n SunMoonIcon,\n TextField,\n Typography,\n isKeyHandled\n} from \"@rebasepro/ui\";\nimport { User } from \"@rebasepro/types\";\nimport { AuthControllerExtended, MfaFactorSummary } from \"@rebasepro/cms-types\";\nimport { ErrorView } from \"../ErrorView\";\nimport { RebaseLogo } from \"../RebaseLogo\";\nimport { LanguageToggle } from \"../LanguageToggle\";\nimport { useModeController, useTranslation } from \"../../hooks\";\nimport { consumeOAuthCallback, startOAuthRedirect } from \"./oauth-redirect-flow\";\nimport { authErrorMessage } from \"./auth-error-message\";\nimport { appAddressOfEmailLink, readEmailLinkAction } from \"./email-link\";\nimport { emailChangeErrorMessage } from \"../email-change-message\";\nimport { canAnswerMfa, classifyMfaRefusal, PendingMfaSignIn, readMfaRequired } from \"./mfa-required\";\n\n/**\n * Props for the generic LoginView.\n * Consumes {@link AuthControllerExtended} — works with any backend\n * (Rebase custom backend, Firebase, etc.)\n */\nexport interface LoginViewProps {\n /**\n * Auth controller — must implement AuthControllerExtended.\n */\n authController: AuthControllerExtended;\n\n /**\n * Path to the logo displayed in the login screen\n */\n logo?: string;\n\n /**\n * Enable the skip login button\n */\n allowSkipLogin?: boolean;\n\n /**\n * Disable the login buttons\n */\n disabled?: boolean;\n\n /**\n * Prevent users from creating new accounts.\n * If not set, checks `authController.capabilities.registrationEnabled`.\n */\n disableSignupScreen?: boolean;\n\n /**\n * Display this component when no user is found\n */\n noUserComponent?: ReactNode;\n\n /**\n * Display this component below the sign-in buttons\n */\n additionalComponent?: ReactNode;\n\n /**\n * Display this component above the sign-in buttons\n */\n topComponent?: ReactNode;\n\n /**\n * Error message when user is not allowed access\n */\n notAllowedError?: string | Error;\n\n\n /**\n * Google client ID for Google OAuth.\n * Required when Google login is enabled via ID token flow.\n */\n googleClientId?: string;\n\n /**\n * GitHub client ID for GitHub OAuth.\n */\n githubClientId?: string;\n\n /**\n * LinkedIn client ID for LinkedIn OAuth.\n */\n linkedinClientId?: string;\n\n /**\n * Optional custom title shown above options\n */\n title?: string;\n\n /**\n * Optional custom subtitle shown above options\n */\n subtitle?: string;\n\n /**\n * When true, shows bootstrap/setup UI (first-user creation).\n * If not set, derived from `authController` if it exposes `needsSetup`.\n */\n needsSetup?: boolean;\n\n /**\n * Whether registration is enabled.\n * If not set, derived from `authController.capabilities.registrationEnabled`.\n */\n registrationEnabled?: boolean;\n\n /**\n * Pre-fill the email field (e.g. for demo or testing environments).\n */\n defaultEmail?: string;\n\n /**\n * Pre-fill the password field (e.g. for demo or testing environments).\n */\n defaultPassword?: string;\n\n /**\n * When set, a \"Join the newsletter\" opt-in checkbox is offered. Called with\n * the address that just authenticated — by any method — if the box was\n * ticked. Wire it to whatever stores the subscription; failures are the\n * callback's problem, the login flow never waits on it.\n *\n * The checkbox sits on the **provider screen**, beside the buttons that\n * choose how to sign in, rather than on the credentials form. It is a\n * decision about the visitor, not about the password: asking on the\n * credentials form put it in front of only the people who got that far by\n * typing an address, so anyone signing in with Google was never offered it\n * at all. Bootstrap mode is the exception — there is no provider screen\n * there, so the form keeps it.\n */\n onNewsletterOptIn?: (email: string) => void;\n}\n\ntype AuthMode = \"buttons\" | \"login\" | \"register\" | \"forgot\" | \"reset-password\" | \"verify-email\" | \"confirm-email-change\" | \"magic-link\";\n\n/**\n * The shared field background mixin (`dark:bg-black/30`) is invisible on the\n * near-black login card, so login inputs get an explicit border in dark mode.\n */\nconst loginFieldClasses = \"w-full dark:border dark:border-surface-700/70 dark:hover:border-surface-600\";\n\n/** One warning per provider per page load — this is a config hint, not a log stream. */\nconst warnedProviders = new Set<string>();\n\n/**\n * An OAuth button needs a client id in the frontend *and* the provider\n * configured on the backend. Half a configuration renders nothing at all, with\n * no error anywhere — the button simply is not there, which reads as \"the\n * feature broke\" rather than \"one env var is missing\". Say which half is\n * missing instead.\n */\nfunction warnAboutHalfConfiguredOAuth(\n provider: string,\n clientId: string | undefined,\n backendProviders: string[]\n) {\n const backendHasIt = backendProviders.includes(provider);\n if (Boolean(clientId) === backendHasIt) return; // both or neither — nothing to say\n if (warnedProviders.has(provider)) return;\n warnedProviders.add(provider);\n\n const envVar = `${provider.toUpperCase()}_CLIENT_ID`;\n console.warn(\n clientId\n ? `[Rebase] ${provider} login is hidden: the login view has a client id, but the backend reports no \"${provider}\" provider. `\n + `Set ${envVar} (and ${provider.toUpperCase()}_CLIENT_SECRET) on the server and restart it.`\n : `[Rebase] ${provider} login is hidden: the backend has a \"${provider}\" provider, but the login view was given no client id. `\n + `Pass it to the login view (e.g. VITE_${envVar}) and restart the frontend so the new env var is picked up.`\n );\n}\n\n/**\n * Whether a provider's error code means \"the visitor backed out\" rather than\n * \"the sign-in failed\". Closing the popup is an answer, not a fault, and\n * showing it in red reads as a broken login.\n */\nfunction isUserCancellation(code: string | undefined): boolean {\n if (!code) return false;\n return [\n \"access_denied\",\n \"popup_closed\",\n \"popup_closed_by_user\",\n \"user_cancel\",\n \"immediate_failed\"\n ].includes(code);\n}\n\n/**\n * The controller's last refused sign-in, as a sign-in screen should show it:\n * not at all once a user is present — a stale failure must not sit over a\n * screen that has since succeeded — and not at all for an `MFA_REQUIRED` this\n * view can take to its code step, where it is a cue rather than a failure.\n */\nfunction signInRefusal(authController: AuthControllerExtended): unknown {\n const error = authController.authProviderError;\n if (!error || authController.user) return null;\n if (canAnswerMfa(authController) && readMfaRequired(error)) return null;\n return error;\n}\n\n/**\n * Generic login view component that works with any AuthControllerExtended.\n * Feature-detects capabilities to show/hide login methods.\n * @group Core\n */\nexport function LoginView({\n logo,\n authController,\n noUserComponent,\n disableSignupScreen = false,\n disabled = false,\n notAllowedError,\n googleClientId,\n githubClientId,\n linkedinClientId,\n title,\n subtitle,\n needsSetup,\n registrationEnabled,\n additionalComponent,\n topComponent,\n defaultEmail,\n defaultPassword,\n onNewsletterOptIn\n}: LoginViewProps) {\n\n const modeState = useModeController();\n const { mode: colorMode, setMode: setColorMode } = modeState;\n const { t } = useTranslation();\n\n // A link from an auth email opens this screen on its own step: setting a\n // new password (a reset, or an invitation's first password) or confirming\n // an address. Read once — the token is spent by the step it opens.\n const [emailLink] = useState(() => typeof window === \"undefined\" ? null : readEmailLinkAction(window.location));\n const [mode, setMode] = useState<AuthMode>(emailLink?.kind ?? \"buttons\");\n const [fadeIn, setFadeIn] = useState(false);\n const [viewVisible, setViewVisible] = useState(true);\n // Failures that never reach the auth controller: a provider that answers the\n // popup with an error, a redirect whose `state` does not match, a Google\n // script that never loaded. The controller records everything it is *given*\n // in `authProviderError`, so it cannot speak for the half of the flow that\n // happens before the code reaches it.\n const [providerError, setProviderError] = useState<string | null>(null);\n // Lives here, not in LoginForm: the box is ticked on the provider screen\n // and read after a sign-in that happens one or two screens later, so it has\n // to outlive both. The form also unmounts on every login↔register switch.\n const [newsletterOptIn, setNewsletterOptIn] = useState(false);\n // A sign-in waiting for its second factor. Every sign-in method — the\n // email form, Google, an OAuth redirect — reports an `MFA_REQUIRED`\n // refusal through the controller, so this is taken from there rather\n // than from any one of them, and shown in place of whichever screen\n // started it. Back clears it and that screen is still there.\n const [pendingMfa, setPendingMfa] = useState<PendingMfaSignIn | null>(null);\n const mfaAnswerable = canAnswerMfa(authController);\n useEffect(() => {\n if (!mfaAnswerable || authController.user) return;\n const pending = readMfaRequired(authController.authProviderError);\n if (!pending) return;\n setProviderError(null);\n setPendingMfa(pending);\n }, [authController.authProviderError, authController.user, mfaAnswerable]);\n\n // A magic link has done its job once somebody is signed in: by its own\n // token, by the code step after it, or before it was ever opened. The app\n // starts at its own address, not at the link's — and an already signed-in\n // visitor does not spend the link at all.\n const signedIn = Boolean(authController.user);\n useEffect(() => {\n if (emailLink?.kind === \"magic-link\" && signedIn) leaveEmailLink();\n }, [emailLink, signedIn]);\n\n // The controller as of the latest render. A provider callback resolves long\n // after the click that started it, and the `authController` captured in that\n // closure is the one from the render that mounted the button — which, for a\n // controller replaced on each render, has no `user` on it yet.\n const authControllerRef = useRef(authController);\n authControllerRef.current = authController;\n\n /**\n * Subscribe the address that just authenticated, if the visitor asked for\n * it. Every sign-in path calls this, which is the point: the checkbox sits\n * beside the provider buttons, so it has to mean the same thing whichever\n * one is pressed.\n *\n * Only ever from a resolution path — a ticked box on a *failed* attempt\n * must not subscribe an address nobody proved they control.\n */\n const subscribeIfOptedIn = useCallback((email?: string | null) => {\n if (!newsletterOptIn || !onNewsletterOptIn || !email) return;\n onNewsletterOptIn(email);\n }, [newsletterOptIn, onNewsletterOptIn]);\n\n const switchMode = (newMode: AuthMode) => {\n // A message about the last Google attempt has nothing to say about the\n // email form the visitor just opened.\n setProviderError(null);\n setViewVisible(false);\n setTimeout(() => {\n setMode(newMode);\n setViewVisible(true);\n }, 150);\n };\n\n // Resolve capabilities — explicit props override authController.capabilities\n const caps = authController.capabilities ?? {};\n const isBootstrapMode = needsSetup\n ?? (\"needsSetup\" in authController && !!(authController as { needsSetup?: boolean }).needsSetup)\n ?? false;\n const canRegister = registrationEnabled ?? caps.registrationEnabled ?? false;\n // Every OAuth button needs BOTH halves: a client id here and the matching\n // provider configured on the backend. `enabledProviders` is always an array\n // (the controller defaults it to `[]`), so a missing entry means \"the\n // backend has no such provider\" — never \"unknown\". A client id on its own\n // shows nothing, which is silent enough that `warnAboutHalfConfiguredOAuth`\n // below says so out loud.\n const backendProviders = caps.enabledProviders ?? [];\n const hasGoogleLogin = Boolean(googleClientId) && backendProviders.includes(\"google\");\n const hasGitHubLogin = githubClientId && backendProviders.includes(\"github\");\n const hasLinkedinLogin = linkedinClientId && backendProviders.includes(\"linkedin\");\n\n useEffect(() => {\n // `enabledProviders` is empty until /auth/config lands, which looks\n // exactly like \"the backend has no providers\" — so wait for the value\n // to settle. A config that arrives late re-runs this effect and cancels\n // the pending warning.\n const timer = setTimeout(() => {\n warnAboutHalfConfiguredOAuth(\"google\", googleClientId, backendProviders);\n warnAboutHalfConfiguredOAuth(\"github\", githubClientId, backendProviders);\n warnAboutHalfConfiguredOAuth(\"linkedin\", linkedinClientId, backendProviders);\n }, 3000);\n return () => clearTimeout(timer);\n }, [googleClientId, githubClientId, linkedinClientId, backendProviders.join(\",\")]);\n const hasPasswordReset = caps.passwordReset ?? !!authController.forgotPassword;\n\n const showRegistration = !disableSignupScreen && canRegister;\n\n useEffect(() => {\n const timer = setTimeout(() => setFadeIn(true), 50);\n return () => clearTimeout(timer);\n }, []);\n\n // Effect to handle incoming redirect OAuth codes (GitHub, LinkedIn, etc.).\n //\n // The `code` is only spent when it belongs to an authorization this browser\n // started: `consumeOAuthCallback` matches the returned `state` against the\n // one generated at button-click time. Without that, an attacker who starts\n // their own authorization, captures the code and gets the victim to load\n // `?code=<theirs>` hands the victim a session on the *attacker's* account.\n useEffect(() => {\n const result = consumeOAuthCallback(window.location.search);\n if (result.status === \"none\") return;\n\n // Clear URL search params without page reload. The entry's state is\n // kept as it is: it is the router's `{ usr, key, idx }`, and an entry\n // without its index makes the next Back a navigation the router cannot\n // measure, which it lets through past every unsaved-changes blocker.\n const cleanUrl = window.location.origin + window.location.pathname;\n window.history.replaceState(window.history.state, document.title, cleanUrl);\n\n if (result.status === \"error\") {\n console.error(`OAuth sign-in failed: ${result.error}`);\n if (!isUserCancellation(result.error)) {\n setProviderError(`Sign-in failed: ${result.error}`);\n }\n return;\n }\n if (result.status === \"mismatch\") {\n console.error(\"Ignoring an OAuth code that does not match a sign-in this browser started.\");\n setProviderError(\"This sign-in could not be verified as one you started in this browser. Please try again.\");\n return;\n }\n\n if (authController.oauthLogin) {\n // The rejection is recorded in `authProviderError`, which the screen\n // renders — the catch is here so a shown error does not also surface\n // as an unhandled rejection.\n authController.oauthLogin(result.provider, {\n code: result.code,\n redirectUri: result.redirectUri,\n ...(result.codeVerifier ? { codeVerifier: result.codeVerifier } : {})\n }).catch((err: unknown) => {\n console.error(`${result.provider} login failed:`, err);\n });\n }\n }, [authController]);\n\n\n\n let logoComponent;\n if (logo) {\n logoComponent = <img src={logo}\n style={{\n height: \"100%\",\n width: \"100%\",\n objectFit: \"cover\"\n }}\n alt={\"Logo\"}/>;\n } else {\n logoComponent = <RebaseLogo/>;\n }\n\n // The controller's own record of the last rejected sign-in — see\n // `signInRefusal`. `LoginForm` renders the same value for the email path.\n const refusal = signInRefusal(authController);\n const controllerError = refusal ? authErrorMessage(refusal, t) : null;\n const buttonsErrorMessage = providerError ?? controllerError;\n\n let notAllowedMessage: string | undefined;\n if (notAllowedError) {\n if (typeof notAllowedError === \"string\") {\n notAllowedMessage = notAllowedError;\n } else if (notAllowedError instanceof Error) {\n notAllowedMessage = notAllowedError.message;\n } else {\n notAllowedMessage = \"It looks like you don't have access, based on the specified access configuration\";\n }\n }\n\n return (\n <div\n className={cls(\n \"relative flex items-center justify-center h-screen w-screen p-4 transition-opacity duration-500 bg-surface-frame overflow-hidden\",\n fadeIn ? \"opacity-100\" : \"opacity-0\"\n )}>\n\n {/* Top-right controls */}\n <div className=\"absolute top-4 right-4 flex items-center gap-1 z-10\">\n <LanguageToggle/>\n <Menu\n trigger={<IconButton\n aria-label=\"Toggle theme\">\n {colorMode === \"dark\"\n ? <MoonIcon size={iconSize.small}/>\n : <SunIcon size={iconSize.small}/>}\n </IconButton>}>\n <MenuItem onClick={() => setColorMode(\"dark\")}><MoonIcon size={iconSize.smallest}/> {t(\"dark_mode\")}</MenuItem>\n <MenuItem onClick={() => setColorMode(\"light\")}><SunIcon size={iconSize.smallest}/> {t(\"light_mode\")}</MenuItem>\n <MenuItem onClick={() => setColorMode(\"system\")}><SunMoonIcon size={iconSize.smallest}/> {t(\"system_mode\")}</MenuItem>\n </Menu>\n </div>\n\n <div className=\"relative flex flex-col items-center w-[440px] max-w-full p-8 sm:p-10 bg-surface-card/70 backdrop-blur-xl border border-hairline-strong rounded-2xl shadow-2xl z-10 transition-all duration-300 hover:shadow-primary/5\">\n {/* Logo */}\n <div className=\"w-24 h-24 m-2 mb-4 drop-shadow-md\">\n {logoComponent}\n </div>\n\n {notAllowedMessage && (\n <div className=\"p-4 w-full\">\n <ErrorView error={notAllowedMessage}/>\n </div>\n )}\n\n <div className={cls(\n \"w-full transition-opacity duration-150\",\n viewVisible ? \"opacity-100\" : \"opacity-0\"\n )}>\n\n {/* Bootstrap mode: show setup form directly */}\n {isBootstrapMode && !authController.user && (\n <LoginForm\n authController={authController}\n registrationMode={true}\n onClose={() => {}}\n onForgotPassword={() => {}}\n disableSignupScreen={false}\n bootstrapMode={true}\n defaultEmail={defaultEmail}\n defaultPassword={defaultPassword}\n onSignedIn={subscribeIfOptedIn}\n newsletterOptIn={newsletterOptIn}\n setNewsletterOptIn={setNewsletterOptIn}\n showNewsletterOptIn={Boolean(onNewsletterOptIn)}\n />\n )}\n\n {/* The second step of a sign-in, whichever screen began it */}\n {!isBootstrapMode && pendingMfa && (\n <MfaChallengeForm\n key={pendingMfa.mfaToken}\n pending={pendingMfa}\n authController={authController}\n onBack={() => setPendingMfa(null)}\n onSignedIn={() => subscribeIfOptedIn(authControllerRef.current.user?.email)}\n />\n )}\n\n {/* Normal mode */}\n {!isBootstrapMode && !pendingMfa && (\n <>\n {/* Provider buttons screen */}\n {mode === \"buttons\" && (\n <div className=\"w-full flex flex-col gap-3 mt-2\">\n {/* Every provider button fails here, and this\n screen used to render nothing for it: a\n refused Google sign-in closed the popup\n and returned the visitor to an unchanged\n login screen, with the reason only in the\n browser console. */}\n {buttonsErrorMessage && (\n <ErrorView error={buttonsErrorMessage}/>\n )}\n {(title || subtitle) && (\n <div className=\"text-center mb-2\">\n {title && (\n <Typography variant=\"h6\" className=\"mb-0.5 font-semibold\">\n {title}\n </Typography>\n )}\n {subtitle && (\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-4\">\n {subtitle}\n </Typography>\n )}\n </div>\n )}\n {topComponent && (\n <div className=\"w-full\">\n {topComponent}\n </div>\n )}\n {/* Above the buttons, not below them: it is a\n condition on the sign-in you are about to\n make, and it reads as one more line of the\n consent block a host puts in\n `topComponent` — the demo's privacy tick\n sits directly above it.\n\n Which is why it pulls back most of the\n column's `gap-3`: at the full gap the two\n ticks sat 24px apart and read as two\n unrelated questions rather than one\n consent block. The offset is against this\n column's own gap, not against whatever\n margins the host's `topComponent` happens\n to carry, so it lands the same way under\n any of them — but only when there is\n something above to hug. With no header\n and no `topComponent` this row is the\n column's first child, and pulling back a\n gap that is not there would crowd it into\n the logo. */}\n {onNewsletterOptIn && (\n <label className={cls(\n \"flex items-center gap-2 cursor-pointer\",\n (topComponent || title || subtitle) && \"-mt-3\"\n )}>\n <Checkbox\n checked={newsletterOptIn}\n onCheckedChange={(checked) => setNewsletterOptIn(checked === true)}\n size=\"small\"\n />\n <Typography variant=\"caption\" color=\"secondary\" className=\"select-none\">\n {t(\"join_newsletter\")}\n </Typography>\n </label>\n )}\n <LoginButton\n disabled={disabled}\n text={\"Sign in with email\"}\n icon={<MailIcon/>}\n onClick={() => switchMode(\"login\")}\n />\n {hasGoogleLogin && googleClientId && (\n <GoogleLoginButton\n disabled={disabled}\n googleClientId={googleClientId}\n authController={authController}\n onSignedIn={() => subscribeIfOptedIn(authControllerRef.current.user?.email)}\n onError={setProviderError}\n />\n )}\n {hasGitHubLogin && githubClientId && (\n <GitHubLoginButton\n disabled={disabled}\n githubClientId={githubClientId}\n />\n )}\n {hasLinkedinLogin && linkedinClientId && (\n <LinkedInLoginButton\n disabled={disabled}\n linkedinClientId={linkedinClientId}\n />\n )}\n {showRegistration && (\n <div className=\"mt-2 text-center\">\n <Typography variant=\"body2\" color=\"secondary\">\n Don&apos;t have an account?{\" \"}\n <button\n type=\"button\"\n className=\"font-semibold hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={() => switchMode(\"register\")}\n >\n Create one\n </button>\n </Typography>\n </div>\n )}\n </div>\n )}\n\n {/* Login form */}\n {mode === \"login\" && (\n <LoginForm\n authController={authController}\n registrationMode={false}\n onClose={() => switchMode(\"buttons\")}\n onForgotPassword={hasPasswordReset ? () => switchMode(\"forgot\") : undefined}\n noUserComponent={noUserComponent}\n disableSignupScreen={disableSignupScreen}\n switchToRegister={showRegistration ? () => switchMode(\"register\") : undefined}\n defaultEmail={defaultEmail}\n defaultPassword={defaultPassword}\n onSignedIn={subscribeIfOptedIn}\n />\n )}\n\n {/* Registration form */}\n {mode === \"register\" && (\n <LoginForm\n authController={authController}\n registrationMode={true}\n onClose={() => switchMode(\"buttons\")}\n onForgotPassword={hasPasswordReset ? () => switchMode(\"forgot\") : undefined}\n noUserComponent={noUserComponent}\n disableSignupScreen={disableSignupScreen}\n switchToLogin={() => switchMode(\"login\")}\n defaultEmail={defaultEmail}\n defaultPassword={defaultPassword}\n onSignedIn={subscribeIfOptedIn}\n />\n )}\n\n {/* Forgot password form */}\n {mode === \"forgot\" && authController.forgotPassword && (\n <ForgotPasswordForm\n authController={authController}\n onClose={() => switchMode(\"login\")}\n />\n )}\n\n {/* Opened from a reset or invitation email */}\n {mode === \"reset-password\" && emailLink?.kind === \"reset-password\" && (\n <ResetPasswordForm\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n\n {/* Opened from a verification email */}\n {mode === \"verify-email\" && emailLink?.kind === \"verify-email\" && (\n <VerifyEmailView\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n\n {/* Opened from a magic link */}\n {mode === \"magic-link\" && emailLink?.kind === \"magic-link\" && !signedIn && (\n <MagicLinkView\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n\n {/* Opened from the link an address change mails to the new address */}\n {mode === \"confirm-email-change\" && emailLink?.kind === \"confirm-email-change\" && (\n <ConfirmEmailChangeView\n token={emailLink.token}\n authController={authController}\n onDone={leaveEmailLink}\n />\n )}\n </>\n )}\n </div>\n\n {additionalComponent && !isBootstrapMode && mode === \"buttons\" && !pendingMfa && (\n <div className=\"w-full\">\n {additionalComponent}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction LoginButton({\n icon,\n onClick,\n text,\n disabled\n}: { icon: React.ReactNode, onClick: () => void, text: string, disabled?: boolean }) {\n return (\n <Button\n disabled={disabled}\n className=\"w-full transition-transform duration-200 active:scale-[0.98]\"\n variant=\"outlined\"\n size=\"large\"\n onClick={onClick}>\n <div className=\"flex items-center justify-center w-full gap-3 py-1\">\n <span className=\"flex items-center justify-center w-5 h-5\">\n {icon}\n </span>\n <Typography variant=\"button\">{text}</Typography>\n </div>\n </Button>\n );\n}\n\nconst GoogleIcon = () => (\n <svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\">\n <path fill=\"#4285F4\"\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"/>\n <path fill=\"#34A853\"\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/>\n <path fill=\"#FBBC05\"\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/>\n <path fill=\"#EA4335\"\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/>\n </svg>\n);\n\nfunction GoogleLoginButton({\n disabled,\n googleClientId,\n authController,\n onSignedIn,\n onError\n}: {\n disabled?: boolean,\n googleClientId: string,\n authController: AuthControllerExtended,\n /** Called once the controller has accepted the provider's code. */\n onSignedIn?: () => void,\n /**\n * Reports a failure the auth controller never saw — Google answering the\n * popup with an error, or its script never having loaded. A rejected\n * `googleLogin` is not reported here: the controller already records it.\n */\n onError?: (message: string | null) => void\n}) {\n const codeClientRef = useRef<{ requestCode(): void } | null>(null);\n // The code client is built once and its callback closes over this render's\n // props forever. A ref keeps the callback reaching the *current* handler\n // rather than the one that existed when Google's script happened to load.\n const onSignedInRef = useRef(onSignedIn);\n onSignedInRef.current = onSignedIn;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n\n /**\n * Build Google's code client, if its script has arrived. Google's script\n * tag is `async`, so it routinely lands after this button has mounted:\n * the click tries again rather than trusting whatever the mount saw.\n */\n const ensureCodeClient = useCallback(() => {\n if (codeClientRef.current || !authController.googleLogin) return codeClientRef.current;\n\n const google = window.google;\n if (!google) return null;\n\n codeClientRef.current = google.accounts.oauth2.initCodeClient({\n client_id: googleClientId,\n scope: \"openid email profile\",\n ux_mode: \"popup\",\n callback: async (response: { code?: string; error?: string }) => {\n if (response.error || !response.code) {\n console.error(\"Google login error:\", response.error);\n if (!isUserCancellation(response.error)) {\n onErrorRef.current?.(\n response.error\n ? `Google sign-in failed: ${response.error}`\n : \"Google sign-in failed. Please try again.\"\n );\n }\n return;\n }\n onErrorRef.current?.(null);\n try {\n // Send the authorization code to the backend.\n // redirectUri \"postmessage\" is required when using popup ux_mode.\n await authController.googleLogin!({\n code: response.code,\n redirectUri: \"postmessage\"\n });\n // After the await, and only on the resolution path: a\n // newsletter tick must not subscribe an address whose\n // sign-in the controller rejected.\n onSignedInRef.current?.();\n } catch (err: unknown) {\n console.error(\"Google login error:\", err);\n }\n }\n });\n return codeClientRef.current;\n }, [googleClientId, authController]);\n\n useEffect(() => {\n ensureCodeClient();\n }, [ensureCodeClient]);\n\n const handleClick = () => {\n const codeClient = ensureCodeClient();\n if (!codeClient) {\n console.error(\"Google Sign-In not loaded\");\n onErrorRef.current?.(\"Google Sign-In could not be loaded. Check your connection or any script blockers, then try again.\");\n return;\n }\n onErrorRef.current?.(null);\n codeClient.requestCode();\n };\n\n return (\n <LoginButton\n disabled={disabled}\n text=\"Sign in with Google\"\n icon={<GoogleIcon/>}\n onClick={handleClick}\n />\n );\n}\n\nconst GitHubIcon = () => (\n <svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\">\n <path d=\"M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.464-1.11-1.464-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.579.688.481C19.137 20.162 22 16.418 22 12c0-5.523-4.477-10-10-10z\"/>\n </svg>\n);\n\nfunction GitHubLoginButton({\n disabled,\n githubClientId\n}: {\n disabled?: boolean,\n githubClientId: string\n}) {\n const handleClick = () => {\n // GitHub OAuth Apps do not implement PKCE, so `state` is the whole\n // binding between this click and the code that comes back.\n void startOAuthRedirect({\n provider: \"github\",\n authorizeUrl: \"https://github.com/login/oauth/authorize\",\n clientId: githubClientId,\n redirectUri: window.location.origin + window.location.pathname,\n scope: \"read:user,user:email\"\n });\n };\n\n return (\n <LoginButton\n disabled={disabled}\n text=\"Sign in with GitHub\"\n icon={<GitHubIcon/>}\n onClick={handleClick}\n />\n );\n}\n\nconst LinkedInIcon = () => (\n <svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\">\n <path d=\"M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z\"/>\n </svg>\n);\n\nfunction LinkedInLoginButton({\n disabled,\n linkedinClientId\n}: {\n disabled?: boolean,\n linkedinClientId: string\n}) {\n const handleClick = () => {\n void startOAuthRedirect({\n provider: \"linkedin\",\n authorizeUrl: \"https://www.linkedin.com/oauth/v2/authorization\",\n clientId: linkedinClientId,\n redirectUri: window.location.origin + window.location.pathname,\n scope: \"openid profile email\"\n });\n };\n\n return (\n <LoginButton\n disabled={disabled}\n text=\"Sign in with LinkedIn\"\n icon={<LinkedInIcon/>}\n onClick={handleClick}\n />\n );\n}\n\nfunction LoginForm({\n onClose,\n onForgotPassword,\n authController,\n registrationMode,\n noUserComponent,\n disableSignupScreen,\n bootstrapMode = false,\n switchToRegister,\n switchToLogin,\n defaultEmail,\n defaultPassword,\n onSignedIn,\n newsletterOptIn = false,\n setNewsletterOptIn,\n showNewsletterOptIn = false\n}: {\n onClose: () => void,\n onForgotPassword?: () => void,\n authController: AuthControllerExtended,\n registrationMode: boolean,\n noUserComponent?: ReactNode,\n disableSignupScreen: boolean,\n bootstrapMode?: boolean,\n switchToRegister?: () => void,\n switchToLogin?: () => void,\n defaultEmail?: string,\n defaultPassword?: string,\n /** The address the controller just accepted, reported after every success. */\n onSignedIn?: (email: string) => void,\n newsletterOptIn?: boolean,\n setNewsletterOptIn?: (checked: boolean) => void,\n /**\n * Render the newsletter opt-in here. Only bootstrap mode does: everywhere\n * else it lives on the provider screen, which bootstrap mode never shows.\n */\n showNewsletterOptIn?: boolean\n}) {\n const passwordRef = useRef<HTMLInputElement | null>(null);\n const { t } = useTranslation();\n\n // `Typography variant=\"label\"` already renders a real <label> element, it just\n // never pointed at anything, so each field fell back to naming itself after its\n // own placeholder — the password field announced as eight bullets. Associating\n // the existing labels beats passing the kit's `label` prop here: that one moves\n // the text inside the box (`pt-6 pb-2` at this size) and hides the placeholder\n // until focus, which would redesign the login screen to fix a name.\n const emailId = useId();\n const passwordId = useId();\n const [confirmationSent, setConfirmationSent] = useState(false);\n const displayNameId = useId();\n\n const [email, setEmail] = useState<string | undefined>(defaultEmail);\n const [password, setPassword] = useState<string | undefined>(defaultPassword);\n const [displayName, setDisplayName] = useState<string>();\n\n useEffect(() => {\n if (!document) return;\n const escFunction = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && !isKeyHandled(event)) {\n event.preventDefault();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", escFunction, false);\n return () => {\n document.removeEventListener(\"keydown\", escFunction, false);\n };\n }, [onClose]);\n\n // Both controller methods record the failure in `authProviderError` — which\n // this form renders above — and then rethrow for programmatic callers. This\n // is not one of those: without a catch here every rejected sign-in becomes an\n // unhandled rejection, reported as a crash by anything listening for one,\n // while the user has already been shown the error.\n // Fires only on the resolution path, i.e. after the controller accepted\n // the credentials — a ticked box on a failed attempt must not subscribe\n // an address its owner never proved they control.\n function reportSignedIn(email: string) {\n onSignedIn?.(email);\n }\n\n function handleEnterPassword() {\n if (email && password && authController.emailPasswordLogin) {\n void Promise.resolve(authController.emailPasswordLogin(email, password))\n .then(() => reportSignedIn(email))\n .catch(() => undefined);\n }\n }\n\n function handleRegistration() {\n if (email && password && authController.register) {\n void Promise.resolve(authController.register(email, password, displayName))\n .then((result) => {\n // Confirm-first: nobody is signed in until the link in the\n // mail is followed.\n if (result?.confirmationRequired) setConfirmationSent(true);\n else reportSignedIn(email);\n })\n .catch(() => undefined);\n }\n }\n\n const handleSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n if (registrationMode)\n handleRegistration();\n else\n handleEnterPassword();\n };\n\n const title = bootstrapMode\n ? \"Welcome!\"\n : registrationMode\n ? \"Create account\"\n : \"Sign in\";\n\n const subtitle = bootstrapMode\n ? \"Create your admin account to get started. This account will have admin privileges.\"\n : registrationMode\n ? \"Fill in your details to create a new account\"\n : \"Enter your credentials to continue\";\n\n const buttonLabel = registrationMode ? \"Create account\" : \"Sign in\";\n\n if (confirmationSent) {\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_confirm_email_sent_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_confirm_email_sent_body\")}\n </Typography>\n </div>\n <Button onClick={onClose} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n {!bootstrapMode && (\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton aria-label={t(\"back\")} onClick={onClose}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n )}\n\n {(() => {\n const err = signInRefusal(authController);\n if (!err) return null;\n const msg = authErrorMessage(err, t);\n return (\n <div className=\"w-full mb-2\">\n <ErrorView error={msg}/>\n </div>\n );\n })()}\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {title}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {subtitle}\n </Typography>\n\n {registrationMode && !bootstrapMode && noUserComponent && (\n <div className=\"w-full mb-2\">\n {noUserComponent}\n </div>\n )}\n\n {registrationMode && (\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={displayNameId}>\n Display Name\n </Typography>\n <TextField placeholder=\"Jane Doe (optional)\"\n id={displayNameId}\n className={loginFieldClasses}\n value={displayName ?? \"\"}\n disabled={authController.initialLoading}\n type=\"text\"\n size=\"medium\"\n onChange={(event) => setDisplayName(event.target.value)}/>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={emailId}>\n Email\n </Typography>\n <TextField placeholder=\"you@example.com\"\n id={emailId}\n className={loginFieldClasses}\n autoFocus\n value={email ?? \"\"}\n disabled={authController.initialLoading}\n type=\"email\"\n size=\"medium\"\n onChange={(event) => setEmail(event.target.value)}/>\n </div>\n\n <div className=\"w-full mb-1\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={passwordId}>\n Password\n </Typography>\n <TextField placeholder=\"••••••••\"\n id={passwordId}\n className={loginFieldClasses}\n value={password ?? \"\"}\n disabled={authController.initialLoading}\n inputRef={passwordRef}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setPassword(event.target.value)}/>\n </div>\n\n {registrationMode && (\n <Typography variant=\"caption\" color=\"secondary\" className=\"mb-3\">\n Password must be 8+ characters with uppercase, lowercase, and a number\n </Typography>\n )}\n\n {!registrationMode && onForgotPassword && (\n <div className=\"w-full text-right mb-3\">\n <button\n type=\"button\"\n className=\"text-xs font-medium hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={onForgotPassword}\n >\n Forgot password?\n </button>\n </div>\n )}\n\n {/* Bootstrap mode only — see `showNewsletterOptIn`. Every other\n route to this form came through the provider screen, which is\n where the box now is. */}\n {showNewsletterOptIn && (\n <label className=\"flex items-center gap-2 cursor-pointer mt-1 mb-1\">\n <Checkbox\n checked={newsletterOptIn}\n onCheckedChange={(checked) => setNewsletterOptIn?.(checked === true)}\n size=\"small\"\n />\n <Typography variant=\"caption\" color=\"secondary\" className=\"select-none\">\n {t(\"join_newsletter\")}\n </Typography>\n </label>\n )}\n\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={authController.authLoading}\n disabled={authController.authLoading || !email || !password}\n >\n {buttonLabel}\n </LoadingButton>\n\n {/* Switch between login/register */}\n {switchToRegister && (\n <div className=\"mt-4 text-center\">\n <Typography variant=\"body2\" color=\"secondary\">\n Don&apos;t have an account?{\" \"}\n <button\n type=\"button\"\n className=\"font-semibold hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={switchToRegister}\n >\n Create one\n </button>\n </Typography>\n </div>\n )}\n\n {switchToLogin && (\n <div className=\"mt-4 text-center\">\n <Typography variant=\"body2\" color=\"secondary\">\n Already have an account?{\" \"}\n <button\n type=\"button\"\n className=\"font-semibold hover:underline cursor-pointer text-primary dark:text-primary-light\"\n onClick={switchToLogin}\n >\n Sign in\n </button>\n </Typography>\n </div>\n )}\n </form>\n );\n}\n\n/** How a factor is named in the picker: the name its owner gave it, if any. */\nfunction factorName(factor: MfaFactorSummary, index: number, t: (key: string) => string): string {\n if (factor.friendlyName) return factor.friendlyName;\n const kind = factor.factorType === \"totp\" ? t(\"auth_mfa_factor_totp\") : factor.factorType;\n return `${kind} ${index + 1}`;\n}\n\n/**\n * The second step of a sign-in refused with `MFA_REQUIRED`: a code from the\n * authenticator app, or one of the recovery codes, in the same field — the\n * server tries the one and then the other.\n *\n * The challenge is opened on the first submit and answered by every code\n * after it until it is spent, which is after five wrong ones: the next code\n * then opens a new one. The pending token behind both lasts five minutes from\n * the password; once it has lapsed nothing here can help, so the step says so\n * and sends the visitor back to sign in again.\n */\nfunction MfaChallengeForm({\n pending,\n authController,\n onBack,\n onSignedIn\n}: {\n pending: PendingMfaSignIn,\n authController: AuthControllerExtended,\n /** Back to the sign-in screen the refusal came from. */\n onBack: () => void,\n /** Called once the controller has accepted a code. */\n onSignedIn?: () => void\n}) {\n const { t } = useTranslation();\n const factorFieldId = useId();\n const codeId = useId();\n const [factorId, setFactorId] = useState(pending.factors[0].id);\n const [code, setCode] = useState(\"\");\n const [challengeId, setChallengeId] = useState<string | null>(null);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [expired, setExpired] = useState(false);\n\n // A challenge belongs to one factor: another factor needs its own.\n const chooseFactor = (id: string) => {\n setFactorId(id);\n setChallengeId(null);\n setError(null);\n };\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n const answer = code.trim();\n const { startMfaChallenge, verifyMfaChallenge } = authController;\n if (!answer || submitting || expired || !startMfaChallenge || !verifyMfaChallenge) return;\n\n setError(null);\n setSubmitting(true);\n try {\n const id = challengeId ?? await startMfaChallenge(pending.mfaToken, factorId);\n setChallengeId(id);\n await verifyMfaChallenge(pending.mfaToken, id, answer);\n onSignedIn?.();\n } catch (err: unknown) {\n switch (classifyMfaRefusal(err)) {\n case \"invalid-code\":\n setCode(\"\");\n setError(t(\"auth_mfa_code_invalid\"));\n break;\n case \"exhausted\":\n setCode(\"\");\n setChallengeId(null);\n setError(t(\"auth_mfa_challenge_exhausted\"));\n break;\n case \"expired\":\n setExpired(true);\n setError(t(\"auth_mfa_expired\"));\n break;\n default:\n setError(authErrorMessage(err, t));\n }\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton onClick={onBack} aria-label={t(\"back\")}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_mfa_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {t(\"auth_mfa_subtitle\")}\n </Typography>\n\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n\n {pending.factors.length > 1 && (\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={factorFieldId}>\n {t(\"auth_mfa_factor_label\")}\n </Typography>\n <Select\n id={factorFieldId}\n aria-label={t(\"auth_mfa_factor_label\")}\n value={factorId}\n onValueChange={chooseFactor}\n disabled={submitting || expired}\n size=\"medium\"\n fullWidth\n >\n {pending.factors.map((factor, index) => (\n <SelectItem key={factor.id} value={factor.id}>\n {factorName(factor, index, t)}\n </SelectItem>\n ))}\n </Select>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={codeId}>\n {t(\"auth_mfa_code_label\")}\n </Typography>\n {/* Text, not numeric: a recovery code has letters in it. */}\n <TextField\n id={codeId}\n className={loginFieldClasses}\n autoFocus\n autoComplete=\"one-time-code\"\n autoCapitalize=\"none\"\n spellCheck={false}\n value={code}\n disabled={expired}\n type=\"text\"\n size=\"medium\"\n onChange={(event) => setCode(event.target.value)}\n />\n </div>\n\n {expired\n ? (\n <Button onClick={onBack} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full mt-1\">\n {t(\"auth_mfa_sign_in_again\")}\n </Button>\n )\n : (\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={submitting}\n disabled={submitting || !code.trim()}\n >\n {t(\"auth_mfa_verify\")}\n </LoadingButton>\n )}\n </form>\n );\n}\n\n/**\n * Leave an email link for the app's own address, with a fresh load.\n *\n * The router, when there is one, still stands on `/reset-password`: rewriting\n * the address under it would leave it rendering a route that does not exist\n * the moment the user signs in. A load starts it where the app starts, and the\n * spent token leaves the address bar and the history entry with it.\n */\nfunction leaveEmailLink() {\n window.location.replace(appAddressOfEmailLink(window.location));\n}\n\n/** What to say about a refused email-link token, or any other failure. */\nfunction emailLinkErrorMessage(error: unknown, t: (key: string) => string): string {\n if (error instanceof Error && \"code\" in error && error.code === \"INVALID_TOKEN\") {\n return t(\"auth_link_invalid_or_expired\");\n }\n return authErrorMessage(error, t);\n}\n\n/**\n * The step a reset link opens: a new password for the account the token was\n * issued to. An invitation sends the same link, so this is also where an\n * invited user — created without a password — sets their first one.\n */\nfunction ResetPasswordForm({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n /** Back to the app's own address, and the sign-in screen. */\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const passwordId = useId();\n const confirmationId = useId();\n const [password, setPassword] = useState(\"\");\n const [confirmation, setConfirmation] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [changed, setChanged] = useState(false);\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n setError(null);\n\n if (!authController.resetPassword) {\n setError(t(\"auth_password_reset_unavailable\"));\n return;\n }\n if (password !== confirmation) {\n setError(t(\"passwords_dont_match\"));\n return;\n }\n\n setSubmitting(true);\n try {\n await authController.resetPassword(token, password);\n setChanged(true);\n } catch (err: unknown) {\n setError(emailLinkErrorMessage(err, t));\n } finally {\n setSubmitting(false);\n }\n };\n\n if (changed) {\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_password_changed_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_password_changed_body\")}\n </Typography>\n </div>\n\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton onClick={onDone} aria-label={t(\"back\")}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_new_password_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {t(\"auth_new_password_subtitle\")}\n </Typography>\n\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={passwordId}>\n {t(\"new_password\")}\n </Typography>\n <TextField\n id={passwordId}\n className={loginFieldClasses}\n autoFocus\n autoComplete=\"new-password\"\n value={password}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setPassword(event.target.value)}\n />\n </div>\n\n <div className=\"w-full mb-1\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={confirmationId}>\n {t(\"confirm_password\")}\n </Typography>\n <TextField\n id={confirmationId}\n className={loginFieldClasses}\n autoComplete=\"new-password\"\n value={confirmation}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setConfirmation(event.target.value)}\n />\n </div>\n\n <Typography variant=\"caption\" color=\"secondary\" className=\"mb-3\">\n {t(\"auth_password_requirements\")}\n </Typography>\n\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={submitting}\n disabled={submitting || !password || !confirmation}\n >\n {t(\"auth_set_password\")}\n </LoadingButton>\n </form>\n );\n}\n\n/**\n * The step a verification link opens.\n *\n * The link proves the inbox, not who registered the address. So when the\n * account holds a password, the server asks for it before keeping it\n * (`PROOF_REQUIRED`): the owner types the password they chose and is signed\n * in; someone who never set one — whose address a stranger registered —\n * verifies without it, and the stranger's password is removed.\n */\nfunction VerifyEmailView({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const [status, setStatus] = useState<\"verifying\" | \"proof\" | \"verified\" | \"failed\">(\"verifying\");\n const [error, setError] = useState<string | null>(null);\n const [password, setPassword] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [passwordRemoved, setPasswordRemoved] = useState(false);\n const passwordId = useId();\n // Once per token. A second call — a development double-mount, say —\n // would race the first for the same token.\n const requestedRef = useRef(false);\n\n const verify = useCallback(async (options?: { password?: string; removeUnproven?: boolean }) => {\n setError(null);\n try {\n if (!authController.verifyEmail) return;\n const result = await authController.verifyEmail(token, options);\n setPasswordRemoved(result?.passwordRemoved === true);\n setStatus(\"verified\");\n } catch (err: unknown) {\n if (err instanceof Error && \"code\" in err && err.code === \"PROOF_REQUIRED\") {\n setStatus(\"proof\");\n return;\n }\n if (options?.password !== undefined && err instanceof Error && \"code\" in err && err.code === \"INVALID_CREDENTIALS\") {\n setError(t(\"auth_verify_email_wrong_password\"));\n return;\n }\n setError(emailLinkErrorMessage(err, t));\n setStatus(\"failed\");\n }\n }, [authController, token, t]);\n\n useEffect(() => {\n if (requestedRef.current) return;\n requestedRef.current = true;\n if (!authController.verifyEmail) {\n setError(t(\"auth_email_verification_unavailable\"));\n setStatus(\"failed\");\n return;\n }\n void verify();\n }, [authController, verify, t]);\n\n if (status === \"verifying\") {\n return (\n <div className=\"flex flex-col items-center w-full gap-4 mt-6 mb-4\">\n <CircularProgress size=\"small\"/>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_verifying_email\")}\n </Typography>\n </div>\n );\n }\n\n if (status === \"proof\") {\n const submit = (options: { password?: string; removeUnproven?: boolean }) => {\n setSubmitting(true);\n void verify(options).finally(() => setSubmitting(false));\n };\n return (\n <form\n className=\"flex flex-col w-full gap-1 mt-2\"\n onSubmit={(event) => {\n event.preventDefault();\n if (password) submit({ password });\n }}\n >\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_verify_email_proof_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n {t(\"auth_verify_email_proof_body\")}\n </Typography>\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={passwordId}>\n {t(\"auth_verify_email_password_label\")}\n </Typography>\n <TextField\n id={passwordId}\n className={loginFieldClasses}\n autoFocus\n autoComplete=\"current-password\"\n value={password}\n type=\"password\"\n size=\"medium\"\n onChange={(event) => setPassword(event.target.value)}\n />\n </div>\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n color=\"primary\"\n className=\"w-full mt-1\"\n size=\"large\"\n loading={submitting}\n disabled={submitting || !password}\n >\n {t(\"auth_verify_email_with_password\")}\n </LoadingButton>\n <Button\n variant=\"text\"\n className=\"w-full mt-1\"\n disabled={submitting}\n onClick={() => submit({ removeUnproven: true })}\n >\n {t(\"auth_verify_email_without_password\")}\n </Button>\n </form>\n );\n }\n\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n {status === \"verified\"\n ? (\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_email_verified_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {passwordRemoved ? t(\"auth_email_verified_password_removed_body\") : t(\"auth_email_verified_body\")}\n </Typography>\n </div>\n )\n : (\n <>\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_email_verification_failed_title\")}\n </Typography>\n {error && <ErrorView error={error}/>}\n </>\n )}\n\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n}\n\n/**\n * The step a magic link opens: it signs in with the link's token as soon as the\n * screen loads. Success is not shown here — the user is signed in, and the\n * view leaves for the app's address. A second factor takes over the screen\n * the way it does after any sign-in, because the controller records the\n * refusal where the code step reads it.\n */\nfunction MagicLinkView({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const [error, setError] = useState<string | null>(null);\n // Once per token: a magic link is single use, and a second request would\n // find it spent and say so over a sign-in that worked.\n const requestedRef = useRef(false);\n\n useEffect(() => {\n if (requestedRef.current) return;\n requestedRef.current = true;\n if (!authController.magicLinkLogin) {\n setError(t(\"auth_magic_link_unavailable\"));\n return;\n }\n authController.magicLinkLogin(token).catch((err: unknown) => {\n // The code step answers this one; it is not a failure.\n if (err instanceof Error && \"code\" in err && err.code === \"MFA_REQUIRED\") return;\n setError(emailLinkErrorMessage(err, t));\n });\n }, [authController, token, t]);\n\n if (!error) {\n return (\n <div className=\"flex flex-col items-center w-full gap-4 mt-6 mb-4\">\n <CircularProgress size=\"small\"/>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_signing_in_with_link\")}\n </Typography>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_magic_link_failed_title\")}\n </Typography>\n <ErrorView error={error}/>\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_continue_to_sign_in\")}\n </Button>\n </div>\n );\n}\n\n/**\n * The step an address-change link opens: the account moves onto its new\n * address as soon as the screen loads, signed in or not — the link proves the\n * new inbox, which is all the move needs.\n */\nfunction ConfirmEmailChangeView({\n token,\n authController,\n onDone\n}: {\n token: string,\n authController: AuthControllerExtended,\n onDone: () => void\n}) {\n const { t } = useTranslation();\n const [status, setStatus] = useState<\"confirming\" | \"confirmed\" | \"failed\">(\"confirming\");\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<{ email: string; removedProviders: string[] } | null>(null);\n // Once per token: a second request — a development double-mount — would\n // find it spent and report a failure over a change that happened.\n const requestedRef = useRef(false);\n\n useEffect(() => {\n if (requestedRef.current) return;\n requestedRef.current = true;\n if (!authController.confirmEmailChange) {\n setError(t(\"auth_email_change_unavailable\"));\n setStatus(\"failed\");\n return;\n }\n authController.confirmEmailChange(token).then((moved) => {\n setResult(moved);\n setStatus(\"confirmed\");\n }).catch((err: unknown) => {\n setError(emailChangeErrorMessage(err, t));\n setStatus(\"failed\");\n });\n }, [authController, token, t]);\n\n if (status === \"confirming\") {\n return (\n <div className=\"flex flex-col items-center w-full gap-4 mt-6 mb-4\">\n <CircularProgress size=\"small\"/>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_confirming_email_change\")}\n </Typography>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n {status === \"confirmed\" && result\n ? (\n <div className=\"flex flex-col items-center text-center rounded-xl p-6 bg-surface-raised\">\n <CheckCircle2Icon size={iconSize.large} className=\"mb-3 text-primary\"/>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n {t(\"auth_email_change_confirmed_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"auth_email_change_confirmed_body\", { email: result.email })}\n </Typography>\n {result.removedProviders.length > 0 && (\n <Typography variant=\"body2\" color=\"secondary\" className=\"mt-2\">\n {t(\"auth_email_change_providers_removed\", { providers: result.removedProviders.join(\", \") })}\n </Typography>\n )}\n </div>\n )\n : (\n <>\n <Typography variant=\"h6\" className=\"mb-0.5\">\n {t(\"auth_email_change_failed_title\")}\n </Typography>\n {error && <ErrorView error={error}/>}\n </>\n )}\n\n <Button onClick={onDone} variant=\"filled\" color=\"primary\" size=\"large\" className=\"w-full\">\n {t(\"auth_email_change_continue\")}\n </Button>\n </div>\n );\n}\n\nfunction ForgotPasswordForm({\n onClose,\n authController\n}: {\n onClose: () => void,\n authController: AuthControllerExtended\n}) {\n const { t } = useTranslation();\n const [email, setEmail] = useState<string>(\"\");\n const [submitted, setSubmitted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const emailId = useId();\n\n useEffect(() => {\n if (!document) return;\n const escFunction = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && !isKeyHandled(event)) {\n event.preventDefault();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", escFunction, false);\n return () => {\n document.removeEventListener(\"keydown\", escFunction, false);\n };\n }, [onClose]);\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n setError(null);\n\n if (!email) {\n setError(\"Please enter your email address\");\n return;\n }\n\n if (!authController.forgotPassword) {\n setError(\"Password reset is not available with this auth provider.\");\n return;\n }\n\n try {\n await authController.forgotPassword(email);\n setSubmitted(true);\n } catch (err: unknown) {\n // Check for EMAIL_NOT_CONFIGURED error\n if (err instanceof Error && (err as { code?: string }).code === \"EMAIL_NOT_CONFIGURED\") {\n setError(\"Password reset is not available. Please contact your administrator.\");\n } else {\n // Still show success (security: don't reveal if email exists)\n setSubmitted(true);\n }\n }\n };\n\n if (submitted) {\n return (\n <div className=\"flex flex-col w-full gap-4 mt-2\">\n <div className=\"w-full -ml-2.5\">\n <IconButton aria-label={t(\"back\")} onClick={onClose}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <div className=\"text-center rounded-xl p-6 bg-surface-raised\">\n <div className=\"text-3xl mb-3\">📧</div>\n <Typography variant=\"subtitle1\" className=\"mb-2\">\n Check your email\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n If an account exists for <strong>{email}</strong>, you&apos;ll receive a password reset link shortly.\n </Typography>\n </div>\n\n <Button onClick={onClose} variant=\"text\" className=\"mt-2\">\n Back to sign in\n </Button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"flex flex-col w-full gap-1 mt-2\">\n <div className=\"w-full mb-2 -ml-2.5\">\n <IconButton aria-label={t(\"back\")} onClick={onClose}>\n <ArrowLeftIcon/>\n </IconButton>\n </div>\n\n <Typography variant=\"h6\" className=\"mb-0.5\">\n Reset password\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\" className=\"mb-5\">\n Enter your email and we&apos;ll send you a reset link.\n </Typography>\n\n {error && (\n <div className=\"w-full mb-3\">\n <ErrorView error={error}/>\n </div>\n )}\n\n <div className=\"w-full mb-3\">\n <Typography variant=\"label\" component=\"label\" color=\"secondary\" className=\"mb-1\" htmlFor={emailId}>\n Email\n </Typography>\n <TextField\n placeholder=\"you@example.com\"\n id={emailId}\n className={loginFieldClasses}\n autoFocus\n value={email}\n type=\"email\"\n size=\"medium\"\n onChange={(event) => setEmail(event.target.value)}\n />\n </div>\n\n <LoadingButton\n type=\"submit\"\n variant=\"filled\"\n className=\"w-full\"\n size=\"large\"\n loading={authController.authLoading}\n disabled={authController.authLoading || !email}\n >\n Send reset link\n </LoadingButton>\n </form>\n );\n}\n","import React, { useLayoutEffect, useRef } from \"react\";\nimport { useRebaseRegistryDispatch } from \"../hooks\";\nimport type { RebaseAuthViewConfig } from \"@rebasepro/cms-types\";\n\n/**\n * Declarative component to configure authentication in Rebase.\n * Renders nothing — purely registers config into the RebaseRegistry.\n *\n * This is a framework-level component that lives in core since\n * authentication is cross-cutting (admin, Studio, any app area).\n * @group Core\n */\nexport function RebaseAuth({ loginView }: RebaseAuthViewConfig) {\n const dispatch = useRebaseRegistryDispatch();\n const registeredRef = useRef(false);\n\n useLayoutEffect(() => {\n dispatch.registerAuth({ loginView });\n registeredRef.current = true;\n return () => {\n registeredRef.current = false;\n dispatch.unregisterAuth();\n };\n }, [dispatch, loginView]);\n\n return null;\n}\n","import React, { useCallback, useSyncExternalStore } from \"react\";\nimport { Alert, Typography } from \"@rebasepro/ui\";\nimport type { RealtimeConnectionState, RebaseClient } from \"@rebasepro/types\";\nimport { useRebaseClient } from \"../hooks/useRebaseClient\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\nconst noUnsubscribe = () => undefined;\n\n/**\n * The realtime connection's state, re-rendering on every change.\n *\n * `undefined` when there is no client, or it was built without realtime —\n * there is no connection to describe.\n *\n * @group Hooks and utilities\n */\nexport function useRealtimeConnectionState(): RealtimeConnectionState | undefined {\n const ws = useRebaseClient<RebaseClient>()?.ws;\n // A client implementation that predates the state (or is not the Rebase\n // SDK at all) has nothing to subscribe to, which reads as \"no state\".\n const observable = ws && typeof ws.onStateChange === \"function\" ? ws : undefined;\n const subscribe = useCallback(\n (notify: () => void) => observable ? observable.onStateChange(notify) : noUnsubscribe,\n [observable]\n );\n const read = useCallback(() => observable?.state, [observable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport interface ConnectionLostBannerProps {\n className?: string;\n}\n\n/**\n * Says that live updates have stopped, while they have.\n *\n * Shown once the realtime client reports the connection `disconnected`: the\n * socket has been down for longer than a blip, so tables, boards and open\n * records are showing what they last received and nothing else will arrive\n * until it is back. They keep their data rather than turning into errors — this\n * banner is how the user learns it may be out of date. It disappears by itself\n * when the connection returns, and every live view then refreshes.\n *\n * A brief drop (`reconnecting`) shows nothing: a deploy blips every socket for\n * a second or two, and a banner that flashes on each one teaches people to\n * ignore it.\n *\n * @group Components\n */\nexport function ConnectionLostBanner({ className }: ConnectionLostBannerProps) {\n const state = useRealtimeConnectionState();\n const { t } = useTranslation();\n\n if (state !== \"disconnected\") return null;\n\n return (\n <div role=\"status\" aria-live=\"polite\" className={className}>\n <Alert color=\"warning\" size=\"small\" role={null}>\n <div className=\"flex flex-col gap-0.5\">\n <Typography variant=\"label\">\n {t(\"realtime_connection_lost_title\")}\n </Typography>\n <Typography variant=\"body2\" color=\"secondary\">\n {t(\"realtime_connection_lost_body\")}\n </Typography>\n </div>\n </Alert>\n </div>\n );\n}\n","import React, { Suspense } from \"react\";\nimport { hasAdminRole } from \"@rebasepro/types\";\nimport { useRlsSimulation } from \"../../contexts/RlsSimulationContext\";\nimport { useAuthController } from \"../../hooks/useAuthController\";\n\n// The pill and the banner are fetched the first time someone may see them, so\n// the startup bundle carries only these two wrappers.\nconst RlsSimulatorBarPanel = React.lazy(() =>\n import(\"./RlsSimulatorPanel\").then((module) => ({ default: module.RlsSimulatorBarPanel })));\nconst RlsSimulationBannerPanel = React.lazy(() =>\n import(\"./RlsSimulatorPanel\").then((module) => ({ default: module.RlsSimulationBannerPanel })));\n\nexport interface RlsSimulatorBarProps {\n className?: string;\n /** An icon button instead of the pill — for a collapsed drawer rail. */\n compact?: boolean;\n side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n align?: \"start\" | \"center\" | \"end\";\n /** Where the popover mounts — inside a floating drawer, so hovering it keeps the drawer open. */\n portalContainer?: HTMLElement | null;\n}\n\n/**\n * Whether the signed-in person may simulate access here: an administrator,\n * with data views that ride a client able to derive a simulated one.\n *\n * @group Hooks and utilities\n */\nexport function useCanSimulateAccess(): boolean {\n const authController = useAuthController();\n const { available } = useRlsSimulation();\n return available && hasAdminRole(authController.user?.roles);\n}\n\n/**\n * \"Simulate access\": the app bar pill that runs every data view as a role, a\n * user or a service key, so an administrator sees exactly the rows and fields\n * that identity's row-level security lets it read.\n *\n * Shown only to an administrator, and only when the data views ride a client\n * that can derive a simulated one. The server checks the first again on every\n * request: anyone else sending the simulation headers gets a 403.\n *\n * @group Components\n */\nexport function RlsSimulatorBar(props: RlsSimulatorBarProps) {\n const canSimulate = useCanSimulateAccess();\n if (!canSimulate) return null;\n return (\n <Suspense fallback={null}>\n <RlsSimulatorBarPanel {...props}/>\n </Suspense>\n );\n}\n\n/**\n * The banner every screen shows while access is simulated: who the data views\n * run as, how many collections show that identity nothing, how many fields its\n * roles cannot read — and the way out.\n *\n * @group Components\n */\nexport function RlsSimulationBanner({ className }: { className?: string }) {\n const { simulation } = useRlsSimulation();\n if (!simulation) return null;\n return (\n <Suspense fallback={null}>\n <RlsSimulationBannerPanel className={className}/>\n </Suspense>\n );\n}\n","\"use client\";\nimport type { RebaseProps } from \"./RebaseProps\";\nimport type { CustomizationController, RebasePlugin, AnySlotContribution } from \"@rebasepro/cms-types\";\nimport type { ComponentOverrideMap } from \"@rebasepro/cms-types\";\n\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { CenteredView, TooltipProvider, Typography } from \"@rebasepro/ui\";\nimport { AccessSimulation, User, CollectionRegistryController, DataDriver, DataSourceDefinition, RebaseData, DEFAULT_DATA_SOURCE_KEY, StorageSource, StorageSourceDefinition, DEFAULT_STORAGE_SOURCE_KEY } from \"@rebasepro/types\";\nimport { RebaseContext, UNRENDERED_SLOTS } from \"@rebasepro/cms-types\";\nimport { PluginProviderStack } from \"./PluginProviderStack\";\nimport { PluginLifecycleManager } from \"./PluginLifecycleManager\";\nimport { warnDeprecatedPluginKeys } from \"./deprecated_plugin_keys\";\nimport { AuthControllerContext, CollectionResolverRegistrationContext, CollectionResolver, CollectionResolverRegistration, DataPathResolver } from \"../contexts\";\nimport { useCustomizationController, useRebaseContext, useAuthSubscription } from \"../hooks\";\nimport { ApiConfigProvider, useApiConfig } from \"../hooks/ApiConfigContext\";\nimport { ErrorView } from \"../components\";\nimport { StorageSourceContext } from \"../contexts/StorageSourceContext\";\nimport { UserConfigurationPersistenceContext } from \"../contexts/UserConfigurationPersistenceContext\";\nimport { RebaseDataContext } from \"../contexts/RebaseDataContext\";\nimport { RlsSimulationContext, type RlsSimulationController, type RlsSimulationLabel } from \"../contexts/RlsSimulationContext\";\nimport { DataSourcesContext, DataSourcesContextValue } from \"../contexts/DataSourcesContext\";\nimport { StorageSourcesContext, StorageSourcesContextValue } from \"../contexts/StorageSourcesContext\";\nimport { DatabaseAdminContext } from \"../contexts/DatabaseAdminContext\";\nimport { ModeControllerProvider, AdminModeControllerProvider, SnackbarProvider } from \"../contexts\";\nimport { RebaseI18nProvider } from \"../i18n/RebaseI18nProvider\";\nimport { RebaseRegistryProvider } from \"../hooks/useRebaseRegistry\";\nimport { SchemaDriftProvider } from \"../components/SchemaDriftBanner\";\nimport { GlobalComponentOverrideProvider } from \"../contexts/ComponentOverrideContext\";\nimport { useBuildModeController } from \"../hooks/useBuildModeController\";\nimport { useBuildAdminModeController } from \"../hooks/useBuildAdminModeController\";\nimport { useBuildLocalConfigurationPersistence } from \"../hooks/useBuildLocalConfigurationPersistence\";\nimport { RebaseClientInstanceContext } from \"../contexts/RebaseClientInstanceContext\";\nimport { DialogsProvider } from \"../contexts/DialogsProvider\";\nimport { buildRebaseData, wrapAsEntityData, CollectionRegistry } from \"@rebasepro/common\";\nimport { CustomizationControllerContext } from \"../contexts/CustomizationControllerContext\";\nimport { AnalyticsContext } from \"../contexts/AnalyticsContext\";\n\nimport { EffectiveRoleControllerContext } from \"../contexts/EffectiveRoleController\";\nimport { useEffectiveRoleState } from \"./effective_role_state\";\n\n/**\n * If you are using independent components of the admin\n * you need to wrap them with this main component, so the internal hooks work.\n *\n * This is the main component of Rebase. It acts as the provider of all the\n * internal contexts and hooks.\n *\n * You only need to use this component if you are building a custom app.\n *\n * @group Core\n */\n/**\n * Does this socket carry the admin surface?\n *\n * `RebaseWebSocket` declares none of `DatabaseAdmin`'s methods — the SQL console\n * is served over the same socket only when the backend enables it — so the\n * question is genuinely a runtime one. It used to be asked as\n * `typeof (ws as unknown as Record<string, unknown>).executeSql === \"function\"`\n * and then answered a second time, one line down, by asserting the whole socket\n * to `DatabaseAdmin`: a check and a claim, with nothing connecting them. A\n * predicate makes the check *be* the narrowing, so the five method reads below\n * are checked against the interface they came from.\n */\nfunction canExecuteSql(ws: object): ws is import(\"@rebasepro/types\").DatabaseAdmin {\n return typeof (ws as { executeSql?: unknown }).executeSql === \"function\";\n}\n\n/**\n * The `slots` default. A `[]` in the parameter list was a new array on every\n * render, which rebuilt the customization controller — and with it\n * `useRebaseContext()` for every consumer — each time `<Rebase>` rendered.\n */\nconst EMPTY_SLOTS: AnySlotContribution[] = [];\n\nexport function Rebase<USER extends User, DB = unknown>(props: RebaseProps<USER, DB>) {\n\n const {\n children,\n entityLinkBuilder,\n userConfigPersistence,\n dateTimeFormat,\n locale,\n client,\n authController: authControllerProp,\n storageSource: storageSourceProp,\n dataSources: dataSourcesProp,\n storageSources: storageSourcesProp,\n\n databaseAdmin,\n plugins: pluginsProp,\n slots: directSlots = EMPTY_SLOTS,\n onAnalyticsEvent,\n propertyConfigs,\n entityViews,\n collectionViews,\n entityActions,\n\n effectiveRoleController,\n modeController: modeControllerProp,\n apiUrl,\n translations,\n components: componentsProp\n } = props;\n\n const plugins = pluginsProp;\n\n // Validate plugin key uniqueness\n if (plugins) {\n const keys = plugins.map((p) => p.key);\n if (new Set(keys).size !== keys.length) {\n console.error(\"Duplicate plugin keys detected:\", keys.filter((k, i) => keys.indexOf(k) !== i));\n }\n }\n\n // A plugin key nothing calls is a plugin doing nothing, silently.\n useEffect(() => {\n if (plugins) warnDeprecatedPluginKeys(plugins);\n }, [plugins]);\n\n // Per-user table preferences — a resized column, a reordered one, the view\n // mode a collection was left in — are local by nature, so the panel keeps\n // its own localStorage-backed store unless the host app supplies one.\n // Without a default here the context was `undefined` for every app that\n // did not pass `userConfigPersistence` (which is every app the CLI\n // scaffolds), and each of those preferences was written nowhere and lost\n // on the next render.\n const localUserConfigPersistence = useBuildLocalConfigurationPersistence();\n const resolvedUserConfigPersistence = userConfigPersistence ?? localUserConfigPersistence;\n\n // Merge direct slots with plugin slots.\n const resolvedSlots: AnySlotContribution[] = useMemo(() => [\n ...directSlots,\n ...((plugins ?? []).flatMap((p) => p.slots ?? []))\n ], [directSlots, plugins]);\n\n // A declared slot that is rendered nowhere has a props interface and a row\n // in the public slot reference, so registering for one looks exactly like\n // registering for one that works — and then nothing happens, with no way to\n // tell whether the fault is the plugin's. `UNRENDERED_SLOTS` is empty today\n // and `slot-render-sites.test.ts` keeps it honest in both directions, so\n // this loop warns about nothing until a slot is declared ahead of its\n // render site again.\n useEffect(() => {\n const dead = new Set<string>(UNRENDERED_SLOTS);\n const registered = new Set(resolvedSlots.map(s => s.slot).filter(slot => dead.has(slot)));\n for (const slot of registered) {\n console.warn(\n `[Rebase] A component is registered for the \"${slot}\" slot, which this ` +\n \"build declares but renders nowhere — nothing will appear. This is a gap \" +\n \"in Rebase, not in your plugin.\"\n );\n }\n }, [resolvedSlots]);\n\n\n // Auth fallback logic\n const clientAuthController = useAuthSubscription(authControllerProp ? undefined : client?.auth);\n const authController = authControllerProp ?? clientAuthController;\n\n const normalizedDataSources = useMemo(() => {\n return dataSourcesProp ?? [];\n }, [dataSourcesProp]);\n\n // Rows arrive as columns only; their address is derived from the\n // collection's primary keys. A direct driver is handed the path a\n // collection declares for its store rather than its slug. The collections\n // live below us (in RebaseCMS), so they register both resolvers here and we\n // read them lazily, per call. Headless apps register nothing and are\n // unaffected.\n //\n // More than one layer may own collections — the CMS navigation and any\n // standalone `CollectionsProvider` — each registered under its own owner.\n const resolversRef = useRef(new Map<string, { resolveCollection?: CollectionResolver, resolveDataPath?: DataPathResolver }>());\n const registerCollectionResolver = React.useCallback<CollectionResolverRegistration>((resolver, resolveDataPath, owner = \"default\") => {\n if (!resolver && !resolveDataPath) {\n resolversRef.current.delete(owner);\n return;\n }\n resolversRef.current.set(owner, { resolveCollection: resolver, resolveDataPath });\n }, []);\n const entityDataOptions = useMemo(() => ({\n resolveCollection: (slug: string) => {\n for (const { resolveCollection } of resolversRef.current.values()) {\n const collection = resolveCollection?.(slug);\n if (collection) return collection;\n }\n return undefined;\n },\n // The owner that knows the collection decides where it is stored; with\n // none that does, the first that answers (a registry hands an unknown\n // path back unchanged).\n resolveDataPath: (path: string) => {\n const registrations = [...resolversRef.current.values()];\n const owning = registrations.find(({ resolveCollection }) => resolveCollection?.(path) !== undefined);\n if (owning?.resolveDataPath) return owning.resolveDataPath(path);\n for (const { resolveDataPath } of registrations) {\n const dataPath = resolveDataPath?.(path);\n if (dataPath !== undefined) return dataPath;\n }\n return undefined;\n }\n }), []);\n\n // Build the data-source context: the declared registry plus a RebaseData\n // per direct/custom source (those carrying a client-side driver). Server-\n // mediated sources have no entry — they ride the default client.\n //\n // Shallow-compared against the previous build (key/engine/transport +\n // driver instances) so inline `dataSources` literals don't rebuild\n // RebaseData instances every render and thrash data-fetch effects that\n // key off the data identity.\n const dataSourcesRef = useRef<{\n sig: { key: string; engine: string; transport?: string; driver?: DataDriver }[];\n value: DataSourcesContextValue;\n } | null>(null);\n const dataSourcesValue = useMemo<DataSourcesContextValue>(() => {\n const sig = normalizedDataSources.map((d) => ({ key: d.key, engine: d.engine, transport: d.transport, driver: d.driver }));\n const prev = dataSourcesRef.current;\n if (prev\n && prev.sig.length === sig.length\n && sig.every((s, i) => prev.sig[i].key === s.key\n && prev.sig[i].engine === s.engine\n && prev.sig[i].transport === s.transport\n && prev.sig[i].driver === s.driver)) {\n return prev.value;\n }\n const registry: Record<string, DataSourceDefinition> = {};\n const sources: Record<string, RebaseData> = {};\n for (const ds of normalizedDataSources) {\n const { driver, ...definition } = ds;\n // Materialize the inferred transport so downstream consumers\n // (routing, editor capabilities) always see a concrete value.\n registry[ds.key] = {\n ...definition,\n transport: ds.transport ?? (driver ? \"direct\" : \"server\")\n };\n if (driver) sources[ds.key] = buildRebaseData(driver, entityDataOptions);\n }\n const value: DataSourcesContextValue = { registry, sources };\n dataSourcesRef.current = { sig, value };\n return value;\n }, [normalizedDataSources, entityDataOptions]);\n\n // The RLS simulator. While a simulation is set the default data source is\n // a client derived with `client.simulate()`: the same server and token,\n // the simulation headers on every request, no socket and no offline\n // cache. The data identity changes with it, so every data view refetches\n // as the simulated identity. Dropped when the signed-in account changes.\n const [simulationState, setSimulationState] = useState<{\n simulation: AccessSimulation;\n label: RlsSimulationLabel | null;\n uid: string | undefined;\n } | null>(null);\n const signedInUid = authController.user?.uid;\n const activeSimulation = simulationState && simulationState.uid === signedInUid ? simulationState : null;\n const simulationAvailable = Boolean(client?.simulate) && !dataSourcesValue.sources[DEFAULT_DATA_SOURCE_KEY];\n const simulatedClient = useMemo(\n () => (activeSimulation && simulationAvailable && client?.simulate ? client.simulate(activeSimulation.simulation) : undefined),\n [activeSimulation, simulationAvailable, client]\n );\n // Every view below remounts when the simulated identity changes. A data\n // view keeps the rows it last loaded when a read fails, so switching in\n // place would leave the administrator's rows on screen under an identity\n // that cannot read them — the one thing a simulator must never show.\n const simulationResetKey = activeSimulation ? JSON.stringify(activeSimulation.simulation) : \"self\";\n const rlsSimulationController = useMemo<RlsSimulationController>(() => ({\n available: simulationAvailable,\n simulation: activeSimulation?.simulation ?? null,\n label: activeSimulation?.label ?? null,\n setSimulation: (simulation, label) => setSimulationState(simulation\n ? { simulation, label: label ?? null, uid: signedInUid }\n : null)\n }), [simulationAvailable, activeSimulation, signedInUid]);\n\n // Default data source — serves every collection not routed to a\n // registered direct/custom source. Resolution:\n // 1. A \"(default)\"-keyed data source with a driver.\n // 2. `client.data`.\n // 3. The sole registered source, when it is the only candidate.\n const resolvedData = useMemo(() => {\n const registeredDefault = dataSourcesValue.sources[DEFAULT_DATA_SOURCE_KEY];\n if (registeredDefault) return registeredDefault;\n // admin boundary: the SDK client returns flat rows; wrap them into the\n // Entity view-model the admin (`useData()`) renders.\n if (simulatedClient) return wrapAsEntityData(simulatedClient.data, entityDataOptions);\n if (client?.data) return wrapAsEntityData(client.data, entityDataOptions);\n const built = Object.values(dataSourcesValue.sources);\n if (built.length === 1) return built[0];\n if (built.length > 1) {\n throw new Error(\n \"[Rebase] Several data sources are registered but none is the default. \" +\n \"Pass a `client`, or key one `dataSources` entry \\\"(default)\\\".\"\n );\n }\n throw new Error(\"Rebase requires either `client` or a `dataSources` entry with a driver to be provided\");\n }, [client, simulatedClient, dataSourcesValue, entityDataOptions]);\n\n // Storage fallback logic\n const resolvedStorage = storageSourceProp ?? client?.storage;\n\n // ── Storage sources (mirrors the dataSources pattern) ────────────\n // Storage-source definitions discovered from the backend via\n // `GET /api/storage/sources`. The backend is the single source of truth;\n // server-transport sources are auto-wired on the client, `direct` sources\n // are completed by the `storageSources` prop (which holds live instances).\n const [remoteStorageSources, setRemoteStorageSources] = useState<StorageSourceDefinition[]>([]);\n // Who is signed in, not the user object: a token refresh or a profile edit\n // hands over a new object for the same person, and the listing does not\n // depend on anything but being allowed to ask.\n const authUid = authController.user?.uid;\n const loginSkipped = authController.loginSkipped;\n // Not asked when `GET /auth/config` says the backend has no storage: the\n // answer is already known, and asking would cost a request on every page\n // load. While that config is still in flight (`null`), wait for it.\n const storageEnabled = authController.storageEnabled;\n useEffect(() => {\n if (!client?.fetchStorageSources) return;\n if (storageEnabled === false || storageEnabled === null) return;\n let cancelled = false;\n client.fetchStorageSources()\n .then((defs) => { if (!cancelled) setRemoteStorageSources(defs); })\n .catch((e) => {\n // A 401 before auth is expected; the effect re-runs once the\n // user logs in (authUid/loginSkipped change) and retries.\n //\n // Guarded on `cancelled` like the success path: once this\n // provider is gone (or the effect re-ran) the outcome of the\n // request describes nothing that still exists, and the request\n // outlives the provider by however long the network takes to\n // give up — so an unguarded write here lands at an arbitrary\n // later moment. In a test worker that moment is after the file\n // finished, which closes the run's console channel mid-write\n // and fails an otherwise green suite.\n if (!cancelled) console.debug(\"[Rebase] Could not load storage sources\", e);\n });\n return () => { cancelled = true; };\n }, [client, authUid, loginSkipped, storageEnabled]);\n\n // Normalize the prop + discovered definitions into a registry + sources map.\n const storageSourcesRef = useRef<{\n propList: { key: string; source?: StorageSource; transport?: string }[];\n remote: StorageSourceDefinition[];\n resolvedStorage?: StorageSource;\n client?: typeof client;\n value: StorageSourcesContextValue;\n } | null>(null);\n const storageSourcesValue = useMemo<StorageSourcesContextValue>(() => {\n const list = storageSourcesProp ?? [];\n const prev = storageSourcesRef.current;\n // Stable identity unless an input actually changed (the prop may be a\n // fresh array literal on every render; sources are compared by identity).\n if (prev\n && prev.remote === remoteStorageSources\n && prev.resolvedStorage === resolvedStorage\n && prev.client === client\n && prev.propList.length === list.length\n && list.every((s, i) => prev.propList[i].key === s.key\n && prev.propList[i].source === s.source\n && prev.propList[i].transport === s.transport)) {\n return prev.value;\n }\n const registry: Record<string, StorageSourceDefinition> = {};\n const sources: Record<string, StorageSource> = {};\n\n // 1. Definitions discovered from the backend (labels, engine, transport).\n for (const def of remoteStorageSources) {\n registry[def.key] = def;\n }\n\n // 2. Server-backed named sources wired on the client registry: the\n // default, `createRebaseClient({ storageSources })`, and any\n // server-transport sources auto-registered by `fetchStorageSources`.\n if (client?.storageRegistry) {\n for (const key of client.storageRegistry.list()) {\n const source = client.storageRegistry.get(key);\n if (source) sources[key] = source;\n }\n }\n\n // 3. App-provided definitions: `direct` live sources and overrides.\n for (const ss of list) {\n const { source, ...definition } = ss;\n registry[ss.key] = definition;\n if (source) {\n // `direct` transport: app-provided live source (e.g. Firebase).\n sources[ss.key] = source;\n } else if (!sources[ss.key]\n && ss.transport === \"server\"\n && ss.key !== DEFAULT_STORAGE_SOURCE_KEY\n && client?.createStorageSource) {\n // `server` transport declared only on the prop: build a\n // backend-routed source so requests carry `?storageId=key`.\n sources[ss.key] = client.createStorageSource(ss.key);\n }\n }\n // 4. Default/server storage from the client.\n if (resolvedStorage && !sources[DEFAULT_STORAGE_SOURCE_KEY]) {\n sources[DEFAULT_STORAGE_SOURCE_KEY] = resolvedStorage;\n }\n // A key no source above answers — `/storage/sources` has not loaded,\n // or failed — is still routed to the server under its own name, never\n // to the default source. One instance per key.\n const buildSource = client?.createStorageSource;\n const built = new Map<string, StorageSource>();\n const createSource = buildSource\n ? (key: string): StorageSource => {\n const existing = built.get(key);\n if (existing) return existing;\n const source = buildSource(key);\n built.set(key, source);\n return source;\n }\n : undefined;\n const value: StorageSourcesContextValue = { registry, sources, createSource };\n storageSourcesRef.current = {\n propList: list.map((s) => ({ key: s.key, source: s.source, transport: s.transport })),\n remote: remoteStorageSources,\n resolvedStorage,\n client,\n value\n };\n return value;\n }, [storageSourcesProp, remoteStorageSources, resolvedStorage, client]);\n\n // Database admin — use explicit prop, or derive from client.ws / driver when available.\n const resolvedDatabaseAdmin = useMemo(() => {\n if (databaseAdmin) return databaseAdmin;\n\n // 1. The default source's DataDriver exposes `.admin` capability object\n const defaultDriver = normalizedDataSources.find((d) => d.key === DEFAULT_DATA_SOURCE_KEY && d.driver)?.driver\n ?? (!client && normalizedDataSources.length === 1 ? normalizedDataSources[0].driver : undefined);\n if (defaultDriver?.admin) {\n return defaultDriver.admin;\n }\n\n // 2. Auto-derive from the client's WebSocket connection (Rebase backend)\n const ws = client?.ws;\n if (ws && canExecuteSql(ws)) {\n const wsAdmin = ws;\n return {\n executeSql: wsAdmin.executeSql!.bind(wsAdmin),\n runSqlScript: wsAdmin.runSqlScript?.bind(wsAdmin),\n fetchAvailableDatabases: wsAdmin.fetchAvailableDatabases?.bind(wsAdmin),\n fetchAvailableRoles: wsAdmin.fetchAvailableRoles?.bind(wsAdmin),\n fetchApplicationRoles: wsAdmin.fetchApplicationRoles?.bind(wsAdmin),\n fetchCurrentDatabase: wsAdmin.fetchCurrentDatabase?.bind(wsAdmin),\n fetchUnmappedTables: wsAdmin.fetchUnmappedTables?.bind(wsAdmin),\n fetchTableMetadata: wsAdmin.fetchTableMetadata?.bind(wsAdmin),\n // Branch admin capabilities\n ...(typeof wsAdmin.createBranch === \"function\" ? {\n createBranch: wsAdmin.createBranch.bind(wsAdmin),\n deleteBranch: wsAdmin.deleteBranch!.bind(wsAdmin),\n listBranches: wsAdmin.listBranches!.bind(wsAdmin)\n } : {})\n };\n }\n\n return undefined;\n }, [databaseAdmin, client, normalizedDataSources]);\n\n if (!resolvedStorage && typeof console !== \"undefined\") {\n console.warn(\n \"[Rebase] No storageSource provided. File upload features will not work. \" +\n \"Provide storageSource via props or through a RebaseClient.\"\n );\n }\n\n const pluginsLoading = plugins?.some((p) => p.loading) ?? false;\n\n const loading = authController.initialLoading || pluginsLoading;\n\n const customizationController: CustomizationController = useMemo(() => ({\n dateTimeFormat,\n locale,\n entityLinkBuilder,\n plugins,\n resolvedSlots,\n entityViews: entityViews ?? [],\n collectionViews: collectionViews ?? [],\n entityActions: entityActions ?? [],\n propertyConfigs: propertyConfigs ?? {},\n components: componentsProp\n }), [dateTimeFormat, locale, entityLinkBuilder, plugins, resolvedSlots, entityViews, collectionViews, entityActions, propertyConfigs, componentsProp]);\n\n // Keyed on the handler: an inline one — gated on consent, say — closes over\n // that render's state, and the first one frozen kept its consent forever.\n const analyticsController = useMemo(() => ({\n onAnalyticsEvent\n }), [onAnalyticsEvent]);\n\n const fallbackEffectiveRoleController = useEffectiveRoleState();\n const activeEffectiveRoleController = effectiveRoleController ?? fallbackEffectiveRoleController;\n\n // Built either way (a hook cannot be skipped), but switched off — no class\n // on <html>, no media query, no storage — when the host owns the theme.\n const ownModeController = useBuildModeController({ enabled: !modeControllerProp });\n const modeController = modeControllerProp ?? ownModeController;\n const adminModeController = useBuildAdminModeController();\n\n if (authController.authError) {\n return (\n <CenteredView maxWidth={\"md\"}>\n <ErrorView\n title={\"Error loading auth\"}\n error={authController.authError as Error | string}/>\n </CenteredView>\n );\n }\n\n // One tooltip provider for the whole admin: a tooltip under it uses it\n // instead of mounting its own, and neighbouring tooltips share the skip\n // delay (moving along a row of icons does not wait on each).\n const content = (\n <TooltipProvider>\n <RebaseI18nProvider locale={locale} translations={translations}>\n <GlobalComponentOverrideProvider overrides={componentsProp}>\n <SnackbarProvider>\n <ModeControllerProvider value={modeController}>\n <AdminModeControllerProvider value={adminModeController}>\n <RebaseClientInstanceContext.Provider value={client}>\n <AnalyticsContext.Provider value={analyticsController}>\n <CustomizationControllerContext.Provider value={customizationController}>\n <UserConfigurationPersistenceContext.Provider\n value={resolvedUserConfigPersistence}>\n <StorageSourcesContext.Provider\n value={storageSourcesValue}>\n <StorageSourceContext.Provider\n value={resolvedStorage}>\n <CollectionResolverRegistrationContext.Provider\n value={registerCollectionResolver}>\n <DataSourcesContext.Provider\n value={dataSourcesValue}>\n <RlsSimulationContext.Provider\n value={rlsSimulationController}>\n <RebaseDataContext.Provider\n value={resolvedData}>\n <DatabaseAdminContext.Provider\n value={resolvedDatabaseAdmin}>\n <AuthControllerContext.Provider\n value={authController}>\n <EffectiveRoleControllerContext.Provider value={activeEffectiveRoleController}>\n <DialogsProvider>\n <SchemaDriftProvider>\n <RebaseRegistryProvider>\n <RebaseInternal\n loading={loading}\n resetKey={simulationResetKey}>\n {children}\n </RebaseInternal>\n </RebaseRegistryProvider>\n </SchemaDriftProvider>\n </DialogsProvider>\n </EffectiveRoleControllerContext.Provider>\n </AuthControllerContext.Provider>\n </DatabaseAdminContext.Provider>\n </RebaseDataContext.Provider>\n </RlsSimulationContext.Provider>\n </DataSourcesContext.Provider>\n </CollectionResolverRegistrationContext.Provider>\n </StorageSourceContext.Provider>\n </StorageSourcesContext.Provider>\n </UserConfigurationPersistenceContext.Provider>\n </CustomizationControllerContext.Provider>\n </AnalyticsContext.Provider>\n </RebaseClientInstanceContext.Provider>\n </AdminModeControllerProvider>\n </ModeControllerProvider>\n </SnackbarProvider>\n </GlobalComponentOverrideProvider>\n </RebaseI18nProvider>\n </TooltipProvider>\n );\n\n const resolvedApiUrl = apiUrl || client?.baseUrl || (typeof window !== \"undefined\" ? window.location.origin : \"\");\n\n if (resolvedApiUrl) {\n return (\n <ApiConfigProvider\n apiUrl={resolvedApiUrl}\n apiPath={client?.apiPath}\n getAuthToken={authController.getAuthToken}\n >\n {content}\n </ApiConfigProvider>\n );\n }\n\n return content;\n\n}\n\nfunction RebaseInternal({\n loading,\n resetKey,\n children\n}: {\n loading: boolean;\n /** Remounts the app below when it changes — see `simulationResetKey`. */\n resetKey: string;\n children: React.ReactNode | ((props: { context: RebaseContext; loading: boolean; }) => React.ReactNode);\n}) {\n\n const context = useRebaseContext();\n const customizationController = useCustomizationController();\n\n const childrenResult = (\n <React.Fragment key={resetKey}>\n {typeof children === \"function\" ? children({ context, loading }) : children}\n </React.Fragment>\n );\n\n const plugins = customizationController.plugins;\n const authController = context.authController;\n const authReady = !loading\n && !authController.authLoading\n && (Boolean(authController.user) || authController.loginSkipped);\n\n if (plugins && plugins.length > 0) {\n return (\n <PluginProviderStack\n plugins={plugins}\n scope=\"root\"\n scopeProps={{ context }}>\n <PluginLifecycleManager plugins={plugins} context={context} authReady={authReady}/>\n {childrenResult}\n </PluginProviderStack>\n );\n }\n\n return childrenResult;\n}\n\n","import { createBrowserRouter } from \"react-router\"\nimport { RouterProvider } from \"react-router/dom\"\nimport { removeInitialAndTrailingSlashes } from \"@rebasepro/app\";\n\nexport function RebaseRouter({\n children,\n basePath\n}: {\n children: React.ReactNode,\n basePath?: string;\n}) {\n return <RouterProvider router={createBrowserRouter([\n {\n path: basePath ? `${removeInitialAndTrailingSlashes(basePath)}/*` : \"/*\",\n element: children\n }\n ])}/>;\n}\n","import React from \"react\";\nimport { Route, Routes, useLocation } from \"react-router\";\n\n\n/**\n * A drop-in replacement for react-router's `<Routes>` that preserves the\n * underlying view when a side dialog navigates the URL to a different path.\n *\n * When opening a side dialog from e.g. `/posts` to `authors/123#side`,\n * the `base_location` stored in router state is used so the route tree\n * keeps rendering the original `/posts` view underneath the dialog overlay.\n *\n * Additionally, registered views from `useNavigationStateController()` are\n * automatically routed — no need to manually map them to `<Route>` elements.\n * Views with `nestedRoutes: true` get a wildcard route (slug/*) as well.\n * Explicitly declared `children` routes take priority.\n */\nexport function RebaseRoutes({ children }: { children?: React.ReactNode }) {\n const location = useLocation();\n const state = location.state as Record<string, unknown> | null;\n const baseLocation = state?.base_location ?? location;\n\n return <Routes location={baseLocation}>{children}</Routes>;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { deepEqual } from \"fast-equals\";\nimport { RebaseClientError } from \"@rebasepro/types\";\nimport type { User, AuthChangeEvent, RebaseSession } from \"@rebasepro/types\";\nimport type { AuthConfigResponse } from \"./api\";\nimport { RebaseAuthController, RebaseAuthControllerProps } from \"./types\";\nimport { bindSessionCachesToUser, clearSessionCaches } from \"./session_caches\";\n\n/**\n * Auth controller hook for JWT-based authentication.\n *\n * This is a thin React binding over the headless SDK `client.auth`.\n * It synchronizes React state with the SDK's internal state and delegates\n * all operations to the SDK to ensure a single source of truth for\n * authentication sessions across the entire application.\n *\n * @param props Configuration options\n * @returns RebaseAuthController instance\n */\nexport function useRebaseAuthController(\n props: RebaseAuthControllerProps = {}\n): RebaseAuthController {\n const { client, onSignOut, defineRolesFor } = props;\n const auth = client?.auth;\n\n const [user, setUser] = useState<User | null>(null);\n const [authLoading, setAuthLoading] = useState(false);\n const [initialLoading, setInitialLoading] = useState(true);\n const [authError, setAuthError] = useState<Error | null>(null);\n const [authProviderError, setAuthProviderError] = useState<Error | null>(null);\n const [loginSkipped, setLoginSkipped] = useState(false);\n const [extra, setExtra] = useState<unknown>(null);\n const [authConfig, setAuthConfig] = useState<AuthConfigResponse | null>(null);\n const [authConfigFailed, setAuthConfigFailed] = useState(false);\n const [heldScopes, setHeldScopes] = useState<string[] | undefined>(undefined);\n\n const isMountedRef = useRef(true);\n // Keep a stable ref to onSignOut so the listener never goes stale.\n const onSignOutRef = useRef(onSignOut);\n onSignOutRef.current = onSignOut;\n // Keep a stable ref to defineRolesFor too, so an inline (non-memoized)\n // function from the consumer does not re-run the sync effect on every\n // render — which would re-subscribe to auth events and re-fetch the\n // (uncached) auth config each time.\n const defineRolesForRef = useRef(defineRolesFor);\n defineRolesForRef.current = defineRolesFor;\n\n const clearError = useCallback(() => {\n setAuthProviderError(null);\n }, []);\n\n // Sync state with client.auth\n useEffect(() => {\n if (!auth) {\n setInitialLoading(false);\n return;\n }\n\n isMountedRef.current = true;\n\n // `defineRolesFor` is usually a fetch, so updates can finish out of\n // order. Only the latest one may set the user: an earlier call that\n // resolves last would otherwise bring back a user who has since signed\n // out, or overwrite the one who signed in after them.\n let latestUpdate = 0;\n\n const updateState = async (session: RebaseSession | null) => {\n if (!isMountedRef.current) return;\n const update = ++latestUpdate;\n\n let userToSet = session?.user ?? null;\n const defineRolesFor = defineRolesForRef.current;\n if (userToSet && defineRolesFor) {\n try {\n const roles = await defineRolesFor(userToSet);\n if (roles && isMountedRef.current) {\n userToSet = { ...userToSet, roles };\n }\n } catch (e) {\n console.error(\"Error defining roles:\", e);\n }\n }\n\n if (update !== latestUpdate) return;\n if (isMountedRef.current) {\n const nextUser = userToSet;\n if (nextUser) bindSessionCachesToUser(nextUser.uid);\n // A token refresh (hourly, and a few times at boot) hands over a\n // freshly mapped user every time. The same user, field for field,\n // keeps the object the app already holds: as a new one it changed\n // the controller, and with it every context consumer, and re-ran\n // every effect keyed on the user.\n setUser(previous => (previous && nextUser && deepEqual(previous, nextUser)) ? previous : nextUser);\n }\n };\n\n // Fetched at mount and again on every sign-in and sign-out. The config\n // is not fixed for the life of the tab: `needsSetup` turns false the\n // moment the first admin is created, and a stale `true` showed only\n // the bootstrap form to the next person to sign out — no way to sign\n // in until a reload. Only the latest answer is applied.\n let latestConfigRequest = 0;\n function loadAuthConfig() {\n if (!auth) return;\n const request = ++latestConfigRequest;\n auth.getAuthConfig().then((config: AuthConfigResponse) => {\n if (isMountedRef.current && request === latestConfigRequest) setAuthConfig(config);\n }).catch((e: unknown) => {\n // Swallowed entirely before. This is what tells the login view which\n // providers exist, so losing it renders a login form that is wrong\n // rather than one that is broken — the hardest kind to report. Not\n // promoted to `authError`, which blanks the whole app: a signed-in\n // user is unaffected by this failing.\n console.warn(\"[Rebase] Could not load the backend auth configuration; \" +\n \"the login view will fall back to defaults.\", e);\n if (isMountedRef.current && request === latestConfigRequest) setAuthConfigFailed(true);\n });\n }\n\n const syncState = async (event: AuthChangeEvent, session: RebaseSession | null) => {\n if (event === \"SIGNED_IN\" || event === \"SIGNED_OUT\") {\n loadAuthConfig();\n }\n if (event === \"SIGNED_OUT\") {\n // What the session that just ended read. The caches are\n // module-level and keyed by path only, so without this the next\n // user in the same tab is shown rows they may not be allowed to\n // read — tables and previews render straight out of them.\n clearSessionCaches();\n }\n await updateState(session);\n if (event === \"SIGNED_OUT\") {\n if (isMountedRef.current) {\n setLoginSkipped(false);\n }\n onSignOutRef.current?.();\n }\n };\n\n // Initial sync with whatever is currently in the SDK\n updateState(auth.getSession());\n\n // Wait for SDK initialization (restoring session from storage or silent refresh)\n auth.isInitialized().then(() => {\n if (isMountedRef.current) {\n updateState(auth.getSession());\n setInitialLoading(false);\n }\n }).catch(() => {\n if (isMountedRef.current) setInitialLoading(false);\n });\n\n // Fetch backend auth configuration\n loadAuthConfig();\n\n const unsubscribe = auth.onAuthStateChange(syncState);\n\n return () => {\n isMountedRef.current = false;\n unsubscribe();\n };\n }, [auth]);\n\n // The scopes the signed-in user holds, read again whenever who that is, or\n // which roles they have, changes. A screen offers an admin action only to\n // those its route admits; `undefined` — not yet known — admits nobody.\n const scopeListing = client?.personalKeys;\n const signedInAs = user ? `${user.uid}|${(user.roles ?? []).join(\",\")}` : undefined;\n useEffect(() => {\n setHeldScopes(undefined);\n if (!signedInAs || !scopeListing) return;\n let current = true;\n scopeListing.listScopes()\n .then(({ held }) => { if (current) setHeldScopes(held); })\n .catch((e: unknown) => console.warn(\"[Rebase] Could not read the scopes this user holds.\", e));\n return () => { current = false; };\n }, [signedInAs, scopeListing]);\n\n const getAuthToken = useCallback(async (): Promise<string> => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n let session = auth.getSession();\n\n // On load the session may still be being restored (in cookie mode it\n // always is, until the server answers): what that finds is the answer.\n if (!session) {\n await auth.isInitialized().catch(() => undefined);\n session = auth.getSession();\n }\n\n // Nobody is signed in, so there is nothing to refresh. Asking anyway\n // sent a `POST /auth/refresh` the server could only refuse, an error in\n // the console for every anonymous caller.\n if (!session) {\n throw new RebaseClientError(\"Not signed in: there is no session to read a token from.\", { code: \"NOT_SIGNED_IN\" });\n }\n\n // If we have a valid token, return it\n if (session.accessToken && session.expiresAt > Date.now() + 10000) {\n return session.accessToken;\n }\n\n // Otherwise, refresh\n const newSession = await auth.refreshSession();\n return newSession.accessToken;\n }, [auth]);\n\n const signOut = useCallback(async () => {\n if (!auth) return;\n setAuthLoading(true);\n try {\n await auth.signOut();\n // signOut emits SIGNED_OUT → syncState calls onSignOutRef.current\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const emailPasswordLogin = useCallback(async (email: string, password: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.signInWithEmail(email, password);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const register = useCallback(async (email: string, password: string, displayName?: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n const result = await auth.signUp(email, password, displayName);\n const confirmationRequired = typeof result === \"object\" && result !== null\n && \"confirmationRequired\" in result && result.confirmationRequired === true;\n return { confirmationRequired };\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const googleLogin = useCallback(async (\n payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }\n ) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.signInWithGoogle(payload);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const oauthLogin = useCallback(async (providerId: string, payload: Record<string, unknown>) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.signInWithOAuth(providerId, payload);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n /**\n * Open the challenge that finishes a sign-in refused with `MFA_REQUIRED`.\n *\n * `mfaToken` is that refusal's `details.mfaToken`, sent on this request\n * only. Every sign-in method above lands such a refusal in\n * `authProviderError`, which is where the login view reads it from.\n */\n const startMfaChallenge = useCallback(async (mfaToken: string, factorId: string) => {\n if (!auth?.mfa) throw new Error(\"Rebase client with MFA is required\");\n const { challengeId } = await auth.mfa.challenge(factorId, { mfaToken });\n return challengeId;\n }, [auth]);\n\n /**\n * Answer that challenge. On success the SDK adopts the session and emits\n * SIGNED_IN, which sets the user like any other sign-in.\n *\n * A refused code is rethrown and NOT recorded in `authProviderError`: the\n * code step reports it itself, and the refusal it would replace is the\n * `MFA_REQUIRED` that says a sign-in is still waiting for its second\n * factor.\n */\n const verifyMfaChallenge = useCallback(async (mfaToken: string, challengeId: string, code: string) => {\n if (!auth?.mfa) throw new Error(\"Rebase client with MFA is required\");\n setAuthLoading(true);\n try {\n await auth.mfa.verifyChallenge(challengeId, code, { mfaToken });\n // Answered. Left in place, the refusal would reopen the code step\n // — for a token long expired — the next time the login screen is\n // shown, after a sign-out.\n setAuthProviderError(null);\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const skipLogin = useCallback(() => {\n setLoginSkipped(true);\n setUser(null);\n }, []);\n\n const forgotPassword = useCallback(async (email: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.resetPasswordForEmail(email);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const resetPassword = useCallback(async (token: string, password: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.resetPassword(token, password);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const verifyEmail = useCallback(async (token: string, options?: { password?: string; removeUnproven?: boolean }) => {\n if (!auth?.verifyEmail) throw new Error(\"Rebase client with email verification is required\");\n const result = await auth.verifyEmail(token, options);\n const isObject = typeof result === \"object\" && result !== null;\n return {\n passwordRemoved: isObject && \"passwordRemoved\" in result && result.passwordRemoved === true,\n signedIn: isObject && \"session\" in result && Boolean(result.session)\n };\n }, [auth]);\n\n const changePassword = useCallback(async (oldPassword: string, newPassword: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n // The SDK adopts the fresh session the server answers with: this\n // device stays signed in, every other one is signed out.\n await auth.changePassword(oldPassword, newPassword);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n /**\n * Sign in with a magic link's token. The SDK adopts the session and emits\n * SIGNED_IN; a refusal lands in `authProviderError` like every other\n * sign-in's, which is how an `MFA_REQUIRED` reaches the code step.\n */\n const magicLinkLogin = useCallback(async (token: string) => {\n if (!auth?.verifyMagicLink) throw new Error(\"Rebase client with magic links is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n await auth.verifyMagicLink(token);\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n\n const changeEmail = useCallback(async (newEmail: string) => {\n if (!auth?.changeEmail) throw new Error(\"Rebase client with email change is required\");\n return await auth.changeEmail(newEmail);\n }, [auth]);\n\n const confirmEmailChange = useCallback(async (token: string) => {\n if (!auth?.confirmEmailChange) throw new Error(\"Rebase client with email change is required\");\n const { email, removedProviders } = await auth.confirmEmailChange(token);\n return { email, removedProviders };\n }, [auth]);\n\n const updateProfile = useCallback(async (displayName?: string, photoURL?: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n setAuthLoading(true);\n setAuthProviderError(null);\n try {\n const updatedUser = await auth.updateUser({ displayName, photoURL });\n return updatedUser;\n } catch (error: unknown) {\n const err = error instanceof Error ? error : new Error(String(error));\n setAuthProviderError(err);\n throw error;\n } finally {\n setAuthLoading(false);\n }\n }, [auth]);\n\n const fetchSessions = useCallback(async () => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n return await auth.getSessions();\n }, [auth]);\n\n const revokeSession = useCallback(async (sessionId: string) => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n await auth.revokeSession(sessionId);\n }, [auth]);\n\n const revokeAllSessions = useCallback(async () => {\n if (!auth) throw new Error(\"Rebase client with auth is required\");\n await auth.revokeAllSessions();\n }, [auth]);\n\n const baseUrl = client?.baseUrl;\n const getApiUrl = useCallback(() => baseUrl, [baseUrl]);\n const googleClientId = props.googleClientId;\n\n // One object per state, not per render: the controller is the auth\n // context's value, and `useRebaseContext()` is rebuilt — for every consumer\n // in the app — whenever it changes. Every field it carries is in the deps.\n return useMemo<RebaseAuthController>(() => ({\n user,\n authLoading,\n initialLoading,\n authError,\n authProviderError,\n loginSkipped,\n needsSetup: authConfig?.needsSetup ?? false,\n registrationEnabled: authConfig?.registrationEnabled ?? false,\n getAuthToken,\n getApiUrl,\n signOut,\n emailPasswordLogin,\n register,\n googleLogin,\n oauthLogin,\n skipLogin,\n forgotPassword,\n resetPassword,\n verifyEmail,\n changePassword,\n // Offered only when the client can, so the settings view and the\n // link's screen can tell a missing feature from a failed request.\n changeEmail: auth?.changeEmail ? changeEmail : undefined,\n magicLinkLogin: auth?.verifyMagicLink ? magicLinkLogin : undefined,\n confirmEmailChange: auth?.confirmEmailChange ? confirmEmailChange : undefined,\n updateProfile,\n fetchSessions,\n revokeSession,\n revokeAllSessions,\n clearError,\n setAuthProviderError,\n // Offered only when the client can answer a challenge, so a login\n // view can tell a second step it can take from one it cannot.\n startMfaChallenge: auth?.mfa ? startMfaChallenge : undefined,\n verifyMfaChallenge: auth?.mfa ? verifyMfaChallenge : undefined,\n heldScopes,\n // `null` until the config has been read, so the panel waits for it\n // rather than asking for storage sources the backend may not have.\n // `undefined` when it cannot be read, or says nothing: ask then.\n storageEnabled: authConfig\n ? authConfig.storage\n : (auth && !authConfigFailed ? null : undefined),\n extra,\n setExtra,\n // `authConfig` is null until `GET /auth/config` lands, so each fallback\n // is what to assume *while it is still in flight* — not a stand-in for a\n // backend that might omit the field. The backend always sends all of them.\n capabilities: {\n emailPasswordLogin: true,\n googleLogin: !!(googleClientId),\n registrationEnabled: authConfig?.registrationEnabled ?? false,\n passwordReset: authConfig?.passwordReset ?? false,\n // True while loading: the admin UI's \"Reset Password\" action is worth\n // showing optimistically and hiding once a backend says it cannot.\n adminPasswordReset: authConfig?.adminPasswordReset ?? true,\n sessionManagement: true,\n profileUpdate: true,\n emailVerification: authConfig?.emailVerification ?? false,\n enabledProviders: authConfig?.enabledProviders ?? []\n }\n }), [\n user, authLoading, initialLoading, authError, authProviderError, loginSkipped,\n authConfig, authConfigFailed, heldScopes, extra, auth, googleClientId,\n getAuthToken, getApiUrl, signOut, emailPasswordLogin, register, googleLogin, oauthLogin,\n skipLogin, forgotPassword, resetPassword, verifyEmail, changePassword, changeEmail,\n magicLinkLogin, confirmEmailChange, updateProfile, fetchSessions, revokeSession,\n revokeAllSessions, clearError, startMfaChallenge, verifyMfaChallenge\n ]);\n}\n","/**\n * Auth-config fetch helper for the Rebase React frontend.\n *\n * The former per-endpoint auth client (login, register, refresh, OAuth,\n * sessions, …) has been removed: `useRebaseAuthController` now delegates to\n * the headless SDK's `client.auth` (from `@rebasepro/client`), which is the\n * single source of truth for the auth session. The only piece that remains\n * here is the unauthenticated `/api/auth/config` probe used to detect\n * bootstrap mode and enabled providers before a session exists.\n */\n\nimport { RebaseApiError } from \"@rebasepro/types\";\nimport type { AuthConfigDocument } from \"@rebasepro/types\";\nimport { DEFAULT_API_PATH } from \"../hooks/ApiConfigContext\";\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n let data: Record<string, unknown>;\n try {\n data = await response.json();\n } catch (parseError) {\n // Response wasn't JSON - could be network error or server issue\n throw new RebaseApiError(\n `Server returned non-JSON response (status: ${response.status})`,\n { status: response.status, code: \"PARSE_ERROR\" }\n );\n }\n\n if (!response.ok) {\n throw new RebaseApiError(\n (data as Record<string, Record<string, string>>).error?.message || \"Request failed\",\n {\n status: response.status,\n code: (data as Record<string, Record<string, string>>).error?.code || \"UNKNOWN_ERROR\"\n }\n );\n }\n\n return data as T;\n}\n\n/**\n * Wrapper for fetch that catches generic network failures (like server down)\n * and translates them to a {@link RebaseApiError} with code `NETWORK_ERROR`.\n */\nasync function fetchWithHandling(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n try {\n return await fetch(input, init);\n } catch (error: unknown) {\n if (error instanceof TypeError && error.message.includes(\"Failed to fetch\")) {\n throw new RebaseApiError(\n \"Failed to connect to the backend server. The backend might be down or failed to initialize (e.g., database connection timeout).\",\n { code: \"NETWORK_ERROR\", cause: error }\n );\n }\n throw new RebaseApiError(\n \"Network error: \" + (error instanceof Error ? error.message : String(error)),\n { code: \"NETWORK_ERROR\", cause: error }\n );\n }\n}\n\n/**\n * What `GET /api/auth/config` answers.\n *\n * The wire contract is declared once, in `@rebasepro/types`, and re-exported\n * here under the name this module uses. Three near-copies of it used to exist —\n * this one listed an `emailServiceEnabled` flag no backend sends, and marked as\n * optional fields every backend always returns.\n */\nexport type AuthConfigResponse = AuthConfigDocument;\n\n/**\n * Cache container for `fetchAuthConfig` — holds both the inflight promise\n * (to deduplicate concurrent calls) and the cached result.\n */\nexport interface AuthConfigCache {\n cached: AuthConfigResponse | null;\n inflight: Promise<AuthConfigResponse> | null;\n}\n\n/**\n * Create a fresh `AuthConfigCache` instance.\n * Callers own the cache object and pass it into `fetchAuthConfig` / `clearAuthConfigCache`.\n */\nexport function createAuthConfigCache(): AuthConfigCache {\n return { cached: null, inflight: null };\n}\n\n/**\n * Fetch auth configuration / status from the backend\n * This is an unauthenticated endpoint used to detect bootstrap mode.\n *\n * Results are cached for the session lifetime.\n * Concurrent calls are deduplicated: only one network request is made\n * and all callers share the same promise.\n */\nexport async function fetchAuthConfig(\n apiUrl: string,\n cache: AuthConfigCache,\n /** The backend's `basePath`; only needed if it is not the default. */\n apiPath: string = DEFAULT_API_PATH\n): Promise<AuthConfigResponse> {\n if (cache.cached) {\n return cache.cached;\n }\n\n if (cache.inflight) {\n return cache.inflight;\n }\n\n cache.inflight = (async () => {\n const response = await fetchWithHandling(`${apiUrl.replace(/\\/+$/, \"\")}${apiPath}/auth/config`, {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" }\n });\n return handleResponse<AuthConfigResponse>(response);\n })();\n\n try {\n const result = await cache.inflight;\n cache.cached = result;\n return result;\n } finally {\n cache.inflight = null;\n }\n}\n\n/**\n * Clear the cached auth config (e.g. on logout or for testing).\n */\nexport function clearAuthConfigCache(cache: AuthConfigCache): void {\n cache.cached = null;\n cache.inflight = null;\n}\n","const iconSynonyms: Record<string, string> = {};\nimport { iconKeys } from \"@rebasepro/ui\";\nimport Fuse from \"fuse.js\";\n\n\nconst map = iconKeys\n .map((importName) => {\n const iconSynonym = importName in iconSynonyms ? iconSynonyms[importName] : \"\";\n return {\n key: importName,\n synonyms: iconSynonym\n }\n });\nexport const iconsSearch = new Fuse(map, {\n isCaseSensitive: false,\n shouldSort: true,\n ignoreLocation: true,\n distance: 0,\n keys: [\"key\", \"synonyms\"]\n})\n\n\n","import React from \"react\";\nimport {\n cls,\n colorClassesMapping,\n coolIconKeys,\n IconColor,\n iconKeys,\n iconSize,\n LucideIconByName\n} from \"@rebasepro/ui\";\nimport { deepEqual as equal } from \"fast-equals\"\nimport { hashString, slugify } from \"@rebasepro/utils\";\n\n// iconKeys are now PascalCase strings (e.g. \"ShoppingCart\", \"Users\")\nconst iconKeysMap: Record<string, string> = iconKeys.reduce((acc: Record<string, string>, key) => {\n // Also add lowercase versions and snake_case versions to support legacy lookups\n const lower = key.toLowerCase();\n const snake = key.replace(/([A-Z])/g, \"_$1\").toLowerCase().replace(/^_/, \"\");\n acc[lower] = key;\n acc[snake] = key;\n acc[key] = key;\n return acc;\n}, {});\n\n/**\n * Render an icon element from a string key or existing React element.\n *\n * Whether a key names an icon is decided here, against `iconKeys` — an array\n * of strings. The component behind the key is fetched by `LucideIconByName` on\n * first use: this used to index lucide's full `icons` map, which is the whole\n * library and cannot be tree-shaken.\n */\nexport function getIcon(iconKey?: string | React.ReactNode,\n className?: string,\n color?: IconColor,\n size?: \"smallest\" | \"small\" | \"medium\" | \"large\" | number): React.ReactElement | undefined {\n\n if (React.isValidElement(iconKey)) {\n return iconKey;\n }\n\n if (!iconKey) return undefined;\n if (typeof iconKey === \"string\") {\n const lowerKey = iconKey.toLowerCase();\n const slugifiedKey = slugify(iconKey).replace(/-/g, \"_\");\n\n const mappedKey = iconKeysMap[iconKey] || iconKeysMap[lowerKey] || iconKeysMap[slugifiedKey];\n\n if (!mappedKey) {\n return undefined;\n }\n\n const sizeInPx = typeof size === \"number\" ? size : iconSize[size ?? \"medium\"];\n return <LucideIconByName\n name={mappedKey}\n size={sizeInPx}\n className={cls(\n color ? colorClassesMapping[color] : \"\",\n \"select-none shrink-0\",\n className\n )}\n />;\n }\n\n console.warn(\"Invalid icon key provided:\", iconKey);\n return undefined;\n}\n\nexport type IconViewProps = {\n slug: string;\n name: string;\n singularName?: string;\n group?: string;\n icon?: string | React.ReactNode;\n}\n\nexport const IconForView = React.memo(\n function IconForView({\n collectionOrView,\n className,\n color,\n size = \"medium\"\n }: {\n collectionOrView?: IconViewProps,\n color?: IconColor,\n className?: string,\n size?: \"smallest\" | \"small\" | \"medium\" | \"large\" | number,\n }): React.ReactElement {\n if (!collectionOrView) return <></>;\n const icon = getIcon(collectionOrView.icon, className, color, size);\n if (collectionOrView?.icon && icon)\n return icon;\n\n let pathname = slugify((\"singularName\" in collectionOrView ? collectionOrView.singularName : undefined) ?? collectionOrView.name).replace(/-/g, \"_\");\n\n let key: string | undefined;\n if (pathname in iconKeysMap)\n key = iconKeysMap[pathname];\n\n if (!key) {\n pathname = slugify(collectionOrView.slug).replace(/-/g, \"_\");\n if (pathname in iconKeysMap)\n key = iconKeysMap[pathname];\n }\n\n const iconsCount = coolIconKeys.length;\n\n if (!key)\n key = coolIconKeys[hashString(collectionOrView.slug) % iconsCount];\n\n const sizeInPx = typeof size === \"number\" ? size : iconSize[size];\n return <LucideIconByName\n name={key}\n size={sizeInPx}\n className={cls(\n color ? colorClassesMapping[color] : \"\",\n \"select-none shrink-0\",\n className\n )}\n />;\n }, (prevProps, nextProps) => {\n return equal(prevProps.collectionOrView?.icon, nextProps.collectionOrView?.icon) &&\n prevProps.collectionOrView?.name === nextProps.collectionOrView?.name &&\n prevProps.collectionOrView?.slug === nextProps.collectionOrView?.slug &&\n prevProps.collectionOrView?.singularName === nextProps.collectionOrView?.singularName &&\n equal(prevProps.color, nextProps.color) &&\n prevProps.className === nextProps.className &&\n prevProps.size === nextProps.size;\n });\n","import { FormexController } from \"@rebasepro/forms\";\n\nexport function createFormexStub<T extends object>(values: T): FormexController<T> {\n const errorMessage = \"You are in a read-only context. You cannot modify the formex controller.\";\n\n return {\n debugId: \"\",\n values,\n initialValues: values,\n touched: {} as Record<string, boolean>,\n dirty: false,\n errors: {} as Record<string, string>,\n submitCount: 0,\n isSubmitting: false,\n isValidating: false,\n version: 0,\n canUndo: false,\n canRedo: false,\n\n setValues: () => {\n throw new Error(errorMessage);\n },\n setTouched(touched: Record<string, boolean>): void {\n throw new Error(errorMessage);\n },\n setFieldValue: () => {\n throw new Error(errorMessage);\n },\n setFieldTouched: () => {\n throw new Error(errorMessage);\n },\n setDirty: () => {\n throw new Error(errorMessage);\n },\n setSubmitCount: () => {\n throw new Error(errorMessage);\n },\n setFieldError: () => {\n throw new Error(errorMessage);\n },\n handleChange: () => {\n throw new Error(errorMessage);\n },\n handleBlur: () => {\n throw new Error(errorMessage);\n },\n handleSubmit: () => {\n throw new Error(errorMessage);\n },\n validate: () => {\n throw new Error(errorMessage);\n },\n resetForm: () => {\n throw new Error(errorMessage);\n },\n setSubmitting: () => {\n throw new Error(errorMessage);\n },\n undo: () => {\n throw new Error(errorMessage);\n },\n redo: () => {\n throw new Error(errorMessage);\n }\n };\n}\n","\nimport type { ArrayProperty, Property, StringProperty } from \"@rebasepro/types\";\nimport Compressor from \"compressorjs\";\nimport { deepEqual as equal } from \"fast-equals\";\n\nimport { resourceKeyOf } from \"@rebasepro/types\";\nimport { EntityValues, StorageConfig, StorageSource, StorageSourceRegistry, UploadFileProps } from \"@rebasepro/types\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { resolveStorageFilenameString, resolveStoragePathString, resolveStorageSource } from \"@rebasepro/common\";\nimport { useAuthController } from \"../hooks\";\nimport { useStorageSources } from \"../contexts/StorageSourcesContext\";\nimport { randomString } from \"@rebasepro/utils\";\n\nexport type StorageFieldSize = \"smallest\" | \"small\" | \"medium\" | \"large\" | number;\n\n/**\n * Internal representation of an item in the storage\n * It can have two states, having a storagePathOrDownloadUrl set,\n * which means the file has been uploaded, and it is rendered as a preview\n * Or have a pending file being uploaded.\n */\nexport interface StorageFieldItem {\n id: number; // generated on the fly for internal use only\n storagePathOrDownloadUrl?: string;\n file?: File;\n fileName?: string;\n metadata?: Record<string, unknown>,\n size: StorageFieldSize\n}\n\nexport function useStorageUploadController<M extends Record<string, unknown>>({\n entityId,\n entityValues,\n path,\n value,\n property,\n propertyKey,\n storageSource,\n storageSourceRegistry,\n collectionSlug,\n disabled,\n onChange\n}:\n {\n entityId?: string | number,\n entityValues: EntityValues<M>,\n value: string | string[] | null;\n path?: string,\n propertyKey: string,\n property: StringProperty | ArrayProperty | StringProperty | ArrayProperty,\n storageSource: StorageSource,\n /** Optional explicit registry. When omitted, the hook reads from the\n * `StorageSourcesContext` provided by `<Rebase storageSources={...}>`. */\n storageSourceRegistry?: StorageSourceRegistry,\n /** The slug of the collection the property belongs to, so the server\n * can hold the upload to the property's own `maxSize`/`acceptedFiles`. */\n collectionSlug?: string,\n disabled: boolean,\n onChange: (value: string | string[] | null) => void\n }) {\n\n const authController = useAuthController();\n const storageSources = useStorageSources();\n const storage: StorageConfig | undefined = property.type === \"string\"\n ? property.storage\n : property.type === \"array\" &&\n (property.of as Property).type === \"string\"\n ? (property.of as StringProperty).storage\n : undefined;\n\n // Resolve the correct storage source for this property.\n // Priority: explicit registry prop → StorageSourcesContext → default.\n const propertySource = useMemo(() => resolveStorageSource({\n sourceKey: storage?.storageSource === undefined ? undefined : resourceKeyOf(storage.storageSource),\n registry: storageSourceRegistry,\n sources: storageSources.sources,\n defaultSource: storageSource,\n createSource: storageSources.createSource\n }), [storage?.storageSource, storageSourceRegistry, storageSources.sources, storageSources.createSource, storageSource]);\n\n const multipleFilesSupported = property.type === \"array\";\n\n // What every upload of this property tells the storage source beyond the\n // file: `storage.public` (stored under the public prefix, served by a\n // stable token-less URL) and which property it is for. Neither used to be\n // sent, so a `public: true` field stored private files with expiring URLs,\n // and the server could not hold the upload to the property's own limits.\n //\n // Carried by the source this hook hands out — the one the field provides\n // to its upload components — so every upload of the property sends them,\n // whichever component calls `putObject`.\n const isPublic = storage?.public === true;\n const resolvedStorageSource = useMemo(() => withUploadOptions(propertySource, {\n ...(isPublic ? { public: true } : {}),\n ...(collectionSlug ? { context: { collection: collectionSlug, property: propertyKey } } : {})\n }), [propertySource, isPublic, collectionSlug, propertyKey]);\n\n if (!storage)\n throw Error(\"Storage meta must be specified\");\n\n const processFile = storage?.processFile;\n\n const metadata: Record<string, unknown> | undefined = storage?.metadata;\n // One preview size. A single-file field asked for \"large\" (a 220px\n // thumbnail) while a multi-file field asked for \"medium\" (118px), so two\n // upload fields in the same form reserved wildly different heights and\n // neither matched its own empty state.\n const size = \"medium\";\n\n const imageResize = storage?.imageResize;\n\n const internalInitialValue: StorageFieldItem[] =\n getInternalInitialValue(multipleFilesSupported, value, metadata, size);\n\n const [initialValue, setInitialValue] = useState<string | string[] | null>(value);\n const [internalValue, setInternalValue] = useState<StorageFieldItem[]>(internalInitialValue);\n\n useEffect(() => {\n if (!equal(initialValue, value)) {\n setInitialValue(value);\n setInternalValue(internalInitialValue);\n }\n }, [internalInitialValue, value, initialValue]);\n\n const fileNameBuilder = useCallback(async (file: File) => {\n if (storage.fileName) {\n const fileName = await resolveStorageFilenameString({\n input: storage.fileName,\n storage,\n values: entityValues,\n entityId,\n path,\n property: property,\n file,\n propertyKey\n });\n if (!fileName || fileName.length === 0) {\n throw Error(\"You need to return a valid filename\");\n }\n return fileName;\n }\n return randomString() + \"_\" + file.name;\n }, [entityId, entityValues, path, property, propertyKey, storage]);\n\n const storagePathBuilder = useCallback((file: File) => {\n return resolveStoragePathString({\n input: storage.storagePath,\n storage,\n values: entityValues,\n entityId,\n path,\n property: property,\n file,\n propertyKey\n }) ?? \"/\";\n }, [entityId, entityValues, path, property, propertyKey, storage]);\n\n const onFileUploadComplete = useCallback(async (uploadedPath: string,\n entry: StorageFieldItem,\n metadata?: Record<string, unknown>,\n uploadedUrl?: string) => {\n\n console.debug(\"onFileUploadComplete\", uploadedPath, entry);\n\n let uploadPathOrDownloadUrl: string | null = uploadedPath;\n\n if (storage.includeBucketUrl) {\n if (!uploadedUrl) {\n console.warn(\"includeBucketUrl is set but no fully-qualified storage URL was returned by the StorageSource. Falling back to the storage path.\");\n } else {\n uploadPathOrDownloadUrl = uploadedUrl;\n }\n }\n\n if (storage.storeUrl) {\n uploadPathOrDownloadUrl = (await resolvedStorageSource.getSignedUrl(uploadedPath)).url;\n }\n if (storage.postProcess && uploadPathOrDownloadUrl) {\n uploadPathOrDownloadUrl = await storage.postProcess(uploadPathOrDownloadUrl);\n }\n\n if (!uploadPathOrDownloadUrl) {\n console.warn(\"uploadPathOrDownloadUrl is null\")\n return;\n }\n\n let newValue: StorageFieldItem[];\n\n entry.storagePathOrDownloadUrl = uploadPathOrDownloadUrl;\n entry.metadata = metadata;\n newValue = [...internalValue];\n\n newValue = removeDuplicates(newValue);\n setInternalValue(newValue);\n\n const fieldValue = newValue\n .filter(e => !!e.storagePathOrDownloadUrl)\n .map(e => e.storagePathOrDownloadUrl as string);\n\n if (multipleFilesSupported) {\n onChange(fieldValue);\n } else {\n onChange(fieldValue ? fieldValue[0] : null);\n }\n }, [internalValue, multipleFilesSupported, onChange, storage, resolvedStorageSource]);\n\n const onFileUploadError = useCallback((entry: StorageFieldItem) => {\n console.debug(\"onFileUploadError\", entry);\n\n // Remove the failed entry from internalValue\n const newValue = internalValue.filter(item => item.id !== entry.id);\n setInternalValue(newValue);\n }, [internalValue]);\n\n const onFilesAdded = useCallback(async (acceptedFiles: File[]) => {\n\n if (!acceptedFiles.length || disabled)\n return;\n\n if (processFile) {\n try {\n acceptedFiles = await Promise.all(acceptedFiles.map(async file => {\n const processedFile = await processFile(file);\n if (!processedFile) {\n return file;\n }\n return processedFile;\n }));\n } catch (e) {\n console.error(\"Error processing file with custom code. Attempting to continue uploading.\", e);\n }\n }\n\n let newInternalValue: StorageFieldItem[];\n\n if (multipleFilesSupported) {\n newInternalValue = [...internalValue,\n ...(await Promise.all(acceptedFiles.map(async file => {\n if (imageResize && isImageFile(file)) {\n file = await resizeImage(file, imageResize);\n }\n\n return {\n id: getRandomId(),\n file,\n fileName: await fileNameBuilder(file),\n metadata,\n size\n } as StorageFieldItem;\n })))];\n } else {\n let file = acceptedFiles[0];\n if (imageResize && isImageFile(file)) {\n file = await resizeImage(file, imageResize);\n }\n\n newInternalValue = [{\n id: getRandomId(),\n file,\n fileName: await fileNameBuilder(file),\n metadata,\n size\n }];\n }\n\n // Remove either storage path or file duplicates\n newInternalValue = removeDuplicates(newInternalValue);\n setInternalValue(newInternalValue);\n }, [disabled, fileNameBuilder, internalValue, metadata, multipleFilesSupported, size, imageResize]);\n\n return {\n internalValue,\n setInternalValue,\n storage,\n fileNameBuilder,\n storagePathBuilder,\n onFileUploadComplete,\n onFileUploadError,\n onFilesAdded,\n multipleFilesSupported,\n /** The resolved StorageSource for this property — may differ from the\n * default context source when `StorageConfig.storageSource` is set —\n * whose uploads carry the property's `public` flag and `context`. */\n resolvedStorageSource\n }\n}\n\nfunction getInternalInitialValue(multipleFilesSupported: boolean,\n value: string | string[] | null,\n metadata: Record<string, unknown> | undefined,\n size: StorageFieldSize): StorageFieldItem[] {\n let strings: string[] = [];\n if (multipleFilesSupported) {\n if (Array.isArray(value) && value.every((v) => typeof v === \"string\")) {\n strings = (value ?? []) as string[];\n }\n } else {\n if (typeof value === \"string\") {\n strings = value ? [value as string] : [];\n }\n }\n\n return strings\n .map(entry => (\n {\n id: getRandomId(),\n storagePathOrDownloadUrl: entry,\n metadata,\n size\n }\n ));\n}\n\nfunction removeDuplicates(items: StorageFieldItem[]) {\n return items.filter(\n (item, i) => {\n return ((items.map((v) => v.storagePathOrDownloadUrl).indexOf(item.storagePathOrDownloadUrl) === i) || !item.storagePathOrDownloadUrl) &&\n ((items.map((v) => v.file).indexOf(item.file) === i) || !item.file);\n }\n );\n}\n\nfunction getRandomId() {\n return Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER));\n}\n\n/**\n * Check if a file is an image type supported for resizing\n */\nfunction isImageFile(file: File): boolean {\n return file.type === \"image/jpeg\" ||\n file.type === \"image/png\" ||\n file.type === \"image/webp\";\n}\n\n/**\n * Resize and compress an image using compressorjs.\n */\nasync function resizeImage(\n file: File,\n imageResize?: StorageConfig[\"imageResize\"]\n): Promise<File> {\n const maxWidth = imageResize?.maxWidth;\n const maxHeight = imageResize?.maxHeight;\n const quality = (imageResize?.quality ?? 80) / 100;\n const mode = imageResize?.mode ?? \"contain\";\n\n // Determine output format\n let mimeType = file.type;\n if (imageResize?.format && imageResize.format !== \"original\") {\n mimeType = `image/${imageResize.format}`;\n }\n\n return new Promise<File>((resolve, reject) => {\n new Compressor(file, {\n quality,\n maxWidth,\n maxHeight,\n mimeType,\n // Use cover mode if specified (crops to fit)\n // Otherwise use contain mode (scales to fit)\n ...(mode === \"cover\" || mode === undefined ? {\n width: maxWidth,\n height: maxHeight,\n resize: \"cover\" as const\n } : {}),\n success: (result) => {\n const compressedFile = new File([result], file.name, {\n type: result.type,\n lastModified: Date.now()\n });\n resolve(compressedFile);\n },\n error: reject\n });\n });\n}\n\n/**\n * `source`, with `options` sent on every `putObject` (a call's own values win).\n * Delegates method by method rather than spreading, so a class-based source\n * keeps its `this`.\n */\nfunction withUploadOptions(\n source: StorageSource,\n options: Pick<UploadFileProps, \"public\" | \"context\">\n): StorageSource {\n if (options.public === undefined && options.context === undefined) return source;\n return {\n putObject: (props) => source.putObject({ ...options, ...props }),\n getSignedUrl: (keyOrUrl, bucket) => source.getSignedUrl(keyOrUrl, bucket),\n getObject: (key, bucket) => source.getObject(key, bucket),\n deleteObject: (key, bucket) => source.deleteObject(key, bucket),\n listObjects: (prefix, options) => source.listObjects(prefix, options)\n };\n}\n","import { EnumValueConfig } from \"@rebasepro/types\";\nimport { ChipColorScheme, getColorSchemeForKey, getColorSchemeForSeed } from \"@rebasepro/ui\";\nimport { getLabelOrConfigFrom } from \"@rebasepro/common\";\n\nexport function getColorScheme(enumValues: EnumValueConfig[], key: string | number): ChipColorScheme | undefined {\n const labelOrConfig = getLabelOrConfigFrom(enumValues, key);\n if (!labelOrConfig?.color)\n return getColorSchemeForSeed(key.toString());\n if (typeof labelOrConfig === \"object\" && \"color\" in labelOrConfig) {\n if (typeof labelOrConfig.color === \"string\")\n // Not a raw table lookup: a config naming a colour this build does\n // not have still deserves a colour rather than `undefined`.\n return getColorSchemeForKey(labelOrConfig.color);\n if (typeof labelOrConfig.color === \"object\")\n return labelOrConfig.color;\n }\n return undefined;\n}\n\nexport function isEnumValueDisabled(labelOrConfig?: string | EnumValueConfig) {\n return typeof labelOrConfig === \"object\" && (labelOrConfig as EnumValueConfig).disabled;\n}\n\nexport function buildEnumLabel(\n labelOrConfig?: string | EnumValueConfig\n): string | undefined {\n if (labelOrConfig === undefined)\n return undefined;\n if (typeof labelOrConfig === \"object\") {\n return labelOrConfig.label;\n } else {\n return labelOrConfig;\n }\n}\n","export const STUDIO_NAVIGATION_GROUPS = [\n \"Database\",\n \"Compute\",\n \"API\",\n \"Storage\",\n \"Access Control\"\n];\n","/**\n * Layout width primitives used by the framework's own side-panel and form\n * dialog sizing logic.\n *\n * @internal Not part of the stable public API — exported only because\n * `@rebasepro/cms` and `@rebasepro/studio` need them to compute the same\n * dialog widths as the framework. Do not depend on these for app code; they\n * may change shape or be removed without a major version bump.\n */\nexport const CONTAINER_FULL_WIDTH = \"100vw\";\n\n/** @internal See {@link CONTAINER_FULL_WIDTH}. */\nexport const FORM_CONTAINER_WIDTH = \"768px\";\n\n/**\n * How wide the side panel opens when neither the caller nor the collection\n * says otherwise.\n *\n * Sized from what it has to hold rather than from a round number: the form's\n * content column plus its metadata rail plus gutters, which is also the width\n * at which the form stops being a single stack and picks up the same\n * two-column layout it has in full screen. Capped against the viewport so a\n * panel never becomes the whole window on a laptop — at that point you want\n * full screen, and there is a button for it.\n *\n * @internal See {@link CONTAINER_FULL_WIDTH}.\n */\nexport const SIDE_PANEL_DEFAULT_WIDTH = \"min(1160px, 88vw)\";\n","import React, { useCallback, useEffect, useRef } from \"react\";\nimport { useLocation } from \"react-router\";\n\nconst scrollsMap: Record<string, number> = {};\n\n/**\n * Restores per-route scroll position on a scrollable container, keyed by\n * router location. Used by the framework's own home page implementations.\n *\n * @internal Not part of the stable public API — exported only because\n * `@rebasepro/cms` and `@rebasepro/studio` reuse it in their home page\n * components. Its behavior (module-level scroll cache, router coupling) is\n * an implementation detail and may change without a major version bump.\n */\nexport function useRestoreScroll() {\n\n const location = useLocation();\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [scroll, setScroll] = React.useState(0);\n const [direction, setDirection] = React.useState<\"up\" | \"down\">(\"down\");\n\n // Use ref to track previous scroll for direction calculation\n // This avoids recreating handleScroll on every scroll\n const prevScrollRef = useRef(0);\n\n const handleScroll = useCallback(() => {\n if (!containerRef.current || !location.key) return;\n const scrollTop = containerRef.current.scrollTop;\n scrollsMap[location.key] = scrollTop;\n setScroll(scrollTop);\n setDirection(scrollTop > prevScrollRef.current ? \"down\" : \"up\");\n prevScrollRef.current = scrollTop;\n }, [location.key]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n container.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n return () => {\n if (container)\n container.removeEventListener(\"scroll\", handleScroll);\n };\n }, [handleScroll]);\n\n // Defer scroll restoration to next tick to allow async content to render\n // This is necessary because DefaultHomePage content loads asynchronously\n useEffect(() => {\n const savedScroll = scrollsMap[location.key];\n if (!containerRef.current || !savedScroll) return;\n\n const timeoutId = setTimeout(() => {\n if (!containerRef.current) return;\n containerRef.current.scrollTo({\n top: savedScroll,\n behavior: \"auto\"\n });\n }, 0);\n\n return () => clearTimeout(timeoutId);\n }, [location.key]);\n\n return {\n containerRef,\n scroll,\n direction\n };\n}\n","import React from \"react\";\nimport { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from \"@rebasepro/ui\";\nimport { useTranslation } from \"../hooks/useTranslation\";\n\nexport interface UnsavedChangesDialogProps {\n open: boolean;\n body?: React.ReactNode;\n title?: string;\n handleOk: () => void;\n handleCancel: () => void;\n}\n\nexport function UnsavedChangesDialog({\n open,\n handleOk,\n handleCancel,\n body,\n title\n}: UnsavedChangesDialogProps) {\n\n const { t } = useTranslation();\n\n return (\n <Dialog\n onEscapeKeyDown={() => {\n handleCancel();\n }}\n open={open}\n >\n <DialogTitle variant={\"h6\"}>{title}</DialogTitle>\n <DialogContent>\n\n <Typography>\n {body ?? t(\"unsaved_changes\")}\n </Typography>\n\n </DialogContent>\n <DialogActions>\n <Button variant=\"text\"\n onClick={handleCancel} autoFocus> {t(\"cancel\")} </Button>\n <Button\n onClick={handleOk}> {t(\"ok\")} </Button>\n </DialogActions>\n </Dialog>\n );\n}\n","import React, { createContext, useCallback, useContext, useMemo, useRef, useState } from \"react\";\nimport type {\n CollectionRegistryController\n} from \"@rebasepro/types\";\nimport type {\n SidePanelController,\n UrlController,\n NavigationStateController,\n BreadcrumbEntry,\n BreadcrumbsController\n} from \"@rebasepro/cms-types\";\n\nexport type { BreadcrumbEntry, BreadcrumbsController };\n\n// ─── Breadcrumbs ──────────────────────────────────────────────────\n\n\n// ─── Bridge interface ───────────────────────────────────────────────\n\n/**\n * StudioBridge provides optional admin capabilities to Studio components.\n * When the admin is present, a bridge provider injects real implementations.\n * When the admin is absent, noop defaults ensure Studio works standalone.\n */\n/**\n * Editing a collection's source through the admin's plan/apply flow.\n *\n * Studio has its own writers — the RLS editor saves a policy, the collection\n * editor saves a property — and until this existed they did not go to the same\n * place. Saving a policy on a mapped table POSTed the rules straight to\n * `/schema-editor/collection/save`: no plan, no dialog, no record of what SQL\n * the change would produce, while the identical edit made two tabs away in the\n * collection editor showed all three.\n *\n * `available` is false when there is no collection editor above this Studio —\n * the hosted console against somebody else's container, or a panel that never\n * enabled it — and the caller falls back to whatever it did before.\n */\nexport interface StudioSchemaEditing {\n available: boolean;\n /**\n * Merge `patch` into the collection and take it through plan → confirm →\n * apply: the same dialog `useLiveSchemaEditing` shows the collection\n * editor.\n *\n * Resolves once the change has been applied, or written source-only if\n * that is what was chosen. Rejects with `SchemaChangeCancelled` when the\n * dialog was closed — which is not an error to report, it is an answer.\n */\n updateCollection: (collectionId: string, patch: Record<string, unknown>) => Promise<void>;\n}\n\nexport interface StudioBridge {\n collectionRegistry: CollectionRegistryController;\n schemaEditing: StudioSchemaEditing;\n sidePanelController: SidePanelController;\n urlController: UrlController;\n navigationState: NavigationStateController;\n breadcrumbs: BreadcrumbsController;\n capabilities: StudioCapabilities;\n}\n\n/**\n * What the *host* of these tools can do, as opposed to what the backend can.\n *\n * Studio is mounted in two very different places. In a project's own admin\n * panel it runs next to the collection source files and can edit them through\n * the schema-editor routes. In the hosted console it runs against somebody\n * else's deployed container: there is no source to edit — the container is\n * rebuilt from the customer's repository on every deploy — and the routes that\n * would edit it are not mounted at all, because the framework switches the\n * schema editor off under `NODE_ENV=production`.\n *\n * Tools that would otherwise offer a write into the codebase read this to\n * decide whether that write is even meaningful.\n */\nexport interface StudioCapabilities {\n /**\n * Whether the host has the project's collection source at hand and can\n * write to it.\n *\n * Defaults to `true`, which is what an admin panel running beside its own\n * `collectionsDir` has always assumed.\n */\n codebase: boolean;\n}\n\n// ─── Noop defaults ──────────────────────────────────────────────────\n\nconst NOOP_COLLECTION_REGISTRY: CollectionRegistryController = {\n getCollection: () => undefined,\n getRawCollection: () => undefined,\n resolveDataPath: (path) => path,\n resolveCollectionPath: (path) => path,\n getParentReferencesFromPath: () => [],\n getParentCollectionSlugs: () => [],\n getParentEntityIds: () => [],\n convertIdsToPaths: () => [],\n initialised: false\n};\n\nconst NOOP_SCHEMA_EDITING: StudioSchemaEditing = {\n available: false,\n updateCollection: async () => {\n throw new Error(\"No collection editor is mounted — check `available` before calling this.\");\n }\n};\n\nconst NOOP_SIDE_PANEL: SidePanelController = {\n open: () => {},\n replace: () => {},\n close: () => {}\n};\n\nconst NOOP_URL_CONTROLLER: UrlController = {\n basePath: \"/\",\n baseCollectionPath: \"/c\",\n urlPathToDataPath: () => \"\",\n homeUrl: \"/\",\n isUrlCollectionPath: () => false,\n buildUrlCollectionPath: () => \"\",\n buildAppUrlPath: () => \"\",\n resolveDatabasePathsFrom: () => \"\",\n navigate: () => {}\n};\n\nconst NOOP_NAVIGATION_STATE: NavigationStateController = {\n loading: false,\n refreshNavigation: () => {}\n};\n\nconst NOOP_BREADCRUMBS: BreadcrumbsController = {\n breadcrumbs: [],\n set: () => {}\n};\n\nconst DEFAULT_CAPABILITIES: StudioCapabilities = {\n codebase: true\n};\n\nconst NOOP_BRIDGE: StudioBridge = {\n collectionRegistry: NOOP_COLLECTION_REGISTRY,\n schemaEditing: NOOP_SCHEMA_EDITING,\n sidePanelController: NOOP_SIDE_PANEL,\n urlController: NOOP_URL_CONTROLLER,\n navigationState: NOOP_NAVIGATION_STATE,\n breadcrumbs: NOOP_BREADCRUMBS,\n capabilities: DEFAULT_CAPABILITIES\n};\n\n// ─── Context & Provider ─────────────────────────────────────────────\n\nexport const StudioBridgeContext = createContext<StudioBridge>(NOOP_BRIDGE);\n\n/**\n * Provider that injects admin capabilities into Studio.\n * Accepts partial overrides — any field not provided falls back to noop.\n *\n * Usage (in app wiring, when the admin is present):\n * ```tsx\n * <StudioBridgeProvider value={{\n * collectionRegistry: useCollectionRegistryController(),\n * sidePanelController: useSidePanel(),\n * urlController: useUrlController(),\n * navigationState: useNavigationStateController(),\n * breadcrumbs: useBreadcrumbsController(),\n * }}>\n * <RebaseStudio ... />\n * </StudioBridgeProvider>\n * ```\n */\nexport function StudioBridgeProvider({\n value,\n children\n}: {\n value: Partial<StudioBridge>;\n children: React.ReactNode;\n}) {\n // Keyed on the slices rather than on `value`: callers write the object\n // inline (`value={{ collectionRegistry }}`), so a `[value]` dependency\n // rebuilt the context on every render of the host and re-rendered every\n // Studio consumer with it.\n const merged = React.useMemo(\n () => ({ ...NOOP_BRIDGE,\n...value }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n value.collectionRegistry,\n value.sidePanelController,\n value.urlController,\n value.navigationState,\n value.breadcrumbs,\n value.capabilities\n ]\n );\n return (\n <StudioBridgeContext.Provider value={merged}>\n {children}\n </StudioBridgeContext.Provider>\n );\n}\n\n// ─── Convenience hooks ──────────────────────────────────────────────\n\n/**\n * Source editing through the admin's plan/apply dialog. `available` is false\n * when no collection editor is mounted.\n */\nexport function useStudioSchemaEditing(): StudioSchemaEditing {\n return useContext(StudioBridgeContext).schemaEditing;\n}\n\n/** Collection registry — returns noop if the admin is not present. */\nexport function useStudioCollectionRegistry(): CollectionRegistryController {\n return useContext(StudioBridgeContext).collectionRegistry;\n}\n\n/** Side panel controller — returns noop if the admin is not present. */\nexport function useStudioSidePanelController(): SidePanelController {\n return useContext(StudioBridgeContext).sidePanelController;\n}\n\n/** URL controller — returns noop if the admin is not present. */\nexport function useStudioUrlController(): UrlController {\n return useContext(StudioBridgeContext).urlController;\n}\n\n/** Navigation state — returns noop if the admin is not present. */\nexport function useStudioNavigationState(): NavigationStateController {\n return useContext(StudioBridgeContext).navigationState;\n}\n\n/** Breadcrumbs controller — returns noop if the admin is not present. */\nexport function useStudioBreadcrumbs(): BreadcrumbsController {\n return useContext(StudioBridgeContext).breadcrumbs;\n}\n\n/** What the host can do — see {@link StudioCapabilities}. */\nexport function useStudioCapabilities(): StudioCapabilities {\n return useContext(StudioBridgeContext).capabilities;\n}\n\n// ─── Self-Assembling Bridge Registry ────────────────────────────────\n\n/**\n * Registry that controllers use to self-register their implementations\n * into the Studio bridge. Each controller calls `register(key, value)`\n * on mount and `unregister(key)` on unmount.\n */\nexport interface StudioBridgeRegistry {\n register: <K extends keyof StudioBridge>(key: K, value: StudioBridge[K]) => void;\n unregister: (key: keyof StudioBridge) => void;\n}\n\nexport const StudioBridgeRegistryContext = createContext<StudioBridgeRegistry | null>(null);\n\n/**\n * Provider that creates a self-assembling bridge.\n *\n * Mount this above the controller providers. Each controller calls\n * `useBridgeRegistration(key, value)` to inject its implementation.\n * The bridge context value is automatically kept in sync.\n *\n * ```tsx\n * <StudioBridgeRegistryProvider>\n * <CollectionRegistryProvider> // auto-registers\n * <SidePanelProvider> // auto-registers\n * <UrlProvider> // auto-registers\n * <RebaseStudio /> // consumes bridge\n * </UrlProvider>\n * </SidePanelProvider>\n * </CollectionRegistryProvider>\n * </StudioBridgeRegistryProvider>\n * ```\n */\nexport function StudioBridgeRegistryProvider({ children }: { children: React.ReactNode }) {\n const [version, setVersion] = useState(0);\n const slicesRef = useRef<Partial<StudioBridge>>({});\n\n const register = useCallback(<K extends keyof StudioBridge>(key: K, value: StudioBridge[K]) => {\n slicesRef.current[key] = value;\n setVersion(v => v + 1);\n }, []);\n\n const unregister = useCallback((key: keyof StudioBridge) => {\n delete slicesRef.current[key];\n setVersion(v => v + 1);\n }, []);\n\n const registry = useMemo<StudioBridgeRegistry>(() => ({ register,\nunregister }), [register, unregister]);\n\n const bridgeValue = useMemo<StudioBridge>(() => ({\n ...NOOP_BRIDGE,\n ...slicesRef.current\n }), [version]);\n\n return (\n <StudioBridgeRegistryContext.Provider value={registry}>\n <StudioBridgeContext.Provider value={bridgeValue}>\n {children}\n </StudioBridgeContext.Provider>\n </StudioBridgeRegistryContext.Provider>\n );\n}\n","import { useContext, useEffect } from \"react\";\nimport type { StudioBridge } from \"./useStudioBridge\";\nimport { StudioBridgeRegistryContext } from \"./useStudioBridge\";\n\n/**\n * Registers a value into the self-assembling Studio bridge.\n *\n * Each controller (collectionRegistry, sidePanel, url, navigation, breadcrumbs)\n * calls this hook on mount to inject its real implementation into the bridge.\n * On unmount the slice is automatically removed, reverting to the noop default.\n *\n * Usage:\n * ```tsx\n * function SomeProvider({ children }) {\n * const controller = useBuildSomeController();\n * useBridgeRegistration(\"sidePanelController\", controller);\n * return <SomeContext.Provider value={controller}>{children}</SomeContext.Provider>;\n * }\n * ```\n */\nexport function useBridgeRegistration<K extends keyof StudioBridge>(\n key: K,\n value: StudioBridge[K]\n): void {\n const registry = useContext(StudioBridgeRegistryContext);\n\n useEffect(() => {\n if (!registry) return;\n registry.register(key, value);\n return () => registry.unregister(key);\n }, [registry, key, value]);\n}\n","/**\n * Collection helpers that only the admin panel needs.\n *\n * These lived in `@rebasepro/common`, which is on the backend's dependency path,\n * and they read presentation fields — `defaultSelectedView`, `localChangesBackup`\n * — that now live under a collection's `admin` block. A server has no use for\n * either, and `resolveDefaultSelectedView` was the *only* thing making\n * `@rebasepro/common` name an admin view-model type\n * (`DefaultSelectedViewBuilder`), which was the last UI symbol any core package\n * imported.\n */\nimport type { ChildViewSource, CollectionConfig } from \"@rebasepro/types\";\nimport { type AdminCollection, type DefaultSelectedViewBuilder, type DefaultSelectedViewParams, resolveAdminCollection } from \"@rebasepro/cms-types\";\nimport { getEntityChildViews } from \"@rebasepro/common\";\n\nexport function resolveDefaultSelectedView(\n defaultSelectedView: string | DefaultSelectedViewBuilder | undefined,\n params: DefaultSelectedViewParams\n) {\n if (!defaultSelectedView) {\n return undefined;\n } else if (typeof defaultSelectedView === \"string\") {\n return defaultSelectedView;\n } else {\n return defaultSelectedView(params);\n }\n}\n\nexport function getLocalChangesBackup(collection: AdminCollection) {\n if (!collection.localChangesBackup) {\n return \"manual_apply\";\n }\n\n return collection.localChangesBackup;\n}\n\n/**\n * Returns the primary keys for a entity collection by inspecting the properties\n * and finding any properties with `isId`.\n * Fallbacks to `[\"id\"]` if no properties are marked as `isId: true`.\n * @param collection\n */\n/**\n * A collection's child collections, as the panel's view model.\n *\n * `getSubcollections` in `@rebasepro/common` returns the contract type, so the\n * children of a resolved collection arrived un-flattened and reading\n * `child.icon` or `child.hideFromNavigation` failed. Resolving is not recursive\n * on purpose — children are fetched lazily through a thunk\n * (`childCollections`/`subcollections`), so walking the whole tree eagerly to\n * flatten it would defeat that.\n */\nexport function getAdminSubcollections(\n collection: AdminCollection | CollectionConfig\n): AdminCollection[] {\n return getAdminEntityChildViews(collection).map(view => view.collection);\n}\n\n/**\n * A collection's child views as the panel's view model, keeping the `source`\n * that says what kind of list each one is.\n *\n * The tabs need it: on a junction-backed relation the parent owns the *link*,\n * so the destructive action is a removal from this record, not a delete. Every\n * caller that renders a tab should prefer this over\n * {@link getAdminSubcollections}, which flattens that distinction away.\n */\nexport function getAdminEntityChildViews(\n collection: AdminCollection | CollectionConfig\n): { key: string; collection: AdminCollection; source: ChildViewSource }[] {\n return (getEntityChildViews(collection as CollectionConfig) ?? []).map(view => ({\n key: view.key,\n collection: resolveAdminCollection(view.collection),\n source: view.source\n }));\n}\n","/**\n * Reading a collection's `display` block.\n *\n * Two questions, kept apart because they are answered at different times: which\n * *property* fills a role (readable from values already in hand) and which\n * *resolver* fills it (may have to go to the network). A caller that cannot\n * await — a sort comparator, an export column, a server render — uses the key\n * and is documented to ignore resolvers.\n */\nimport type {\n AdminCollection,\n EntityDisplayResolver,\n EntityDisplayRole\n} from \"@rebasepro/cms-types\";\n\n/**\n * What the collection declares for a role, before deciding which form it is.\n *\n * One field states it: `display[role]`. `admin.titleProperty` used to be a\n * second way to say `display.title` and is gone — a role with two spellings is\n * a role with two readers, and this one had grown seven.\n */\nfunction getDeclaredSource<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): string | EntityDisplayResolver<M, unknown> | undefined {\n const display = collection.display as Record<string, unknown> | undefined;\n const declared = display?.[role];\n return declared === undefined\n ? undefined\n : declared as string | EntityDisplayResolver<M, unknown>;\n}\n\n/**\n * The property path a role is declared to read, when it is declared as a path.\n *\n * Returns `undefined` for a role filled by a resolver — a resolver has no key —\n * and for a role the collection says nothing about, which is then derived.\n *\n * @group Collections\n */\nexport function getDisplayPropertyKey<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): string | undefined {\n const declared = getDeclaredSource(collection, role);\n return typeof declared === \"string\" ? declared : undefined;\n}\n\n/**\n * The resolver a role is declared to use, when it is declared as one.\n *\n * @group Collections\n */\nexport function getDisplayResolver<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): EntityDisplayResolver<M, unknown> | undefined {\n const declared = getDeclaredSource(collection, role);\n return typeof declared === \"function\" ? declared : undefined;\n}\n\n/**\n * True when the collection states this role at all, in either form.\n *\n * The derivation is a guess about what a collection probably means; a statement\n * outranks it, and the heuristics that look for \"the first enum\" or \"the leading\n * relation\" have to stand down when one exists.\n *\n * @group Collections\n */\nexport function hasDeclaredDisplay<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n role: EntityDisplayRole\n): boolean {\n return getDeclaredSource(collection, role) !== undefined;\n}\n","import { CollectionConfig } from \"@rebasepro/types\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { getDisplayPropertyKey } from \"./entity-display\";\n\n/**\n * The property that fills a record's image slot.\n *\n * `admin.display.image` first, then six fallbacks in descending confidence —\n * the first image-typed storage property, an array of them, a URL rendered as an\n * image, and so on. The ladder stays for collections that say nothing; a\n * collection that names its picture is not guessed at.\n */\nexport function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: CollectionConfig<M>): string | undefined {\n\n const declared = getDisplayPropertyKey(collection as AdminCollection<M>, \"image\");\n if (declared) return declared;\n\n // find first storage property of type image\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // alternatively, look for the first array of images\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // also check for URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.admin?.urlPreview === \"image\") {\n return key;\n }\n }\n // and arrays of URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && property.of && !Array.isArray(property.of) && property.of.type === \"string\" && property.of.admin?.urlPreview === \"image\") {\n return key;\n }\n }\n // fallback: any storage property without explicit acceptedFiles (e.g. a generic \"picture\" field)\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage && !property.storage.acceptedFiles) {\n return key;\n }\n }\n // fallback: any array of storage properties without explicit acceptedFiles\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage && !property.of.storage.acceptedFiles) {\n return key;\n }\n }\n return undefined;\n}\n","import {\n ALL_WHERE_FILTER_OPS,\n DataType,\n DEFAULT_FILTERABLE_RELATION_KINDS,\n getDataSourceCapabilities,\n Property,\n RelationProperty,\n WhereFilterOp\n} from \"@rebasepro/types\";\n\n/**\n * Default operators offered per property type, before engine capabilities and\n * per-property narrowing are applied. These mirror what the built-in filter\n * fields can render.\n */\nconst COMPARISON_OPS: readonly WhereFilterOp[] = [\"==\", \"!=\", \">\", \">=\", \"<\", \"<=\"];\nconst NULL_CHECK_OPS: readonly WhereFilterOp[] = [\"is-null\", \"is-not-null\"];\nconst MEMBERSHIP_OPS: readonly WhereFilterOp[] = [\"in\", \"not-in\"];\nconst PATTERN_OPS: readonly WhereFilterOp[] = [\"like\", \"ilike\", \"not-like\", \"not-ilike\"];\n\nconst DEFAULT_OPS_BY_TYPE: Partial<Record<DataType, readonly WhereFilterOp[]>> = {\n string: [...COMPARISON_OPS, ...MEMBERSHIP_OPS, ...PATTERN_OPS, ...NULL_CHECK_OPS],\n number: [...COMPARISON_OPS, ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS],\n date: [...COMPARISON_OPS, ...NULL_CHECK_OPS],\n boolean: [\"==\", \"!=\", ...NULL_CHECK_OPS],\n reference: [\"==\", \"!=\", ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS],\n relation: [\"==\", \"!=\", ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS]\n // geopoint, map, vector, binary, array (as a container): not filterable\n // through the generic filter UI.\n};\n\n/** Operators offered when the property is an *array of* a filterable type. */\nconst ARRAY_OPS: readonly WhereFilterOp[] = [\"array-contains\", \"array-contains-any\"];\n\n/**\n * Item types an array can be filtered by — the ones a filter field can take a\n * single item value for. An array of booleans, maps or geopoints is not: the\n * dialog used to offer `array-contains` for every item type, so an array of\n * maps listed a row with nothing to fill in.\n */\nconst ARRAY_ITEM_FILTERABLE_TYPES: readonly DataType[] = [\"string\", \"number\", \"date\", \"reference\", \"relation\"];\n\n/**\n * Whether a relation is one the collection's engine can compile into a\n * `WHERE`.\n *\n * Which kinds those are is the *driver's* answer, not this function's, so it\n * comes from {@link DataSourceCapabilities.filterableRelationKinds}. The admin\n * is one UI over Postgres, MongoDB, Firestore and whatever a developer\n * registers, and \"a many-to-many compiles to an `EXISTS` over the junction\" is\n * a fact about the Postgres driver — true today, and not the sort of thing to\n * assert on an engine's behalf.\n *\n * Offering an uncompilable filter is not a cosmetic bug. The Postgres driver\n * used to drop a filter key it could not resolve, which *widened* the result\n * set — filtering a many-to-many column returned every row instead of none.\n * That now fails closed with a 400, which is correct for a real schema drift\n * and wrong as the answer to a control the admin itself put on screen.\n *\n * A relation whose kind cannot be determined at all — no inline `relation`\n * block and no stamped `resolvedRelation` — stays filterable. The server\n * resolves relations before the config reaches the admin, so this is the\n * hand-built-property case, and silently dropping a working filter there would\n * be its own regression.\n */\nexport function isFilterableRelation(property: Property, engine?: string): boolean {\n if (property.type !== \"relation\") return true;\n const relationProperty = property as RelationProperty;\n const kind = relationProperty.relation?.kind ?? relationProperty.resolvedRelation?.kind;\n if (!kind) return true;\n const kinds = getDataSourceCapabilities(engine).filterableRelationKinds\n ?? DEFAULT_FILTERABLE_RELATION_KINDS;\n return kinds.includes(kind);\n}\n\nexport interface ResolveFilterOperatorsParams {\n /**\n * The property to filter on. For array properties, pass the **item**\n * property (`property.of`) together with `isArray: true` — the same\n * convention the filter field dispatchers use.\n */\n property: Property;\n /** True when filtering an array of `property`. */\n isArray?: boolean;\n /**\n * The engine backing the collection (`collection.engine`, e.g.\n * `\"postgres\"`, `\"firestore\"`). Falls back to the default engine's\n * capabilities when omitted.\n */\n engine?: string;\n}\n\n/**\n * Resolve which filter operators the UI should offer for a property.\n *\n * The result is the **intersection** of three sets:\n * 1. what the engine can execute — {@link DataSourceCapabilities.filterOperators}\n * (e.g. Firestore cannot run the LIKE family);\n * 2. what makes sense for the property type (e.g. no `>` on booleans);\n * 3. the developer's optional narrowing — `property.admin.filterOperators`.\n *\n * Returns an empty array when the property is not filterable — by type, by\n * developer narrowing (`filterOperators: []`), or because it is a relation the\n * query layer has no column for (see {@link isFilterableRelation}).\n *\n * @group Models\n */\nexport function resolveFilterOperators({\n property,\n isArray,\n engine\n}: ResolveFilterOperatorsParams): WhereFilterOp[] {\n if (!isFilterableRelation(property, engine)) return [];\n\n const typeDefaults: readonly WhereFilterOp[] = isArray\n ? (ARRAY_ITEM_FILTERABLE_TYPES.includes(property.type) ? ARRAY_OPS : [])\n : DEFAULT_OPS_BY_TYPE[property.type] ?? [];\n if (typeDefaults.length === 0) return [];\n\n const engineOps = new Set(getDataSourceCapabilities(engine).filterOperators ?? ALL_WHERE_FILTER_OPS);\n\n const narrowing = property.admin?.filterOperators;\n const narrowingSet = narrowing !== undefined ? new Set(narrowing) : undefined;\n\n return typeDefaults.filter(op =>\n engineOps.has(op) && (narrowingSet === undefined || narrowingSet.has(op)));\n}\n\n/**\n * Whether a property can be filtered at all — the one answer the table header\n * and the filters dialog both give.\n *\n * They used to answer it with a predicate each, and disagreed: the header\n * allowed an array only of strings, numbers, dates, references and relations;\n * the dialog allowed an array of anything, and listed an array of maps with an\n * empty control. The header, for its part, ignored both the developer's\n * `filterOperators: []` and a custom `admin.Filter`.\n *\n * A property with a custom filter field is filterable: the developer owns that\n * field. Otherwise it is filterable when at least one operator survives\n * {@link resolveFilterOperators} — for an array, on its item type. A tuple\n * array (`of: [a, b]`) has no single item type to filter by.\n *\n * @group Models\n */\nexport function isPropertyFilterable(property: Property, engine?: string): boolean {\n const isArray = property.type === \"array\";\n const base = isArray\n ? (property.of && !Array.isArray(property.of) ? property.of : undefined)\n : property;\n if (!base) return false;\n if (base.admin?.Filter) return true;\n return resolveFilterOperators({ property: base, isArray, engine }).length > 0;\n}\n","/**\n * Form layout resolution.\n *\n * Turns a collection into the shape the entity form renders: an ordered list of\n * sections holding grid-spanned fields, plus the metadata rail beside them.\n *\n * A field takes the full row unless its property sets `admin.span`, with one\n * exception: two neighbouring fields whose editors are both small and of the\n * same kind — two numbers, two switches, two dates, two short selects — share a\n * row. Nothing wider is ever guessed. Pairing by type alone put Namespace beside\n * Custom Domain and Git Branch beside Git Repository URL, values that sat\n * together only because both were strings; a string's editor says nothing about\n * how long its value is, so a free-text field is never paired. Nothing here\n * looks at which property is the record's title either.\n */\nimport type {\n AdminCollection,\n FormSection,\n PropertySpan\n} from \"@rebasepro/cms-types\";\nimport type { EnumValues, Property } from \"@rebasepro/types\";\nimport { effectiveAccess } from \"@rebasepro/common\";\nimport { isHidden } from \"./property_presentation\";\n\n/**\n * Columns in the form grid.\n *\n * A local literal rather than an import of `FORM_GRID_COLUMNS`: everything else\n * this module takes from `@rebasepro/cms-types` is a *type*, erased at build\n * time, and a runtime value would make this pure function depend on that\n * package's built output — which is exactly what broke the dev server, since\n * `@rebasepro/app` resolves that package to its dist. `satisfies PropertySpan`\n * keeps the two honest: a full-width field and the column count are the same\n * number by definition.\n */\nconst GRID_COLUMNS = 4 satisfies PropertySpan;\n\n/** A field placed on the grid. */\nexport interface ResolvedFormField {\n key: string;\n /** Columns occupied, out of `GRID_COLUMNS`. Ignored in the rail. */\n span: PropertySpan;\n /** True for an `additionalFields` entry rather than a property. */\n additional: boolean;\n /** The span was written on the property. Pairing leaves these alone. */\n spanExplicit?: boolean;\n}\n\nexport interface ResolvedFormSection {\n key: string;\n title?: string;\n collapsible: boolean;\n /** Initial state only; the form owns it after first interaction. */\n collapsed: boolean;\n fields: ResolvedFormField[];\n /**\n * Declared arrangement for the read-only view. Carried through untouched —\n * the resolver decides *which* fields a section holds, not how the surface\n * that renders it stacks them, and only the read view honours this.\n */\n readVariant?: \"grid\" | \"summary\";\n}\n\nexport interface ResolvedFormLayout {\n sections: ResolvedFormSection[];\n /** Fields shown in the rail. Empty means no rail fields. */\n sidebar: ResolvedFormField[];\n /** Show the read-only id/created/updated block at the foot of the rail. */\n showRecordMeta: boolean;\n /** True when there is anything at all to put in the rail. */\n hasRail: boolean;\n}\n\nexport interface ResolveFormLayoutParams<M extends Record<string, unknown>> {\n collection: AdminCollection<M>;\n /**\n * Field keys in render order, already filtered by `propertiesOrder` — i.e.\n * the output of `getFormFieldKeys`. Passed in rather than recomputed so the\n * form and the layout can never disagree about which fields exist.\n */\n fieldKeys: string[];\n /**\n * Which fields the user may edit right now. A manual id is editable while\n * creating and frozen afterwards, and that decides whether it belongs in the\n * form at all or only in the record block.\n */\n status: \"new\" | \"existing\" | \"copy\";\n}\n\n/* -------------------------------------------------------------------------- */\n/* id handling */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Can the user still type this id?\n *\n * A `manual` id is a real field while creating and frozen once the row exists.\n * Every generated strategy (`uuid`, `cuid`, a raw SQL default) is never typed.\n * Getting this wrong in the \"frozen\" direction would make manual-id collections\n * uncreatable, so it fails towards showing the field.\n */\nexport function isIdPropertyEditable(property: Property, status: \"new\" | \"existing\" | \"copy\"): boolean {\n if (!(\"isId\" in property) || !property.isId) return true;\n if (status === \"existing\") return false;\n return property.isId === \"manual\";\n}\n\nfunction isIdProperty(property: Property | undefined): boolean {\n return Boolean(property && \"isId\" in property && property.isId);\n}\n\n/**\n * An audit timestamp the database maintains — `created_at`, `updated_at`.\n *\n * Not a guess from the name: `autoValue` says the column is written by the\n * system on create or update, so the field is never typed. Rendering it as an\n * input in the middle of the form promised an edit that cannot happen, and the\n * record block already shows both values — the same two dates twice on one\n * screen.\n */\nexport function isAuditTimestamp(property: Property | undefined): boolean {\n return Boolean(\n property\n && property.type === \"date\"\n && property.autoValue\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* pairing */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Longest label, help text and option label a field can carry and still take\n * half a row. Past these a half-width field truncates its label, or wraps its\n * help text into a block that leaves its neighbour floating above a hole — the\n * App Capacity field, whose paragraph of help sat beside a one-line App Region.\n */\nconst PAIR_MAX_LABEL = 32;\nconst PAIR_MAX_DESCRIPTION = 60;\nconst PAIR_MAX_OPTION_LABEL = 32;\n\n/** What a field's editor is, for the purpose of sitting beside another one. */\ntype PairKind = \"number\" | \"switch\" | \"date\" | \"date_time\" | \"select\";\n\nfunction enumLabels(values: EnumValues | Map<unknown, unknown>): string[] {\n const entries: unknown[] = values instanceof Map\n ? [...values.values()]\n : Array.isArray(values) ? values : Object.values(values);\n return entries.map(entry =>\n typeof entry === \"string\" ? entry : String((entry as { label?: unknown })?.label ?? \"\"));\n}\n\n/**\n * The kind of compact editor this property renders, or `undefined` when its\n * editor needs the row — or when nothing about it says how long its value is.\n *\n * Deliberately narrow. A plain string is never compact: \"Namespace\" and \"Git\n * Branch\" are both strings and nothing in the schema tells a 6-character branch\n * from a 60-character URL. Neither is a relation, whose preview is the related\n * record's own text. Only editors whose width is bounded by what they are —\n * a number, a switch, a date picker, a select over short options — qualify.\n */\nexport function pairKind(property: Property): PairKind | undefined {\n // A custom editor's size is unknown, and a partner that hides itself on a\n // condition strands the other half of its row.\n if (property.admin?.Field) return undefined;\n if (property.conditions) return undefined;\n // Nor does one the form may not render for its user: a field-level read\n // rule (or `excludeFromApi`) hides it, as `EntityForm` does.\n if (effectiveAccess(property)) return undefined;\n if ((property.name?.length ?? 0) > PAIR_MAX_LABEL) return undefined;\n if ((property.description?.length ?? 0) > PAIR_MAX_DESCRIPTION) return undefined;\n\n switch (property.type) {\n case \"boolean\":\n return \"switch\";\n case \"date\":\n return property.mode === \"date_time\" ? \"date_time\" : \"date\";\n case \"number\":\n case \"string\": {\n if (property.enum) {\n const labels = enumLabels(property.enum as EnumValues);\n return labels.every(label => label.length <= PAIR_MAX_OPTION_LABEL) ? \"select\" : undefined;\n }\n return property.type === \"number\" ? \"number\" : undefined;\n }\n default:\n return undefined;\n }\n}\n\n/**\n * Put neighbouring fields of the same compact kind two to a row.\n *\n * Greedy and in declaration order: a run of three numbers is a pair and a full\n * row, never a pair with the third pulled out of order. A pair only starts at\n * the beginning of a row — the grid flows, so a pair placed after an author's\n * `span: 2` would split across two rows. Fields with a span the author wrote are\n * left as written, and nothing is widened to close a gap they leave.\n */\nexport function pairCompactFields(\n fields: ResolvedFormField[],\n propertyOf: (key: string) => Property | undefined\n): ResolvedFormField[] {\n const kindOf = (field: ResolvedFormField | undefined): PairKind | undefined => {\n if (!field || field.additional || field.spanExplicit) return undefined;\n const property = propertyOf(field.key);\n return property ? pairKind(property) : undefined;\n };\n\n const out = [...fields];\n let used = 0; // columns taken in the current row\n for (let i = 0; i < out.length; i++) {\n const kind = kindOf(out[i]);\n if (used === 0 && kind && kindOf(out[i + 1]) === kind) {\n out[i] = {\n ...out[i],\n span: 2\n };\n out[i + 1] = {\n ...out[i + 1],\n span: 2\n };\n i++;\n continue;\n }\n const span = out[i].span;\n if (used + span > GRID_COLUMNS) used = 0;\n used = (used + span) % GRID_COLUMNS;\n }\n return out;\n}\n\n/* -------------------------------------------------------------------------- */\n/* resolution */\n/* -------------------------------------------------------------------------- */\n\nfunction buildField<M extends Record<string, unknown>>(\n key: string,\n collection: AdminCollection<M>\n): ResolvedFormField | undefined {\n const property = collection.properties?.[key] as Property | undefined;\n\n if (!property) {\n // An additionalFields entry: a rendered card, not an input. Full width,\n // because we have no idea what the Builder puts inside it.\n const additional = collection.additionalFields?.some(f => f.key === key);\n return additional ? { key, span: GRID_COLUMNS, additional: true } : undefined;\n }\n\n if (isHidden(property)) return undefined;\n\n return {\n key,\n span: property.admin?.span ?? GRID_COLUMNS,\n additional: false,\n spanExplicit: property.admin?.span !== undefined\n };\n}\n\n/**\n * Resolve the layout for a collection's generated form.\n *\n * Never drops a field: anything not named by a section lands in a trailing\n * group, so adding a column to the database cannot make it silently invisible\n * in the panel.\n */\nexport function resolveFormLayout<M extends Record<string, unknown>>({\n collection,\n fieldKeys,\n status\n}: ResolveFormLayoutParams<M>): ResolvedFormLayout {\n\n const config = collection.form;\n\n const available = new Map<string, ResolvedFormField>();\n for (const key of fieldKeys) {\n const field = buildField(key, collection);\n if (field) available.set(key, field);\n }\n\n /* ---- the id ---------------------------------------------------------- */\n // A single surrogate key is routed out of the form and into the record\n // block, unless it is still typeable. This is what `hideIdFromForm` used to\n // be for; that flag now only decides whether the record block shows it.\n //\n // A COMPOSITE key is not. Postgres has no `id` — a row is addressed by one\n // or more real columns, and `entity.id` is a token we synthesise on top\n // (`a:::b`, see `buildCompositeId`). When the key spans several columns\n // those columns are data: on a junction row, `order_id` and `product_id`\n // are *which order* and *which product*. Hiding them behind an address\n // nobody can read would remove the only meaningful thing on the form.\n const idKeys = [...available.keys()].filter(key =>\n isIdProperty(collection.properties?.[key] as Property | undefined));\n\n if (idKeys.length === 1) {\n const property = collection.properties?.[idKeys[0]] as Property;\n if (!isIdPropertyEditable(property, status)) {\n available.delete(idKeys[0]);\n }\n }\n\n /* ---- audit timestamps ------------------------------------------------ */\n // Same treatment as the id, and for the same reason: the record block shows\n // them, so leaving them in the column renders each date twice — once as a\n // disabled input the user cannot change, once as metadata.\n const showRecordMetaResolved = config?.showRecordMeta ?? !collection.hideIdFromForm;\n if (showRecordMetaResolved) {\n for (const key of [...available.keys()]) {\n const property = collection.properties?.[key] as Property | undefined;\n // An explicit `sidebar` entry wins — the author asked for it there.\n if (config?.sidebar?.includes(key as never)) continue;\n if (isAuditTimestamp(property)) available.delete(key);\n }\n }\n\n /* ---- the rail -------------------------------------------------------- */\n const sidebar: ResolvedFormField[] = [];\n if (config?.sidebar) {\n for (const key of config.sidebar as string[]) {\n const field = available.get(key);\n if (!field) continue; // unknown, hidden, or already the id\n sidebar.push(field);\n available.delete(key);\n }\n }\n\n const showRecordMeta = showRecordMetaResolved;\n\n /* ---- sections -------------------------------------------------------- */\n const sections: ResolvedFormSection[] = [];\n\n if (config?.sections?.length) {\n for (const section of config.sections as FormSection<M>[]) {\n const fields: ResolvedFormField[] = [];\n for (const key of section.properties as string[]) {\n const field = available.get(key);\n if (!field) continue;\n fields.push(field);\n available.delete(key);\n }\n const titled = Boolean(section.title);\n sections.push({\n key: section.key,\n title: section.title,\n collapsible: section.collapsible ?? titled,\n collapsed: titled ? Boolean(section.collapsed) : false,\n fields,\n readVariant: section.readVariant\n });\n }\n }\n\n // Whatever no section claimed. Appended rather than dropped — a new column\n // showing up unstyled is recoverable, a new column vanishing is not.\n const leftovers = fieldKeys\n .map(key => available.get(key))\n .filter((f): f is ResolvedFormField => Boolean(f));\n\n if (leftovers.length) {\n // Always a trailing group, never merged into an existing section. Folding\n // them into the first untitled section put `created_at`/`updated_at`\n // between the product's images and its pricing — the reader cannot tell\n // \"we grouped this here\" from \"nobody placed this yet\", and the second is\n // what actually happened.\n sections.push({\n key: sections.length ? \"__other\" : \"__main\",\n collapsible: false,\n collapsed: false,\n fields: leftovers\n });\n }\n\n // A configured section that ended up empty (every key hidden, unknown, or\n // claimed by the rail) would render as a heading over nothing.\n const propertyOf = (key: string) => collection.properties?.[key] as Property | undefined;\n return {\n sections: sections\n .filter(s => s.fields.length > 0)\n .map(s => ({\n ...s,\n fields: pairCompactFields(s.fields, propertyOf)\n })),\n sidebar,\n showRecordMeta,\n hasRail: sidebar.length > 0 || showRecordMeta\n };\n}\n","\n\nimport { getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n\nexport function addInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s;\n else return `/${s}`;\n}\n\nexport function getLastSegment(path: string) {\n const cleanPath = removeInitialAndTrailingSlashes(path);\n if (cleanPath.includes(\"/\")) {\n const segments = cleanPath.split(\"/\");\n return segments[segments.length - 1];\n }\n return cleanPath;\n}\n\nexport function resolveCollectionPathIds(path: string, allCollections: AdminCollection[]): string {\n let remainingPath = removeInitialAndTrailingSlashes(path);\n if (!remainingPath) {\n return \"\";\n }\n\n let currentCollections: AdminCollection[] | undefined = allCollections;\n const resolvedPathParts: string[] = [];\n\n while (remainingPath.length > 0) {\n if (!currentCollections || currentCollections.length === 0) {\n // We have remaining path segments but no more collections to match against\n console.warn(`resolveCollectionPathIds: Path structure implies subcollections, but none found before segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath);\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n let foundMatch = false;\n // Sort potential matches by length descending to prioritize longer matches (e.g., \"a/b\" over \"a\")\n const potentialMatches: { col: AdminCollection; match: string; }[] = currentCollections\n .flatMap(col => [{\n col,\n match: col.slug\n }])\n // Whole segments only: a bare `startsWith` read `users/abc123` as the\n // collection `user` followed by the id `s`.\n .filter(p => p.match && (remainingPath === p.match || remainingPath.startsWith(`${p.match}/`)))\n .sort((a, b) => b.match.length - a.match.length);\n\n if (potentialMatches.length > 0) {\n const {\n col: foundCollection,\n match: matchString\n } = potentialMatches[0];\n\n resolvedPathParts.push(foundCollection.slug); // Use the defined path\n remainingPath = removeInitialSlash(remainingPath.substring(matchString.length));\n\n // Check if we are at the end of the path\n if (remainingPath.length === 0) {\n foundMatch = true;\n break; // Path ends with a collection segment\n }\n\n // The next segment must be a entity ID\n const idSeparatorIndex = remainingPath.indexOf(\"/\");\n let entityId: string | number;\n if (idSeparatorIndex > -1) {\n entityId = remainingPath.substring(0, idSeparatorIndex);\n remainingPath = remainingPath.substring(idSeparatorIndex + 1);\n } else {\n // This should not happen if the original path is valid (odd segments)\n // but handle it defensively: assume the rest is the ID\n entityId = remainingPath;\n remainingPath = \"\";\n console.warn(`resolveCollectionPathIds: Path seems to end with a entity ID \"${entityId}\" instead of a collection segment in original path \"${path}\". This might indicate an invalid input path.`);\n // Even if it ends here, we still need to push the ID\n }\n\n resolvedPathParts.push(entityId); // Append entity ID\n currentCollections = getSubcollections(foundCollection); // Move to subcollections\n foundMatch = true;\n\n if (!currentCollections && remainingPath.length > 0) {\n // Warn if the path continues but no subcollections were defined\n console.warn(`resolveCollectionPathIds: Path continues after entity ID \"${entityId}\", but no subcollections are defined for the preceding collection \"${foundCollection.slug}\" in path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n }\n\n if (!foundMatch) {\n // Collection definition not found for the start of the remaining path\n console.warn(`resolveCollectionPathIds: Collection definition not found for segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n }\n\n return resolvedPathParts.join(\"/\");\n}\n\n/**\n * Find the corresponding view at any depth for a given path.\n * Note that path or segments of the paths can be collection aliases.\n * @param slugOrPath\n * @param collections\n */\nexport function getCollectionBySlugWithin(slugOrPath: string, collections: AdminCollection[]): AdminCollection | undefined {\n\n const path = removeInitialAndTrailingSlashes(slugOrPath);\n const subpathCombinations = getCollectionPathsCombinations(path.split(\"/\"));\n let result: AdminCollection | undefined;\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n const navigationEntry = collections && collections\n .sort((a, b) => (a.slug ?? \"\").localeCompare(b.slug ?? \"\"))\n .find((entry) => entry.slug === subpathCombination);\n\n if (navigationEntry) {\n // Counted from where the slug ends, not over the whole path, whose\n // count the slug's own slashes would decide. What follows a\n // collection pairs up as (entity id, subcollection), so an odd\n // remainder ends at a record.\n const rest = path.split(\"/\").slice(subpathCombination.split(\"/\").length);\n if (rest.length % 2 !== 0) {\n throw Error(`getCollectionBySlug: Collection paths must end at a collection, not at a record: ${slugOrPath}`);\n }\n if (rest.length === 0) {\n result = navigationEntry;\n } else if (getSubcollections(navigationEntry).length > 0) {\n result = getCollectionBySlugWithin(rest.slice(1).join(\"/\"), getSubcollections(navigationEntry));\n }\n }\n if (result) break;\n }\n return result;\n}\n\n/**\n * Every leading run of whole segments of a path, longest first: the\n * candidates for the collection the path starts with.\n * \"sites/es/locales\" => [\"sites/es/locales\", \"sites/es\", \"sites\"]\n *\n * Every length, not only the odd ones. A slug may contain slashes, so\n * `content/podcasts/abc123/episodes` starts with the two-segment collection\n * `content/podcasts`, and a path's own segment count says nothing about where\n * its first collection ends.\n * @param subpaths\n */\nexport function getCollectionPathsCombinations(subpaths: string[]): string[] {\n const result: string[] = [];\n for (let i = subpaths.length; i > 0; i--) {\n result.push(subpaths.slice(0, i).join(\"/\"));\n }\n return result;\n}\n","\ntype EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = { key: string; [key: string]: unknown };\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\nexport type NavigationViewInternal<M extends Record<string, unknown> = Record<string, unknown>> =\n | NavigationViewEntityInternal<M>\n | NavigationViewCollectionInternal<M>\n | NavigationViewEntityCustomInternal<M>;\n\nexport interface NavigationViewEntityInternal<M extends Record<string, unknown>> {\n type: \"entity\";\n entityId: string | number;\n slug: string;\n path: string;\n parentCollection: AdminCollection<M>;\n}\n\nexport interface NavigationViewCollectionInternal<M extends Record<string, unknown>> {\n type: \"collection\";\n id: string;\n slug: string;\n path: string;\n collection: AdminCollection<M>;\n}\n\nexport interface NavigationViewEntityCustomInternal<M extends Record<string, unknown>> {\n type: \"custom_view\";\n slug: string;\n path: string;\n entityId: string | number;\n view: EntityCustomView<M>;\n}\n\nexport function getNavigationEntriesFromPath(props: {\n path: string,\n collections: AdminCollection[] | undefined,\n currentFullPath?: string,\n contextEntityViews?: EntityCustomView[]\n}): NavigationViewInternal[] {\n\n const {\n path,\n collections = [],\n currentFullPath\n } = props;\n\n const subpaths = removeInitialAndTrailingSlashes(path).split(\"/\");\n const subpathCombinations = getCollectionPathsCombinations(subpaths);\n\n const result: NavigationViewInternal[] = [];\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n\n const collection = collections && collections.find((entry) => entry.slug === subpathCombination);\n\n if (collection) {\n const collectionPath = currentFullPath && currentFullPath.length > 0\n ? (currentFullPath + \"/\" + collection.slug)\n : collection.slug;\n result.push({\n type: \"collection\",\n id: collection.slug,\n slug: collectionPath,\n path: collectionPath,\n collection\n });\n const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, \"\"));\n const nextSegments = restOfThePath.length > 0 ? restOfThePath.split(\"/\") : [];\n if (nextSegments.length > 0) {\n const entityId = nextSegments[0];\n const path = collectionPath + \"/\" + entityId;\n result.push({\n type: \"entity\",\n entityId,\n slug: collectionPath,\n path,\n parentCollection: collection\n });\n if (nextSegments.length > 1) {\n const newPath = nextSegments.slice(1).join(\"/\");\n if (!collection) {\n throw Error(\"collection not found resolving path: \" + collection);\n }\n const entityViews = collection.entityViews;\n const customView = entityViews && entityViews\n .map((entry) => resolveEntityView(entry, props.contextEntityViews))\n .filter((v): v is EntityCustomView => v != null)\n .find((entry) => entry.key === newPath);\n const subcollections = getSubcollections(collection);\n if (customView) {\n result.push({\n type: \"custom_view\",\n slug: collectionPath,\n entityId: entityId,\n path: path + \"/\" + customView.key,\n view: customView\n });\n } else if (subcollections) {\n result.push(...getNavigationEntriesFromPath({\n path: newPath,\n collections: subcollections,\n currentFullPath: path,\n contextEntityViews: props.contextEntityViews\n }));\n }\n }\n }\n break;\n }\n\n }\n return result;\n}\n\nfunction resolveEntityView(entityView: string | EntityCustomView, contextEntityViews?: EntityCustomView[]): EntityCustomView | undefined {\n if (typeof entityView === \"string\") {\n return contextEntityViews?.find((entry) => entry.key === entityView);\n } else {\n return entityView;\n }\n}\n","import { EntityReference } from \"@rebasepro/types\";\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"@rebasepro/common\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\n\nexport function getParentReferencesFromPath(props: {\n path: string,\n collections: AdminCollection[] | undefined,\n currentFullPath?: string,\n}): EntityReference[] {\n\n const {\n path,\n collections = [],\n currentFullPath\n } = props;\n\n const subpaths = removeInitialAndTrailingSlashes(path).split(\"/\");\n const subpathCombinations = getCollectionPathsCombinations(subpaths);\n\n const result: EntityReference[] = [];\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n\n const collection: AdminCollection | undefined = collections && collections.find((entry) => entry.slug === subpathCombination);\n\n // If we find a collection, we add the reference and continue\n if (collection) {\n const collectionPath = currentFullPath && currentFullPath.length > 0\n ? (currentFullPath + \"/\" + collection.slug) // Use the current full path if provided\n : collection.slug;\n\n const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, \"\"));\n const nextSegments = restOfThePath.length > 0 ? restOfThePath.split(\"/\") : [];\n if (nextSegments.length > 0) {\n const entityId = nextSegments[0];\n const path = collectionPath + \"/\" + entityId;\n result.push(new EntityReference({ id: entityId,\npath: collectionPath }));\n if (nextSegments.length > 1) {\n const newPath = nextSegments.slice(1).join(\"/\");\n if (!collection) {\n throw Error(\"collection not found resolving path: \" + collection);\n }\n if (getSubcollections(collection).length > 0) {\n result.push(...getParentReferencesFromPath({\n path: newPath,\n collections: getSubcollections(collection),\n currentFullPath: path\n }));\n }\n }\n }\n break;\n }\n\n }\n return result;\n}\n","import { isRelationalCollectionConfig, type Property, type Relation } from \"@rebasepro/types\";\nimport { generateForeignKeyName } from \"@rebasepro/utils\";\nimport type { AdminCollection } from \"@rebasepro/cms-types\";\nimport { getPrimaryKeys, isPropertyBuilder } from \"@rebasepro/common\";\nimport { getPropertyInPath } from \"./property-path\";\nimport { getDisplayPropertyKey, hasDeclaredDisplay } from \"./entity-display\";\nimport { isStorageProperty } from \"./summary-property\";\n\n/**\n * How good a property is as the human-readable title of an entity.\n * Higher wins; ties are broken by declaration order.\n * `DISQUALIFIED` means the property can never be a title.\n */\nconst SCORE = {\n DISQUALIFIED: -1,\n /**\n * Points at another entity. Only readable once the target resolves, and it\n * renders as the raw key until then — last resort, for collections (like\n * junction tables) that hold no text of their own.\n */\n REFERENCE: 5,\n RELATION: 10,\n /** A user picker: resolves to a person's name, like a relation does */\n USER: 10,\n /** Long form text — readable, but a description, not a name */\n LONG_TEXT: 20,\n /** A closed set of values: shared by many rows, so it identifies nothing */\n ENUM: 30,\n /** Identifying, but PII and usually secondary to a name */\n EMAIL: 45,\n /** Any plain, short, free text field */\n PLAIN_TEXT: 60,\n /** Free text whose name says it holds the entity's label */\n NAMED: 100\n} as const;\n\n/**\n * Keys whose name states outright that the property is the entity label.\n * This is a *bonus* on top of the structural rules — never a requirement, and\n * never the mechanism that keeps identifiers out of the title slot.\n */\nconst TITLE_LIKE_KEYS = new Set([\n \"name\",\n \"fullname\",\n \"displayname\",\n \"title\",\n \"label\",\n \"heading\",\n \"subject\",\n \"username\",\n \"nickname\"\n]);\n\nfunction normalizeKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nfunction isHidden(property: Property): boolean {\n return Boolean(property.admin?.hideFromCollection);\n}\n\n/**\n * Every column on this collection that stores a foreign key: the `localKey` of\n * each owning relation (declared inline on a property or in `relations[]`), the\n * source column of a junction, and the key a many-to-many joins on.\n *\n * These hold another entity's id, so they must never fill the title slot even\n * though they are declared as plain strings.\n */\nfunction getForeignKeyColumns<M extends Record<string, unknown>>(collection: AdminCollection<M>): Set<string> {\n const keys = new Set<string>();\n\n const addRelationKeys = (relation: Relation) => {\n switch (relation.kind) {\n case \"belongsTo\":\n // Left to be inferred, the column still takes the conventional\n // `<relation>_id` name.\n keys.add(relation.localKey ?? generateForeignKeyName(relation.relationName ?? \"\"));\n break;\n case \"manyToMany\":\n if (relation.through?.sourceColumn) keys.add(relation.through.sourceColumn);\n break;\n case \"via\": {\n // Only the first hop starts on this collection's table.\n const from = relation.joinPath?.[0]?.on?.from;\n for (const column of Array.isArray(from) ? from : [from]) {\n if (column) keys.add(column);\n }\n break;\n }\n default:\n // hasOne / hasMany put their column on the *target*.\n break;\n }\n };\n\n for (const relation of (isRelationalCollectionConfig(collection) ? collection.relations : undefined) ?? []) {\n addRelationKeys(relation);\n }\n\n for (const [key, propertyRaw] of Object.entries(collection.properties ?? {})) {\n const property = propertyRaw as Property | undefined;\n if (!property || isPropertyBuilder(property) || property.type !== \"relation\") continue;\n if (property.relation) {\n addRelationKeys({ ...property.relation,\nrelationName: property.relation.relationName ?? key });\n }\n }\n\n return keys;\n}\n\n/**\n * True when the property is declared to hold an opaque identifier rather than\n * something a person reads: a primary key, a foreign key, a UUID column, or a\n * picker bound to an auth user id. Decided from the property *schema*, never\n * from the key name.\n */\nfunction isIdentifierProperty(property: Property, key: string, idKeys: Set<string>, foreignKeys: Set<string>): boolean {\n if (idKeys.has(key)) return true;\n if (foreignKeys.has(key)) return true;\n if (\"isId\" in property && property.isId) return true;\n if (property.type === \"string\" && property.columnType === \"uuid\") return true;\n return false;\n}\n\nfunction scoreTitleCandidate(property: Property, key: string, idKeys: Set<string>, foreignKeys: Set<string>): number {\n if (isHidden(property)) return SCORE.DISQUALIFIED;\n if (isIdentifierProperty(property, key, idKeys, foreignKeys)) return SCORE.DISQUALIFIED;\n if (isStorageProperty(property)) return SCORE.DISQUALIFIED;\n\n if (property.type === \"relation\") {\n const isMany = property.resolvedRelation\n ? property.resolvedRelation.cardinality === \"many\"\n : property.relation?.kind === \"hasMany\" || property.relation?.kind === \"manyToMany\";\n return isMany ? SCORE.DISQUALIFIED : SCORE.RELATION;\n }\n if (property.type === \"reference\") {\n return SCORE.REFERENCE;\n }\n if (property.type !== \"string\") {\n // Numbers, dates, booleans, maps and arrays never read as a title.\n return SCORE.DISQUALIFIED;\n }\n\n // A user picker stores an auth user id but renders the person behind it, so\n // it ranks with relations: usable as a title, but only as a last resort.\n if (property.userSelect) return SCORE.USER;\n if (property.enum) return SCORE.ENUM;\n if (property.admin?.multiline || property.admin?.markdown) return SCORE.LONG_TEXT;\n if (property.email) return SCORE.EMAIL;\n if (TITLE_LIKE_KEYS.has(normalizeKey(key))) return SCORE.NAMED;\n return SCORE.PLAIN_TEXT;\n}\n\n/**\n * All properties that could serve as the entity title, best first.\n *\n * Candidates are ranked from the property *schema* — identifiers (primary\n * keys, foreign keys, UUID columns, user pickers), images and hidden fields are\n * excluded structurally, so a collection whose id column is called something\n * other than `id` is handled the same as one where it isn't.\n *\n * When the collection declares `propertiesOrder` the developer has already\n * stated what comes first, so qualifying candidates keep that order; otherwise\n * they are ranked (a name beats a description beats a relation).\n *\n * @group Collections\n */\nexport function getTitlePropertyCandidates<M extends Record<string, unknown>>(\n collection: AdminCollection<M>\n): string[] {\n if (!collection.properties) return [];\n\n // `getPropertyInPath`, not `properties[key]`: a declared title on a nested\n // field — `profile.display_name` — was looked up flat, found nothing, and\n // silently fell through to the derived ranking. The dotted form has been\n // documented as valid the whole time.\n const declared = getDisplayPropertyKey(collection, \"title\");\n if (declared && getPropertyInPath(collection.properties, declared)) {\n return [declared];\n }\n\n const idKeys = new Set<string>(getPrimaryKeys(collection) as string[]);\n const foreignKeys = getForeignKeyColumns(collection);\n const explicitOrder = collection.propertiesOrder as string[] | undefined;\n const order = explicitOrder ?? Object.keys(collection.properties);\n\n const scored: { key: string; score: number; index: number }[] = [];\n order.forEach((key, index) => {\n const property = collection.properties[key];\n if (!property || isPropertyBuilder(property)) return;\n const score = scoreTitleCandidate(property as Property, key, idKeys, foreignKeys);\n if (score === SCORE.DISQUALIFIED) return;\n scored.push({ key,\nscore,\nindex });\n });\n\n // An explicit `propertiesOrder` is a statement of what matters first, so it\n // wins over the ranking — the ranking only decides between properties the\n // developer never ordered.\n if (!explicitOrder) {\n scored.sort((a, b) => (b.score - a.score) || (a.index - b.index));\n }\n\n return scored.map(candidate => candidate.key);\n}\n\n/**\n * The relation a collection *leads* with, if it leads with one.\n *\n * A junction-shaped collection — a pipeline entry, a membership, a booking —\n * holds no label of its own: it is \"this candidate, for that vacancy\". The\n * general ranking puts relations last (they only read once the target\n * resolves), so the title slot would otherwise fall to whatever free text\n * happens to follow: a note, a comment. Preview surfaces that render one row\n * per entity (list, cards, board) prefer the leading relation instead.\n *\n * The decision is structural — the first property that could be a title, in the\n * order the developer declared (or ordered) them. Declaration order is a\n * statement about what the collection is about; property *names* are not\n * consulted here.\n *\n * Returns `undefined` when that first property is anything but a\n * single-cardinality relation, or when the collection states its own\n * `display.title`.\n *\n * @group Collections\n */\nexport function getLeadingRelationTitleKey<M extends Record<string, unknown>>(\n collection: AdminCollection<M>\n): string | undefined {\n if (!collection.properties) return undefined;\n // The collection states what it is called, in one form or the other; either\n // way it is not asking for the leading-relation heuristic.\n if (hasDeclaredDisplay(collection, \"title\")) return undefined;\n\n const idKeys = new Set<string>(getPrimaryKeys(collection) as string[]);\n const foreignKeys = getForeignKeyColumns(collection);\n const order = (collection.propertiesOrder as string[] | undefined) ?? Object.keys(collection.properties);\n\n for (const key of order) {\n const property = collection.properties[key];\n if (!property || isPropertyBuilder(property)) continue;\n if (scoreTitleCandidate(property as Property, key, idKeys, foreignKeys) === SCORE.DISQUALIFIED) continue;\n return (property as Property).type === \"relation\" ? key : undefined;\n }\n\n return undefined;\n}\n\n/**\n * The property that should fill the title slot for a collection, ignoring any\n * concrete values. Prefer {@link getTitlePropertyKeyForValues} when an entity\n * is at hand — it can skip candidates that happen to be empty or to hold an id.\n *\n * @group Collections\n */\nexport function getTitlePropertyKey<M extends Record<string, unknown>>(\n collection: AdminCollection<M>\n): string | undefined {\n return getTitlePropertyCandidates(collection)[0];\n}\n\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst LONG_HEX_REGEX = /^[0-9a-f]{24,}$/i;\nconst CUID_REGEX = /^c[a-z0-9]{20,}$/i;\n\n/**\n * True when a value reads as a machine identifier (UUID, ObjectId/long hex,\n * cuid) rather than as something worth showing to a person.\n *\n * @group Collections\n */\nexport function looksLikeIdentifierValue(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n return UUID_REGEX.test(trimmed) || LONG_HEX_REGEX.test(trimmed) || CUID_REGEX.test(trimmed);\n}\n\n/**\n * The title property for a concrete entity: the best-ranked candidate that\n * actually carries a readable value. Candidates that are empty, that repeat the\n * entity id, or that hold an opaque identifier are skipped, so a free-text\n * column that happens to store UUIDs never ends up as the title.\n *\n * Returns the top-ranked candidate when none of them has a usable value, so\n * callers can still render a placeholder for that property.\n *\n * @group Collections\n */\nexport function getTitlePropertyKeyForValues<M extends Record<string, unknown>>(\n collection: AdminCollection<M>,\n values: Record<string, unknown> | undefined,\n entityId?: string | number\n): string | undefined {\n const candidates = getTitlePropertyCandidates(collection);\n if (!values || candidates.length === 0) return candidates[0];\n\n for (const key of candidates) {\n const value = values[key];\n if (value === undefined || value === null || value === \"\") continue;\n if (typeof value === \"string\") {\n if (looksLikeIdentifierValue(value)) continue;\n if (entityId !== undefined && value === String(entityId)) continue;\n }\n return key;\n }\n\n return candidates[0];\n}\n"],"mappings":"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"}