@burojs/react 0.4.0 → 0.5.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.
- package/README.md +15 -6
- package/dist/flows-runtime.cjs +1162 -0
- package/dist/flows-runtime.cjs.map +1 -0
- package/dist/flows-runtime.d.cts +153 -0
- package/dist/flows-runtime.d.ts +153 -0
- package/dist/flows-runtime.js +1157 -0
- package/dist/flows-runtime.js.map +1 -0
- package/dist/index.cjs +1629 -3862
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2259 -723
- package/dist/index.d.ts +2259 -723
- package/dist/index.js +1412 -3692
- package/dist/index.js.map +1 -1
- package/dist/present-flow-BM8vaiZX.cjs +10152 -0
- package/dist/present-flow-BM8vaiZX.cjs.map +1 -0
- package/dist/present-flow-pFzbn0cZ.js +9015 -0
- package/dist/present-flow-pFzbn0cZ.js.map +1 -0
- package/dist/types-DH3beUOO.d.cts +488 -0
- package/dist/types-DH3beUOO.d.ts +488 -0
- package/package.json +24 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["cancelledError","structuralKey","configurationError","sameSession","configurationError","cancelledError","isRecord","sameSnapshot","sessionSnapshot","cancelledError","samePortableValue","isCurrentGeneration","execute","cancelledError","#descriptor","#runtime","#queryClient","#key","#lease","#consumerGeneration","#listeners","#state","#stateForLease","#consumeLease","#unsubscribeLease","#unsubscribeSession","#retire","#active","#dirtyBeforeFirstQuery","#hasStartedQuery","#reduceQuery","#scheduleDirtyRefetch","#close","#protocolFailure","#withProtocolFailure","#seenEvent","#markDirty","#reduceSnapshot","#publish","#failProtocol","#latestRevision","#latestValue","#compare","#equals","#failConflict","#protocolReconciliationRequested","#protocolTerminal","#dirtyGeneration","#scheduled","#refetching","samePortableValue","AppContext","sessionSnapshot","resourceHandle","#runtime","#descriptor","#listeners","#state","#active","#set","#tailPromise","#tailController","sessionSnapshot","resourceHandle","AppContext","EMPTY","AppContext","isRecord","EMPTY","#entries","#listeners","#handleUnsubscribes","#attachHandle","#invalidate","#notify","#snapshot","#detachAll","#detachHandle"],"sources":["../src/data/batch-coordinator.ts","../src/data/live/coordinator.ts","../src/data/provider-registry.ts","../src/data/runtime.ts","../src/data/context.tsx","../src/data/ssr.ts","../src/auth/controller.ts","../src/auth/context.tsx","../src/hooks/auth/use-auth.ts","../src/data/query-options.ts","../src/data/query-execution.ts","../src/data/live/query-live-observer.ts","../src/hooks/data/use-query-descriptor.ts","../src/runtime.tsx","../src/context.ts","../src/hooks/use-t.ts","../src/hooks/data/use-standard-query-descriptor.ts","../src/hooks/data/use-list.ts","../src/hooks/data/use-one.ts","../src/hooks/data/use-many.ts","../src/hooks/data/use-count.ts","../src/data/infinite-list-observer.ts","../src/hooks/data/use-infinite-list.ts","../src/data/count-policy.ts","../src/hooks/data/use-custom-query.ts","../src/data/invalidation.ts","../src/data/mutation-options.ts","../src/hooks/data/use-standard-mutation-descriptor.ts","../src/hooks/data/use-create.ts","../src/hooks/data/use-update.ts","../src/hooks/data/use-delete.ts","../src/hooks/data/use-custom-mutation.ts","../src/audit/context.ts","../src/hooks/router/router-adapter.tsx","../src/audit/use-nav-audit.ts","../src/hooks/use-app.ts","../src/hooks/use-doc-panel.tsx","../src/fields/definitions.ts","../src/fields/provider.tsx","../src/runtime/manifest-hydration.tsx","../src/ui-settings/local-storage-adapter.ts","../src/ui-settings/context.ts","../src/ui-settings/provider.tsx","../src/ui/context.tsx","../src/hooks/use-component.ts","../src/ui/ui-presentations.tsx","../src/ui/mount.tsx","../src/ui/use-ui-present.ts","../src/provider.tsx","../src/audit/form-diff.ts","../src/audit/use-form-submit-audit.ts","../src/ui-settings/use-ui-settings.ts","../src/data/action-data-access.ts","../src/hooks/use-resource.ts","../src/fields/use-field-implementation.ts","../src/fields/define-field-with-implementation.ts","../src/hooks/use-doc.ts","../src/hooks/use-current-resource.ts","../src/hooks/use-ctx.ts","../src/hooks/use-permissions.ts","../src/hooks/use-visible-templates.ts","../src/hooks/use-capability.ts","../src/hooks/use-availability.ts","../src/hooks/use-app-actions.ts","../src/hooks/use-set-slice.ts","../src/hooks/use-test-ids.ts","../src/hooks/use-record-title.ts","../src/hooks/use-action.ts","../src/hooks/use-task-run.ts","../src/checks/use-checks.ts","../src/checks/use-check-gate.ts","../src/hooks/use-bulk-action.ts","../src/hooks/use-local-storage.ts","../src/hooks/use-debounced-value.ts","../src/hooks/file/use-file-storage.ts","../src/hooks/file/use-file-field.ts","../src/hooks/file/url-cache.ts","../src/hooks/file/use-file-urls.ts","../src/hooks/use-enum-values.ts","../src/hooks/relation-aggregator.tsx","../src/hooks/url-state/codec.ts","../src/hooks/url-state/use-resource-url-state.ts","../src/hooks/url-state/get-resource-params.ts","../src/hooks/saved-views/saved-view-setting.ts","../src/hooks/saved-views/use-saved-views.ts","../src/hooks/saved-views/apply-view-to-url-state.ts","../src/hooks/command-palette/use-command-palette.ts","../src/hooks/command-palette/use-track-recent-record.ts","../src/hooks/use-item-actions.ts","../src/hooks/use-resource-list/helpers.ts","../src/hooks/use-resource-list/use-filter-fields.ts","../src/hooks/use-resource-list/row-href.ts","../src/hooks/use-resource-list/use-resource-list.ts","../src/hooks/use-resource-list/context.tsx","../src/merge-components.ts","../src/components/buro-routes.tsx","../src/locales/en.ts","../src/locales/ru.ts","../src/forms/conditional.ts","../src/forms/use-declarative-form.ts","../src/export/runs-store.ts","../src/export/use-export.ts","../src/index.ts"],"sourcesContent":["import {\n normalizeDataError,\n queryKeyFor,\n validateBatchResult,\n type BatchedQueryOperation,\n type DataError,\n type DataProviderSessionSnapshot,\n type ErasedQueryDescriptor,\n type QueryContext,\n type RequestContext,\n} from '@burojs/core';\n\nfunction cancelledError(code: 'aborted' | 'stale-generation' = 'aborted'): DataError {\n return {\n kind: 'cancelled',\n code,\n message:\n code === 'aborted'\n ? 'Data query was aborted.'\n : 'Data query completed after its session generation changed.',\n };\n}\n\nexport interface BatchExecutionContext {\n /** Opaque resolved provider-instance identity; provider IDs are insufficient. */\n readonly serviceIdentity: object;\n readonly providerServiceKey: string;\n readonly requestContext: Readonly<RequestContext>;\n readonly session: DataProviderSessionSnapshot;\n readonly signal: AbortSignal;\n readonly batch: (\n operations: readonly BatchedQueryOperation[],\n context: QueryContext,\n ) => Promise<unknown>;\n}\n\nexport interface BatchCoordinator {\n execute<T>(operation: BatchedQueryOperation, context: BatchExecutionContext): Promise<T>;\n cancelGeneration(generation: number): void;\n dispose(): void;\n}\n\ninterface Waiter<T = unknown> {\n readonly resolve: (value: T) => void;\n readonly reject: (reason: DataError) => void;\n readonly signal: AbortSignal;\n removeAbortListener(): void;\n}\n\ninterface Entry {\n readonly operation: BatchedQueryOperation;\n readonly descriptorKey: string;\n readonly group: Group;\n readonly waiters: Set<Waiter>;\n}\n\ninterface Group {\n readonly key: string;\n readonly context: BatchExecutionContext;\n readonly entries: Map<string, Entry>;\n readonly controller: AbortController;\n dispatched: boolean;\n}\n\nfunction structuralKey(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction operationKey(descriptor: ErasedQueryDescriptor): string {\n return structuralKey(queryKeyFor(descriptor));\n}\n\n/**\n * Groups optional provider batch requests without widening their authority:\n * a group is bound to the resolved provider object, active execution session,\n * scope, and binding revision of each descriptor.\n */\nexport function createBatchCoordinator(): BatchCoordinator {\n let disposed = false;\n let nextObjectToken = 0;\n let nextOperationToken = 0;\n const objectTokens = new WeakMap<object, number>();\n /** Includes dispatched groups which a newer same-key microtask superseded. */\n const activeGroups = new Set<Group>();\n const groups = new Map<string, Group>();\n\n function objectToken(value: object): number {\n const existing = objectTokens.get(value);\n if (existing !== undefined) return existing;\n nextObjectToken += 1;\n objectTokens.set(value, nextObjectToken);\n return nextObjectToken;\n }\n\n function groupKey(operation: BatchedQueryOperation, context: BatchExecutionContext): string {\n return structuralKey([\n objectToken(context.serviceIdentity),\n context.session.sessionKey,\n context.session.generation,\n context.session.scopeKey,\n operation.descriptor.sessionKey,\n operation.descriptor.scopeKey,\n operation.descriptor.bindingRevision,\n ]);\n }\n\n function rejectWaiter(waiter: Waiter, error: DataError): void {\n waiter.removeAbortListener();\n waiter.reject(error);\n }\n\n function settleEntry(\n entry: Entry,\n result:\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: DataError },\n ): void {\n for (const waiter of [...entry.waiters]) {\n entry.waiters.delete(waiter);\n waiter.removeAbortListener();\n if (result.ok) waiter.resolve(result.value);\n else waiter.reject(result.error);\n }\n }\n\n function discardEntry(entry: Entry): void {\n entry.group.entries.delete(entry.descriptorKey);\n }\n\n function abortSubmittedGroupWhenEmpty(group: Group): void {\n if (!group.dispatched) return;\n if ([...group.entries.values()].every((entry) => entry.waiters.size === 0)) {\n group.controller.abort();\n }\n }\n\n function cancelWaiter(entry: Entry, waiter: Waiter, code: 'aborted' | 'stale-generation'): void {\n if (!entry.waiters.delete(waiter)) return;\n rejectWaiter(waiter, cancelledError(code));\n if (!entry.group.dispatched && entry.waiters.size === 0) discardEntry(entry);\n abortSubmittedGroupWhenEmpty(entry.group);\n }\n\n function finishGroup(group: Group): void {\n activeGroups.delete(group);\n if (groups.get(group.key) === group) groups.delete(group.key);\n }\n\n async function dispatch(group: Group): Promise<void> {\n if (disposed || group.entries.size === 0) {\n finishGroup(group);\n return;\n }\n group.dispatched = true;\n const entries = [...group.entries.values()];\n const operations = entries.map((entry) => entry.operation);\n const context: QueryContext = Object.freeze({\n signal: group.controller.signal,\n requestContext: group.context.requestContext,\n session: group.context.session,\n providerServiceKey: group.context.providerServiceKey,\n });\n\n try {\n const response = validateBatchResult(\n operations,\n await group.context.batch(operations, context),\n );\n const results = new Map(response.results.map((result) => [result.id, result]));\n for (const entry of entries) {\n const result = results.get(entry.operation.id);\n if (result === undefined) continue; // Core validation already rejects this protocol violation.\n if (entry.waiters.size === 0) continue;\n if (result.status === 'success') settleEntry(entry, { ok: true, value: result.value });\n else settleEntry(entry, { ok: false, error: result.error });\n }\n } catch (error) {\n const normalized = normalizeDataError(error);\n for (const entry of entries) {\n if (entry.waiters.size > 0) settleEntry(entry, { ok: false, error: normalized });\n }\n } finally {\n finishGroup(group);\n }\n }\n\n function schedule(group: Group): void {\n queueMicrotask(() => {\n void dispatch(group);\n });\n }\n\n return Object.freeze({\n execute<T>(operation: BatchedQueryOperation, context: BatchExecutionContext): Promise<T> {\n if (disposed) {\n return Promise.reject({\n kind: 'configuration',\n code: 'batch-coordinator-disposed',\n message: 'Batch coordinator has been disposed.',\n } satisfies DataError);\n }\n if (context.signal.aborted) return Promise.reject(cancelledError());\n\n const descriptorKey = operationKey(operation.descriptor);\n const key = groupKey(operation, context);\n let group = groups.get(key);\n if (group === undefined || group.dispatched) {\n group = {\n key,\n context,\n entries: new Map(),\n controller: new AbortController(),\n dispatched: false,\n };\n groups.set(key, group);\n activeGroups.add(group);\n schedule(group);\n }\n let entry = group.entries.get(descriptorKey);\n if (entry === undefined) {\n nextOperationToken += 1;\n entry = {\n operation: Object.freeze({\n id: `buro-batch-${nextOperationToken.toString(36)}`,\n descriptor: operation.descriptor,\n }),\n descriptorKey,\n group,\n waiters: new Set(),\n };\n group.entries.set(descriptorKey, entry);\n }\n\n return new Promise<T>((resolve, reject) => {\n let waiter: Waiter;\n const abort = () => cancelWaiter(entry!, waiter, 'aborted');\n waiter = {\n resolve: resolve as (value: unknown) => void,\n reject,\n signal: context.signal,\n removeAbortListener() {\n context.signal.removeEventListener('abort', abort);\n },\n };\n entry.waiters.add(waiter);\n context.signal.addEventListener('abort', abort, { once: true });\n if (context.signal.aborted) abort();\n });\n },\n cancelGeneration(generation: number) {\n for (const group of [...activeGroups]) {\n if (group.context.session.generation !== generation) continue;\n for (const entry of [...group.entries.values()]) {\n for (const waiter of [...entry.waiters]) cancelWaiter(entry, waiter, 'stale-generation');\n }\n }\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n for (const group of [...activeGroups]) {\n for (const entry of [...group.entries.values()]) {\n for (const waiter of [...entry.waiters]) cancelWaiter(entry, waiter, 'aborted');\n }\n group.controller.abort();\n }\n groups.clear();\n activeGroups.clear();\n },\n });\n}\n","import {\n isDataError,\n normalizeDataError,\n queryKeyFor,\n resolveDataCapability,\n type DataError,\n type DataSessionController,\n type ErasedQueryDescriptor,\n type LiveConnectionStatus,\n type LiveObserver,\n type LivePlan,\n type Unsubscribe,\n} from '@burojs/core';\n\nimport type { AppRuntime } from '@burojs/core';\n\nimport type { DataProviderRegistry } from '../provider-registry.js';\nimport type { LiveCoordinator, LiveEvent, LiveLease, LiveState } from './types.js';\n\nexport interface LiveCoordinatorRuntime {\n readonly app: AppRuntime;\n readonly dataSession: DataSessionController;\n readonly providers: DataProviderRegistry;\n readonly liveSetupTimeoutMs: number;\n}\n\ninterface Lease<T = unknown> {\n readonly entry: Entry;\n readonly generation: number;\n readonly listeners: Set<() => void>;\n released: boolean;\n state: LiveState<T>;\n}\n\ninterface Entry {\n readonly key: string;\n readonly descriptor: ErasedQueryDescriptor;\n readonly controller: AbortController;\n readonly leases: Set<Lease>;\n executionGeneration: number;\n active: boolean;\n terminal: boolean;\n state: LiveState;\n unsubscribe?: Unsubscribe;\n cleanup?: Promise<void>;\n}\n\nconst OFF_STATE: LiveState = Object.freeze({ status: 'off' });\n\nfunction structuralKey(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction setupTimeoutError(phase: 'open' | 'subscribe'): DataError {\n return {\n kind: 'transport',\n code: 'live-setup-timeout',\n message: `Live ${phase} setup exceeded the runtime timeout.`,\n retryable: true,\n };\n}\n\nfunction invalidPlanError(): DataError {\n return {\n kind: 'protocol',\n code: 'invalid-live-plan',\n message: 'Data provider returned an invalid live plan.',\n };\n}\n\nfunction isValidPlan(value: unknown): value is LivePlan {\n if (value === null || typeof value !== 'object') return false;\n const candidate = value as Partial<LivePlan>;\n if (typeof candidate.subscribe !== 'function') return false;\n return (\n (candidate.kind === 'invalidate' && candidate.initial === 'query') ||\n (candidate.kind === 'snapshot' &&\n (candidate.initial === 'query' || candidate.initial === 'stream'))\n );\n}\n\nfunction readinessTimeout(plan: LivePlan, remaining: number): number | undefined {\n if (plan.initial === 'stream') return undefined;\n const declared = plan.readinessTimeoutMs;\n if (declared === undefined) return remaining;\n if (!Number.isFinite(declared) || declared <= 0) return 0;\n return Math.min(declared, remaining);\n}\n\nfunction planView<T>(plan: LivePlan<T>): LivePlan<T> {\n return plan;\n}\n\n/**\n * Owns one logical provider subscription per canonical descriptor. It is\n * deliberately cache-free: Task 11 interprets its invalidation/snapshot events.\n */\nexport function createLiveCoordinator(runtime: LiveCoordinatorRuntime): LiveCoordinator {\n let disposed = false;\n let nextExecutionGeneration = 0;\n const entries = new Map<string, Entry>();\n\n function notify(lease: Lease): void {\n for (const listener of lease.listeners) listener();\n }\n\n function updateLease<T>(lease: Lease<T>, state: LiveState<T>): void {\n if (lease.released) return;\n lease.state = state;\n notify(lease);\n }\n\n function publish(entry: Entry, state: LiveState): void {\n if (!entry.active) return;\n entry.state = state;\n for (const lease of entry.leases) updateLease(lease, state);\n }\n\n function publishEvent(entry: Entry, event: LiveEvent): void {\n if (!entry.active) return;\n publish(entry, { ...entry.state, event });\n }\n\n async function callUnsubscribe(unsubscribe: Unsubscribe | undefined): Promise<void> {\n if (unsubscribe === undefined) return;\n try {\n await unsubscribe();\n } catch {\n // Provider close is best effort. Setup errors remain the observable state.\n }\n }\n\n function close(entry: Entry): Promise<void> {\n if (!entry.active) return entry.cleanup ?? Promise.resolve();\n entry.active = false;\n entry.executionGeneration += 1;\n entry.controller.abort();\n if (entries.get(entry.key) === entry) entries.delete(entry.key);\n entry.cleanup = callUnsubscribe(entry.unsubscribe);\n return entry.cleanup;\n }\n\n function release(lease: Lease): void {\n if (lease.released) return;\n lease.released = true;\n lease.listeners.clear();\n lease.entry.leases.delete(lease);\n if (lease.entry.leases.size === 0) void close(lease.entry);\n }\n\n function statusForProvider(status: LiveConnectionStatus): LiveState['status'] {\n return status;\n }\n\n function createObserver(entry: Entry, plan: LivePlan, generation: number): LiveObserver {\n return {\n next(value: unknown) {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n const event: LiveEvent =\n plan.kind === 'invalidate'\n ? { type: 'invalidate' }\n : { type: 'snapshot', value, initial: plan.initial };\n publishEvent(entry, event);\n },\n status(status) {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n publish(entry, { ...entry.state, status: statusForProvider(status) });\n },\n error(error) {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n entry.terminal = true;\n publish(entry, {\n ...entry.state,\n status: 'degraded',\n error: isDataError(error) ? error : normalizeDataError(error),\n });\n },\n complete() {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n entry.terminal = true;\n publish(entry, { ...entry.state, status: 'degraded' });\n },\n };\n }\n\n async function awaitWithTimeout<T>(\n entry: Entry,\n value: Promise<T>,\n timeoutMs: number | undefined,\n phase: 'open' | 'subscribe',\n ): Promise<T> {\n if (timeoutMs === undefined) return value;\n if (timeoutMs <= 0) {\n entry.controller.abort();\n throw setupTimeoutError(phase);\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n value,\n new Promise<T>((_resolve, reject) => {\n timer = setTimeout(() => {\n entry.controller.abort();\n reject(setupTimeoutError(phase));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n async function begin(entry: Entry): Promise<void> {\n const generation = entry.executionGeneration;\n const startedAt = Date.now();\n try {\n const service = runtime.providers.resolve(entry.descriptor.providerId);\n const capability = resolveDataCapability(service.provider, {\n lifecycle: 'live',\n kind: entry.descriptor.kind,\n });\n if (isDataError(capability)) throw capability;\n const plan = await awaitWithTimeout(\n entry,\n Promise.resolve(\n capability(entry.descriptor, {\n signal: entry.controller.signal,\n requestContext: runtime.app.requestContext,\n session: service.session,\n providerServiceKey: service.id,\n }),\n ),\n runtime.liveSetupTimeoutMs,\n 'open',\n );\n if (!entry.active || entry.executionGeneration !== generation) return;\n if (plan === null) {\n throw {\n kind: 'capability',\n code: 'live-unavailable',\n message: 'Data provider declined live execution for this descriptor.',\n } satisfies DataError;\n }\n if (!isValidPlan(plan)) throw invalidPlanError();\n\n publish(entry, { status: 'connecting', plan: planView(plan) });\n const remaining = Math.max(0, runtime.liveSetupTimeoutMs - (Date.now() - startedAt));\n const subscribe = Promise.resolve(\n plan.subscribe(createObserver(entry, plan, generation), {\n signal: entry.controller.signal,\n }),\n );\n // A timeout wins the race below, but the provider may still finish its\n // asynchronous registration. That handle belongs to the cancelled\n // lifecycle and must never be adopted by a later descriptor entry.\n void subscribe.then(\n (lateHandle) => {\n if (\n !entry.active ||\n entry.executionGeneration !== generation ||\n entry.controller.signal.aborted\n ) {\n void callUnsubscribe(lateHandle);\n }\n },\n () => undefined,\n );\n const handle = await awaitWithTimeout(\n entry,\n subscribe,\n readinessTimeout(plan, remaining),\n 'subscribe',\n );\n if (\n !entry.active ||\n entry.executionGeneration !== generation ||\n entry.controller.signal.aborted\n ) {\n // The continuation registered on `subscribe` above owns late-handle\n // disposal, including this cancellation window.\n return;\n }\n entry.unsubscribe = handle;\n if (entry.terminal) return;\n publish(entry, { ...entry.state, status: 'connected' });\n } catch (error) {\n if (!entry.active || entry.executionGeneration !== generation) return;\n entry.terminal = true;\n publish(entry, { ...entry.state, status: 'degraded', error: normalizeDataError(error) });\n }\n }\n\n function acquire<T>(descriptor: ErasedQueryDescriptor, consumerGeneration: number): LiveLease<T> {\n if (disposed) {\n throw new Error('Live coordinator has been disposed.');\n }\n const key = structuralKey(queryKeyFor(descriptor));\n let entry = entries.get(key);\n if (entry === undefined) {\n entry = {\n key,\n descriptor,\n controller: new AbortController(),\n leases: new Set(),\n executionGeneration: ++nextExecutionGeneration,\n active: true,\n terminal: false,\n state: { status: 'connecting' },\n };\n entries.set(key, entry);\n void begin(entry);\n }\n\n const lease: Lease<T> = {\n entry,\n generation: consumerGeneration,\n listeners: new Set(),\n released: false,\n state: entry.state as LiveState<T>,\n };\n entry.leases.add(lease);\n return Object.freeze({\n getState: () => lease.state,\n subscribe(listener: () => void): () => void {\n if (lease.released) return () => undefined;\n lease.listeners.add(listener);\n return () => lease.listeners.delete(listener);\n },\n release: () => release(lease),\n });\n }\n\n function cancelGeneration(generation: number): void {\n for (const entry of [...entries.values()]) {\n for (const lease of [...entry.leases]) {\n if (lease.generation === generation) release(lease);\n }\n }\n }\n\n async function dispose(): Promise<void> {\n if (disposed) return;\n disposed = true;\n await Promise.all([...entries.values()].map((entry) => close(entry)));\n }\n\n return Object.freeze({ acquire, cancelGeneration, dispose });\n}\n","import {\n type AppRuntime,\n type DataError,\n type DataProvider,\n type DataProviderFactoryContext,\n type DataProviderRegistration,\n type DataSessionSnapshot,\n type PushInvalidationBinding,\n PUSH_INVALIDATION_NOT_ROUTABLE_CODE,\n collectPushInvalidationMismatches,\n formatPushInvalidationRefusal,\n normalizeDataError,\n resourceKey,\n} from '@burojs/core';\n\nexport interface ProviderServiceRef {\n readonly id: string;\n /** Opaque per-provider-instance identity for cache and execution partitioning. */\n readonly identity: object;\n readonly provider: DataProvider;\n readonly session: DataSessionSnapshot;\n}\n\nexport interface DataProviderRegistry {\n start(session: DataSessionSnapshot): Promise<void>;\n resolve(id?: string): ProviderServiceRef;\n replaceScope(next: DataSessionSnapshot, previous: DataSessionSnapshot): Promise<void>;\n rotateSession(next: DataSessionSnapshot, previous: DataSessionSnapshot): Promise<void>;\n dispose(): Promise<void>;\n}\n\nexport interface CreateDataProviderRegistryOptions {\n /** Request-local SSR cannot safely reuse caller-owned provider instances. */\n readonly requestDependentSsr?: boolean;\n}\n\ninterface OwnedProviderService {\n readonly ownership: 'owned';\n readonly controller: AbortController;\n readonly ref: ProviderServiceRef;\n disposed: boolean;\n}\n\ninterface BorrowedProviderService {\n readonly ownership: 'borrowed';\n readonly ref: ProviderServiceRef;\n}\n\ntype ProviderService = OwnedProviderService | BorrowedProviderService;\n\nfunction configurationError(code: string, message: string): DataError {\n return Object.assign(new Error(message), {\n kind: 'configuration' as const,\n code,\n });\n}\n\nfunction assertProvider(value: unknown, id: string): asserts value is DataProvider {\n if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {\n throw configurationError(\n 'invalid-provider',\n `Data provider '${id}' factory returned a non-object value.`,\n );\n }\n}\n\nfunction serviceRef(\n id: string,\n provider: DataProvider,\n session: DataSessionSnapshot,\n): ProviderServiceRef {\n return Object.freeze({\n id,\n identity: Object.freeze({}),\n provider,\n session,\n });\n}\n\nfunction sameSession(left: DataSessionSnapshot, right: DataSessionSnapshot): boolean {\n return (\n left === right || (left.sessionKey === right.sessionKey && left.generation === right.generation)\n );\n}\n\n/**\n * Every registered resource's binding, as the app runtime resolves it.\n *\n * A resource whose binding cannot be resolved at all (no effective provider,\n * or a provider id that is not registered) is skipped: that is a different,\n * pre-existing failure with its own error, and swallowing it here would\n * replace a precise message with a vaguer one.\n */\nfunction resolvedBindings(app: AppRuntime): readonly PushInvalidationBinding[] {\n const bindings: PushInvalidationBinding[] = [];\n for (const resource of app.registry.list()) {\n try {\n const binding = app.resolveDataBinding(resource.ref ?? resource.name);\n bindings.push({\n ref: resourceKey(binding.ref),\n resource: binding.resource,\n providerId: binding.providerId,\n });\n } catch {\n // See the doc comment above: not this check's failure to report.\n }\n }\n return bindings;\n}\n\n/**\n * REFUSES A PUSH-INVALIDATION OPT-IN THAT CAN NEVER FIRE, at registration.\n *\n * The opt-in is provider-side (`@burojs/hasura`'s `ResourceMapping.live`) and\n * the runtime resolves a descriptor's live channel from\n * `descriptor.providerId`, so a provider is only ever asked to `open` for\n * resources it already serves. An opt-in written against a resource ANOTHER\n * provider serves is therefore unreachable — and it used to be silent in\n * every observable way: the declaring provider's `open` was never called, the\n * serving provider declined (or, like `@burojs/pocketbase`, had no live slot\n * at all), the live coordinator published `degraded` onto a lease\n * `ResourceListController` deliberately does not re-expose, and no console\n * channel was touched.\n *\n * ⚠️ REGISTRATION, NOT SUBSCRIBE TIME — deliberately. Registration knows every\n * provider instance and every resource binding at once, which is exactly what\n * this mismatch is about, and it fails before a single query runs rather than\n * only when someone opens the affected screen. The cost is the other half:\n * registration cannot see a resource that is registered LAZILY afterwards, so\n * an opt-in naming a not-yet-registered resource is skipped rather than\n * refused (see `collectPushInvalidationMismatches`).\n *\n * Two further limits, recorded rather than assumed away:\n *\n * - It runs on `start` only. `replaceScope` and `rotateSession` recreate owned\n * providers from the SAME registrations, so a capability set cannot change\n * in practice; a factory returning a differently CONFIGURED provider per\n * session would slip through.\n * - It compares an opt-in against the provider that SERVES the resource. A\n * resource served by a provider with a push channel that simply did not opt\n * in stays silent exactly as before — there is no resource-side statement of\n * intent to compare against, and inventing one would create two declarations\n * that must agree.\n */\nfunction assertPushInvalidationIsRoutable(\n app: AppRuntime,\n services: ReadonlyMap<string, ProviderService>,\n): void {\n const declarations: [string, readonly string[]][] = [];\n for (const [id, service] of services) {\n const declared = service.ref.provider.live?.declaredPushInvalidation?.();\n if (declared !== undefined && declared.length > 0) declarations.push([id, declared]);\n }\n if (declarations.length === 0) return;\n\n const mismatches = collectPushInvalidationMismatches(declarations, resolvedBindings(app));\n if (mismatches.length === 0) return;\n throw configurationError(\n PUSH_INVALIDATION_NOT_ROUTABLE_CODE,\n formatPushInvalidationRefusal(mismatches),\n );\n}\n\n/**\n * Resolves app-registered provider services for exactly one active data\n * session. Owned instances are created from their factory and are always\n * aborted before disposal; borrowed instances are never disposed by React.\n */\nexport function createDataProviderRegistry(\n app: AppRuntime,\n options: CreateDataProviderRegistryOptions = {},\n): DataProviderRegistry {\n let activeSession: DataSessionSnapshot | undefined;\n let disposed = false;\n let disposePromise: Promise<void> | undefined;\n let pendingLifecycleOperations = 0;\n let lifecycleTail: Promise<void> = Promise.resolve();\n const services = new Map<string, ProviderService>();\n\n function assertActive(allowPendingLifecycle = false): DataSessionSnapshot {\n if (disposed)\n throw configurationError('registry-disposed', 'Data provider registry has been disposed.');\n if (!allowPendingLifecycle && pendingLifecycleOperations > 0) {\n throw configurationError(\n 'provider-transitioning',\n 'Data provider registry is transitioning to a new data session.',\n );\n }\n if (activeSession === undefined) {\n throw configurationError('not-started', 'Data provider registry has not been started.');\n }\n return activeSession;\n }\n\n function assertPrevious(previous: DataSessionSnapshot): void {\n const active = assertActive(true);\n if (!sameSession(active, previous)) {\n throw configurationError(\n 'session-mismatch',\n 'Data provider registry transition does not match its active data session.',\n );\n }\n }\n\n function serialize<T>(operation: () => Promise<T>): Promise<T> {\n pendingLifecycleOperations += 1;\n const run = lifecycleTail.then(operation, operation);\n lifecycleTail = run.then(\n () => undefined,\n () => undefined,\n );\n return run.finally(() => {\n pendingLifecycleOperations -= 1;\n });\n }\n\n async function createOwned(\n id: string,\n registration: Extract<DataProviderRegistration, { readonly ownership: 'owned' }>,\n session: DataSessionSnapshot,\n ): Promise<OwnedProviderService> {\n const controller = new AbortController();\n const context: DataProviderFactoryContext = Object.freeze({\n requestContext: app.requestContext,\n session,\n signal: controller.signal,\n });\n\n try {\n const provider = await registration.factory(context);\n assertProvider(provider, id);\n return {\n ownership: 'owned',\n controller,\n ref: serviceRef(id, provider, session),\n disposed: false,\n };\n } catch (error) {\n controller.abort();\n throw normalizeDataError(error);\n }\n }\n\n function createBorrowed(\n id: string,\n registration: Extract<DataProviderRegistration, { readonly ownership: 'borrowed' }>,\n session: DataSessionSnapshot,\n ): BorrowedProviderService {\n if (options.requestDependentSsr) {\n throw configurationError(\n 'borrowed-provider-request-dependent-ssr',\n `Borrowed data provider '${id}' is not allowed for request-dependent SSR.`,\n );\n }\n return {\n ownership: 'borrowed',\n ref: serviceRef(id, registration.provider, session),\n };\n }\n\n async function createService(\n id: string,\n registration: DataProviderRegistration,\n session: DataSessionSnapshot,\n ): Promise<ProviderService> {\n return registration.ownership === 'owned'\n ? createOwned(id, registration, session)\n : createBorrowed(id, registration, session);\n }\n\n async function disposeOwned(service: OwnedProviderService): Promise<void> {\n if (service.disposed) return;\n service.disposed = true;\n service.controller.abort();\n await service.ref.provider.dispose?.();\n }\n\n async function disposeServices(values: Iterable<ProviderService>): Promise<unknown | undefined> {\n let failure: unknown;\n for (const service of values) {\n if (service.ownership !== 'owned') continue;\n try {\n await disposeOwned(service);\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n }\n return failure;\n }\n\n function updateBorrowedSession(\n service: BorrowedProviderService,\n session: DataSessionSnapshot,\n ): BorrowedProviderService {\n return { ownership: 'borrowed', ref: Object.freeze({ ...service.ref, session }) };\n }\n\n function updateOwnedSession(\n service: OwnedProviderService,\n session: DataSessionSnapshot,\n ): OwnedProviderService {\n return { ...service, ref: Object.freeze({ ...service.ref, session }) };\n }\n\n async function startNow(session: DataSessionSnapshot): Promise<void> {\n if (disposed)\n throw configurationError('registry-disposed', 'Data provider registry has been disposed.');\n if (activeSession !== undefined) {\n throw configurationError(\n 'already-started',\n 'Data provider registry has already been started.',\n );\n }\n\n const created = new Map<string, ProviderService>();\n try {\n for (const [id, registration] of app.dataProviderFactories) {\n created.set(id, await createService(id, registration, session));\n }\n assertPushInvalidationIsRoutable(app, created);\n } catch (error) {\n await disposeServices(created.values());\n throw normalizeDataError(error);\n }\n\n activeSession = session;\n for (const [id, service] of created) services.set(id, service);\n }\n\n async function replaceScopeNow(\n next: DataSessionSnapshot,\n previous: DataSessionSnapshot,\n ): Promise<void> {\n assertPrevious(previous);\n activeSession = next;\n\n for (const [id, registration] of app.dataProviderFactories) {\n const current = services.get(id);\n if (registration.ownership === 'borrowed') {\n const borrowed =\n current?.ownership === 'borrowed' ? current : createBorrowed(id, registration, previous);\n try {\n await borrowed.ref.provider.onSessionChange?.(next, previous);\n services.set(id, updateBorrowedSession(borrowed, next));\n } catch (error) {\n throw normalizeDataError(error);\n }\n continue;\n }\n\n if (current?.ownership === 'owned' && current.ref.provider.onSessionChange !== undefined) {\n try {\n await current.ref.provider.onSessionChange(next, previous);\n services.set(id, updateOwnedSession(current, next));\n continue;\n } catch (error) {\n services.delete(id);\n try {\n await disposeOwned(current);\n } catch {\n // The transition error is the observable failure; cleanup remains best effort.\n }\n throw normalizeDataError(error);\n }\n }\n\n if (current?.ownership === 'owned') {\n services.delete(id);\n await disposeOwned(current);\n }\n services.set(id, await createOwned(id, registration, next));\n }\n }\n\n async function rotateSessionNow(\n next: DataSessionSnapshot,\n previous: DataSessionSnapshot,\n ): Promise<void> {\n assertPrevious(previous);\n activeSession = next;\n\n for (const [id, registration] of app.dataProviderFactories) {\n const current = services.get(id);\n if (registration.ownership === 'borrowed') {\n const borrowed =\n current?.ownership === 'borrowed' ? current : createBorrowed(id, registration, previous);\n try {\n await borrowed.ref.provider.onSessionChange?.(next, previous);\n services.set(id, updateBorrowedSession(borrowed, next));\n } catch (error) {\n throw normalizeDataError(error);\n }\n continue;\n }\n\n if (current?.ownership === 'owned') {\n services.delete(id);\n await disposeOwned(current);\n }\n services.set(id, await createOwned(id, registration, next));\n }\n }\n\n function dispose(): Promise<void> {\n if (disposePromise !== undefined) return disposePromise;\n disposed = true;\n disposePromise = serialize(async () => {\n const failure = await disposeServices(services.values());\n services.clear();\n activeSession = undefined;\n if (failure !== undefined) throw failure;\n });\n return disposePromise;\n }\n\n return Object.freeze({\n start(session: DataSessionSnapshot) {\n return serialize(() => startNow(session));\n },\n resolve(id?: string) {\n assertActive();\n const providerId = id ?? app.defaultProviderId;\n if (providerId === undefined) {\n throw configurationError(\n 'missing-default-provider',\n 'No default data provider is configured.',\n );\n }\n const service = services.get(providerId);\n if (service === undefined) {\n throw configurationError(\n 'unknown-provider',\n `Data provider '${providerId}' is not registered.`,\n );\n }\n return service.ref;\n },\n replaceScope(next: DataSessionSnapshot, previous: DataSessionSnapshot) {\n return serialize(() => replaceScopeNow(next, previous));\n },\n rotateSession(next: DataSessionSnapshot, previous: DataSessionSnapshot) {\n return serialize(() => rotateSessionNow(next, previous));\n },\n dispose,\n });\n}\n","import type {\n AppRuntime,\n DataSessionController,\n DataSessionSnapshot,\n DataSessionTransitionParticipant,\n} from '@burojs/core';\nimport { normalizeDataError } from '@burojs/core';\nimport type { QueryClient } from '@tanstack/react-query';\n\nimport type { AuthController } from '../auth/controller.js';\n\nimport { createBatchCoordinator, type BatchCoordinator } from './batch-coordinator.js';\nimport { createLiveCoordinator } from './live/coordinator.js';\nimport type { LiveCoordinator } from './live/types.js';\nimport { createDataProviderRegistry, type DataProviderRegistry } from './provider-registry.js';\n\nconst DEFAULT_LIVE_SETUP_TIMEOUT_MS = 5_000;\n\ninterface ParticipantStartupControl {\n begin(): void;\n activate(): void;\n fail(error: unknown): void;\n}\n\nconst participantStartupControls = new WeakMap<\n DataRuntimeTransitionParticipant,\n ParticipantStartupControl\n>();\n\nfunction configurationError(\n code: string,\n message: string,\n): Error & {\n readonly kind: 'configuration';\n readonly code: string;\n} {\n return Object.assign(new Error(message), { kind: 'configuration' as const, code });\n}\n\nfunction cancelledError(): Error & {\n readonly kind: 'cancelled';\n readonly code: 'aborted';\n} {\n return Object.assign(new Error('Data runtime operation was aborted.'), {\n kind: 'cancelled' as const,\n code: 'aborted' as const,\n });\n}\n\nfunction sameSession(left: DataSessionSnapshot, right: DataSessionSnapshot): boolean {\n return left.sessionKey === right.sessionKey;\n}\n\nexport interface DataRuntimeContextValue {\n readonly app: AppRuntime;\n readonly queryClient: QueryClient;\n readonly dataSession: DataSessionController;\n readonly providers: DataProviderRegistry;\n readonly batchCoordinator: BatchCoordinator;\n readonly liveCoordinator: LiveCoordinator;\n readonly liveSetupTimeoutMs: number;\n /** Present only in React trees configured with a native AuthProvider. */\n readonly authController?: AuthController;\n waitUntilReady(signal?: AbortSignal): Promise<DataSessionSnapshot>;\n}\n\n/**\n * The lease owns Buro's provider/cache coordination only. The app,\n * QueryClient, and DataSession remain caller-owned and are never disposed by\n * React mounting or unmounting.\n */\nexport interface DataRuntimeLease extends DataRuntimeContextValue {\n readonly ownership: 'external';\n dispose(): Promise<void>;\n}\n\nexport interface DataRuntimeTransitionParticipant extends DataSessionTransitionParticipant {\n bind(lease: DataRuntimeLease): void;\n}\n\nexport interface CreateDataRuntimeTransitionParticipantOptions {\n readonly app: AppRuntime;\n readonly queryClient: QueryClient;\n}\n\nexport interface CreateDataRuntimeOptions {\n readonly app: AppRuntime;\n readonly queryClient: QueryClient;\n readonly dataSession: DataSessionController;\n readonly transitionParticipant: DataRuntimeTransitionParticipant;\n readonly liveSetupTimeoutMs?: number;\n readonly requestDependentSsr?: boolean;\n}\n\n/**\n * Creates the participant which core DataSession invokes at each committed\n * lifecycle boundary. Register it on the DataSession before creating its\n * lease; that keeps transition serialization in core.\n */\nexport function createDataRuntimeTransitionParticipant(\n options: CreateDataRuntimeTransitionParticipantOptions,\n): DataRuntimeTransitionParticipant {\n let lease: DataRuntimeLease | undefined;\n let bound = false;\n let creationStarted = false;\n let pendingCancellation: Promise<void> = Promise.resolve();\n let settleStartup!: (value: void | PromiseLike<void>) => void;\n let rejectStartup!: (reason?: unknown) => void;\n const startup = new Promise<void>((resolve, reject) => {\n settleStartup = resolve;\n rejectStartup = reject;\n });\n void startup.catch(() => undefined);\n\n function requireLease(): DataRuntimeLease {\n if (lease === undefined) {\n throw configurationError(\n 'data-runtime-transition-unbound',\n 'Data runtime transition participant must be bound before a session transition.',\n );\n }\n return lease;\n }\n\n const participant: DataRuntimeTransitionParticipant = Object.freeze({\n bind(nextLease: DataRuntimeLease) {\n if (bound) {\n throw configurationError(\n 'data-runtime-transition-already-bound',\n 'Data runtime transition participant is already bound to a lease.',\n );\n }\n if (nextLease.app !== options.app || nextLease.queryClient !== options.queryClient) {\n throw configurationError(\n 'data-runtime-transition-mismatch',\n 'Data runtime transition participant must bind to its original app and QueryClient.',\n );\n }\n lease = nextLease;\n bound = true;\n },\n abort(previous: DataSessionSnapshot) {\n // Startup can reject after this participant is registered but before a\n // lease exists. Core disposal must still leave that caller-owned session\n // safely disposable; transition() below remains the configuration gate.\n const active = lease;\n if (active === undefined) return;\n // Native descriptor keys are added by subsequent tasks. Until then, the\n // lease has one active cache partition, which is cleared atomically at\n // the core session boundary.\n active.batchCoordinator.cancelGeneration(previous.generation);\n active.liveCoordinator.cancelGeneration(previous.generation);\n pendingCancellation = active.queryClient.cancelQueries().then(() => {\n active.queryClient.clear();\n });\n },\n async transition(next: DataSessionSnapshot, previous: DataSessionSnapshot) {\n if (!creationStarted) requireLease();\n const active = requireLease();\n await startup;\n await pendingCancellation;\n if (sameSession(next, previous)) {\n await active.providers.replaceScope(next, previous);\n } else {\n await active.providers.rotateSession(next, previous);\n }\n },\n dispose() {\n // The creator disposes the lease first, then its caller-owned\n // DataSession. This participant deliberately has no second disposal\n // path that could race the lease or take ownership of caller objects.\n },\n });\n\n participantStartupControls.set(participant, {\n begin() {\n creationStarted = true;\n },\n activate() {\n settleStartup();\n },\n fail(error) {\n rejectStartup(error);\n },\n });\n return participant;\n}\n\nfunction waitForReady(\n dataSession: DataSessionController,\n signal: AbortSignal | undefined,\n): Promise<DataSessionSnapshot> {\n if (signal === undefined) return dataSession.waitUntilReady();\n if (signal.aborted) return Promise.reject(cancelledError());\n\n return new Promise<DataSessionSnapshot>((resolve, reject) => {\n const abort = () => reject(cancelledError());\n signal.addEventListener('abort', abort, { once: true });\n dataSession\n .waitUntilReady()\n .then(resolve, reject)\n .finally(() => {\n signal.removeEventListener('abort', abort);\n });\n });\n}\n\n/**\n * Starts the React-owned provider registry for an externally owned app/cache/\n * session triple. It is intentionally separate from BuroProvider so SSR\n * and browser callers choose the full teardown order themselves.\n */\nexport async function createDataRuntime(\n options: CreateDataRuntimeOptions,\n): Promise<DataRuntimeLease> {\n const liveSetupTimeoutMs = options.liveSetupTimeoutMs ?? DEFAULT_LIVE_SETUP_TIMEOUT_MS;\n if (!Number.isFinite(liveSetupTimeoutMs) || liveSetupTimeoutMs < 0) {\n throw configurationError(\n 'invalid-live-setup-timeout',\n 'liveSetupTimeoutMs must be a non-negative finite number.',\n );\n }\n\n const providers = createDataProviderRegistry(options.app, {\n requestDependentSsr: options.requestDependentSsr,\n });\n const batchCoordinator = createBatchCoordinator();\n const liveCoordinator = createLiveCoordinator({\n app: options.app,\n dataSession: options.dataSession,\n providers,\n liveSetupTimeoutMs,\n });\n const initialState = options.dataSession.getState();\n if (initialState.status !== 'ready') {\n throw configurationError(\n 'data-runtime-session-not-ready',\n 'Data runtime can only be created while its DataSession is ready.',\n );\n }\n const initial = initialState.snapshot;\n const startupControl = participantStartupControls.get(options.transitionParticipant);\n startupControl?.begin();\n\n let disposed = false;\n let disposePromise: Promise<void> | undefined;\n const lease: DataRuntimeLease = Object.freeze({\n app: options.app,\n ownership: 'external' as const,\n queryClient: options.queryClient,\n dataSession: options.dataSession,\n providers,\n batchCoordinator,\n liveCoordinator,\n liveSetupTimeoutMs,\n waitUntilReady(signal?: AbortSignal) {\n if (disposed) {\n return Promise.reject(\n configurationError('data-runtime-disposed', 'Data runtime lease has been disposed.'),\n );\n }\n return waitForReady(options.dataSession, signal);\n },\n dispose() {\n if (disposePromise !== undefined) return disposePromise;\n disposed = true;\n disposePromise = (async () => {\n let failure: unknown;\n try {\n batchCoordinator.dispose();\n } catch (error) {\n failure = normalizeDataError(error);\n }\n try {\n await liveCoordinator.dispose();\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n try {\n await options.queryClient.cancelQueries();\n } catch (error) {\n failure = normalizeDataError(error);\n }\n try {\n options.queryClient.clear();\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n try {\n await providers.dispose();\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n if (failure !== undefined) throw failure;\n })();\n return disposePromise;\n },\n });\n\n try {\n options.transitionParticipant.bind(lease);\n await providers.start(initial);\n startupControl?.activate();\n } catch (error) {\n disposed = true;\n startupControl?.fail(error);\n batchCoordinator.dispose();\n await liveCoordinator.dispose();\n try {\n await providers.dispose();\n } catch {\n // Startup failure remains the observable error; registry cleanup is best effort.\n }\n throw normalizeDataError(error);\n }\n\n return lease;\n}\n","import type { ReactElement, ReactNode } from 'react';\nimport { createContext, useContext } from 'react';\n\nimport type { DataRuntimeContextValue } from './runtime.js';\n\nexport const DataRuntimeContext = createContext<DataRuntimeContextValue | null>(null);\n\nexport interface DataRuntimeProviderProps {\n readonly value: DataRuntimeContextValue;\n readonly children: ReactNode;\n}\n\n/** Attaches an externally owned native data-runtime lease to the React tree. */\nexport function DataRuntimeProvider({ value, children }: DataRuntimeProviderProps): ReactElement {\n return <DataRuntimeContext.Provider value={value}>{children}</DataRuntimeContext.Provider>;\n}\n\nexport function useDataRuntime(): DataRuntimeContextValue {\n const runtime = useContext(DataRuntimeContext);\n if (runtime === null) {\n throw new Error('useDataRuntime must be used within BuroProvider.');\n }\n return runtime;\n}\n\n/**\n * Like {@link useDataRuntime}, but tolerant of a missing native data runtime —\n * returns `null` instead of throwing. Mirrors the codebase's established\n * `useOptionalT` (`../hooks/use-t.ts`) / `useOptionalVisibilityCtx`\n * (`../hooks/use-permissions.ts`) / `useOptionalFileStorage`\n * (`../hooks/file/use-file-storage.ts`) precedent for \"may run outside a\n * full provider tree\".\n *\n * `<BuroProvider>` without a `dataRuntime` prop (the \"compat\" mode used by\n * most component-only tests, and by hosts that haven't adopted the native\n * data runtime) never mounts a `DataRuntimeProvider`, so `useDataRuntime()`\n * throws for ANY consumer — appropriate for `useAction` (dispatching an\n * action genuinely requires one), but wrong for a hook whose feature is\n * meaningful even without one (`useChecks`/`useCheckGate`: a check that\n * never touches `di.data` must keep working). Consumers needing the latter\n * behavior read this instead and degrade gracefully.\n */\nexport function useOptionalDataRuntime(): DataRuntimeContextValue | null {\n return useContext(DataRuntimeContext);\n}\n","import {\n clonePortableValue,\n createQueryDescriptor,\n DEFAULT_DATA_DESCRIPTOR_LIMITS,\n queryKeyFor,\n type ApplicationSnapshot,\n type AppRuntime,\n type DataSessionController,\n type ErasedQueryDescriptor,\n type PortableValue,\n type SnapshotHydrationCodec,\n} from '@burojs/core';\nimport { hashKey, hydrate, type Query, type QueryClient } from '@tanstack/react-query';\n\nimport type { DataRuntimeLease } from './runtime.js';\n\nconst QUERY_KEY_PREFIX = 'buro-data';\nconst QUERY_KEY_VERSION = 1;\nconst HYDRATION_VERSION = 1;\n\ntype HydrationReason = 'version' | 'definition' | 'catalog' | 'binding';\ntype QueryKind = ErasedQueryDescriptor['kind'];\n\ninterface PortableHydrationQuery {\n readonly queryHash: string;\n readonly queryKey: PortableValue;\n readonly state: PortableValue;\n readonly dehydratedAt: number;\n}\n\ninterface PortableHydrationState {\n readonly mutations: readonly [];\n readonly queries: readonly PortableHydrationQuery[];\n}\n\ninterface ValidatedQuery {\n readonly queryHash: string;\n readonly queryKey: PortableValue;\n readonly dehydratedAt: number;\n readonly dataUpdateCount: number;\n readonly dataUpdatedAt: number;\n readonly codec: SnapshotHydrationCodec;\n readonly payload: PortableValue;\n}\n\n/** Serialized server query state that is safe to put into an HTML document. */\nexport interface BuroDehydratedData {\n readonly version: 1;\n readonly definitionFingerprint: string;\n readonly implementationCatalogFingerprint: string;\n /** Revision per dehydrated declaration; never includes undeclared bindings. */\n readonly bindingRevisions: Readonly<Record<string, string>>;\n /** Non-secret query partition; it prevents accidental mixed-session payloads. */\n readonly partition: Readonly<{ readonly sessionKey: string; readonly scopeKey: PortableValue }>;\n readonly queryState: PortableValue;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction ownKeysOnly(\n value: Readonly<Record<string, unknown>>,\n allowed: readonly string[],\n): boolean {\n return Object.keys(value).every((key) => allowed.includes(key));\n}\n\nfunction portable(value: unknown): PortableValue | undefined {\n try {\n return clonePortableValue(value, DEFAULT_DATA_DESCRIPTOR_LIMITS) as PortableValue;\n } catch {\n return undefined;\n }\n}\n\nfunction samePortable(left: unknown, right: unknown): boolean {\n return JSON.stringify(left) === JSON.stringify(right);\n}\n\nfunction normalizedRef(\n value: unknown,\n): { readonly namespace: string; readonly id: string } | undefined {\n if (!isRecord(value) || typeof value.namespace !== 'string' || typeof value.id !== 'string')\n return undefined;\n return { namespace: value.namespace, id: value.id };\n}\n\nfunction sameRef(left: unknown, right: unknown): boolean {\n const a = normalizedRef(left);\n const b = normalizedRef(right);\n return a !== undefined && b !== undefined && a.namespace === b.namespace && a.id === b.id;\n}\n\nfunction descriptorKeys(kind: QueryKind): readonly string[] {\n const identity = [\n 'kind',\n 'providerId',\n 'ref',\n 'resource',\n 'sessionKey',\n 'scopeKey',\n 'bindingRevision',\n 'projection',\n 'providerOptions',\n 'dependencies',\n ];\n switch (kind) {\n case 'list':\n return [...identity, 'pagination', 'filter', 'sort'];\n case 'one':\n return [...identity, 'id'];\n case 'many':\n return [...identity, 'ids'];\n case 'count':\n return [...identity, 'filter'];\n case 'custom':\n return [...identity, 'operation', 'input'];\n }\n}\n\n/** Reads only an exact native descriptor whose canonical key can be reconstructed. */\nfunction descriptorFromKey(key: unknown): ErasedQueryDescriptor | undefined {\n if (\n !Array.isArray(key) ||\n key.length !== 3 ||\n key[0] !== QUERY_KEY_PREFIX ||\n key[1] !== QUERY_KEY_VERSION\n )\n return undefined;\n const raw = key[2];\n if (!isRecord(raw) || typeof raw.kind !== 'string') return undefined;\n const kind = raw.kind as QueryKind;\n if (\n !['list', 'one', 'many', 'count', 'custom'].includes(kind) ||\n !ownKeysOnly(raw, descriptorKeys(kind))\n )\n return undefined;\n try {\n const descriptor = createQueryDescriptor(raw as never) as ErasedQueryDescriptor;\n return samePortable(descriptor, raw) && samePortable(queryKeyFor(descriptor), key)\n ? descriptor\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction projectionFor(\n snapshot: ApplicationSnapshot,\n target: {\n readonly kind: 'resource' | 'custom-query';\n readonly ref: { readonly namespace: string; readonly id: string };\n },\n) {\n const projection = snapshot.getProjection(target);\n return projection !== undefined &&\n projection.kind === target.kind &&\n sameRef(projection.ref, target.ref)\n ? projection\n : undefined;\n}\n\nfunction fieldsContainProjection(\n value: PortableValue,\n projection: readonly unknown[] | undefined,\n): boolean {\n if (projection === undefined) return true;\n if (!isRecord(value)) return false;\n const fields = value.fields;\n if (!isRecord(fields)) return false;\n return projection.every((field) => typeof field === 'string' && Object.hasOwn(fields, field));\n}\n\n/** Ensures a key corresponds to a real currently compiled binding and codec. */\nfunction resolveDescriptorCodec(\n snapshot: ApplicationSnapshot,\n descriptor: ErasedQueryDescriptor,\n): SnapshotHydrationCodec | undefined {\n const ref = normalizedRef(descriptor.ref);\n if (ref === undefined || descriptor.bindingRevision !== snapshot.manifest.snapshotId)\n return undefined;\n\n if (descriptor.kind === 'custom') {\n const target = { kind: 'custom-query' as const, ref };\n const projection = projectionFor(snapshot, target);\n const value =\n projection === undefined || !isRecord(projection.value) ? undefined : projection.value;\n const binding = value === undefined || !isRecord(value.binding) ? undefined : value.binding;\n if (\n binding === undefined ||\n binding.provider !== descriptor.providerId ||\n (binding.resource ?? ref.id) !== descriptor.resource ||\n binding.operation !== descriptor.operation\n )\n return undefined;\n return snapshot.resolveHydrationCodec(target);\n }\n\n const target = { kind: 'resource' as const, ref };\n const projection = projectionFor(snapshot, target);\n const value =\n projection === undefined || !isRecord(projection.value) ? undefined : projection.value;\n const binding = value === undefined || !isRecord(value.data) ? undefined : value.data;\n if (\n binding === undefined ||\n binding.provider !== descriptor.providerId ||\n (binding.resource ?? ref.id) !== descriptor.resource ||\n !fieldsContainProjection(projection!.value, descriptor.projection)\n )\n return undefined;\n return snapshot.resolveHydrationCodec(target);\n}\n\nfunction queryState(data: unknown): PortableHydrationState | undefined {\n const cloned = portable(data);\n if (\n !isRecord(cloned) ||\n !Array.isArray(cloned.mutations) ||\n !Array.isArray(cloned.queries) ||\n cloned.mutations.length !== 0\n )\n return undefined;\n const queries: PortableHydrationQuery[] = [];\n for (const entry of cloned.queries) {\n if (!isRecord(entry) || !ownKeysOnly(entry, ['queryHash', 'queryKey', 'state', 'dehydratedAt']))\n return undefined;\n if (\n typeof entry.queryHash !== 'string' ||\n typeof entry.dehydratedAt !== 'number' ||\n !Number.isFinite(entry.dehydratedAt)\n )\n return undefined;\n if (!Array.isArray(entry.queryKey) || entry.queryHash !== hashKey(entry.queryKey))\n return undefined;\n if (descriptorFromKey(entry.queryKey) === undefined || !isRecord(entry.state)) return undefined;\n queries.push({\n queryHash: entry.queryHash,\n queryKey: entry.queryKey as PortableValue,\n state: entry.state as PortableValue,\n dehydratedAt: entry.dehydratedAt,\n });\n }\n return { mutations: [], queries };\n}\n\nfunction dataMatchesSnapshot(\n data: BuroDehydratedData,\n snapshot: ApplicationSnapshot,\n): HydrationReason | undefined {\n if (\n !isRecord(data) ||\n data.version !== HYDRATION_VERSION ||\n typeof data.definitionFingerprint !== 'string' ||\n typeof data.implementationCatalogFingerprint !== 'string' ||\n !isRecord(data.bindingRevisions) ||\n !isRecord(data.partition) ||\n typeof data.partition.sessionKey !== 'string' ||\n !('scopeKey' in data.partition) ||\n portable(data.partition.scopeKey) === undefined ||\n !('queryState' in data)\n )\n return 'version';\n if (data.definitionFingerprint !== snapshot.manifest.definitionFingerprint) return 'definition';\n if (data.implementationCatalogFingerprint !== snapshot.manifest.implementationCatalogFingerprint)\n return 'catalog';\n if (\n Object.values(data.bindingRevisions).some(\n (revision) => revision !== snapshot.manifest.snapshotId,\n )\n )\n return 'binding';\n return undefined;\n}\n\nfunction portableSuccessState(query: Query, payload: PortableValue): PortableValue | undefined {\n const updatedAt = query.state.dataUpdatedAt;\n const updateCount = query.state.dataUpdateCount;\n if (!Number.isFinite(updatedAt) || !Number.isSafeInteger(updateCount) || updateCount < 0)\n return undefined;\n return portable({\n status: 'success',\n error: null,\n data: { payload },\n dataUpdatedAt: updatedAt,\n dataUpdateCount: updateCount,\n });\n}\n\n/**\n * Dehydrates only successful native query results through the declaration-owned\n * compiled codec. Raw provider values, query metadata, credentials, provider\n * instances, errors, live state, and hydration tokens never cross this boundary.\n */\nexport function dehydrateBuroData(\n runtime: DataRuntimeLease,\n options: { readonly shouldDehydrateQuery?: (query: Query) => boolean } = {},\n): BuroDehydratedData {\n const snapshot = runtime.app.runtime.getSnapshot();\n const bindings: Record<string, string> = Object.create(null);\n const queries: PortableHydrationQuery[] = [];\n let partition: { readonly sessionKey: string; readonly scopeKey: PortableValue } | undefined;\n\n for (const query of runtime.queryClient.getQueryCache().getAll()) {\n if (\n query.state.status !== 'success' ||\n query.state.error !== null ||\n query.state.data === undefined ||\n !(options.shouldDehydrateQuery?.(query) ?? true)\n )\n continue;\n const descriptor = descriptorFromKey(query.queryKey);\n const codec =\n descriptor === undefined ? undefined : resolveDescriptorCodec(snapshot, descriptor);\n if (descriptor === undefined || codec === undefined) continue;\n const scopeKey = portable(descriptor.scopeKey);\n if (scopeKey === undefined) continue;\n const nextPartition = { sessionKey: descriptor.sessionKey, scopeKey };\n if (partition !== undefined && !samePortable(partition, nextPartition)) continue;\n const queryKey = portable(query.queryKey);\n if (queryKey === undefined) continue;\n try {\n const payload = portable(codec.encode(query.state.data));\n const state = payload === undefined ? undefined : portableSuccessState(query, payload);\n if (state === undefined) continue;\n const queryHash = hashKey(queryKey as readonly unknown[]);\n bindings[queryHash] = descriptor.bindingRevision;\n partition = nextPartition;\n queries.push({ queryHash, queryKey, state, dehydratedAt: query.state.dataUpdatedAt });\n } catch {\n // A bad or non-portable codec result makes this query ineligible, never raw.\n }\n }\n\n return Object.freeze({\n version: HYDRATION_VERSION,\n definitionFingerprint: snapshot.manifest.definitionFingerprint,\n implementationCatalogFingerprint: snapshot.manifest.implementationCatalogFingerprint,\n bindingRevisions: Object.freeze({ ...bindings }),\n partition: partition ?? Object.freeze({ sessionKey: '', scopeKey: null }),\n queryState: portable({ mutations: [], queries }) ?? { mutations: [], queries: [] },\n });\n}\n\n/** Checks whether the outer payload belongs to this immutable application snapshot. */\nexport function validateBuroHydration(\n data: BuroDehydratedData,\n snapshot: ApplicationSnapshot,\n): { readonly ok: true } | { readonly ok: false; readonly reason: HydrationReason } {\n const reason = dataMatchesSnapshot(data, snapshot);\n return reason === undefined ? { ok: true } : { ok: false, reason };\n}\n\nfunction validateQuery(\n entry: PortableHydrationQuery,\n data: BuroDehydratedData,\n snapshot: ApplicationSnapshot,\n): ValidatedQuery | undefined {\n const descriptor = descriptorFromKey(entry.queryKey);\n if (\n descriptor === undefined ||\n data.bindingRevisions[entry.queryHash] !== descriptor.bindingRevision\n )\n return undefined;\n if (\n !samePortable(\n { sessionKey: descriptor.sessionKey, scopeKey: descriptor.scopeKey },\n data.partition,\n )\n )\n return undefined;\n const codec = resolveDescriptorCodec(snapshot, descriptor);\n if (\n codec === undefined ||\n !isRecord(entry.state) ||\n !ownKeysOnly(entry.state, ['status', 'error', 'data', 'dataUpdatedAt', 'dataUpdateCount'])\n )\n return undefined;\n if (\n entry.state.status !== 'success' ||\n entry.state.error !== null ||\n !isRecord(entry.state.data) ||\n !ownKeysOnly(entry.state.data, ['payload'])\n )\n return undefined;\n if (typeof entry.state.dataUpdatedAt !== 'number' || !Number.isFinite(entry.state.dataUpdatedAt))\n return undefined;\n const dataUpdateCount = entry.state.dataUpdateCount;\n if (\n typeof dataUpdateCount !== 'number' ||\n !Number.isSafeInteger(dataUpdateCount) ||\n dataUpdateCount < 0\n )\n return undefined;\n const payload = portable(entry.state.data.payload);\n return payload === undefined\n ? undefined\n : {\n queryHash: entry.queryHash,\n queryKey: entry.queryKey,\n dehydratedAt: entry.dehydratedAt,\n dataUpdateCount,\n dataUpdatedAt: entry.state.dataUpdatedAt,\n codec,\n payload,\n };\n}\n\n/**\n * Validates every query and its declaration-owned codec before a single\n * TanStack cache write. The helper deliberately has no runtime/session\n * argument; host code adopts the core branded session token separately.\n */\nexport function hydrateBuroData(\n queryClient: QueryClient,\n snapshot: ApplicationSnapshot,\n data: BuroDehydratedData,\n): boolean {\n if (!validateBuroHydration(data, snapshot).ok) return false;\n const state = queryState(data.queryState);\n if (state === undefined || Object.keys(data.bindingRevisions).length !== state.queries.length)\n return false;\n const validated = state.queries.map((entry) => validateQuery(entry, data, snapshot));\n if (validated.some((entry) => entry === undefined)) return false;\n const restored: Array<Record<string, unknown>> = [];\n try {\n for (const entry of validated as ValidatedQuery[]) {\n restored.push({\n queryHash: entry.queryHash,\n queryKey: entry.queryKey,\n dehydratedAt: entry.dehydratedAt,\n state: {\n status: 'success',\n error: null,\n data: entry.codec.decode(entry.payload),\n dataUpdatedAt: entry.dataUpdatedAt,\n dataUpdateCount: entry.dataUpdateCount,\n errorUpdateCount: 0,\n errorUpdatedAt: 0,\n fetchFailureCount: 0,\n fetchFailureReason: null,\n fetchMeta: null,\n fetchStatus: 'idle',\n isInvalidated: false,\n },\n });\n }\n } catch {\n return false;\n }\n hydrate(queryClient, { mutations: [], queries: restored });\n return true;\n}\n\n/** Encodes a hydration payload for inline HTML without permitting script termination. */\nexport function serializeBuroHydration(data: BuroDehydratedData): string {\n return JSON.stringify(data)\n .replace(/</gu, '\\\\u003c')\n .replace(/>/gu, '\\\\u003e')\n .replace(/&/gu, '\\\\u0026')\n .replace(/\\u2028/gu, '\\\\u2028')\n .replace(/\\u2029/gu, '\\\\u2029');\n}\n\ntype RequestResources = {\n readonly dataRuntime: DataRuntimeLease;\n readonly queryClient: QueryClient;\n readonly dataSession: DataSessionController;\n readonly app: AppRuntime;\n};\n\nconst requestDisposals = new WeakMap<object, Promise<void>>();\n\n/** Disposes a host-owned SSR request in the only safe teardown order. */\nexport function disposeBuroRequest(resources: RequestResources): Promise<void> {\n const existing = requestDisposals.get(resources);\n if (existing !== undefined) return existing;\n const disposal = disposeRequest(resources);\n requestDisposals.set(resources, disposal);\n return disposal;\n}\n\nasync function disposeRequest(resources: RequestResources): Promise<void> {\n const failures: unknown[] = [];\n const attempt = async (operation: () => void | Promise<void>): Promise<void> => {\n try {\n await operation();\n } catch (error) {\n failures.push(error);\n }\n };\n await attempt(() => resources.dataRuntime.dispose());\n await attempt(() => resources.queryClient.cancelQueries());\n await attempt(() => resources.queryClient.clear());\n await attempt(() => resources.dataSession.dispose());\n await attempt(() => resources.app.runtime.dispose());\n if (failures.length > 0) throw new AggregateError(failures, 'Buro SSR request disposal failed.');\n}\n","import {\n type AuthCheckResult,\n type AuthContext,\n type AuthErrorResult,\n type AuthProvider,\n type AuthResult,\n type DataError,\n type DataSessionSnapshot,\n normalizeDataError,\n} from '@burojs/core';\n\nimport type { DataRuntimeContextValue } from '../data/runtime.js';\n\nexport interface AuthController<TIdentity = unknown> {\n getIdentity(): Promise<TIdentity | null>;\n check(): Promise<AuthCheckResult>;\n login(params: unknown): Promise<AuthResult>;\n logout(params: unknown): Promise<AuthResult>;\n recover(error: DataError, snapshot: DataSessionSnapshot): Promise<DataError | 'replay'>;\n}\n\nexport interface CreateAuthControllerOptions<TIdentity = unknown> {\n readonly runtime: DataRuntimeContextValue;\n readonly provider: AuthProvider<TIdentity>;\n}\n\nfunction configurationError(code: string, message: string): DataError {\n return { kind: 'configuration', code, message };\n}\n\nfunction sameSnapshot(left: DataSessionSnapshot, right: DataSessionSnapshot): boolean {\n return left.sessionKey === right.sessionKey && left.generation === right.generation;\n}\n\n/**\n * Owns auth-provider invocation at the active DataSession boundary. Refreshes\n * are deliberately shared only while in flight for one captured epoch.\n */\nexport function createAuthController<TIdentity = unknown>(\n options: CreateAuthControllerOptions<TIdentity>,\n): AuthController<TIdentity> {\n const recoveries = new Map<string, Promise<DataError | 'replay'>>();\n let lifecycleTail: Promise<void> = Promise.resolve();\n\n function context(snapshot: DataSessionSnapshot): AuthContext {\n return Object.freeze({\n requestContext: options.runtime.app.requestContext,\n sessionKey: snapshot.sessionKey,\n scopeKey: snapshot.scopeKey,\n generation: snapshot.generation,\n });\n }\n\n async function activeSnapshot(): Promise<DataSessionSnapshot> {\n return options.runtime.waitUntilReady();\n }\n\n function serializeLifecycle<T>(operation: () => Promise<T>): Promise<T> {\n const queued = lifecycleTail.then(operation, operation);\n lifecycleTail = queued.then(\n () => undefined,\n () => undefined,\n );\n return queued;\n }\n\n async function currentSnapshot(): Promise<DataSessionSnapshot> {\n const snapshot = await activeSnapshot();\n const state = options.runtime.dataSession.getState();\n if (state.status !== 'ready' || !sameSnapshot(state.snapshot, snapshot))\n return currentSnapshot();\n return snapshot;\n }\n\n async function resolveRecovery(\n error: DataError,\n snapshot: DataSessionSnapshot,\n ): Promise<DataError | 'replay'> {\n let result: AuthErrorResult;\n try {\n result =\n options.provider.onError === undefined\n ? { action: 'propagate' }\n : await options.provider.onError(error, context(snapshot));\n } catch (failure) {\n return normalizeDataError(failure);\n }\n if (result.action === 'refreshed') return 'replay';\n if (result.action === 'logout') {\n try {\n await serializeLifecycle(async () => {\n const state = options.runtime.dataSession.getState();\n if (state.status !== 'ready' || !sameSnapshot(state.snapshot, snapshot)) return false;\n await options.runtime.dataSession.rotateSession();\n return true;\n });\n } catch (failure) {\n return normalizeDataError(failure);\n }\n return error;\n }\n return result.error ?? error;\n }\n\n const controller: AuthController<TIdentity> = {\n async getIdentity() {\n const snapshot = await activeSnapshot();\n try {\n return await options.provider.getIdentity(context(snapshot));\n } catch (error) {\n throw normalizeDataError(error);\n }\n },\n async check() {\n const snapshot = await activeSnapshot();\n try {\n return await options.provider.check(context(snapshot));\n } catch (error) {\n throw normalizeDataError(error);\n }\n },\n async login(params: unknown) {\n return serializeLifecycle(async () => {\n try {\n await options.runtime.dataSession.rotateSession();\n const snapshot = await currentSnapshot();\n if (options.provider.login === undefined) {\n return {\n success: false,\n error: configurationError(\n 'login-unsupported',\n 'Authentication provider does not support login.',\n ),\n };\n }\n const result = await options.provider.login(params, context(snapshot));\n // A second rotation on SUCCESS ONLY (SP3 stage B Task 5 finding):\n // the FIRST rotation above starts `useIdentity()`/`useIsAuthenticated()`\n // fetching for the NEW session generation, but `provider.login()`\n // itself (the network call + wherever it persists the session,\n // e.g. `localStorage`) has not written anything yet at the moment\n // those queries read — they settle \"no session\" a beat too early,\n // and with no further generation bump nothing ever asks again\n // unless some OTHER, unrelated component happens to mount fresh\n // for the exact same query key afterward (what made this go\n // unnoticed: every app in this repo navigates immediately after a\n // successful login, and the destination route usually mounts a\n // component that also calls `useIdentity()`/`useIsAuthenticated()`,\n // incidentally re-triggering a correctly-timed fetch — an app\n // whose post-login route does not, or whose auth-state UI lives\n // outside the routed tree entirely, e.g. a header identity badge,\n // sees a stale \"signed out\" display until something else happens\n // to remount). Rotating again, strictly after `provider.login()`\n // has returned, guarantees the query that finally answers\n // \"who is signed in\" only ever starts once the provider has\n // actually finished writing that answer.\n if (result.success) await options.runtime.dataSession.rotateSession();\n return result;\n } catch (error) {\n return { success: false, error: normalizeDataError(error) };\n }\n });\n },\n async logout(params: unknown) {\n return serializeLifecycle(async () => {\n try {\n await options.runtime.dataSession.rotateSession();\n const snapshot = await currentSnapshot();\n if (options.provider.logout === undefined) {\n return {\n success: false,\n error: configurationError(\n 'logout-unsupported',\n 'Authentication provider does not support logout.',\n ),\n };\n }\n const result = await options.provider.logout(params, context(snapshot));\n // Same reasoning as `login` above, for the symmetric case: without\n // this, an identity/check query built right after the FIRST\n // rotation can settle using whatever the provider's `logout()`\n // had not yet cleared.\n if (result.success) await options.runtime.dataSession.rotateSession();\n return result;\n } catch (error) {\n return { success: false, error: normalizeDataError(error) };\n }\n });\n },\n async recover(error: DataError, captured: DataSessionSnapshot) {\n const state = options.runtime.dataSession.getState();\n if (state.status !== 'ready' || !sameSnapshot(state.snapshot, captured)) return error;\n const key = `${captured.sessionKey}:${captured.generation}`;\n const existing = recoveries.get(key);\n const pending = existing ?? resolveRecovery(error, captured);\n if (existing === undefined) recoveries.set(key, pending);\n let result: DataError | 'replay';\n try {\n result = await pending;\n } finally {\n if (recoveries.get(key) === pending) recoveries.delete(key);\n }\n if (result !== 'replay') return result;\n const current = options.runtime.dataSession.getState();\n return current.status === 'ready' && sameSnapshot(current.snapshot, captured)\n ? 'replay'\n : error;\n },\n };\n return Object.freeze(controller);\n}\n","import type { AuthProvider } from '@burojs/core';\nimport { createContext, useContext, useMemo, type ReactElement, type ReactNode } from 'react';\n\nimport { DataRuntimeProvider } from '../data/context.js';\nimport type { DataRuntimeContextValue } from '../data/runtime.js';\nimport { createAuthController, type AuthController } from './controller.js';\n\nexport const AuthControllerContext = createContext<AuthController | null>(null);\n\nexport interface AuthRuntimeProviderProps {\n readonly runtime: DataRuntimeContextValue;\n readonly provider: AuthProvider;\n readonly children: ReactNode;\n}\n\n/** Installs a native auth provider beside the caller-owned data runtime lease. */\nexport function AuthRuntimeProvider({\n runtime,\n provider,\n children,\n}: AuthRuntimeProviderProps): ReactElement {\n const controller = useMemo(\n () => createAuthController({ runtime, provider }),\n [provider, runtime],\n );\n const value = useMemo<DataRuntimeContextValue>(\n () => Object.freeze({ ...runtime, authController: controller }),\n [controller, runtime],\n );\n return (\n <AuthControllerContext.Provider value={controller}>\n <DataRuntimeProvider value={value}>{children}</DataRuntimeProvider>\n </AuthControllerContext.Provider>\n );\n}\n\nexport function useAuthController(): AuthController {\n const controller = useContext(AuthControllerContext);\n if (controller === null)\n throw new Error('Native auth hooks must be used within BuroProvider with authProvider.');\n return controller;\n}\n","import type { AuthCheckResult, AuthResult, DataError, DataSessionState } from '@burojs/core';\nimport {\n type UseMutationResult,\n type UseQueryResult,\n useMutation,\n useQuery,\n} from '@tanstack/react-query';\nimport { useSyncExternalStore } from 'react';\n\nimport { useAuthController } from '../../auth/context.js';\nimport { useDataRuntime } from '../../data/context.js';\n\nfunction sessionState(runtime: ReturnType<typeof useDataRuntime>): DataSessionState {\n return runtime.dataSession.getState();\n}\n\nfunction sessionSnapshot(state: DataSessionState) {\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\n/**\n * Gates the query on the DataSession being genuinely 'ready' for the exact\n * snapshot the query key already reflects — not merely \"has a session\".\n *\n * What this is MEASURED to do (`packages/react/tests/auth-query-session-gate.test.tsx`,\n * which reddens per line if either `enabled` below is removed): no auth query\n * is ever ISSUED while a transition is open. Without the gate, a query built\n * from a 'transitioning' snapshot starts fetching immediately, and\n * `AuthController.check()`/`.getIdentity()` themselves `await` that SAME\n * transition finishing (`createAuthController`'s `activeSnapshot()` →\n * `runtime.waitUntilReady()`) before they can answer, so the fetch parks\n * there and is then thrown away by the `queryClient.cancelQueries()`/\n * `.clear()` that `createDataRuntimeTransitionParticipant`'s `abort()` runs\n * at the next boundary. Counted: one `rotateSession()` costs 2\n * `getIdentity()` calls with the gate and 3 without; two back-to-back\n * rotations 2 vs 4; a `replaceScope()` then a rotation 3 vs 5. Wasted\n * provider work on every session rotation and every scope replacement,\n * removed.\n *\n * What this is NOT measured to do, despite an earlier claim in this repo\n * that it was: prevent the query getting permanently STUCK after a\n * same-route transition. That failure mode is arguable from the mechanism\n * above, but nobody has reproduced it. `abort()` runs synchronously right\n * after the 'transitioning' state is published and before React can render\n * the new query key, so the cancel lands before the new query exists; and\n * every later transition changes the key again, which mounts a fresh query.\n * Four scenarios built to provoke it (a transition held open across a React\n * render, two back-to-back rotations, a rotation landing mid-flight, a\n * `replaceScope`) settled on the fresh value with the gate and without it.\n * See `examples/marketplace-ops/docs/coverage-matrix.md` for the full\n * measurement in both states, including the app-stack tests that were once\n * recorded as proving this and do not.\n *\n * Consequence to keep in mind when consuming these hooks: during a\n * transition the query is DISABLED, so it reports `status: 'pending'` with\n * `fetchStatus: 'idle'` and therefore `isLoading === false`. Guards must\n * branch on `status`, not on `isLoading`.\n */\nfunction isReady(state: DataSessionState): boolean {\n return state.status === 'ready';\n}\n\n/** Returns the current auth-provider identity without making any UI decision. */\nexport function useIdentity<TIdentity = unknown>(): UseQueryResult<TIdentity | null, DataError> {\n const runtime = useDataRuntime();\n const controller = useAuthController();\n const state = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionState(runtime),\n () => sessionState(runtime),\n );\n const session = sessionSnapshot(state);\n return useQuery({\n queryKey: ['buro-auth', 'identity', session.sessionKey, session.generation, session.scopeKey],\n queryFn: () => controller.getIdentity() as Promise<TIdentity | null>,\n enabled: isReady(state),\n retry: false,\n });\n}\n\n/** Returns the auth-provider check result without redirecting or notifying. */\nexport function useIsAuthenticated(): UseQueryResult<AuthCheckResult, DataError> {\n const runtime = useDataRuntime();\n const controller = useAuthController();\n const state = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionState(runtime),\n () => sessionState(runtime),\n );\n const session = sessionSnapshot(state);\n return useQuery({\n queryKey: ['buro-auth', 'check', session.sessionKey, session.generation, session.scopeKey],\n queryFn: () => controller.check(),\n enabled: isReady(state),\n retry: false,\n });\n}\n\nexport function useLogin(): UseMutationResult<AuthResult, DataError, unknown> {\n const controller = useAuthController();\n return useMutation({ mutationFn: (params: unknown) => controller.login(params), retry: false });\n}\n\nexport function useLogout(): UseMutationResult<AuthResult, DataError, unknown> {\n const controller = useAuthController();\n return useMutation({ mutationFn: (params: unknown) => controller.logout(params), retry: false });\n}\n","import {\n queryKeyFor,\n type DataError,\n type DataQueryKey,\n type ErasedQueryDescriptor,\n type QueryResultFor,\n} from '@burojs/core';\nimport type { UseQueryOptions } from '@tanstack/react-query';\n\n/** Returns the canonical cache identity for a native data descriptor. */\nexport function buroQueryOptions<T extends ErasedQueryDescriptor>(\n descriptor: T,\n): UseQueryOptions<QueryResultFor<T>, DataError, QueryResultFor<T>, DataQueryKey> {\n return { queryKey: queryKeyFor(descriptor) };\n}\n","import {\n isDataError,\n normalizeDataError,\n resolveDataCapability,\n type DataError,\n type DataSessionSnapshot,\n type ErasedQueryDescriptor,\n type QueryContext,\n type QueryResultFor,\n} from '@burojs/core';\n\nimport type { DataRuntimeContextValue } from './runtime.js';\n\nfunction cancelledError(code: 'aborted' | 'stale-generation' = 'aborted'): DataError {\n return {\n kind: 'cancelled',\n code,\n message:\n code === 'aborted'\n ? 'Data query was aborted.'\n : 'Data query completed after its session generation changed.',\n };\n}\n\nfunction sameSnapshot(left: DataSessionSnapshot, right: DataSessionSnapshot): boolean {\n return left.sessionKey === right.sessionKey && left.generation === right.generation;\n}\n\nfunction samePortableValue(left: unknown, right: unknown): boolean {\n if (Object.is(left, right)) return true;\n if (left === null || right === null || typeof left !== 'object' || typeof right !== 'object')\n return false;\n if (Array.isArray(left) || Array.isArray(right)) {\n return (\n Array.isArray(left) &&\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((value, index) => samePortableValue(value, right[index]))\n );\n }\n const leftEntries = Object.entries(left);\n const rightRecord = right as Record<string, unknown>;\n return (\n leftEntries.length === Object.keys(rightRecord).length &&\n leftEntries.every(\n ([key, value]) =>\n Object.prototype.hasOwnProperty.call(rightRecord, key) &&\n samePortableValue(value, rightRecord[key]),\n )\n );\n}\n\nfunction replayStillMatches<T extends ErasedQueryDescriptor>(\n runtime: DataRuntimeContextValue,\n descriptor: T,\n captured: DataSessionSnapshot,\n): boolean {\n const state = runtime.dataSession.getState();\n return (\n state.status === 'ready' &&\n sameSnapshot(state.snapshot, captured) &&\n descriptor.sessionKey === captured.sessionKey &&\n samePortableValue(descriptor.scopeKey, captured.scopeKey)\n );\n}\n\nfunction linkedAbortController(signals: readonly AbortSignal[]): {\n readonly controller: AbortController;\n dispose(): void;\n} {\n const controller = new AbortController();\n const abort = () => controller.abort();\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort();\n break;\n }\n signal.addEventListener('abort', abort, { once: true });\n }\n return {\n controller,\n dispose() {\n for (const signal of signals) signal.removeEventListener('abort', abort);\n },\n };\n}\n\nfunction isCurrentGeneration<T extends ErasedQueryDescriptor>(\n runtime: DataRuntimeContextValue,\n descriptor: T,\n snapshot: DataSessionSnapshot,\n serviceIdentity: object,\n): boolean {\n const state = runtime.dataSession.getState();\n if (state.status !== 'ready' || !sameSnapshot(state.snapshot, snapshot)) return false;\n try {\n return runtime.providers.resolve(descriptor.providerId).identity === serviceIdentity;\n } catch {\n return false;\n }\n}\n\n/**\n * Executes a descriptor only within the active core session generation. A\n * provider that ignores abort still cannot return data for a replacement\n * provider/session identity.\n */\nexport async function executeQuery<T extends ErasedQueryDescriptor>(args: {\n readonly descriptor: T;\n readonly runtime: DataRuntimeContextValue;\n readonly signal: AbortSignal;\n readonly replayCount?: 0 | 1;\n readonly replaySnapshot?: DataSessionSnapshot;\n}): Promise<QueryResultFor<T>> {\n if (\n args.replaySnapshot !== undefined &&\n !replayStillMatches(args.runtime, args.descriptor, args.replaySnapshot)\n ) {\n throw cancelledError('stale-generation');\n }\n let captured: DataSessionSnapshot | undefined;\n try {\n return await executeQueryAttempt(args, (snapshot) => {\n captured = snapshot;\n });\n } catch (error) {\n const failure = normalizeDataError(error);\n if (\n args.replayCount !== 1 &&\n failure.kind === 'auth' &&\n captured !== undefined &&\n args.runtime.authController !== undefined\n ) {\n const recovery = await args.runtime.authController.recover(failure, captured);\n if (recovery === 'replay') {\n return executeQuery({ ...args, replayCount: 1, replaySnapshot: captured });\n }\n throw recovery;\n }\n throw failure;\n }\n}\n\nasync function executeQueryAttempt<T extends ErasedQueryDescriptor>(\n args: {\n readonly descriptor: T;\n readonly runtime: DataRuntimeContextValue;\n readonly signal: AbortSignal;\n readonly replaySnapshot?: DataSessionSnapshot;\n },\n capture: (snapshot: DataSessionSnapshot) => void,\n): Promise<QueryResultFor<T>> {\n const linked = linkedAbortController([args.signal]);\n let stopObservingGeneration: (() => void) | undefined;\n\n try {\n const snapshot = await args.runtime.waitUntilReady(linked.controller.signal);\n if (\n args.replaySnapshot !== undefined &&\n !replayStillMatches(args.runtime, args.descriptor, args.replaySnapshot)\n ) {\n throw cancelledError('stale-generation');\n }\n capture(snapshot);\n if (linked.controller.signal.aborted) throw cancelledError();\n\n const service = args.runtime.providers.resolve(args.descriptor.providerId);\n if (!sameSnapshot(service.session, snapshot)) throw cancelledError('stale-generation');\n stopObservingGeneration = args.runtime.dataSession.subscribe(() => {\n if (!isCurrentGeneration(args.runtime, args.descriptor, snapshot, service.identity)) {\n linked.controller.abort();\n }\n });\n if (!isCurrentGeneration(args.runtime, args.descriptor, snapshot, service.identity)) {\n throw cancelledError('stale-generation');\n }\n const batch = service.provider.batch?.queries;\n const result =\n batch === undefined\n ? await executeDirectQuery(args.descriptor, service.provider, {\n signal: linked.controller.signal,\n requestContext: args.runtime.app.requestContext,\n session: snapshot,\n providerServiceKey: service.id,\n })\n : await args.runtime.batchCoordinator.execute<QueryResultFor<T>>(\n { id: '', descriptor: args.descriptor },\n {\n serviceIdentity: service.identity,\n providerServiceKey: service.id,\n requestContext: args.runtime.app.requestContext,\n session: snapshot,\n signal: linked.controller.signal,\n batch,\n },\n );\n\n if (\n linked.controller.signal.aborted ||\n !isCurrentGeneration(args.runtime, args.descriptor, snapshot, service.identity)\n ) {\n throw cancelledError(linked.controller.signal.aborted ? 'aborted' : 'stale-generation');\n }\n return result;\n } catch (error) {\n if (linked.controller.signal.aborted) throw cancelledError();\n throw normalizeDataError(error);\n } finally {\n stopObservingGeneration?.();\n linked.dispose();\n }\n}\n\nasync function executeDirectQuery<T extends ErasedQueryDescriptor>(\n descriptor: T,\n provider: Parameters<typeof resolveDataCapability>[0],\n context: QueryContext,\n): Promise<QueryResultFor<T>> {\n const capability = resolveDataCapability(provider, {\n lifecycle: 'query',\n kind: descriptor.kind,\n });\n if (isDataError(capability)) throw capability;\n const execute = capability as unknown as (\n current: T,\n value: QueryContext,\n ) => Promise<QueryResultFor<T>>;\n return execute(descriptor, context);\n}\n","import {\n normalizeDataError,\n queryKeyFor,\n type DataError,\n type ErasedQueryDescriptor,\n type LivePlan,\n type QueryResultFor,\n} from '@burojs/core';\nimport type { QueryClient } from '@tanstack/react-query';\n\nimport { executeQuery } from '../query-execution.js';\nimport type { DataRuntimeContextValue } from '../runtime.js';\nimport type { LiveLease, LiveState } from './types.js';\n\nexport interface QueryLiveObserverState {\n readonly live: LiveState;\n /** Only observer-detected protocol violations synthesize query failure. */\n readonly protocolError?: DataError;\n}\n\nconst OFF_STATE: QueryLiveObserverState = Object.freeze({\n live: Object.freeze({ status: 'off' as const }),\n});\n\nfunction cancelledError(): DataError {\n return { kind: 'cancelled', code: 'aborted', message: 'Live query observer was disposed.' };\n}\n\nfunction protocolError(code: string, message: string): DataError {\n return { kind: 'protocol', code, message };\n}\n\nfunction revisionOf(value: unknown): string | number | undefined {\n if (value === null || typeof value !== 'object') return undefined;\n const revision = (value as { readonly revision?: unknown }).revision;\n return typeof revision === 'string' || typeof revision === 'number' ? revision : undefined;\n}\n\nfunction asSnapshotPlan(\n plan: LivePlan | undefined,\n): Extract<LivePlan, { readonly kind: 'snapshot'; readonly initial: 'query' }> | undefined {\n return plan?.kind === 'snapshot' && plan.initial === 'query' ? plan : undefined;\n}\n\n/**\n * Reduces a descriptor's shared live lease into its canonical TanStack cache\n * entry. It owns no provider resources beyond its lease and becomes inert as\n * soon as that lease is released, which prevents retired session work from\n * writing into a replacement cache partition.\n */\nexport class QueryLiveObserver<T extends ErasedQueryDescriptor = ErasedQueryDescriptor> {\n readonly #descriptor: T;\n readonly #runtime: DataRuntimeContextValue;\n readonly #queryClient: QueryClient;\n readonly #key: ReturnType<typeof queryKeyFor>;\n readonly identity: string;\n readonly #lease: LiveLease<QueryResultFor<T>>;\n readonly #consumerGeneration: number;\n readonly #listeners = new Set<() => void>();\n #unsubscribeLease: (() => void) | undefined;\n #unsubscribeSession: (() => void) | undefined;\n #active = true;\n #state: QueryLiveObserverState;\n #seenEvent: unknown;\n #latestValue: QueryResultFor<T> | undefined;\n #latestRevision: string | number | undefined;\n #protocolFailure: DataError | undefined;\n #protocolReconciliationRequested = false;\n #protocolTerminal = false;\n #hasStartedQuery = false;\n #dirtyBeforeFirstQuery = false;\n #dirtyGeneration = 0;\n #scheduled = false;\n #refetching = false;\n\n constructor(args: {\n readonly descriptor: T;\n readonly runtime: DataRuntimeContextValue;\n readonly queryClient: QueryClient;\n }) {\n this.#descriptor = args.descriptor;\n this.#runtime = args.runtime;\n this.#queryClient = args.queryClient;\n this.#key = queryKeyFor(this.#descriptor);\n this.identity = JSON.stringify(this.#key);\n const session = this.#runtime.dataSession.getState();\n this.#consumerGeneration =\n session.status === 'ready' ? session.snapshot.generation : session.target.generation;\n this.#lease = this.#runtime.liveCoordinator.acquire<QueryResultFor<T>>(\n this.#descriptor,\n this.#consumerGeneration,\n );\n this.#state = this.#stateForLease();\n this.#consumeLease();\n this.#unsubscribeLease = this.#lease.subscribe(() => this.#consumeLease());\n this.#unsubscribeSession = this.#runtime.dataSession.subscribe(() => {\n const current = this.#runtime.dataSession.getState();\n const generation =\n current.status === 'ready' ? current.snapshot.generation : current.target.generation;\n if (generation !== this.#consumerGeneration) this.#retire();\n });\n }\n\n getState = (): QueryLiveObserverState => this.#state;\n\n subscribe = (listener: () => void): (() => void) => {\n if (!this.#active) return () => undefined;\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n };\n\n /** Whether a regular query should execute after the selected live plan is ready. */\n get queryEnabled(): boolean {\n if (!this.#active) return false;\n const live = this.#state.live;\n if (live.status === 'connecting') return false;\n return !(\n live.status === 'connected' &&\n live.plan?.kind === 'snapshot' &&\n live.plan.initial === 'stream'\n );\n }\n\n async execute(signal: AbortSignal): Promise<QueryResultFor<T>> {\n if (!this.#active) throw cancelledError();\n const requiresFollowingRefetch = this.#dirtyBeforeFirstQuery;\n this.#dirtyBeforeFirstQuery = false;\n this.#hasStartedQuery = true;\n const result = await executeQuery({\n descriptor: this.#descriptor,\n runtime: this.#runtime,\n signal,\n });\n if (!this.#active) throw cancelledError();\n const reduced = this.#reduceQuery(result);\n if (requiresFollowingRefetch) this.#scheduleDirtyRefetch();\n return reduced;\n }\n\n dispose(): void {\n if (!this.#active) return;\n this.#close(false);\n }\n\n #retire(): void {\n if (!this.#active) return;\n this.#close(true);\n }\n\n #close(notify: boolean): void {\n this.#active = false;\n this.#unsubscribeLease?.();\n this.#unsubscribeLease = undefined;\n this.#unsubscribeSession?.();\n this.#unsubscribeSession = undefined;\n this.#lease.release();\n this.#state = OFF_STATE;\n if (notify) {\n for (const listener of this.#listeners) listener();\n }\n this.#listeners.clear();\n }\n\n #publish(): void {\n if (!this.#active) return;\n this.#state = this.#stateForLease();\n for (const listener of this.#listeners) listener();\n }\n\n #stateForLease(): QueryLiveObserverState {\n return this.#protocolFailure === undefined\n ? { live: this.#lease.getState() }\n : {\n live: this.#withProtocolFailure(this.#lease.getState()),\n protocolError: this.#protocolFailure,\n };\n }\n\n #withProtocolFailure(live: LiveState): LiveState {\n return this.#protocolFailure === undefined ? live : { ...live, error: this.#protocolFailure };\n }\n\n #consumeLease(): void {\n if (!this.#active) return;\n const state = this.#lease.getState();\n const event = state.event;\n if (event !== undefined && event !== this.#seenEvent) {\n this.#seenEvent = event;\n if (event.type === 'invalidate') {\n this.#markDirty();\n } else {\n this.#reduceSnapshot(event.value as QueryResultFor<T>, state.plan);\n }\n }\n this.#publish();\n }\n\n #reduceSnapshot(value: QueryResultFor<T>, plan: LivePlan | undefined): void {\n if (!this.#active) return;\n const snapshotQuery = asSnapshotPlan(plan);\n if (snapshotQuery !== undefined) {\n const revision = revisionOf(value);\n if (revision === undefined) {\n this.#failProtocol(\n 'live-revision-required',\n 'Snapshot-query live values must include a comparable revision.',\n );\n return;\n }\n if (this.#latestRevision !== undefined && this.#latestValue !== undefined) {\n const comparison = this.#compare(snapshotQuery, revision, this.#latestRevision);\n if (comparison === undefined) return;\n if (comparison < 0) return;\n if (comparison === 0) {\n if (!this.#equals(snapshotQuery, value, this.#latestValue)) {\n this.#failConflict();\n }\n return;\n }\n }\n this.#latestRevision = revision;\n }\n this.#latestValue = value;\n this.#queryClient.setQueryData(this.#key, value);\n }\n\n #reduceQuery(value: QueryResultFor<T>): QueryResultFor<T> {\n const snapshotQuery = asSnapshotPlan(this.#lease.getState().plan);\n if (snapshotQuery === undefined) return value;\n const revision = revisionOf(value);\n if (revision === undefined) {\n this.#failProtocol(\n 'live-revision-required',\n 'Snapshot-query query results must include a comparable revision.',\n );\n return this.#latestValue ?? value;\n }\n if (this.#latestRevision === undefined || this.#latestValue === undefined) {\n this.#latestRevision = revision;\n this.#latestValue = value;\n return value;\n }\n const comparison = this.#compare(snapshotQuery, revision, this.#latestRevision);\n if (comparison === undefined) return this.#latestValue;\n if (comparison < 0) return this.#latestValue;\n if (comparison === 0) {\n if (!this.#equals(snapshotQuery, value, this.#latestValue)) {\n const snapshot = this.#latestValue;\n this.#failConflict();\n return snapshot;\n }\n return this.#latestValue;\n }\n this.#latestRevision = revision;\n this.#latestValue = value;\n return value;\n }\n\n #compare(\n plan: Extract<LivePlan, { readonly kind: 'snapshot'; readonly initial: 'query' }>,\n left: string | number,\n right: string | number,\n ): number | undefined {\n try {\n const result = plan.compareRevision(left, right);\n if (!Number.isFinite(result))\n throw new Error('Revision comparator returned a non-finite value.');\n return result;\n } catch (error) {\n this.#failProtocol(\n 'live-revision-non-comparable',\n error instanceof Error ? error.message : 'Live revisions are not comparable.',\n );\n return undefined;\n }\n }\n\n #equals(\n plan: Extract<LivePlan, { readonly kind: 'snapshot'; readonly initial: 'query' }>,\n left: QueryResultFor<T>,\n right: QueryResultFor<T>,\n ): boolean {\n try {\n return plan.equalsSnapshot(left, right);\n } catch (error) {\n this.#failProtocol(\n 'live-snapshot-equality-failed',\n error instanceof Error ? error.message : 'Live snapshot equality comparison failed.',\n );\n return false;\n }\n }\n\n #failConflict(): void {\n this.#failProtocol(\n 'live-revision-conflict',\n 'Equal live revisions carried unequal mapped result envelopes.',\n );\n // The reconciliation response is the next authoritative baseline. Keeping\n // the conflicting snapshot here would turn that response into a second,\n // spurious equal-revision conflict.\n this.#latestValue = undefined;\n this.#latestRevision = undefined;\n }\n\n #failProtocol(code: string, message: string): void {\n if (!this.#active) return;\n this.#protocolFailure ??= protocolError(code, message);\n if (!this.#protocolReconciliationRequested && !this.#protocolTerminal) {\n this.#protocolReconciliationRequested = true;\n this.#scheduleDirtyRefetch();\n } else {\n this.#protocolTerminal = true;\n }\n this.#publish();\n }\n\n #markDirty(): void {\n if (!this.#active) return;\n this.#dirtyGeneration += 1;\n if (!this.#hasStartedQuery) {\n this.#dirtyBeforeFirstQuery = true;\n return;\n }\n this.#scheduleDirtyRefetch();\n }\n\n #scheduleDirtyRefetch(): void {\n if (!this.#active || this.#protocolTerminal) return;\n if (this.#scheduled || this.#refetching) return;\n this.#scheduled = true;\n queueMicrotask(() => {\n this.#scheduled = false;\n if (!this.#active || this.#refetching) return;\n const generation = this.#dirtyGeneration;\n const query = this.#queryClient.getQueryCache().find({ queryKey: this.#key, exact: true });\n const wasFetching = query?.state.fetchStatus === 'fetching';\n this.#refetching = true;\n void this.#queryClient\n .invalidateQueries({ queryKey: this.#key, exact: true }, { cancelRefetch: false })\n .then(() =>\n wasFetching && this.#active\n ? this.#queryClient.refetchQueries(\n { queryKey: this.#key, exact: true },\n { cancelRefetch: false },\n )\n : undefined,\n )\n .catch((error) => {\n this.#protocolFailure ??= normalizeDataError(error);\n this.#publish();\n })\n .finally(() => {\n this.#refetching = false;\n if (this.#active && this.#dirtyGeneration > generation) this.#markDirty();\n });\n });\n }\n}\n\nexport function offLiveQueryState(): QueryLiveObserverState {\n return OFF_STATE;\n}\n","import {\n type DataDescriptorIdentity,\n listContinuityIdentityFor,\n type DataError,\n type DataQueryKey,\n type DataSessionController,\n type ErasedQueryDescriptor,\n type PortableValue,\n queryKeyFor,\n} from '@burojs/core';\nimport {\n useQuery,\n type Query,\n type UseQueryOptions,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\n\nimport { buroQueryOptions } from '../../data/query-options.js';\nimport { useDataRuntime } from '../../data/context.js';\nimport { QueryLiveObserver, offLiveQueryState } from '../../data/live/query-live-observer.js';\n\nexport type NativeQueryOptions<TData, TSelected = TData> = Omit<\n UseQueryOptions<TData, DataError, TSelected, DataQueryKey>,\n 'queryKey' | 'queryFn' | 'placeholderData' | 'refetchInterval'\n> & {\n /**\n * Poll this query at N ms (TanStack semantics) — forwarded verbatim into\n * TanStack Query's `refetchInterval` (see `queryOptions` assembly below).\n * Omit for the default `undefined`: no polling, behavior unchanged.\n */\n readonly refetchInterval?: number | false;\n};\n\nexport type NativeQueryResult<TData, TSelected = TData> = UseQueryResult<TSelected, DataError> & {\n readonly isCurrentData: boolean;\n readonly live: import('../../data/live/types.js').LiveState;\n};\n\nconst subscribeOff = (): (() => void) => () => undefined;\n\n/**\n * The generation a live observer must be bound to right now. A transition\n * publishes its TARGET generation before the session reports ready, so reading\n * the target here keeps a freshly created observer on the incoming generation\n * instead of one that is already retiring.\n */\nfunction sessionGenerationOf(session: DataSessionController): number {\n const state = session.getState();\n return state.status === 'ready' ? state.snapshot.generation : state.target.generation;\n}\n\nfunction samePortableValue(left: PortableValue, right: PortableValue): boolean {\n if (Object.is(left, right)) return true;\n if (left === null || right === null || typeof left !== 'object' || typeof right !== 'object') {\n return false;\n }\n if (Array.isArray(left) || Array.isArray(right)) {\n if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;\n return left.every((value, index) => samePortableValue(value, right[index]!));\n }\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n if (leftKeys.length !== rightKeys.length) return false;\n const rightObject = right as Readonly<Record<string, PortableValue>>;\n return leftKeys.every(\n (key) =>\n Object.prototype.hasOwnProperty.call(rightObject, key) &&\n samePortableValue((left as Readonly<Record<string, PortableValue>>)[key]!, rightObject[key]!),\n );\n}\n\ntype ListIdentityDescriptor = DataDescriptorIdentity & { readonly kind: 'list' };\n\nfunction listDescriptorFromQuery(\n query: Query<unknown, DataError, unknown, DataQueryKey>,\n): ListIdentityDescriptor | undefined {\n const key = query.queryKey;\n if (key[0] !== 'buro-data' || key[1] !== 1) return undefined;\n const descriptor = key[2];\n if (descriptor === null || typeof descriptor !== 'object' || Array.isArray(descriptor))\n return undefined;\n return (descriptor as { readonly kind?: unknown }).kind === 'list'\n ? (descriptor as unknown as ListIdentityDescriptor)\n : undefined;\n}\n\n/** Framework-owned placeholder policy: only list descriptors can retain same-boundary rows. */\nfunction safeListPlaceholderData<TData>(\n descriptor: ListIdentityDescriptor,\n): (\n previousData: TData | undefined,\n previousQuery: Query<unknown, DataError, unknown, DataQueryKey> | undefined,\n) => TData | undefined {\n const continuity = listContinuityIdentityFor(descriptor);\n return (previousData, previousQuery) => {\n if (previousQuery === undefined) return undefined;\n const previous = listDescriptorFromQuery(previousQuery);\n if (previous === undefined) return undefined;\n return samePortableValue(listContinuityIdentityFor(previous), continuity)\n ? previousData\n : undefined;\n };\n}\n\n/** Executes a canonical descriptor with framework-owned cache and continuity policy. */\nexport function useQueryDescriptor<TData, TSelected = TData>(\n descriptor: ErasedQueryDescriptor | DataError,\n options: NativeQueryOptions<TData, TSelected> | undefined,\n): NativeQueryResult<TData, TSelected> {\n const runtime = useDataRuntime();\n const isError =\n 'kind' in descriptor &&\n descriptor.kind !== 'list' &&\n descriptor.kind !== 'one' &&\n descriptor.kind !== 'many' &&\n descriptor.kind !== 'count' &&\n descriptor.kind !== 'custom';\n const placeholderData =\n !isError && descriptor.kind === 'list'\n ? (safeListPlaceholderData<TData>(descriptor) as unknown as UseQueryOptions<\n TData,\n DataError,\n TSelected,\n readonly unknown[]\n >['placeholderData'])\n : undefined;\n const descriptorKey = isError ? undefined : JSON.stringify(queryKeyFor(descriptor));\n // Наблюдатель привязан к ПОКОЛЕНИЮ сессии: на смене поколения он уходит в\n // отставку сам и больше никогда не пускает запрос. Ключ дескриптора при этом\n // может не измениться (смена области с тем же содержимым — ровно то, что\n // делает хост на монтировании), поэтому поколение обязано входить в\n // зависимости эффекта: иначе отставной наблюдатель остаётся навсегда и\n // запрос не уходит в сеть ни разу.\n const sessionGeneration = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionGenerationOf(runtime.dataSession),\n () => sessionGenerationOf(runtime.dataSession),\n );\n const [liveObserver, setLiveObserver] = useState<QueryLiveObserver | undefined>();\n useEffect(() => {\n if (isError || descriptorKey === undefined) {\n setLiveObserver(undefined);\n return undefined;\n }\n // Acquiring a live lease opens provider work, so it belongs to React's\n // committed lifecycle rather than render/memo evaluation. This also makes\n // discarded and StrictMode probe renders resource-free.\n const current = new QueryLiveObserver({\n descriptor,\n runtime,\n queryClient: runtime.queryClient,\n });\n setLiveObserver(current);\n return () => {\n current.dispose();\n setLiveObserver((previous) => (previous === current ? undefined : previous));\n };\n }, [descriptorKey, isError, runtime, sessionGeneration]);\n const activeLiveObserver = liveObserver?.identity === descriptorKey ? liveObserver : undefined;\n const liveState = useSyncExternalStore(\n activeLiveObserver?.subscribe ?? subscribeOff,\n activeLiveObserver?.getState ?? offLiveQueryState,\n offLiveQueryState,\n );\n const requestedEnabled = options?.enabled !== false;\n const enabled = isError\n ? requestedEnabled\n : requestedEnabled && activeLiveObserver?.queryEnabled === true;\n const queryOptions = {\n // `...options` carries every native TanStack option (e.g. `select`,\n // `staleTime`, `refetchInterval`) straight through to `useQuery` below;\n // only the framework-owned keys after it are overridden.\n ...(options as NativeQueryOptions<TData, TSelected>),\n queryKey: isError\n ? ['buro-data-error', 1, descriptor.kind, descriptor.code, descriptor.message]\n : buroQueryOptions(descriptor).queryKey,\n queryFn: ({ signal }: { readonly signal: AbortSignal }) =>\n isError\n ? Promise.reject(descriptor)\n : (activeLiveObserver!.execute(signal) as Promise<TData>),\n placeholderData,\n enabled,\n } as unknown as UseQueryOptions<TData, DataError, TSelected, readonly unknown[]>;\n const result = useQuery(queryOptions);\n const error = liveState.protocolError ?? result.error;\n const syntheticProtocolError = liveState.protocolError !== undefined;\n const hasData = result.data !== undefined;\n return {\n ...result,\n error,\n ...(syntheticProtocolError\n ? {\n // `UseQueryResult` is a discriminated state machine. A live\n // protocol failure is surfaced through that public result, so every\n // status-derived flag must agree with `status: 'error'` rather than\n // retaining TanStack's last successful discriminator.\n status: 'error' as const,\n isError: true,\n isSuccess: false,\n isPending: false,\n isLoading: false,\n isInitialLoading: false,\n isLoadingError: !hasData,\n isRefetchError: hasData,\n isRefetching: result.isFetching,\n // Retained list rows are a continuity presentation state, not a\n // valid result while the observer reports a protocol violation.\n isPlaceholderData: false,\n }\n : {}),\n isCurrentData: result.data !== undefined && !result.isPlaceholderData,\n live: liveState.live,\n } as NativeQueryResult<TData, TSelected>;\n}\n","import type {\n ApplicationSnapshot,\n LayerRuntime,\n LayerStatus,\n PortableProjection,\n PortableValue,\n SnapshotEntityTargetInput,\n} from '@burojs/core';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\nconst LayerRuntimeContext = createContext<LayerRuntime | null>(null);\n\nexport interface BuroRuntimeProviderProps {\n readonly runtime: LayerRuntime;\n readonly children: ReactNode;\n}\n\nexport function BuroRuntimeProvider({ runtime, children }: BuroRuntimeProviderProps): ReactElement {\n return <LayerRuntimeContext.Provider value={runtime}>{children}</LayerRuntimeContext.Provider>;\n}\n\nexport function useLayerRuntime(): LayerRuntime {\n const runtime = useContext(LayerRuntimeContext);\n if (runtime === null) {\n throw new Error('useLayerRuntime must be used within BuroRuntimeProvider.');\n }\n return runtime;\n}\n\nexport function useApplicationSnapshot(): ApplicationSnapshot {\n const runtime = useLayerRuntime();\n return useSyncExternalStore(runtime.subscribe, runtime.getSnapshot, runtime.getServerSnapshot);\n}\n\ntype CommittedSelection<T> =\n | { readonly hasValue: false }\n | { readonly hasValue: true; readonly value: T };\n\nfunction useRuntimeSelection<T>(\n getClientValue: (runtime: LayerRuntime) => T,\n getServerValue: (runtime: LayerRuntime) => T,\n isEqual: (left: T, right: T) => boolean = Object.is,\n): T {\n const runtime = useLayerRuntime();\n const committed = useRef<CommittedSelection<T>>({ hasValue: false });\n\n const [getSnapshot, getServerSnapshot] = useMemo(() => {\n let hasMemo = false;\n let memoizedValue: T;\n\n const select = (nextValue: T): T => {\n if (!hasMemo) {\n hasMemo = true;\n const current = committed.current;\n if (current.hasValue && isEqual(current.value, nextValue)) {\n memoizedValue = current.value;\n return memoizedValue;\n }\n memoizedValue = nextValue;\n return nextValue;\n }\n if (Object.is(memoizedValue, nextValue)) return memoizedValue;\n if (isEqual(memoizedValue, nextValue)) return memoizedValue;\n memoizedValue = nextValue;\n return nextValue;\n };\n\n return [() => select(getClientValue(runtime)), () => select(getServerValue(runtime))] as const;\n }, [getClientValue, getServerValue, isEqual, runtime]);\n\n const value = useSyncExternalStore(runtime.subscribe, getSnapshot, getServerSnapshot);\n useEffect(() => {\n committed.current = { hasValue: true, value };\n }, [value]);\n return value;\n}\n\nfunction samePortableValue(left: PortableValue, right: PortableValue): boolean {\n if (Object.is(left, right)) return true;\n if (left === null || right === null || typeof left !== 'object' || typeof right !== 'object') {\n return false;\n }\n if (Array.isArray(left) || Array.isArray(right)) {\n if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1) {\n if (!samePortableValue(left[index]!, right[index]!)) return false;\n }\n return true;\n }\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n const leftObject = left as { readonly [key: string]: PortableValue };\n const rightObject = right as { readonly [key: string]: PortableValue };\n if (leftKeys.length !== rightKeys.length) return false;\n for (const key of leftKeys) {\n if (!Object.prototype.hasOwnProperty.call(rightObject, key)) return false;\n if (!samePortableValue(leftObject[key]!, rightObject[key]!)) return false;\n }\n return true;\n}\n\nfunction sameProjection(\n left: PortableProjection | undefined,\n right: PortableProjection | undefined,\n): boolean {\n if (Object.is(left, right)) return true;\n if (left === undefined || right === undefined) return false;\n return (\n left.kind === right.kind &&\n left.schemaVersion === right.schemaVersion &&\n left.ref.namespace === right.ref.namespace &&\n left.ref.id === right.ref.id &&\n samePortableValue(left.value, right.value)\n );\n}\n\nexport function useProjection(target: SnapshotEntityTargetInput): PortableProjection | undefined {\n const getProjection = useCallback(\n (runtime: LayerRuntime) => runtime.getSnapshot().getProjection(target),\n [target],\n );\n const getServerProjection = useCallback(\n (runtime: LayerRuntime) => runtime.getServerSnapshot().getProjection(target),\n [target],\n );\n return useRuntimeSelection(getProjection, getServerProjection, sameProjection);\n}\n\nexport function useLayerStatus(id: string): LayerStatus {\n const getStatus = useCallback((runtime: LayerRuntime) => runtime.getLayerStatus(id), [id]);\n return useRuntimeSelection(getStatus, getStatus);\n}\n","import type { Resolver } from '@burojs/context';\nimport type { AppRuntime } from '@burojs/core';\nimport type { I18nFacade } from '@burojs/i18n-core';\nimport { createContext } from 'react';\n\nexport const AppContext = createContext<AppRuntime | null>(null);\nexport const ResolverContext = createContext<Resolver<never> | null>(null);\nexport const I18nContext = createContext<I18nFacade | null>(null);\nexport const ComponentsContext = createContext<Record<string, unknown>>({});\n\nexport interface TestIdContextValue {\n resource?: string;\n view?: string;\n recordId?: string;\n}\nexport const TestIdContext = createContext<TestIdContextValue>({});\n\nexport interface ResourceContextValue {\n resource?: string;\n}\nexport const ResourceContext = createContext<ResourceContextValue>({});\n","import type { I18nCaps } from '@burojs/core';\nimport { type ResourceI18n, createResourceI18n } from '@burojs/i18n-core';\nimport { useCallback, useContext, useMemo, useSyncExternalStore } from 'react';\nimport { I18nContext, ResourceContext } from '../context.js';\n\nexport function useT(): (\n key: string,\n options?: { resource?: string; params?: Record<string, unknown> },\n) => string {\n const i18n = useContext(I18nContext);\n if (!i18n) throw new Error('[useT] must be used within a BuroProvider');\n const ctx = useContext(ResourceContext);\n // Subscribe to locale so a live language switch re-renders every consumer\n // (the returned closure reads the facade fresh, but the component must\n // re-render to call it again). Without this, `useT`-only components stay\n // frozen at the boot locale while `useI18nCaps` ones flip.\n useLocale();\n\n return (key, options) =>\n i18n.t(key, { resource: options?.resource ?? ctx.resource, params: options?.params });\n}\n\n/** `{{name}}` → params.name interpolation for the no-provider fallback path. */\nfunction interpolate(template: string, params?: Record<string, unknown>): string {\n if (!params) return template;\n return template.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (_m, k: string) =>\n params[k] == null ? '' : String(params[k]),\n );\n}\n\n/**\n * Provider-OPTIONAL translator. Behaves like {@link useT} when mounted inside a\n * `BuroProvider`, but does NOT throw when there is no i18n context —\n * instead it returns the supplied `defaultValue` (interpolated with `params`),\n * falling back to the raw key.\n *\n * Use this for components that ship in `@burojs/ui-shadcn` yet may render\n * standalone (outside the provider) — e.g. `<LoginForm>` on a pre-auth screen,\n * or filter toolbars mounted in isolation by tests / Storybook. In-app (with a\n * provider) they translate normally; standalone they degrade to English.\n */\nexport function useOptionalT(): (\n key: string,\n options?: { resource?: string; params?: Record<string, unknown>; defaultValue?: string },\n) => string {\n const i18n = useContext(I18nContext);\n const ctx = useContext(ResourceContext);\n // Re-render on locale change (see useT) so translations flip live.\n useLocale();\n\n return (key, options) => {\n if (i18n) {\n return i18n.t(key, { resource: options?.resource ?? ctx.resource, params: options?.params });\n }\n return interpolate(options?.defaultValue ?? key, options?.params);\n };\n}\n\n/**\n * The active locale code (e.g. `'ru'` / `'en'`), or `'en'` when no i18n\n * provider is mounted. Powers per-locale DATA labels — resolve a\n * `LocalizedText` (enum option labels, etc.) with `resolveLocalizedText(text,\n * useLocale())`. Provider-optional so ui-shadcn components can render\n * standalone.\n */\nexport function useLocale(): string {\n const i18n = useContext(I18nContext);\n // Subscribe to the facade's locale-change event so the whole render-time\n // content model (labels, enums, actions, nav) flips live on a language switch\n // — no page reload. Provider-optional: without a facade the subscription is a\n // no-op and the snapshot is a constant `'en'`, so this stays hook-safe.\n const subscribe = useCallback((cb: () => void) => i18n?.onLocaleChange(cb) ?? (() => {}), [i18n]);\n const getSnapshot = useCallback(() => i18n?.getCurrentLocale() ?? 'en', [i18n]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * The active locale code, or `undefined` when NO i18n provider is mounted.\n *\n * The difference from {@link useLocale} is the whole point: `useLocale`\n * collapses \"the app is running in English\" and \"there is no app\" into the same\n * `'en'`, which is fine for resolving a `LocalizedText` (English is a defensible\n * last resort for a label) and wrong for anything that has its own fallback to\n * fall back TO. A caller that already knows what \"nobody chose a locale\" means\n * for it — `@burojs/ui-shadcn`'s `Intl` formatters resolve a stored preference\n * in that case — must be able to tell the two apart, and with `useLocale` it\n * cannot.\n *\n * Same subscription as `useLocale`, so a live language switch re-renders the\n * consumer either way.\n */\nexport function useOptionalLocale(): string | undefined {\n const i18n = useContext(I18nContext);\n const subscribe = useCallback((cb: () => void) => i18n?.onLocaleChange(cb) ?? (() => {}), [i18n]);\n const getSnapshot = useCallback(() => i18n?.getCurrentLocale(), [i18n]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Returns a `changeLocale(locale)` that switches the active locale IN PLACE\n * (i18next `changeLanguage`) — every component reading {@link useLocale} /\n * {@link useI18nCaps} re-renders and the render-time content model flips without\n * a page reload. The caller is responsible for persistence (e.g. `saveLanguage`)\n * so the choice survives a real reload. No-op without a provider.\n */\nexport function useChangeLocale(): (locale: string) => void {\n const i18n = useContext(I18nContext);\n return useCallback(\n (locale: string) => {\n void i18n?.changeLocale(locale);\n },\n [i18n],\n );\n}\n\n/**\n * Render-time translator, resource-scoped and provider-optional. The canonical\n * name for the i18n content model (react-admin `useTranslate` / i18next `t`).\n * Without a provider it degrades to the raw key. Prefer this over {@link useT}\n * for new code; `useT` is retained for existing call sites.\n */\nexport function useTranslate(): (\n key: string,\n options?: { resource?: string; params?: Record<string, unknown> },\n) => string {\n const i18n = useContext(I18nContext);\n const ctx = useContext(ResourceContext);\n // Re-render on locale change (see useT) so translations flip live.\n useLocale();\n return (key, options) =>\n i18n\n ? i18n.t(key, { resource: options?.resource ?? ctx.resource, params: options?.params })\n : key;\n}\n\n/**\n * The `has` + `t` capabilities bound to the ambient resource, for the pure\n * content-slot resolver (`resolveContentSlot` from `@burojs/core`). `has`\n * probes bundle presence (so an absent optional slot renders nothing instead of\n * the raw key). Provider-optional: without a provider `has` is always false and\n * `t` returns the key, so slot resolution falls through to the inline default /\n * humanize. Recomputes on locale change (reactivity lands in Phase 1).\n */\nexport function useI18nCaps(resource?: string): I18nCaps {\n const i18n = useContext(I18nContext);\n const ctx = useContext(ResourceContext);\n const locale = useLocale();\n // Explicit `resource` arg wins over the ambient ResourceContext — for\n // components that call this at their own top (where the provider they'd mount\n // in their return is not yet an ancestor), e.g. ResourceList.\n const boundResource = resource ?? ctx.resource;\n return useMemo<I18nCaps>(\n () => ({\n has: (key, options) =>\n i18n ? i18n.has(key, { resource: options?.resource ?? boundResource }) : false,\n t: (key, options) =>\n i18n\n ? i18n.t(key, { resource: options?.resource ?? boundResource, params: options?.params })\n : key,\n }),\n // `locale` participates so caps re-resolve when the active locale changes.\n [i18n, boundResource, locale],\n );\n}\n\nexport function useResourceI18n(resource?: string): ResourceI18n {\n const i18n = useContext(I18nContext);\n if (!i18n) throw new Error('[useResourceI18n] must be used within a BuroProvider');\n const ctx = useContext(ResourceContext);\n const name = resource ?? ctx.resource ?? '_';\n return useMemo(() => createResourceI18n(i18n, name), [i18n, name]);\n}\n","import {\n type DataError,\n type DataSessionSnapshot,\n type ErasedResourceHandle,\n type FieldDefBase,\n type PortableObject,\n type QueryDescriptor,\n type ResourceHandle,\n createQueryDescriptor,\n normalizeDataError,\n normalizeEntityRef,\n resolveDescriptorLocale,\n} from '@burojs/core';\nimport { useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../../data/context.js';\nimport { useApplicationSnapshot } from '../../runtime.js';\nimport { useLocale } from '../use-t.js';\n\ntype AnyResource = ResourceHandle<any, Record<string, FieldDefBase>, string, string>;\nexport type ResourceInput<R extends AnyResource> = R | string;\n\nfunction sessionSnapshot(runtime: ReturnType<typeof useDataRuntime>): DataSessionSnapshot {\n const state = runtime.dataSession.getState();\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\nfunction resourceHandle<R extends AnyResource>(\n resource: ResourceInput<R>,\n): R | ErasedResourceHandle {\n return typeof resource === 'string'\n ? ({ kind: 'resource', ref: normalizeEntityRef(resource) } as ErasedResourceHandle)\n : resource;\n}\n\n/** Resolves descriptors from the live app projection rather than authoring handles. */\nexport function useStandardQueryDescriptor<R extends AnyResource, TDescriptor>(\n resource: ResourceInput<R>,\n input: object,\n providerOptionsOverride?: PortableObject,\n): TDescriptor | DataError {\n const runtime = useDataRuntime();\n const snapshot = useApplicationSnapshot();\n const session = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionSnapshot(runtime),\n () => sessionSnapshot(runtime),\n );\n // Subscribed unconditionally (hooks cannot be conditional, and the early\n // returns below come after it). Every data hook therefore RE-RENDERS on a\n // language switch — but only a resource declaring `data.localeVarying` gets\n // the locale into its descriptor, so only that resource's query key changes\n // and only that resource re-fetches. See `@burojs/core`'s `data/locale.ts`.\n const locale = useLocale();\n const handle = resourceHandle(resource);\n const projection = runtime.app.registry.get(handle);\n if (projection === undefined) {\n return normalizeDataError(\n Object.assign(\n new Error(`Resource '${handle.ref.namespace}:${handle.ref.id}' is unavailable.`),\n {\n kind: 'configuration' as const,\n code: 'resource-unavailable',\n },\n ),\n );\n }\n let binding;\n try {\n binding = runtime.app.resolveDataBinding(handle);\n } catch (error) {\n return normalizeDataError(\n Object.assign(\n new Error(error instanceof Error ? error.message : 'Resource data binding is unavailable.'),\n {\n kind: 'configuration' as const,\n code: 'data-binding-unavailable',\n cause: error,\n },\n ),\n );\n }\n return createQueryDescriptor<R>({\n ...input,\n providerId: binding.providerId,\n ref: binding.ref,\n resource: binding.resource,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n ...resolveDescriptorLocale(projection.data, locale),\n bindingRevision: snapshot.manifest.snapshotId,\n ...(projection.data?.providerOptions === undefined\n ? {}\n : { providerOptions: projection.data.providerOptions }),\n ...(projection.data?.dependencies === undefined\n ? {}\n : { dependencies: projection.data.dependencies }),\n ...(providerOptionsOverride === undefined ? {} : { providerOptionsOverride }),\n } as never) as TDescriptor;\n}\n","import type {\n ErasedResourceHandle,\n ErasedQueryDescriptor,\n ListDescriptor,\n FieldDefBase,\n PortableObject,\n QueryResultFor,\n ResourceHandle,\n} from '@burojs/core';\n\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\nimport { type ResourceInput, useStandardQueryDescriptor } from './use-standard-query-descriptor.js';\n\ntype AnyResource = ResourceHandle<unknown, Record<string, FieldDefBase>, string, string>;\nexport type UseListOptions<R extends AnyResource, TSelected = QueryResultFor<ListDescriptor<R>>> = {\n readonly pagination?: ListDescriptor<R> extends { readonly pagination?: infer T } ? T : never;\n readonly filter?: ListDescriptor<R> extends { readonly filter?: infer T } ? T : never;\n readonly sort?: ListDescriptor<R> extends { readonly sort?: infer T } ? T : never;\n readonly projection?: readonly string[];\n readonly providerOptionsOverride?: PortableObject;\n} & NativeQueryOptions<QueryResultFor<ListDescriptor<R>>, TSelected>;\n\nexport function useList<R extends AnyResource, TSelected = QueryResultFor<ListDescriptor<R>>>(\n resource: R,\n options?: UseListOptions<R, TSelected>,\n): NativeQueryResult<QueryResultFor<ListDescriptor<R>>, TSelected>;\nexport function useList<TSelected = QueryResultFor<ListDescriptor<ErasedResourceHandle>>>(\n resource: string,\n options?: UseListOptions<ErasedResourceHandle, TSelected>,\n): NativeQueryResult<QueryResultFor<ListDescriptor<ErasedResourceHandle>>, TSelected>;\nexport function useList(resource: AnyResource | string, options: any = {}): any {\n const { providerOptionsOverride, pagination, filter, sort, projection, ...queryOptions } =\n options;\n const descriptor = useStandardQueryDescriptor<AnyResource, ListDescriptor<AnyResource>>(\n resource,\n {\n kind: 'list',\n ...(pagination === undefined ? {} : { pagination }),\n ...(filter === undefined ? {} : { filter }),\n ...(sort === undefined ? {} : { sort }),\n ...(projection === undefined ? {} : { projection }),\n },\n providerOptionsOverride,\n );\n return useQueryDescriptor(descriptor as unknown as ErasedQueryDescriptor, queryOptions);\n}\n","import type {\n ErasedQueryDescriptor,\n ErasedResourceHandle,\n FieldDefBase,\n OneDescriptor,\n PortableObject,\n QueryResultFor,\n ResourceHandle,\n} from '@burojs/core';\n\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\nimport { type ResourceInput, useStandardQueryDescriptor } from './use-standard-query-descriptor.js';\n\ntype AnyResource = ResourceHandle<unknown, Record<string, FieldDefBase>, string, string>;\nexport type UseOneOptions<R extends AnyResource, TSelected = QueryResultFor<OneDescriptor<R>>> = {\n readonly id: OneDescriptor<R> extends { readonly id: infer T } ? T : never;\n readonly providerOptionsOverride?: PortableObject;\n readonly projection?: readonly string[];\n} & NativeQueryOptions<QueryResultFor<OneDescriptor<R>>, TSelected>;\n\nexport function useOne<R extends AnyResource, TSelected = QueryResultFor<OneDescriptor<R>>>(\n resource: R,\n options: UseOneOptions<R, TSelected>,\n): NativeQueryResult<QueryResultFor<OneDescriptor<R>>, TSelected>;\nexport function useOne<TSelected = QueryResultFor<OneDescriptor<ErasedResourceHandle>>>(\n resource: string,\n options: UseOneOptions<ErasedResourceHandle, TSelected>,\n): NativeQueryResult<QueryResultFor<OneDescriptor<ErasedResourceHandle>>, TSelected>;\nexport function useOne(resource: AnyResource | string, options: any): any {\n const { providerOptionsOverride, projection, id, ...queryOptions } = options;\n const descriptor = useStandardQueryDescriptor<AnyResource, OneDescriptor<AnyResource>>(\n resource,\n {\n kind: 'one',\n id,\n ...(projection === undefined ? {} : { projection }),\n },\n providerOptionsOverride,\n );\n return useQueryDescriptor(descriptor as unknown as ErasedQueryDescriptor, queryOptions);\n}\n","import type {\n ErasedQueryDescriptor,\n ErasedResourceHandle,\n FieldDefBase,\n ManyDescriptor,\n PortableObject,\n QueryResultFor,\n ResourceHandle,\n} from '@burojs/core';\n\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\nimport { type ResourceInput, useStandardQueryDescriptor } from './use-standard-query-descriptor.js';\n\ntype AnyResource = ResourceHandle<unknown, Record<string, FieldDefBase>, string, string>;\nexport type UseManyOptions<R extends AnyResource, TSelected = QueryResultFor<ManyDescriptor<R>>> = {\n readonly ids: ManyDescriptor<R> extends { readonly ids: infer T } ? T : never;\n readonly providerOptionsOverride?: PortableObject;\n readonly projection?: readonly string[];\n} & NativeQueryOptions<QueryResultFor<ManyDescriptor<R>>, TSelected>;\n\nexport function useMany<R extends AnyResource, TSelected = QueryResultFor<ManyDescriptor<R>>>(\n resource: R,\n options: UseManyOptions<R, TSelected>,\n): NativeQueryResult<QueryResultFor<ManyDescriptor<R>>, TSelected>;\nexport function useMany<TSelected = QueryResultFor<ManyDescriptor<ErasedResourceHandle>>>(\n resource: string,\n options: UseManyOptions<ErasedResourceHandle, TSelected>,\n): NativeQueryResult<QueryResultFor<ManyDescriptor<ErasedResourceHandle>>, TSelected>;\nexport function useMany(resource: AnyResource | string, options: any): any {\n const { providerOptionsOverride, projection, ids, ...queryOptions } = options;\n const descriptor = useStandardQueryDescriptor<AnyResource, ManyDescriptor<AnyResource>>(\n resource,\n {\n kind: 'many',\n ids,\n ...(projection === undefined ? {} : { projection }),\n },\n providerOptionsOverride,\n );\n return useQueryDescriptor(descriptor as unknown as ErasedQueryDescriptor, queryOptions);\n}\n","import type {\n CountDescriptor,\n ErasedQueryDescriptor,\n ErasedResourceHandle,\n FieldDefBase,\n PortableObject,\n QueryResultFor,\n ResourceHandle,\n} from '@burojs/core';\n\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\nimport { type ResourceInput, useStandardQueryDescriptor } from './use-standard-query-descriptor.js';\n\ntype AnyResource = ResourceHandle<unknown, Record<string, FieldDefBase>, string, string>;\nexport type UseCountOptions<\n R extends AnyResource,\n TSelected = QueryResultFor<CountDescriptor<R>>,\n> = {\n readonly filter?: CountDescriptor<R> extends { readonly filter?: infer T } ? T : never;\n readonly providerOptionsOverride?: PortableObject;\n readonly projection?: readonly string[];\n} & NativeQueryOptions<QueryResultFor<CountDescriptor<R>>, TSelected>;\n\nexport function useCount<R extends AnyResource, TSelected = QueryResultFor<CountDescriptor<R>>>(\n resource: R,\n options?: UseCountOptions<R, TSelected>,\n): NativeQueryResult<QueryResultFor<CountDescriptor<R>>, TSelected>;\nexport function useCount<TSelected = QueryResultFor<CountDescriptor<ErasedResourceHandle>>>(\n resource: string,\n options?: UseCountOptions<ErasedResourceHandle, TSelected>,\n): NativeQueryResult<QueryResultFor<CountDescriptor<ErasedResourceHandle>>, TSelected>;\nexport function useCount(resource: AnyResource | string, options: any = {}): any {\n const { providerOptionsOverride, projection, filter, ...queryOptions } = options;\n const descriptor = useStandardQueryDescriptor<AnyResource, CountDescriptor<AnyResource>>(\n resource,\n {\n kind: 'count',\n ...(filter === undefined ? {} : { filter }),\n ...(projection === undefined ? {} : { projection }),\n },\n providerOptionsOverride,\n );\n return useQueryDescriptor(descriptor as unknown as ErasedQueryDescriptor, queryOptions);\n}\n","import {\n createQueryDescriptor,\n type DataError,\n type ErasedQueryDescriptor,\n type Pagination,\n} from '@burojs/core';\n\nimport { executeQuery } from './query-execution.js';\nimport type { DataRuntimeContextValue } from './runtime.js';\n\ntype ErasedListDescriptor = Extract<ErasedQueryDescriptor, { readonly kind: 'list' }>;\n\nexport interface InfiniteListPage {\n readonly data: readonly unknown[];\n readonly pageInfo?: {\n readonly nextCursor?: string;\n readonly hasNextPage?: boolean;\n };\n}\n\nexport interface InfiniteListObserverState {\n readonly pages: readonly InfiniteListPage[];\n readonly error: DataError | null;\n readonly isFetchingNextPage: boolean;\n}\n\nconst EMPTY_STATE: InfiniteListObserverState = Object.freeze({\n pages: Object.freeze([]),\n error: null,\n isFetchingNextPage: false,\n});\n\nfunction nextPagination(\n current: Pagination | undefined,\n page: InfiniteListPage,\n): Pagination | undefined {\n if (current?.kind === 'cursor') {\n const after = page.pageInfo?.nextCursor;\n return after === undefined ? undefined : { kind: 'cursor', limit: current.limit, after };\n }\n if (current?.kind === 'offset' && page.pageInfo?.hasNextPage === true) {\n return { kind: 'offset', page: current.page + 1, pageSize: current.pageSize };\n }\n return undefined;\n}\n\n/**\n * Owns one infinite-list page sequence for one canonical descriptor identity.\n * React only subscribes to it; no controller or component keeps page arrays,\n * cancellation handles, or generation checks. The first page comes from the\n * identity's `QueryLiveObserver`; following pages share this sequence's\n * lifetime and execute only through the native descriptor executor.\n */\nexport class InfiniteListObserver {\n readonly #runtime: DataRuntimeContextValue;\n readonly #descriptor: ErasedListDescriptor | undefined;\n readonly #listeners = new Set<() => void>();\n #state = EMPTY_STATE;\n #active = true;\n #tailController: AbortController | undefined;\n #tailPromise: Promise<void> | undefined;\n\n constructor(args: {\n readonly descriptor: ErasedListDescriptor | undefined;\n readonly runtime: DataRuntimeContextValue;\n }) {\n this.#descriptor = args.descriptor;\n this.#runtime = args.runtime;\n }\n\n getState = (): InfiniteListObserverState => this.#state;\n\n subscribe = (listener: () => void): (() => void) => {\n if (!this.#active) return () => undefined;\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n };\n\n acceptInitial(page: InfiniteListPage | undefined, isCurrent: boolean): void {\n if (!this.#active || !isCurrent || page === undefined) return;\n const pages = this.#state.pages.length === 0 ? [page] : [page, ...this.#state.pages.slice(1)];\n this.#set({ ...this.#state, pages });\n }\n\n get hasNextPage(): boolean {\n if (this.#descriptor === undefined) return false;\n const page = this.#state.pages[this.#state.pages.length - 1];\n return page !== undefined && nextPagination(this.#descriptor.pagination, page) !== undefined;\n }\n\n fetchNextPage = async (): Promise<void> => {\n if (this.#tailPromise !== undefined) return this.#tailPromise;\n if (!this.#active || this.#descriptor === undefined) return;\n const page = this.#state.pages[this.#state.pages.length - 1];\n if (page === undefined) return;\n const pagination = nextPagination(this.#descriptor.pagination, page);\n if (pagination === undefined) return;\n const controller = new AbortController();\n this.#tailController = controller;\n this.#set({ ...this.#state, error: null, isFetchingNextPage: true });\n const request = (async () => {\n try {\n const descriptor = createQueryDescriptor({\n ...this.#descriptor,\n pagination,\n } as never) as ErasedListDescriptor;\n const result = await executeQuery({\n descriptor,\n runtime: this.#runtime,\n signal: controller.signal,\n });\n if (!this.#active || controller.signal.aborted) return;\n this.#set({ ...this.#state, pages: [...this.#state.pages, result as InfiniteListPage] });\n } catch (error) {\n if (this.#active && !controller.signal.aborted) {\n this.#set({ ...this.#state, error: error as DataError });\n }\n throw error;\n } finally {\n if (this.#tailController === controller) this.#tailController = undefined;\n if (this.#active) this.#set({ ...this.#state, isFetchingNextPage: false });\n this.#tailPromise = undefined;\n }\n })();\n this.#tailPromise = request;\n return request;\n };\n\n dispose(): void {\n if (!this.#active) return;\n this.#active = false;\n this.#tailController?.abort();\n this.#tailController = undefined;\n this.#listeners.clear();\n }\n\n #set(next: InfiniteListObserverState): void {\n this.#state = next;\n for (const listener of this.#listeners) listener();\n }\n}\n","import {\n isDataError,\n queryKeyFor,\n type DataError,\n type ErasedQueryDescriptor,\n type ErasedResourceHandle,\n type FieldDefBase,\n type ListDescriptor,\n type PortableObject,\n type QueryResultFor,\n type ResourceHandle,\n} from '@burojs/core';\nimport { useEffect, useMemo, useSyncExternalStore } from 'react';\n\nimport { InfiniteListObserver, type InfiniteListPage } from '../../data/infinite-list-observer.js';\nimport { useDataRuntime } from '../../data/context.js';\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\nimport { type ResourceInput, useStandardQueryDescriptor } from './use-standard-query-descriptor.js';\n\ntype AnyResource = ResourceHandle<unknown, Record<string, FieldDefBase>, string, string>;\ntype ErasedListDescriptor = Extract<ErasedQueryDescriptor, { readonly kind: 'list' }>;\n\nexport interface InfiniteListData<TPage = InfiniteListPage> {\n readonly pages: readonly TPage[];\n}\n\nexport type UseInfiniteListOptions<R extends AnyResource> = {\n readonly pagination: ListDescriptor<R> extends { readonly pagination?: infer T } ? T : never;\n readonly filter?: ListDescriptor<R> extends { readonly filter?: infer T } ? T : never;\n readonly sort?: ListDescriptor<R> extends { readonly sort?: infer T } ? T : never;\n readonly projection?: readonly string[];\n readonly providerOptionsOverride?: PortableObject;\n} & NativeQueryOptions<QueryResultFor<ListDescriptor<R>>>;\n\nexport interface NativeInfiniteListResult<TPage = InfiniteListPage>\n extends Omit<NativeQueryResult<TPage>, 'data' | 'isFetching' | 'error'> {\n readonly data: InfiniteListData<TPage> | undefined;\n readonly error: DataError | null;\n readonly isFetching: boolean;\n readonly hasNextPage: boolean;\n readonly isFetchingNextPage: boolean;\n fetchNextPage(): Promise<void>;\n}\n\nfunction identityFor(descriptor: ErasedListDescriptor | DataError): string {\n if (isDataError(descriptor))\n return `error:${descriptor.kind}:${descriptor.code}:${descriptor.message}`;\n return JSON.stringify(queryKeyFor(descriptor));\n}\n\n/**\n * Native infinite-list bridge. The reusable `InfiniteListObserver` owns page\n * sequence, cancellation, and tail execution; React supplies the first page\n * from the identity-bound live query observer and subscribes to its state.\n */\nexport function useInfiniteList<R extends AnyResource>(\n resource: R,\n options: UseInfiniteListOptions<R>,\n): NativeInfiniteListResult<QueryResultFor<ListDescriptor<R>>>;\nexport function useInfiniteList(\n resource: string,\n options: UseInfiniteListOptions<ErasedResourceHandle>,\n): NativeInfiniteListResult<QueryResultFor<ListDescriptor<ErasedResourceHandle>>>;\nexport function useInfiniteList(resource: ResourceInput<AnyResource>, options: any): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, pagination, filter, sort, projection, ...queryOptions } =\n options;\n const descriptor = useStandardQueryDescriptor<AnyResource, ListDescriptor<AnyResource>>(\n resource,\n {\n kind: 'list',\n ...(pagination === undefined ? {} : { pagination }),\n ...(filter === undefined ? {} : { filter }),\n ...(sort === undefined ? {} : { sort }),\n ...(projection === undefined ? {} : { projection }),\n },\n providerOptionsOverride,\n );\n const initial = useQueryDescriptor<QueryResultFor<ListDescriptor<AnyResource>>>(\n descriptor as ErasedQueryDescriptor | DataError,\n queryOptions,\n );\n const identity = identityFor(descriptor as ErasedListDescriptor | DataError);\n const observer = useMemo(\n () =>\n new InfiniteListObserver({\n descriptor: isDataError(descriptor) ? undefined : (descriptor as ErasedListDescriptor),\n runtime,\n }),\n [identity, runtime],\n );\n useEffect(() => () => observer.dispose(), [observer]);\n useEffect(() => {\n observer.acceptInitial(initial.data as InfiniteListPage | undefined, initial.isCurrentData);\n }, [observer, initial.data, initial.isCurrentData]);\n const state = useSyncExternalStore(observer.subscribe, observer.getState, observer.getState);\n return {\n ...initial,\n data: state.pages.length === 0 ? undefined : { pages: state.pages },\n error: state.error ?? initial.error,\n isFetching: initial.isFetching || state.isFetchingNextPage,\n hasNextPage: observer.hasNextPage,\n isFetchingNextPage: state.isFetchingNextPage,\n fetchNextPage: observer.fetchNextPage,\n } as NativeInfiniteListResult<QueryResultFor<ListDescriptor<AnyResource>>>;\n}\n","import type { CountPolicy, DataError } from '@burojs/core';\n\nexport type CountExecution =\n | { readonly kind: 'off' }\n | { readonly kind: 'inline'; readonly total: number }\n | { readonly kind: 'manual'; readonly enabled: false }\n | { readonly kind: 'query'; readonly enabled: true }\n | { readonly kind: 'live'; readonly enabled: true };\n\ntype CountCapability = {\n readonly query: boolean;\n readonly live: boolean;\n};\n\nfunction missingCapability(lifecycle: 'query' | 'live'): DataError {\n const capability = lifecycle === 'query' ? 'queries.count' : 'live.open';\n return {\n kind: 'capability',\n code: 'missing-data-capability',\n message: `Data provider does not implement ${capability}.`,\n details: Object.freeze({ lifecycle, capability }),\n };\n}\n\n/** Resolves count execution without creating a query descriptor or making requests. */\nexport function resolveCountExecution(\n policy: CountPolicy,\n inlineTotal: number | undefined,\n capability: CountCapability,\n): CountExecution | DataError {\n if (policy === 'off') return { kind: 'off' };\n if (policy === 'live') {\n return capability.live ? { kind: 'live', enabled: true } : missingCapability('live');\n }\n if (inlineTotal !== undefined) return { kind: 'inline', total: inlineTotal };\n if (policy === 'provided') return { kind: 'off' };\n if (!capability.query) return missingCapability('query');\n return policy === 'manual'\n ? { kind: 'manual', enabled: false }\n : { kind: 'query', enabled: true };\n}\n","import {\n type CustomQueryDescriptor,\n type CustomQueryHandle,\n type DataError,\n type DataSessionSnapshot,\n type ErasedQueryDescriptor,\n type InferCustomInput,\n type InferCustomOutput,\n type LocaleVaryingBinding,\n type PortableObject,\n createQueryDescriptor,\n normalizeDataError,\n resolveDescriptorLocale,\n} from '@burojs/core';\nimport { useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../../data/context.js';\nimport { useApplicationSnapshot } from '../../runtime.js';\nimport { useLocale } from '../use-t.js';\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\n\nexport type UseCustomQueryOptions<TOutput, TSelected = TOutput> = NativeQueryOptions<\n TOutput,\n TSelected\n> & {\n readonly providerOptionsOverride?: PortableObject;\n readonly projection?: readonly string[];\n};\n\nfunction sessionSnapshot(runtime: ReturnType<typeof useDataRuntime>): DataSessionSnapshot {\n const state = runtime.dataSession.getState();\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\n/** Resolves a trusted custom operation from the current compiled projection. */\nexport function useCustomQuery<\n THandle extends CustomQueryHandle<unknown, unknown>,\n TSelected = InferCustomOutput<THandle>,\n>(\n handle: THandle,\n input: InferCustomInput<THandle>,\n options: UseCustomQueryOptions<InferCustomOutput<THandle>, TSelected> = {},\n): NativeQueryResult<InferCustomOutput<THandle>, TSelected> {\n const runtime = useDataRuntime();\n const snapshot = useApplicationSnapshot();\n const session = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionSnapshot(runtime),\n () => sessionSnapshot(runtime),\n );\n // See `use-standard-query-descriptor.ts` — subscribed unconditionally, but\n // only a binding declaring `localeVarying` puts the locale in the key.\n const locale = useLocale();\n const projection = snapshot.getProjection(handle);\n if (projection === undefined || projection.kind !== 'custom-query') {\n return useQueryDescriptor<InferCustomOutput<THandle>, TSelected>(\n normalizeDataError(\n Object.assign(\n new Error(`Custom query '${handle.ref.namespace}:${handle.ref.id}' is unavailable.`),\n {\n kind: 'configuration' as const,\n code: 'custom-query-unavailable',\n },\n ),\n ),\n options,\n );\n }\n const value = projection.value as Readonly<Record<string, unknown>>;\n const binding = value.binding as Readonly<Record<string, unknown>> | undefined;\n if (\n binding === undefined ||\n typeof binding.provider !== 'string' ||\n typeof binding.operation !== 'string' ||\n (binding.resource !== undefined && typeof binding.resource !== 'string')\n ) {\n return useQueryDescriptor<InferCustomOutput<THandle>, TSelected>(\n normalizeDataError(\n Object.assign(\n new Error(\n `Custom query '${handle.ref.namespace}:${handle.ref.id}' has an invalid binding.`,\n ),\n {\n kind: 'configuration' as const,\n code: 'custom-query-binding-invalid',\n },\n ),\n ),\n options,\n );\n }\n const { providerOptionsOverride, projection: selectedProjection, ...queryOptions } = options;\n const descriptor = createQueryDescriptor({\n kind: 'custom',\n providerId: binding.provider,\n ref: handle.ref,\n resource: binding.resource ?? handle.ref.id,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n // `localeVarying` is normalized to boolean-or-absent by core's\n // `cloneBinding` before it reaches the projection, so the narrow cast\n // cannot smuggle a truthy non-boolean past `resolveDescriptorLocale`.\n ...resolveDescriptorLocale(binding as LocaleVaryingBinding, locale),\n bindingRevision: snapshot.manifest.snapshotId,\n operation: binding.operation,\n input,\n ...(selectedProjection === undefined ? {} : { projection: selectedProjection }),\n ...(binding.providerOptions === undefined\n ? {}\n : { providerOptions: binding.providerOptions as PortableObject }),\n ...(providerOptionsOverride === undefined ? {} : { providerOptionsOverride }),\n }) as CustomQueryDescriptor<InferCustomInput<THandle>, InferCustomOutput<THandle>>;\n return useQueryDescriptor<InferCustomOutput<THandle>, TSelected>(\n descriptor as unknown as ErasedQueryDescriptor,\n queryOptions,\n );\n}\n","import {\n dependencyTagsForQuery,\n normalizeEntityRef,\n sameEntityRef,\n type ErasedMutationDescriptor,\n type ErasedQueryDescriptor,\n type MutationEffectTarget,\n type PartitionedDependencyTag,\n type RecordId,\n} from '@burojs/core';\nimport type { Query, QueryClient } from '@tanstack/react-query';\n\nimport type { ProviderServiceRef } from './provider-registry.js';\nimport type { DataRuntimeContextValue } from './runtime.js';\n\ntype DataQuery = Query<unknown, unknown, unknown, readonly unknown[]>;\n\nfunction descriptorFor(query: DataQuery): ErasedQueryDescriptor | undefined {\n const key = query.queryKey;\n if (key[0] !== 'buro-data' || key[1] !== 1) return undefined;\n const descriptor = key[2];\n if (descriptor === null || typeof descriptor !== 'object' || Array.isArray(descriptor))\n return undefined;\n const kind = (descriptor as { readonly kind?: unknown }).kind;\n return kind === 'list' ||\n kind === 'one' ||\n kind === 'many' ||\n kind === 'count' ||\n kind === 'custom'\n ? (descriptor as ErasedQueryDescriptor)\n : undefined;\n}\n\nfunction equalPortable(left: unknown, right: unknown): boolean {\n if (Object.is(left, right)) return true;\n if (left === null || right === null || typeof left !== 'object' || typeof right !== 'object') {\n return false;\n }\n if (Array.isArray(left) || Array.isArray(right)) {\n return (\n Array.isArray(left) &&\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((value, index) => equalPortable(value, right[index]))\n );\n }\n const leftRecord = left as Readonly<Record<string, unknown>>;\n const rightRecord = right as Readonly<Record<string, unknown>>;\n const keys = Object.keys(leftRecord);\n return (\n keys.length === Object.keys(rightRecord).length &&\n keys.every(\n (key) =>\n Object.prototype.hasOwnProperty.call(rightRecord, key) &&\n equalPortable(leftRecord[key], rightRecord[key]),\n )\n );\n}\n\nfunction queryPartition(\n runtime: DataRuntimeContextValue,\n query: DataQuery,\n mutation: ErasedMutationDescriptor,\n provider: ProviderServiceRef,\n): readonly PartitionedDependencyTag[] | undefined {\n const descriptor = descriptorFor(query);\n if (\n descriptor === undefined ||\n descriptor.providerId !== mutation.providerId ||\n descriptor.sessionKey !== mutation.sessionKey ||\n !equalPortable(descriptor.scopeKey, mutation.scopeKey)\n )\n return undefined;\n try {\n const queryService = runtime.providers.resolve(descriptor.providerId);\n if (queryService.identity !== provider.identity) return undefined;\n return dependencyTagsForQuery(descriptor, { providerServiceKey: queryService.id });\n } catch {\n return undefined;\n }\n}\n\nfunction resourceTagMatches(\n tag: PartitionedDependencyTag,\n resource: ErasedMutationDescriptor['ref'],\n family?: 'collection' | 'record',\n id?: RecordId,\n): boolean {\n const logical = tag[5];\n if (logical[0] !== 'resource' || logical[1] !== 1) return false;\n if (family !== undefined && logical[2] !== family) return false;\n if (!sameEntityRef(logical[3], resource)) return false;\n return id === undefined || (logical[2] === 'record' && Object.is(logical[4], id));\n}\n\nfunction hasResourceTag(\n runtime: DataRuntimeContextValue,\n query: DataQuery,\n provider: ProviderServiceRef,\n mutation: ErasedMutationDescriptor,\n resource: ErasedMutationDescriptor['ref'],\n family?: 'collection' | 'record',\n id?: RecordId,\n): boolean {\n return (\n queryPartition(runtime, query, mutation, provider)?.some((tag) =>\n resourceTagMatches(tag, resource, family, id),\n ) ?? false\n );\n}\n\nfunction descriptorMatchesResource(\n runtime: DataRuntimeContextValue,\n query: DataQuery,\n provider: ProviderServiceRef,\n mutation: ErasedMutationDescriptor,\n resource: ErasedMutationDescriptor['ref'],\n): boolean {\n return hasResourceTag(runtime, query, provider, mutation, resource);\n}\n\nfunction effectResource(effect: MutationEffectTarget): ErasedMutationDescriptor['ref'] {\n const resource = effect.resource;\n return normalizeEntityRef(\n typeof resource === 'object' && resource !== null && 'kind' in resource\n ? resource.ref\n : resource,\n );\n}\n\nfunction hasDeclaredTag(\n runtime: DataRuntimeContextValue,\n query: DataQuery,\n provider: ProviderServiceRef,\n mutation: ErasedMutationDescriptor,\n tag: string,\n): boolean {\n return (\n queryPartition(runtime, query, mutation, provider)?.some((candidate) => {\n const logical = candidate[5];\n return logical[0] === 'declared' && logical[1] === 1 && logical[2] === tag;\n }) ?? false\n );\n}\n\nfunction resultRecord(\n result: unknown,\n): { readonly id: RecordId; readonly record: unknown } | undefined {\n if (result === null || typeof result !== 'object' || Array.isArray(result)) return undefined;\n const value = result as {\n readonly kind?: unknown;\n readonly id?: unknown;\n readonly completeness?: unknown;\n readonly record?: unknown;\n };\n return value.kind === 'record' &&\n value.completeness === 'full' &&\n (typeof value.id === 'string' || typeof value.id === 'number')\n ? { id: value.id, record: value.record }\n : undefined;\n}\n\nfunction writeCompleteOneRecord(\n runtime: DataRuntimeContextValue,\n queryClient: QueryClient,\n provider: ProviderServiceRef,\n mutation: ErasedMutationDescriptor,\n result: unknown,\n): Set<string> {\n const record = resultRecord(result);\n const written = new Set<string>();\n if (record === undefined || (mutation.kind !== 'createOne' && mutation.kind !== 'updateOne'))\n return written;\n for (const query of queryClient.getQueryCache().getAll() as DataQuery[]) {\n const descriptor = descriptorFor(query);\n if (\n descriptor?.kind !== 'one' ||\n descriptor.projection !== undefined ||\n !Object.is(descriptor.id, record.id) ||\n !descriptorMatchesResource(runtime, query, provider, mutation, mutation.ref)\n )\n continue;\n queryClient.setQueryData(query.queryKey, (previous: unknown) =>\n previous !== null && typeof previous === 'object' && !Array.isArray(previous)\n ? { ...(previous as Record<string, unknown>), data: record.record }\n : previous,\n );\n written.add(query.queryHash);\n }\n return written;\n}\n\nfunction mutationRecordIds(\n mutation: ErasedMutationDescriptor,\n result: unknown,\n): readonly RecordId[] | undefined {\n if (mutation.kind === 'updateOne' || mutation.kind === 'deleteOne') return [mutation.id];\n if (\n (mutation.kind === 'updateMany' || mutation.kind === 'deleteMany') &&\n mutation.target.kind === 'ids'\n ) {\n return mutation.target.ids;\n }\n if (\n result !== null &&\n typeof result === 'object' &&\n (result as { target?: unknown }).target === 'ids'\n ) {\n return (result as { succeededIds?: readonly RecordId[] }).succeededIds;\n }\n return undefined;\n}\n\n/**\n * Reconciles canonical cache dependencies after a validated, current mutation.\n * It deliberately uses only core-produced query tags; React never constructs\n * a resource tag or a dependency partition itself.\n */\nexport function reconcileMutation(args: {\n readonly runtime: DataRuntimeContextValue;\n readonly queryClient: QueryClient;\n readonly provider: ProviderServiceRef;\n readonly descriptor: ErasedMutationDescriptor;\n readonly result: unknown;\n readonly effects?: readonly MutationEffectTarget[] | 'none';\n}): void {\n const { runtime, queryClient, provider, descriptor, result } = args;\n const written = writeCompleteOneRecord(runtime, queryClient, provider, descriptor, result);\n const ids = mutationRecordIds(descriptor, result);\n\n if (descriptor.kind === 'deleteOne') {\n queryClient.removeQueries({\n predicate: (query) =>\n hasResourceTag(\n runtime,\n query as DataQuery,\n provider,\n descriptor,\n descriptor.ref,\n 'record',\n descriptor.id,\n ),\n });\n }\n\n queryClient.invalidateQueries({\n predicate: (query) => {\n const current = query as DataQuery;\n const queryDescriptor = descriptorFor(current);\n if (queryDescriptor === undefined) return false;\n const standard = descriptor.kind !== 'custom';\n if (\n standard &&\n descriptorMatchesResource(runtime, current, provider, descriptor, descriptor.ref)\n ) {\n if (queryDescriptor.kind === 'list' || queryDescriptor.kind === 'count') return true;\n if (descriptor.kind === 'createOne' || descriptor.kind === 'createMany') return false;\n if (queryDescriptor.kind === 'one' && written.has(current.queryHash)) return false;\n if (ids === undefined) return true;\n return ids.some((id) =>\n hasResourceTag(runtime, current, provider, descriptor, descriptor.ref, 'record', id),\n );\n }\n\n if (args.effects === undefined || args.effects === 'none') return false;\n return args.effects.some((effect) => {\n const resource = effectResource(effect);\n const resourceMatches = descriptorMatchesResource(\n runtime,\n current,\n provider,\n descriptor,\n resource,\n );\n const recordsMatch =\n effect.records === undefined\n ? resourceMatches\n : effect.records.some((id) =>\n hasResourceTag(runtime, current, provider, descriptor, resource, 'record', id),\n ) ||\n ((queryDescriptor.kind === 'list' || queryDescriptor.kind === 'count') &&\n resourceMatches);\n const tagsMatch =\n effect.tags?.some((tag) => hasDeclaredTag(runtime, current, provider, descriptor, tag)) ??\n false;\n return recordsMatch || tagsMatch;\n });\n },\n });\n}\n","import {\n isDataError,\n isMutationReplaySafe,\n normalizeDataError,\n resolveDataCapability,\n validateMutationResult,\n type DataError,\n type DataSessionSnapshot,\n type ErasedMutationDescriptor,\n type MutationReplayCapability,\n type MutationEffectTarget,\n type MutationResultFor,\n} from '@burojs/core';\nimport type { UseMutationOptions } from '@tanstack/react-query';\n\nimport { reconcileMutation } from './invalidation.js';\nimport type { DataRuntimeContextValue } from './runtime.js';\n\nfunction cancelledError(code: 'aborted' | 'stale-generation' = 'aborted'): DataError {\n return {\n kind: 'cancelled',\n code,\n message:\n code === 'aborted'\n ? 'Data mutation was aborted.'\n : 'Data mutation completed after its session generation changed.',\n };\n}\n\nfunction isCurrentGeneration(\n runtime: DataRuntimeContextValue,\n descriptor: ErasedMutationDescriptor,\n sessionKey: string,\n generation: number,\n serviceIdentity: object,\n): boolean {\n const state = runtime.dataSession.getState();\n if (\n state.status !== 'ready' ||\n descriptor.sessionKey !== sessionKey ||\n state.snapshot.sessionKey !== sessionKey ||\n state.snapshot.generation !== generation\n )\n return false;\n try {\n return runtime.providers.resolve(descriptor.providerId).identity === serviceIdentity;\n } catch {\n return false;\n }\n}\n\nfunction customEffects(\n runtime: DataRuntimeContextValue,\n descriptor: ErasedMutationDescriptor,\n result: unknown,\n): readonly MutationEffectTarget[] | 'none' | undefined {\n if (descriptor.kind !== 'custom') return undefined;\n const projection = runtime.app.runtime\n .getSnapshot()\n .getProjection({ kind: 'custom-mutation', ref: descriptor.ref });\n const value = projection?.value as Readonly<Record<string, unknown>> | undefined;\n if (value?.effects === 'none') return 'none';\n const attachment = value?.effects as Readonly<Record<string, unknown>> | undefined;\n if (attachment?.capability !== 'mutation-effects' || typeof attachment.id !== 'string') {\n throw {\n kind: 'configuration',\n code: 'custom-mutation-effects-unavailable',\n message: 'Custom mutation effects are unavailable from the current application snapshot.',\n } satisfies DataError;\n }\n const declared = runtime.app.getPluginCapability<unknown>('mutation-effects', attachment.id);\n if (typeof declared === 'function') {\n return declared({ input: descriptor.input, output: result }) as readonly MutationEffectTarget[];\n }\n if (!Array.isArray(declared)) {\n throw {\n kind: 'configuration',\n code: 'custom-mutation-effects-unavailable',\n message: 'Custom mutation effects are unavailable from the current application snapshot.',\n } satisfies DataError;\n }\n return declared as readonly MutationEffectTarget[];\n}\n\n/** Executes one pessimistic provider mutation and commits only its active generation. */\nexport async function executeMutation<D extends ErasedMutationDescriptor>(args: {\n readonly descriptor: D;\n readonly runtime: DataRuntimeContextValue;\n readonly replayCount?: 0 | 1;\n}): Promise<MutationResultFor<D>> {\n let captured:\n | { readonly snapshot: DataSessionSnapshot; readonly replaySafe: boolean }\n | undefined;\n try {\n return await executeMutationAttempt(args, (value) => {\n captured = value;\n });\n } catch (error) {\n const failure = normalizeDataError(error);\n if (\n args.replayCount !== 1 &&\n failure.kind === 'auth' &&\n captured?.replaySafe === true &&\n args.runtime.authController !== undefined\n ) {\n const state = args.runtime.dataSession.getState();\n if (\n state.status === 'ready' &&\n state.snapshot.sessionKey === captured.snapshot.sessionKey &&\n state.snapshot.generation === captured.snapshot.generation\n ) {\n const recovery = await args.runtime.authController.recover(failure, captured.snapshot);\n if (recovery === 'replay') return executeMutation({ ...args, replayCount: 1 });\n throw recovery;\n }\n }\n throw failure;\n }\n}\n\nasync function executeMutationAttempt<D extends ErasedMutationDescriptor>(\n args: {\n readonly descriptor: D;\n readonly runtime: DataRuntimeContextValue;\n },\n capture: (value: {\n readonly snapshot: DataSessionSnapshot;\n readonly replaySafe: boolean;\n }) => void,\n): Promise<MutationResultFor<D>> {\n let controller: AbortController | undefined;\n let unsubscribe: (() => void) | undefined;\n try {\n const snapshot = await args.runtime.waitUntilReady();\n const service = args.runtime.providers.resolve(args.descriptor.providerId);\n if (\n args.descriptor.sessionKey !== snapshot.sessionKey ||\n service.session.sessionKey !== snapshot.sessionKey ||\n service.session.generation !== snapshot.generation ||\n !isCurrentGeneration(\n args.runtime,\n args.descriptor,\n snapshot.sessionKey,\n snapshot.generation,\n service.identity,\n )\n )\n throw cancelledError('stale-generation');\n controller = new AbortController();\n unsubscribe = args.runtime.dataSession.subscribe(() => {\n if (\n !isCurrentGeneration(\n args.runtime,\n args.descriptor,\n snapshot.sessionKey,\n snapshot.generation,\n service.identity,\n )\n ) {\n controller?.abort();\n }\n });\n const capability = resolveDataCapability(service.provider, {\n lifecycle: 'mutation',\n kind: args.descriptor.kind,\n });\n if (isDataError(capability)) throw capability;\n const handler = capability as unknown as ((\n descriptor: D,\n context: {\n readonly signal: AbortSignal;\n readonly requestContext: typeof args.runtime.app.requestContext;\n readonly session: typeof snapshot;\n readonly providerServiceKey: string;\n },\n ) => Promise<unknown>) & { readonly replay: MutationReplayCapability };\n capture({\n snapshot,\n replaySafe: isMutationReplaySafe(args.descriptor, handler.replay),\n });\n const response = await handler(args.descriptor, {\n signal: controller.signal,\n requestContext: args.runtime.app.requestContext,\n session: snapshot,\n providerServiceKey: service.id,\n });\n const result = validateMutationResult(args.descriptor, response) as MutationResultFor<D>;\n if (\n controller.signal.aborted ||\n !isCurrentGeneration(\n args.runtime,\n args.descriptor,\n snapshot.sessionKey,\n snapshot.generation,\n service.identity,\n )\n )\n throw cancelledError(controller.signal.aborted ? 'aborted' : 'stale-generation');\n reconcileMutation({\n runtime: args.runtime,\n queryClient: args.runtime.queryClient,\n provider: service,\n descriptor: args.descriptor,\n result,\n effects: customEffects(args.runtime, args.descriptor, result),\n });\n return result;\n } catch (error) {\n if (controller?.signal.aborted) throw cancelledError();\n throw normalizeDataError(error);\n } finally {\n unsubscribe?.();\n }\n}\n\nexport type NativeMutationOptions<TData, TVariables> = Omit<\n UseMutationOptions<TData, DataError, TVariables>,\n 'mutationFn' | 'retry'\n>;\n\n/** Direct TanStack builder with fixed pessimistic execution and no retries. */\nexport function buroMutationOptions<TVariables, D extends ErasedMutationDescriptor>(\n descriptorFor: (variables: TVariables) => D,\n runtime: DataRuntimeContextValue,\n): UseMutationOptions<MutationResultFor<D>, DataError, TVariables> {\n return {\n retry: false,\n mutationFn: (variables) => executeMutation({ descriptor: descriptorFor(variables), runtime }),\n };\n}\n","import {\n createMutationDescriptor,\n normalizeDataError,\n normalizeEntityRef,\n type DataError,\n type DataSessionSnapshot,\n type ErasedMutationDescriptor,\n type ErasedResourceHandle,\n type PortableObject,\n type ResourceHandle,\n} from '@burojs/core';\nimport { useCallback, useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../../data/context.js';\nimport { useApplicationSnapshot } from '../../runtime.js';\n\ntype AnyResource = ResourceHandle<any, any, any, any>;\n\nfunction currentSession(runtime: ReturnType<typeof useDataRuntime>): DataSessionSnapshot {\n const state = runtime.dataSession.getState();\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\nfunction resourceHandle(resource: AnyResource | string): AnyResource | ErasedResourceHandle {\n return typeof resource === 'string'\n ? ({ kind: 'resource', ref: normalizeEntityRef(resource) } as ErasedResourceHandle)\n : resource;\n}\n\n/** Creates standard mutation descriptors from the live app/session snapshot. */\nexport function useStandardMutationDescriptor(\n resource: AnyResource | string,\n providerOptionsOverride?: PortableObject,\n): (input: Readonly<Record<string, unknown>>) => ErasedMutationDescriptor {\n const runtime = useDataRuntime();\n const snapshot = useApplicationSnapshot();\n const session = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => currentSession(runtime),\n () => currentSession(runtime),\n );\n const handle = resourceHandle(resource);\n const projection = runtime.app.registry.get(handle);\n\n return useCallback(\n (input) => {\n if (projection === undefined) {\n throw normalizeDataError(\n Object.assign(\n new Error(`Resource '${handle.ref.namespace}:${handle.ref.id}' is unavailable.`),\n {\n kind: 'configuration' as const,\n code: 'resource-unavailable',\n },\n ),\n ) as DataError;\n }\n let binding;\n try {\n binding = runtime.app.resolveDataBinding(handle);\n } catch (error) {\n throw normalizeDataError(\n Object.assign(\n new Error(\n error instanceof Error ? error.message : 'Resource data binding is unavailable.',\n ),\n { kind: 'configuration' as const, code: 'data-binding-unavailable', cause: error },\n ),\n ) as DataError;\n }\n return createMutationDescriptor({\n ...input,\n providerId: binding.providerId,\n ref: binding.ref,\n resource: binding.resource,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n bindingRevision: snapshot.manifest.snapshotId,\n idField: projection.data?.idField ?? 'id',\n ...(projection.data?.providerOptions === undefined\n ? {}\n : { providerOptions: projection.data.providerOptions }),\n ...(projection.data?.dependencies === undefined\n ? {}\n : { dependencies: projection.data.dependencies }),\n ...(providerOptionsOverride === undefined ? {} : { providerOptionsOverride }),\n } as never) as ErasedMutationDescriptor;\n },\n [\n handle,\n projection,\n providerOptionsOverride,\n runtime.app,\n session,\n snapshot.manifest.snapshotId,\n ],\n );\n}\n","import type {\n CreateManyDescriptor,\n CreateOneDescriptor,\n DataError,\n ErasedResourceHandle,\n FieldDefBase,\n InferCreateInput,\n MutationResultFor,\n PortableObject,\n ResourceHandle,\n} from '@burojs/core';\nimport { useMutation, type UseMutationResult } from '@tanstack/react-query';\n\nimport { buroMutationOptions, type NativeMutationOptions } from '../../data/mutation-options.js';\nimport { useDataRuntime } from '../../data/context.js';\nimport { useStandardMutationDescriptor } from './use-standard-mutation-descriptor.js';\n\ntype AnyResource = ResourceHandle<any, Record<string, FieldDefBase>, string, string>;\nexport type UseCreateOneOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<CreateOneDescriptor<R>>,\n { readonly values: InferCreateInput<R> }\n> & { readonly providerOptionsOverride?: PortableObject };\nexport type UseCreateManyOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<CreateManyDescriptor<R>>,\n { readonly values: readonly InferCreateInput<R>[] }\n> & { readonly providerOptionsOverride?: PortableObject };\n\nexport function useCreateOne<R extends AnyResource>(\n resource: R,\n options?: UseCreateOneOptions<R>,\n): UseMutationResult<\n MutationResultFor<CreateOneDescriptor<R>>,\n DataError,\n { readonly values: InferCreateInput<R> }\n>;\nexport function useCreateOne(\n resource: string,\n options?: UseCreateOneOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<CreateOneDescriptor<ErasedResourceHandle>>,\n DataError,\n { readonly values: unknown }\n>;\nexport function useCreateOne(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly values: unknown }) =>\n descriptorFor({ kind: 'createOne', input: variables.values }),\n runtime,\n ),\n });\n}\n\nexport function useCreateMany<R extends AnyResource>(\n resource: R,\n options?: UseCreateManyOptions<R>,\n): UseMutationResult<\n MutationResultFor<CreateManyDescriptor<R>>,\n DataError,\n { readonly values: readonly InferCreateInput<R>[] }\n>;\nexport function useCreateMany(\n resource: string,\n options?: UseCreateManyOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<CreateManyDescriptor<ErasedResourceHandle>>,\n DataError,\n { readonly values: readonly unknown[] }\n>;\nexport function useCreateMany(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly values: readonly unknown[] }) =>\n descriptorFor({ kind: 'createMany', input: variables.values }),\n runtime,\n ),\n });\n}\n","import type {\n BulkTarget,\n DataError,\n ErasedResourceHandle,\n FieldDefBase,\n InferUpdateInput,\n MutationResultFor,\n PortableObject,\n ResourceHandle,\n UpdateManyDescriptor,\n UpdateOneDescriptor,\n} from '@burojs/core';\nimport { useMutation, type UseMutationResult } from '@tanstack/react-query';\n\nimport { buroMutationOptions, type NativeMutationOptions } from '../../data/mutation-options.js';\nimport { useDataRuntime } from '../../data/context.js';\nimport { useStandardMutationDescriptor } from './use-standard-mutation-descriptor.js';\n\ntype AnyResource = ResourceHandle<any, Record<string, FieldDefBase>, string, string>;\ntype UpdateOneVariables<R extends AnyResource> = {\n readonly id: UpdateOneDescriptor<R>['id'];\n readonly values: InferUpdateInput<R>;\n};\ntype UpdateManyVariables<R extends AnyResource> = {\n readonly target: BulkTarget<R>;\n readonly values: InferUpdateInput<R>;\n};\nexport type UseUpdateOneOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<UpdateOneDescriptor<R>>,\n UpdateOneVariables<R>\n> & { readonly providerOptionsOverride?: PortableObject };\nexport type UseUpdateManyOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<UpdateManyDescriptor<R>>,\n UpdateManyVariables<R>\n> & { readonly providerOptionsOverride?: PortableObject };\n\nexport function useUpdateOne<R extends AnyResource>(\n resource: R,\n options?: UseUpdateOneOptions<R>,\n): UseMutationResult<MutationResultFor<UpdateOneDescriptor<R>>, DataError, UpdateOneVariables<R>>;\nexport function useUpdateOne(\n resource: string,\n options?: UseUpdateOneOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<UpdateOneDescriptor<ErasedResourceHandle>>,\n DataError,\n UpdateOneVariables<ErasedResourceHandle>\n>;\nexport function useUpdateOne(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly id: unknown; readonly values: unknown }) =>\n descriptorFor({ kind: 'updateOne', id: variables.id, input: variables.values }),\n runtime,\n ),\n });\n}\n\nexport function useUpdateMany<R extends AnyResource>(\n resource: R,\n options?: UseUpdateManyOptions<R>,\n): UseMutationResult<MutationResultFor<UpdateManyDescriptor<R>>, DataError, UpdateManyVariables<R>>;\nexport function useUpdateMany(\n resource: string,\n options?: UseUpdateManyOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<UpdateManyDescriptor<ErasedResourceHandle>>,\n DataError,\n UpdateManyVariables<ErasedResourceHandle>\n>;\nexport function useUpdateMany(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly target: unknown; readonly values: unknown }) =>\n descriptorFor({ kind: 'updateMany', target: variables.target, input: variables.values }),\n runtime,\n ),\n });\n}\n","import type {\n BulkTarget,\n DataError,\n DeleteManyDescriptor,\n DeleteOneDescriptor,\n ErasedResourceHandle,\n FieldDefBase,\n MutationResultFor,\n PortableObject,\n ResourceHandle,\n} from '@burojs/core';\nimport { useMutation, type UseMutationResult } from '@tanstack/react-query';\n\nimport { buroMutationOptions, type NativeMutationOptions } from '../../data/mutation-options.js';\nimport { useDataRuntime } from '../../data/context.js';\nimport { useStandardMutationDescriptor } from './use-standard-mutation-descriptor.js';\n\ntype AnyResource = ResourceHandle<any, Record<string, FieldDefBase>, string, string>;\ntype DeleteOneVariables<R extends AnyResource> = { readonly id: DeleteOneDescriptor<R>['id'] };\ntype DeleteManyVariables<R extends AnyResource> = { readonly target: BulkTarget<R> };\nexport type UseDeleteOneOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<DeleteOneDescriptor<R>>,\n DeleteOneVariables<R>\n> & { readonly providerOptionsOverride?: PortableObject };\nexport type UseDeleteManyOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<DeleteManyDescriptor<R>>,\n DeleteManyVariables<R>\n> & { readonly providerOptionsOverride?: PortableObject };\n\nexport function useDeleteOne<R extends AnyResource>(\n resource: R,\n options?: UseDeleteOneOptions<R>,\n): UseMutationResult<MutationResultFor<DeleteOneDescriptor<R>>, DataError, DeleteOneVariables<R>>;\nexport function useDeleteOne(\n resource: string,\n options?: UseDeleteOneOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<DeleteOneDescriptor<ErasedResourceHandle>>,\n DataError,\n DeleteOneVariables<ErasedResourceHandle>\n>;\nexport function useDeleteOne(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly id: unknown }) =>\n descriptorFor({ kind: 'deleteOne', id: variables.id }),\n runtime,\n ),\n });\n}\n\nexport function useDeleteMany<R extends AnyResource>(\n resource: R,\n options?: UseDeleteManyOptions<R>,\n): UseMutationResult<MutationResultFor<DeleteManyDescriptor<R>>, DataError, DeleteManyVariables<R>>;\nexport function useDeleteMany(\n resource: string,\n options?: UseDeleteManyOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<DeleteManyDescriptor<ErasedResourceHandle>>,\n DataError,\n DeleteManyVariables<ErasedResourceHandle>\n>;\nexport function useDeleteMany(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly target: unknown }) =>\n descriptorFor({ kind: 'deleteMany', target: variables.target }),\n runtime,\n ),\n });\n}\n","import {\n createMutationDescriptor,\n normalizeDataError,\n type CustomMutationDescriptor,\n type CustomMutationHandle,\n type DataError,\n type InferCustomInput,\n type InferCustomOutput,\n type PortableObject,\n} from '@burojs/core';\nimport { useMutation, type UseMutationResult } from '@tanstack/react-query';\nimport { useCallback, useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../../data/context.js';\nimport { buroMutationOptions, type NativeMutationOptions } from '../../data/mutation-options.js';\nimport { useApplicationSnapshot } from '../../runtime.js';\n\nexport type UseCustomMutationOptions<TInput, TOutput> = NativeMutationOptions<TOutput, TInput> & {\n readonly providerOptionsOverride?: PortableObject;\n};\n\nfunction sessionSnapshot(runtime: ReturnType<typeof useDataRuntime>) {\n const state = runtime.dataSession.getState();\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\n/** Resolves a trusted custom mutation and its declaration-owned effects. */\nexport function useCustomMutation<THandle extends CustomMutationHandle<unknown, unknown>>(\n handle: THandle,\n options: UseCustomMutationOptions<InferCustomInput<THandle>, InferCustomOutput<THandle>> = {},\n): UseMutationResult<InferCustomOutput<THandle>, DataError, InferCustomInput<THandle>> {\n const runtime = useDataRuntime();\n const snapshot = useApplicationSnapshot();\n const session = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionSnapshot(runtime),\n () => sessionSnapshot(runtime),\n );\n const { providerOptionsOverride, ...mutationOptions } = options;\n const projection = snapshot.getProjection(handle);\n const descriptorFor = useCallback(\n (input: InferCustomInput<THandle>) => {\n if (projection === undefined || projection.kind !== 'custom-mutation') {\n throw normalizeDataError(\n Object.assign(\n new Error(`Custom mutation '${handle.ref.namespace}:${handle.ref.id}' is unavailable.`),\n {\n kind: 'configuration' as const,\n code: 'custom-mutation-unavailable',\n },\n ),\n );\n }\n const value = projection.value as Readonly<Record<string, unknown>>;\n const binding = value.binding as Readonly<Record<string, unknown>> | undefined;\n if (\n binding === undefined ||\n typeof binding.provider !== 'string' ||\n typeof binding.operation !== 'string' ||\n (binding.resource !== undefined && typeof binding.resource !== 'string')\n ) {\n throw normalizeDataError(\n Object.assign(\n new Error(\n `Custom mutation '${handle.ref.namespace}:${handle.ref.id}' has an invalid binding.`,\n ),\n {\n kind: 'configuration' as const,\n code: 'custom-mutation-binding-invalid',\n },\n ),\n );\n }\n return createMutationDescriptor({\n providerId: binding.provider,\n kind: 'custom',\n ref: handle.ref,\n resource: binding.resource ?? handle.ref.id,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n bindingRevision: snapshot.manifest.snapshotId,\n operation: binding.operation,\n input,\n ...(binding.providerOptions === undefined\n ? {}\n : { providerOptions: binding.providerOptions as PortableObject }),\n ...(providerOptionsOverride === undefined ? {} : { providerOptionsOverride }),\n ...(value.replay === undefined\n ? {}\n : (() => {\n const replay = value.replay as Readonly<Record<string, unknown>>;\n const policy =\n replay.capability === 'mutation-replay-policy' && typeof replay.id === 'string'\n ? runtime.app.getPluginCapability('mutation-replay-policy', replay.id)\n : undefined;\n return policy === undefined ? {} : { replay: policy };\n })()),\n } as never) as CustomMutationDescriptor<\n InferCustomInput<THandle>,\n InferCustomOutput<THandle>\n >;\n },\n [handle.ref, projection, providerOptionsOverride, session, snapshot.manifest.snapshotId],\n );\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(descriptorFor, runtime),\n });\n}\n","'use client';\nimport type { Audit } from '@burojs/core';\nimport { createContext, useContext } from 'react';\n\nexport const AuditContext = createContext<Audit | null>(null);\n\n/**\n * The application's audit emitter, or `null` when `<BuroProvider>` got no\n * `audit` prop.\n *\n * Call sites guard with `audit?.emit(...)`, and that guard is deliberate: it is\n * what makes an app without auditing pay nothing, because the work of building\n * an event (a form diff, a list snapshot) never starts.\n *\n * Applications use it to write their own events into the same stream — custom\n * pages and hand-written components are otherwise blind spots by construction:\n *\n * const audit = useAudit();\n * audit?.emit({ type: 'app.export.started', payload: { format: 'xlsx' } });\n */\nexport function useAudit(): Audit | null {\n return useContext(AuditContext);\n}\n","'use client';\nimport * as React from 'react';\n\n/**\n * The framework's whole dependency on a router.\n *\n * It exists because `@burojs/react` used to import `next/navigation`\n * directly, which made the package unusable outside Next for the sake of three\n * hooks. Links were already injected through `LinkComponentProvider`; this is\n * the same idea for location and navigation.\n */\nexport interface RouterAdapter {\n pathname: string;\n searchParams: URLSearchParams;\n /** Navigate without adding a history entry — used for URL-state sync. */\n replace: (url: string) => void;\n push: (url: string) => void;\n}\n\nconst RouterAdapterContext = React.createContext<RouterAdapter | null>(null);\n\nexport interface RouterAdapterProviderProps {\n adapter: RouterAdapter;\n children: React.ReactNode;\n}\n\nexport function RouterAdapterProvider({\n adapter,\n children,\n}: RouterAdapterProviderProps): React.ReactElement {\n return <RouterAdapterContext.Provider value={adapter}>{children}</RouterAdapterContext.Provider>;\n}\n\nexport function useRouterAdapter(): RouterAdapter {\n const found = React.useContext(RouterAdapterContext);\n if (!found) {\n throw new Error(\n 'No RouterAdapterProvider found. URL state (filters, sorting, paging) needs to ' +\n 'read and write the address bar; without a router it would appear to work and ' +\n 'silently never persist. Wrap the app:\\n\\n' +\n ' // Next App Router\\n' +\n ' const adapter = {\\n' +\n ' pathname: usePathname(),\\n' +\n ' searchParams: new URLSearchParams(useSearchParams().toString()),\\n' +\n ' replace: (u) => router.replace(u, { scroll: false }),\\n' +\n ' push: (u) => router.push(u),\\n' +\n ' };\\n\\n' +\n ' // react-router\\n' +\n ' const [sp] = useSearchParams();\\n' +\n ' const navigate = useNavigate();\\n' +\n ' const adapter = {\\n' +\n ' pathname: useLocation().pathname,\\n' +\n ' searchParams: sp,\\n' +\n ' replace: (u) => navigate(u, { replace: true }),\\n' +\n ' push: (u) => navigate(u),\\n' +\n ' };',\n );\n }\n return found;\n}\n\n/**\n * The router adapter, or `null` when none is mounted.\n *\n * `useRouterAdapter` throws by design — URL state that silently never persists\n * is worse than a crash. Audit is the opposite case: an app with no router is\n * legitimate, and auditing must never be the thing that breaks it.\n */\nexport function useOptionalRouterAdapter(): RouterAdapter | null {\n return React.useContext(RouterAdapterContext);\n}\n","'use client';\nimport { matchPath, type AppRuntime, type Audit, type AuditRoute } from '@burojs/core';\nimport { useEffect } from 'react';\nimport { useOptionalRouterAdapter } from '../hooks/router/router-adapter.js';\n\n/**\n * Emit `nav.enter` from pathname transitions.\n *\n * Mounted once by `ReadyBuroProvider`. `app` and `audit` are arguments rather\n * than context reads because the component that mounts this hook is the one\n * that PROVIDES `AppContext` and `AuditContext` — it cannot read its own.\n *\n * Everything happens in an effect, never during render: computing this in a\n * component body yields duplicate events under StrictMode and a side effect in\n * render.\n *\n * **There is deliberately no `nav.leave`.** How long a screen was open is the\n * difference between adjacent `nav.enter` timestamps, so a paired leave event\n * would double the navigation volume to carry information the sink can already\n * derive. That leaves exactly one case a leave would add — the last screen of a\n * session — and that is the case a browser cannot report reliably: closing a tab\n * runs no React cleanup (the page simply dies), and `pagehide` is not delivered\n * at all when a mobile tab is killed while backgrounded. An adopter who needs\n * the session tail owns it at the transport layer, where `visibilitychange` and\n * `sendBeacon` live — that is application policy, not framework behaviour.\n */\nexport function useNavAudit(app: AppRuntime, audit: Audit | null): void {\n const router = useOptionalRouterAdapter();\n const pathname = router?.pathname;\n\n useEffect(() => {\n if (!audit || pathname === undefined) return;\n\n let parsed: AuditRoute = { path: pathname };\n try {\n const match = matchPath(app.registry, pathname);\n if (match) {\n parsed = {\n path: pathname,\n resource: match.name,\n view: match.action,\n recordId: match.id,\n };\n }\n } catch {\n // A registry that cannot resolve this path is not a reason to lose the\n // event — the raw path is still worth recording.\n }\n\n audit.emit({ type: 'nav.enter', route: parsed }, { initiates: true });\n }, [audit, pathname, app]);\n}\n","import type { AppRuntime } from '@burojs/core';\nimport { useContext } from 'react';\nimport { AppContext } from '../context.js';\n\nexport function useApp(): AppRuntime {\n const app = useContext(AppContext);\n if (!app) {\n throw new Error('[useApp] must be used within a BuroProvider');\n }\n return app;\n}\n","'use client';\n\nimport {\n type DocKeyRef,\n type DocsConfig,\n type I18nCaps,\n type ResolvedDocTopic,\n docAddressToKey,\n listDocTopics,\n resolveContentSlot,\n resolveDoc,\n resolveDocLoader,\n resolveConceptLabel,\n resolveEnumLabel,\n} from '@burojs/core';\nimport {\n type ReactNode,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport { useApp } from './use-app.js';\nimport { useI18nCaps, useLocale } from './use-t.js';\n\n/**\n * What the panel is currently showing.\n *\n * `scopes` is a LIST because the natural entry point is the breadcrumb trail,\n * and a trail names several documented things at once — «Документы › wo:2921 ›\n * Коды» offers help for two resources. A single «i» beside one field passes a\n * one-element list.\n */\nexport interface DocPanelTarget {\n /** Scopes offered, in trail order. Always at least one. */\n scopes: string[];\n /** The article currently open, if any. */\n topicId?: string;\n /** Which of `scopes` owns `topicId`. Defaults to the first. */\n scope?: string;\n}\n\ninterface DocPanelState {\n open: boolean;\n target: DocPanelTarget | null;\n /**\n * Id of the element that opened the panel, so Escape can hand focus back.\n * Stored as an ID rather than as a node: a form re-render unmounts the node,\n * and a stale reference would send focus to nothing.\n */\n returnFocusTo: string | null;\n}\n\n/** Panel API. `open` records where focus should go when the panel closes. */\nexport interface DocPanelApi extends DocPanelState {\n openPanel: (target: DocPanelTarget, returnFocusTo?: string) => void;\n /** Navigate WITHIN the panel; the return-focus target is preserved. */\n goTo: (target: DocPanelTarget) => void;\n close: () => void;\n}\n\n/**\n * A tiny external store rather than React state.\n *\n * The panel is opened from `<DocInfo>` buttons scattered all over the tree and\n * rendered once in the layout — there is no common ancestor to hold state that\n * is not the provider itself, and putting it in the provider would re-render\n * the entire application on every open.\n */\nfunction createStore() {\n let state: DocPanelState = { open: false, target: null, returnFocusTo: null };\n const listeners = new Set<() => void>();\n const emit = () => {\n for (const l of listeners) l();\n };\n return {\n subscribe(l: () => void): () => void {\n listeners.add(l);\n // Explicitly `void`: `Set.delete` returns a boolean, and React's\n // EffectCallback rejects a cleanup that returns anything.\n return () => {\n listeners.delete(l);\n };\n },\n get: () => state,\n set(next: DocPanelState) {\n state = next;\n emit();\n },\n };\n}\n\ntype Store = ReturnType<typeof createStore>;\n\ninterface DocsContextValue {\n config: DocsConfig | null;\n store: Store;\n /** Separate store for the on-screen record's documentation variant. */\n variants: Store;\n}\n\nconst DocsContext = createContext<DocsContextValue | null>(null);\n\n/*\n NO URL MIRROR.\n\n The panel used to write `?help=<scope>:<topic>` so an article could be pasted\n into a ticket. Removed on the owner's call, and the reasoning is worth\n keeping: the panel is STICKY ACROSS NAVIGATION by design — it stays put while\n the reader works — so the query param it left behind rode along on every\n subsequent link, describing an article the reader had long since stopped\n looking at. A pointer that goes stale the moment you use the page is worse\n than no pointer.\n\n Sharing a specific article still works, and better: the handbook at `/help`\n carries `?area=` / `?topic=` plus a per-heading anchor, which is a real page\n the recipient lands on rather than a panel that has to be re-opened.\n*/\n\nexport function DocsProvider({\n config,\n children,\n}: {\n config: DocsConfig | undefined;\n children: ReactNode;\n}): ReactNode {\n // One store for the lifetime of the provider; `useRef` rather than `useMemo`\n // because a store must never be recreated by a render.\n const storeRef = useRef<Store | null>(null);\n storeRef.current ??= createStore();\n const store = storeRef.current as Store;\n const variantRef = useRef<Store | null>(null);\n variantRef.current ??= createStore();\n const variants = variantRef.current as Store;\n const value = useMemo<DocsContextValue>(\n () => ({ config: config ?? null, store, variants }),\n [config, store, variants],\n );\n return <DocsContext.Provider value={value}>{children}</DocsContext.Provider>;\n}\n\n/** The article-body configuration, or `null` when the app supplied none. */\nexport function useDocsConfig(): DocsConfig | null {\n return useContext(DocsContext)?.config ?? null;\n}\n\nconst EMPTY: DocPanelState = { open: false, target: null, returnFocusTo: null };\n\n/**\n * Control and observe the documentation panel.\n *\n * State lives in a store, NOT in the URL. Every navigation link in the app is a\n * bare path with no query, so URL-as-source-of-truth would close the panel on\n * each navigation — destroying the one behaviour it exists for, which is being\n * readable WHILE the reader works. The URL is written for sharing and read back\n * on load; it never drives the panel during a session.\n */\nexport function useDocPanel(): DocPanelApi {\n const ctx = useContext(DocsContext);\n const store = ctx?.store;\n const subscribe = useCallback((cb: () => void) => store?.subscribe(cb) ?? (() => {}), [store]);\n const getSnapshot = useCallback(() => store?.get() ?? EMPTY, [store]);\n const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const openPanel = useCallback(\n (target: DocPanelTarget, returnFocusTo?: string) => {\n store?.set({ open: true, target, returnFocusTo: returnFocusTo ?? null });\n },\n [store],\n );\n const goTo = useCallback(\n (target: DocPanelTarget) => {\n const prev = store?.get();\n store?.set({ open: true, target, returnFocusTo: prev?.returnFocusTo ?? null });\n },\n [store],\n );\n const close = useCallback(() => {\n store?.set({ open: false, target: null, returnFocusTo: null });\n }, [store]);\n\n return { ...state, openPanel, goTo, close };\n}\n\n/** A topic plus the title the bundle gives it in the active locale. */\nexport interface DocTopicView extends ResolvedDocTopic {\n title: string;\n /** Scope this topic belongs to — needed once several are listed together. */\n scope: string;\n}\n\n/**\n * Human name for a scope. A resource scope reads its own plural/singular label;\n * an `enum/<ns>/<value>` scope reads the enum VALUE's label, which is what makes\n * a variant group read «Заказ кодов» rather than a raw token.\n */\nfunction resolveScopeLabel(caps: I18nCaps, scope: string, ref: DocKeyRef | undefined): string {\n const parts = scope.split('/');\n if (parts[0] === 'enum' && parts[1] !== undefined && parts[2] !== undefined) {\n return resolveEnumLabel(caps, parts[1], parts[2]);\n }\n // A glossary term names itself. Without this the panel header for a field\n // that defers to one reads the raw address, «concept/gtin».\n if (parts[0] === 'concept' && parts[1] !== undefined) {\n return resolveConceptLabel(caps, parts[1]);\n }\n if (ref?.resource !== undefined) {\n return (\n resolveContentSlot(caps, ['label.plural', 'label.single'], { resource: ref.resource }) ??\n ref.resource\n );\n }\n return scope;\n}\n\n/** One scope's topics, with the scope's own label and summary. */\nexport interface DocScopeView {\n scope: string;\n label: string;\n summary?: string;\n topics: DocTopicView[];\n}\n\n/**\n * Topics of one scope, ordered, each with its resolved title.\n *\n * Order comes from the map (kind, then explicit `order`, then id) and NOT from\n * the title — sorting by title would reshuffle the panel whenever the reader\n * switches language.\n *\n * `fields.<f>` / `actions.<a>` / `tabs.<t>` topics take their title from the\n * entity's own label instead of `doc.topics.<id>`, so a name never has to be\n * written twice.\n */\nexport function useDocTopics(scope: string | undefined): DocTopicView[] {\n const scopes = useMemo(() => (scope ? [scope] : []), [scope]);\n const groups = useDocScopes(scopes);\n return useMemo(() => groups.flatMap((g) => g.topics), [groups]);\n}\n\n/**\n * Topics for SEVERAL scopes at once, each with its label, summary and ordered\n * topic list. Scopes with nothing at all are dropped.\n *\n * One `useI18nCaps()` for the whole walk, with `resource` passed per lookup —\n * `useI18nCaps(scope)` in a loop would be a hook in a loop. Scopes keep the\n * caller's order (the breadcrumb trail), not alphabetical: the trail reads\n * outermost-first and the list should match what the reader just looked at.\n */\nexport function useDocScopes(scopes: readonly string[]): DocScopeView[] {\n const config = useDocsConfig();\n const locale = useLocale();\n const caps = useI18nCaps();\n\n return useMemo(() => {\n const out: DocScopeView[] = [];\n for (const scope of scopes) {\n /*\n No `config` is NOT the same as \"nothing to show\". An app can document\n entirely through bundle summaries and never ship a single article — that\n is the whole of part one of this feature — and such a scope still\n belongs in the trail's help. Articles are the part that needs a config;\n summaries never were.\n */\n const ref = docAddressToKey(scope);\n const opts = ref?.resource !== undefined ? { resource: ref.resource } : {};\n const topics = (config ? listDocTopics(config, scope, locale) : []).map((topic) => {\n /*\n The title key hangs off the ADDRESS, which makes one formula serve\n both kinds of scope: a resource resolves `doc.topics.<id>`, an\n enum-value variant resolves `enums.<ns>.<value>.doc.topics.<id>`.\n\n `fields.*` / `actions.*` / `tabs.*` additionally fall back to the\n entity's own label, so a name is never written twice.\n */\n const entityKey = /^(fields|actions|tabs)\\./.test(topic.id)\n ? [`${topic.id}.label`, topic.id]\n : [];\n const title =\n resolveContentSlot(\n caps,\n [`${ref?.key ?? 'doc'}.topics.${topic.id}`, ...entityKey],\n opts,\n ) ?? topic.id;\n return { ...topic, title, scope };\n });\n /*\n A scope is an ADDRESS, not necessarily a resource name. `document_document`\n is one; `enum/document_type/work_order` is another, and that is how a\n resource's help splits by kind. Routing both through the same address\n grammar means the panel never has to care which it is looking at.\n */\n const summary = ref ? resolveContentSlot(caps, [`${ref.key}.summary`], opts) : undefined;\n const label = resolveScopeLabel(caps, scope, ref);\n if (topics.length === 0 && summary === undefined) continue;\n out.push({\n scope,\n label,\n ...(summary !== undefined ? { summary } : {}),\n topics,\n });\n }\n return out;\n }, [config, scopes, locale, caps]);\n}\n\n/** One topic of a scope, with its title, or `undefined` when it has no body. */\nexport function useDocTopic(\n scope: string | undefined,\n topicId: string | undefined,\n): DocTopicView | undefined {\n const topics = useDocTopics(scope);\n return topicId === undefined ? undefined : topics.find((t) => t.id === topicId);\n}\n\n/** True when the scope has at least one article — the condition for «Подробнее». */\nexport function useHasDocTopics(scope: string | undefined): boolean {\n return useDocTopics(scope).length > 0;\n}\n\n/**\n * The scope a documentation VARIANT currently resolves to, e.g.\n * `enum/document_type/work_order`, or `null` on a page with no variant.\n *\n * A store rather than React context because of where the two ends live: the\n * breadcrumb sits in the app HEADER and the record is loaded by the PAGE, which\n * is a sibling, not an ancestor. Same reason the panel state is a store.\n */\nfunction useVariantStore(): Store | undefined {\n return useContext(DocsContext)?.variants;\n}\n\n/**\n * Publish the variant of the record on screen. Called by whatever renders a\n * record; clears on unmount so the trail never keeps offering help for a\n * document the reader has navigated away from.\n */\nexport function usePublishDocVariant(\n resource: string | undefined,\n record: Record<string, unknown> | undefined,\n): void {\n const app = useApp();\n const store = useVariantStore();\n const def = resource ? app.registry.get(resource) : undefined;\n const variant = def?.docVariant;\n const value = variant && record ? record[variant.field] : undefined;\n const scope =\n variant && (typeof value === 'string' || typeof value === 'number')\n ? `enum/${variant.enum}/${value}`\n : null;\n\n useEffect(() => {\n if (!store) return;\n store.set({ open: false, target: scope ? { scopes: [scope] } : null, returnFocusTo: null });\n return () => {\n store.set({ open: false, target: null, returnFocusTo: null });\n };\n }, [store, scope]);\n}\n\n/**\n * Scopes the trail should offer for one resource: the resource itself, plus its\n * documentation variant when there is one.\n *\n * The variant is read from the published record first, and from the URL query\n * second — a create screen carries `?type=…` and has no record at all, which is\n * exactly when a reader most wants to know what the thing they are creating is.\n */\nexport function useDocTrailScopes(resource: string | undefined): string[] {\n const app = useApp();\n const store = useVariantStore();\n const subscribe = useCallback((cb: () => void) => store?.subscribe(cb) ?? (() => {}), [store]);\n const getSnapshot = useCallback(() => store?.get().target?.scopes[0] ?? null, [store]);\n const published = useSyncExternalStore(subscribe, getSnapshot, () => null);\n\n return useMemo(() => {\n if (!resource) return [];\n const def = app.registry.get(resource);\n /*\n An explicit mapping wins outright. A resource that is a VIEW onto another\n one — the playground's `doc_order_code` is `document_document` filtered to\n one type — cannot be related to its source by anything in the registry:\n they share a table, not a declaration. Left to infer, both its own list\n AND the shared detail page reached from it showed no help at all, because\n the breadcrumb roots at the per-type resource and asked IT.\n */\n if (def?.docScopes && def.docScopes.length > 0) return def.docScopes;\n const variant = def?.docVariant;\n /*\n MOST SPECIFIC FIRST. A reader on a code order is asking about a code\n order; «что такое документ вообще» is the fallback they widen to, not the\n thing they came for. Note this is the opposite of the HANDBOOK, where the\n type is nested UNDER the resource — the handbook shows structure, the\n panel shows relevance, and those are different orderings on purpose.\n */\n if (!variant) return [resource];\n if (published) return [published, resource];\n if (typeof window !== 'undefined') {\n const fromUrl = new URLSearchParams(window.location.search).get(variant.field);\n if (fromUrl) return [`enum/${variant.enum}/${fromUrl}`, resource];\n }\n return [resource];\n }, [app, resource, published]);\n}\n\n/** True when anything in the trail is documented — the condition for the «?». */\nexport function useTrailHasDocs(scopes: readonly string[]): boolean {\n return useDocScopes(scopes).length > 0;\n}\n\n/** Re-exported so consumers need not reach into core for the lookup. */\nexport { resolveDocLoader };\n\n/** One documented area, in the order a handbook should list them. */\nexport interface DocumentedScope {\n /** Doc address, and the key into `DocsConfig.sources`. */\n scope: string;\n /** A glossary term, a resource, or one kind of a resource. */\n kind: 'concept' | 'resource' | 'variant';\n /** For a variant: the resource it belongs under. */\n owner?: string;\n}\n\n/**\n * Every area the reader may browse, ordered: glossary terms first, then each\n * resource with its own kinds nested under it.\n *\n * EXPORTED, and that is the point. This enumeration existed twice — once in the\n * handbook and once in the command palette — and the palette's copy accepted\n * only scopes matching a registered resource. So `concept/gtin` and\n * `enum/document_type/order_code` were dropped from it: ⌘K → «GTIN» returned a\n * packing-config record and not the glossary article, and the whole glossary\n * plus every per-type article were unreachable from the one control people\n * actually use to look things up. Fixing the handbook's copy alone left that\n * standing. One function, two callers, one behaviour.\n *\n * Only scopes the registry knows are listed: a palette that surfaced topics for\n * entities the reader's role cannot see would leak the shape of the app.\n */\nexport function useDocumentedScopes(): DocumentedScope[] {\n const app = useApp();\n const config = useDocsConfig();\n const caps = useI18nCaps();\n\n return useMemo(() => {\n if (!config) return [];\n const resources = app.registry.list();\n const hasArticles = (scope: string) => config.sources[scope] !== undefined;\n const out: DocumentedScope[] = [];\n\n for (const name of config.concepts ?? []) {\n out.push({ scope: `concept/${name}`, kind: 'concept' });\n }\n\n for (const r of resources) {\n /*\n Variants come from the ENUM REGISTRY, not from the article map: a type\n documented with a summary and no `.md` is still a documented type.\n Loader-backed enums expose nothing synchronously, so those contribute\n only the variants that do have articles.\n */\n const variants = new Set<string>();\n const ns = r.docVariant?.enum;\n if (ns !== undefined) {\n for (const v of app.registry.enums.get(ns)?.values ?? []) {\n const scope = `enum/${ns}/${v.value}`;\n if (hasArticles(scope) || resolveDoc(caps, scope)) variants.add(scope);\n }\n for (const scope of Object.keys(config.sources)) {\n if (scope.startsWith(`enum/${ns}/`)) variants.add(scope);\n }\n }\n\n const summary = resolveDoc(caps, r.name)?.summary;\n if (!hasArticles(r.name) && summary === undefined && variants.size === 0) continue;\n out.push({ scope: r.name, kind: 'resource' });\n for (const scope of [...variants].sort()) {\n out.push({ scope, kind: 'variant', owner: r.name });\n }\n }\n return out;\n }, [app, config, caps]);\n}\n","import type { FieldImplementation, FieldImplementationLayout } from './types.js';\n\n/**\n * Trusted React handles for one provider tree. The keys are deliberately the\n * portable field `format` or `type` values; components themselves never enter\n * a declaration, runtime snapshot, or serialized manifest.\n */\nexport type FieldImplementationCatalog = Readonly<Record<string, FieldImplementation<any, any>>>;\n\nexport type FieldImplementationMap = FieldImplementationCatalog;\n\nexport const EMPTY_FIELD_IMPLEMENTATIONS: FieldImplementationCatalog = Object.freeze({});\n\nfunction assertId(id: string): void {\n if (typeof id !== 'string' || id.trim().length === 0) {\n throw new TypeError('A field implementation ID must be a non-empty string.');\n }\n}\n\nfunction copyLayout(value: unknown, id: string): FieldImplementationLayout | undefined {\n if (value === undefined) return undefined;\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new TypeError(`Field implementation '${id}' layout must be an object.`);\n }\n const layout = value as { readonly fullWidth?: unknown };\n if (\n Object.keys(layout).some((key) => key !== 'fullWidth') ||\n (layout.fullWidth !== undefined && typeof layout.fullWidth !== 'boolean')\n ) {\n throw new TypeError(\n `Field implementation '${id}' layout must contain only an optional boolean fullWidth.`,\n );\n }\n return Object.freeze({\n ...(layout.fullWidth === undefined ? {} : { fullWidth: layout.fullWidth }),\n });\n}\n\nfunction copyImplementation(id: string, value: unknown): FieldImplementation<any, any> {\n assertId(id);\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new TypeError(`Field implementation '${id}' must be an object.`);\n }\n const implementation = value as FieldImplementation<any, any>;\n const keys = ['Input', 'Display', 'CollectionInput', 'CollectionDisplay', 'layout'];\n if (Object.keys(implementation).some((key) => !keys.includes(key))) {\n throw new TypeError(`Field implementation '${id}' contains an unsupported key.`);\n }\n const renderers = {\n Input: implementation.Input,\n Display: implementation.Display,\n CollectionInput: implementation.CollectionInput,\n CollectionDisplay: implementation.CollectionDisplay,\n };\n for (const [name, renderer] of Object.entries(renderers)) {\n if (renderer !== undefined && typeof renderer !== 'function') {\n throw new TypeError(`Field implementation '${id}' ${name} must be a React component.`);\n }\n }\n if (Object.values(renderers).every((renderer) => renderer === undefined)) {\n throw new TypeError(`Field implementation '${id}' must define at least one render surface.`);\n }\n return Object.freeze({\n ...(implementation.Input === undefined ? {} : { Input: implementation.Input }),\n ...(implementation.Display === undefined ? {} : { Display: implementation.Display }),\n ...(implementation.CollectionInput === undefined\n ? {}\n : { CollectionInput: implementation.CollectionInput }),\n ...(implementation.CollectionDisplay === undefined\n ? {}\n : { CollectionDisplay: implementation.CollectionDisplay }),\n ...(implementation.layout === undefined\n ? {}\n : { layout: copyLayout(implementation.layout, id) }),\n });\n}\n\n/**\n * Compose immutable host catalogs. Later catalogs intentionally override\n * earlier ones, so an application can layer a local implementation over a\n * shared package catalog without mutating either input.\n */\nexport function composeFieldImplementations(\n ...catalogs: readonly FieldImplementationCatalog[]\n): FieldImplementationCatalog {\n const output: Record<string, FieldImplementation<any, any>> = {};\n for (const catalog of catalogs) {\n if (catalog === null || typeof catalog !== 'object' || Array.isArray(catalog)) {\n throw new TypeError('Field implementations must be a record keyed by implementation ID.');\n }\n for (const [id, implementation] of Object.entries(catalog)) {\n output[id] = copyImplementation(id, implementation);\n }\n }\n return Object.freeze(output);\n}\n","import { createContext, useContext, useMemo, type ReactElement, type ReactNode } from 'react';\nimport {\n EMPTY_FIELD_IMPLEMENTATIONS,\n composeFieldImplementations,\n type FieldImplementationCatalog,\n} from './definitions.js';\n\nconst FieldImplementationCatalogContext = createContext<FieldImplementationCatalog | null>(null);\n\nexport interface FieldImplementationProviderProps {\n readonly fieldImplementations?: FieldImplementationCatalog;\n readonly children: ReactNode;\n}\n\n/**\n * A host-local implementation boundary. Unlike the retired attachment path,\n * this never subscribes to or mutates an AppRuntime; one SSR tree cannot\n * publish code into another tree.\n */\nexport function FieldImplementationProvider({\n fieldImplementations = EMPTY_FIELD_IMPLEMENTATIONS,\n children,\n}: FieldImplementationProviderProps): ReactElement {\n const catalog = useMemo(\n () => composeFieldImplementations(fieldImplementations),\n [fieldImplementations],\n );\n return (\n <FieldImplementationCatalogContext.Provider value={catalog}>\n {children}\n </FieldImplementationCatalogContext.Provider>\n );\n}\n\nexport function useFieldImplementationCatalog(): FieldImplementationCatalog {\n const catalog = useContext(FieldImplementationCatalogContext);\n if (catalog === null) {\n throw new Error(\n 'useFieldImplementation must be used within a BuroProvider or FieldImplementationProvider.',\n );\n }\n return catalog;\n}\n","import {\n resolveManifest,\n serializePortableManifest,\n type AppDefinition,\n type ApplicationSnapshot,\n type LayerRuntime,\n type ManifestFingerprint,\n type ManifestResolution,\n type PortableSnapshotManifest,\n} from '@burojs/core';\n\n/**\n * The portable server snapshot and the static definition which can safely\n * rebuild its framework-owned lookup identities. Request context, services,\n * and other runtime attachments deliberately do not belong here.\n */\nexport interface InitialManifest {\n readonly definition: AppDefinition;\n readonly manifest: PortableSnapshotManifest;\n}\n\nconst SCOPE_SNAPSHOTS: unique symbol = Symbol('buro.manifestHydrationSnapshots');\n\n/** A host/request-owned cache for one server/client manifest handoff. */\nexport interface ManifestHydrationScope {\n readonly [SCOPE_SNAPSHOTS]: Map<\n string,\n {\n readonly serializedManifest: string;\n readonly snapshot: ApplicationSnapshot;\n }\n >;\n}\n\nexport function createManifestHydrationScope(): ManifestHydrationScope {\n return Object.freeze({ [SCOPE_SNAPSHOTS]: new Map() });\n}\n\nexport type ManifestHydration =\n | {\n readonly status: 'hydrated';\n readonly runtime: LayerRuntime;\n readonly snapshot: ApplicationSnapshot;\n activate(): void;\n dispose(): void;\n }\n | {\n readonly status: 'fallback';\n readonly runtime: LayerRuntime;\n readonly snapshot: ApplicationSnapshot;\n readonly verification: Extract<ManifestResolution, { readonly status: 'mismatch' }>;\n activate(): void;\n dispose(): void;\n };\n\nfunction fingerprintOf(snapshot: ApplicationSnapshot): ManifestFingerprint {\n const { compilerVersion, definitionFingerprint, implementationCatalogFingerprint } =\n snapshot.manifest;\n return { compilerVersion, definitionFingerprint, implementationCatalogFingerprint };\n}\n\nconst MAX_RECONSTRUCTED_SNAPSHOTS = 64;\n\nfunction fingerprintKey(fingerprint: ManifestFingerprint): string {\n return `${fingerprint.compilerVersion}\\u0000${fingerprint.definitionFingerprint}\\u0000${fingerprint.implementationCatalogFingerprint}`;\n}\n\nfunction cachedSnapshot(\n manifest: PortableSnapshotManifest,\n fingerprint: ManifestFingerprint,\n snapshot: ApplicationSnapshot,\n scope: ManifestHydrationScope,\n): ApplicationSnapshot {\n // `snapshotId` is the transport identity, but the canonical payload must\n // agree too: a hostile or stale payload must never borrow an unrelated\n // in-process snapshot merely by repeating that ID.\n const serializedManifest = serializePortableManifest(manifest);\n const key = `${fingerprintKey(fingerprint)}\\u0000${manifest.snapshotId}`;\n const snapshots = scope[SCOPE_SNAPSHOTS];\n const existing = snapshots.get(key);\n if (existing?.serializedManifest === serializedManifest) {\n snapshots.delete(key);\n snapshots.set(key, existing);\n return existing.snapshot;\n }\n snapshots.set(key, { serializedManifest, snapshot });\n if (snapshots.size > MAX_RECONSTRUCTED_SNAPSHOTS) {\n const oldest = snapshots.keys().next().value as string | undefined;\n if (oldest !== undefined) snapshots.delete(oldest);\n }\n return snapshot;\n}\n\nfunction runtimeWithInitialSnapshot(\n runtime: LayerRuntime,\n initialSnapshot: ApplicationSnapshot,\n): LayerRuntime {\n let hasPublished = false;\n let observedRuntimeSnapshot = runtime.getSnapshot();\n let stopObserving: (() => void) | undefined;\n const listeners = new Set<() => void>();\n const activate = (): void => {\n if (stopObserving !== undefined) return;\n const currentSnapshot = runtime.getSnapshot();\n if (!Object.is(currentSnapshot, observedRuntimeSnapshot)) {\n hasPublished = true;\n }\n observedRuntimeSnapshot = currentSnapshot;\n // Snapshot IDs may repeat after a publication, so snapshot object identity\n // detects a publication that occurred while this adapter was inactive.\n stopObserving = runtime.subscribe(() => {\n hasPublished = true;\n observedRuntimeSnapshot = runtime.getSnapshot();\n for (const listener of [...listeners]) listener();\n });\n };\n const dispose = (): void => {\n stopObserving?.();\n stopObserving = undefined;\n listeners.clear();\n };\n const getSnapshot = (): ApplicationSnapshot => {\n return hasPublished ? runtime.getSnapshot() : initialSnapshot;\n };\n return Object.freeze(\n Object.defineProperties(Object.create(runtime), {\n getSnapshot: { value: getSnapshot, enumerable: true },\n getServerSnapshot: { value: getSnapshot, enumerable: true },\n subscribe: {\n value: (listener: () => void) => {\n listeners.add(listener);\n activate();\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) dispose();\n };\n },\n enumerable: true,\n },\n activateManifestHydration: { value: activate, enumerable: false },\n disposeManifestHydration: { value: dispose, enumerable: false },\n }),\n ) as LayerRuntime;\n}\n\n/**\n * Verifies and reconstructs a server-provided portable manifest for one\n * already-created runtime. A fingerprint mismatch is deliberately non-fatal:\n * the host keeps its local request-scoped runtime and can render a controlled\n * fallback instead of binding stale server declarations to local code.\n */\nexport function hydrateManifest(\n runtime: LayerRuntime,\n initialManifest: InitialManifest,\n scope: ManifestHydrationScope = createManifestHydrationScope(),\n): ManifestHydration {\n const fallback = runtime.getSnapshot();\n const fingerprint = fingerprintOf(fallback);\n const resolution = resolveManifest(\n initialManifest.manifest,\n initialManifest.definition,\n fingerprint,\n );\n if (resolution.status === 'mismatch') {\n return Object.freeze({\n status: 'fallback' as const,\n runtime,\n snapshot: fallback,\n verification: resolution,\n activate: () => undefined,\n dispose: () => undefined,\n });\n }\n const snapshot = cachedSnapshot(\n initialManifest.manifest,\n fingerprint,\n resolution.snapshot,\n scope,\n );\n const hydratedRuntime = runtimeWithInitialSnapshot(runtime, snapshot) as LayerRuntime & {\n activateManifestHydration(): void;\n disposeManifestHydration(): void;\n };\n return Object.freeze({\n status: 'hydrated' as const,\n runtime: hydratedRuntime,\n snapshot,\n activate: () => hydratedRuntime.activateManifestHydration(),\n dispose: () => hydratedRuntime.disposeManifestHydration(),\n });\n}\n","/**\n * The default browser `localStorage`-backed `UiSettingsAdapter`.\n *\n * One framework-owned scope (`buro:local-user`) covers every entry this\n * adapter ever produces — there is exactly one browser, one local user. Each\n * `open()` call stores at most one versioned JSON envelope under a single\n * `localStorage` key derived from the canonical `typeId`/`params` pair\n * (`buro:ui-settings:v1:<encoded-key>`); a singleton collection's\n * envelope holds at most one entry, a collection's holds any number.\n *\n * This module is the ERASED adapter boundary (see `@burojs/core`'s\n * `./adapter.ts`): it receives portable `typeId`/`params`/`valueVersion`,\n * never a typed `UiSettingTypeDefinition`, and every value it reads back out\n * of storage is opaque `unknown` — core validates and clones it on the way\n * back in through `createUiSettingsStore`.\n *\n * SSR safety: every `window`/`localStorage` access is guarded by\n * `typeof window === 'undefined'`. Opening a collection during server\n * render (or with `localStorage` unavailable — private browsing, a locked\n * down iframe) yields an empty, ready snapshot and never throws; the real\n * client-side content is picked up the moment `open()` next runs in a\n * browser (see `provider.tsx`'s no-adapter fallback, which constructs a\n * fresh adapter/store per mounted tree rather than reusing one across a\n * server/client boundary).\n */\n\nimport type {\n UiSettingCardinality,\n UiSettingEntry,\n UiSettingEntryPermissions,\n UiSettingMutationResult,\n UiSettingScope,\n UiSettingsAdapter,\n UiSettingsAdapterCollection,\n UiSettingsAdapterOpenInput,\n UiSettingsAdapterSnapshot,\n UiSettingsIssue,\n} from '@burojs/core';\n\n/**\n * The one framework-owned scope every entry this adapter creates belongs\n * to. Task 9 recognizes entries by this EXACT `id` and swaps `label`\n * reactively through i18n — every other part of the framework must keep\n * treating it as an ordinary opaque `UiSettingScope`, never special-casing\n * its id itself.\n */\nexport const LOCAL_USER_SCOPE_ID = 'buro:local-user';\n\nconst LOCAL_USER_SCOPE: UiSettingScope = Object.freeze({\n id: LOCAL_USER_SCOPE_ID,\n label: 'My settings',\n});\n\n/** The user owns their own local settings outright — every permission is granted. */\nconst FULL_PERMISSIONS: UiSettingEntryPermissions = Object.freeze({\n update: true,\n remove: true,\n fork: true,\n export: true,\n});\n\nconst STORAGE_KEY_PREFIX = 'buro:ui-settings:v1:';\nconst ENVELOPE_FORMAT_VERSION = 1 as const;\n\nexport interface LocalStorageUiSettingsAdapterOptions {\n /**\n * Overrides the `Storage` instance the adapter reads/writes. Defaults to\n * `window.localStorage`, resolved lazily (never at construction time) so\n * constructing the adapter itself is always SSR-safe. Tests use this to\n * inject an isolated in-memory `Storage`, share one fake store across two\n * adapter instances (simulating two tabs), or simulate quota failures.\n */\n readonly storage?: Storage;\n}\n\n/** One entry as persisted on disk — the scope/permissions are NOT stored, since both are constant. */\ninterface StoredEntryRecord {\n readonly id: string;\n readonly label?: string;\n readonly value: unknown;\n readonly revision: string;\n readonly createdAt: string;\n readonly updatedAt: string;\n}\n\ninterface StoredEnvelope {\n readonly formatVersion: typeof ENVELOPE_FORMAT_VERSION;\n readonly cardinality: UiSettingCardinality;\n readonly valueVersion: number;\n readonly entries: readonly StoredEntryRecord[];\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isStoredEntryRecord(value: unknown): value is StoredEntryRecord {\n if (!isPlainObject(value)) return false;\n if (typeof value.id !== 'string' || value.id.length === 0) return false;\n if (typeof value.revision !== 'string' || value.revision.length === 0) return false;\n if (typeof value.createdAt !== 'string' || typeof value.updatedAt !== 'string') return false;\n if (value.label !== undefined && typeof value.label !== 'string') return false;\n return true;\n}\n\nfunction computeStorageKey(typeId: string, params: unknown): string {\n const canonical = JSON.stringify([typeId, params]);\n return `${STORAGE_KEY_PREFIX}${encodeURIComponent(canonical)}`;\n}\n\nlet localIdCounter = 0;\n\n/** Collision-resistant entry/revision id. Prefers `crypto.randomUUID`; falls back when unavailable. */\nfunction newLocalId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n localIdCounter += 1;\n return `local-${Date.now().toString(36)}-${localIdCounter.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction toPublicEntry(record: StoredEntryRecord): UiSettingEntry<unknown> {\n return Object.freeze({\n id: record.id,\n ...(record.label === undefined ? {} : { label: record.label }),\n value: record.value,\n scope: LOCAL_USER_SCOPE,\n permissions: FULL_PERMISSIONS,\n revision: record.revision,\n createdAt: record.createdAt,\n updatedAt: record.updatedAt,\n });\n}\n\nfunction buildSnapshot(\n entries: readonly StoredEntryRecord[],\n issues: readonly UiSettingsIssue[],\n): UiSettingsAdapterSnapshot {\n return {\n entries: entries.map(toPublicEntry),\n writeScopes: [LOCAL_USER_SCOPE],\n pending: false,\n issues,\n };\n}\n\nfunction rejected(issues: readonly UiSettingsIssue[]): UiSettingMutationResult<unknown> {\n return { status: 'rejected', issues };\n}\n\nfunction corruptedEnvelopeIssue(storageKey: string, error: unknown): UiSettingsIssue {\n return {\n code: 'local-storage-envelope-corrupted',\n message:\n `Stored UI settings at \"${storageKey}\" could not be read and were ignored: ` +\n `${error instanceof Error ? error.message : String(error)}`,\n severity: 'warning',\n };\n}\n\nfunction unreadableStorageIssue(storageKey: string, error: unknown): UiSettingsIssue {\n return {\n code: 'local-storage-unreadable',\n message:\n `Stored UI settings at \"${storageKey}\" could not be read from localStorage: ` +\n `${error instanceof Error ? error.message : String(error)}`,\n severity: 'warning',\n };\n}\n\nfunction unavailableIssue(): UiSettingsIssue {\n return {\n code: 'local-storage-unavailable',\n message:\n 'localStorage is not available in this environment (server render or a blocked browser context).',\n severity: 'error',\n };\n}\n\nfunction writeFailedIssue(error: unknown): UiSettingsIssue {\n const quota =\n (typeof DOMException !== 'undefined' &&\n error instanceof DOMException &&\n (error.name === 'QuotaExceededError' || error.code === 22 || error.code === 1014)) ||\n (error instanceof Error && /quota/i.test(error.message));\n return {\n code: quota ? 'local-storage-quota-exceeded' : 'local-storage-write-failed',\n message: error instanceof Error ? error.message : 'Writing UI settings to localStorage failed.',\n severity: 'error',\n };\n}\n\nfunction invalidScopeIssue(scopeId: string): UiSettingsIssue {\n return {\n code: 'local-storage-invalid-scope',\n message: `Scope \"${scopeId}\" is not writable; only \"${LOCAL_USER_SCOPE_ID}\" is.`,\n severity: 'error',\n scopeId,\n };\n}\n\nfunction entryNotFoundIssue(entryId: string): UiSettingsIssue {\n return {\n code: 'local-storage-entry-not-found',\n message: `UI setting entry \"${entryId}\" does not exist.`,\n severity: 'error',\n entryId,\n };\n}\n\n/** Reads and parses the envelope for `storageKey`. Never throws — corruption degrades to empty + an issue. */\nfunction readEnvelope(\n storage: Storage,\n storageKey: string,\n): { entries: StoredEntryRecord[]; issues: UiSettingsIssue[] } {\n let raw: string | null;\n try {\n raw = storage.getItem(storageKey);\n } catch (error) {\n return { entries: [], issues: [unreadableStorageIssue(storageKey, error)] };\n }\n if (raw === null) return { entries: [], issues: [] };\n try {\n const parsed: unknown = JSON.parse(raw);\n if (!isPlainObject(parsed) || !Array.isArray(parsed.entries)) {\n throw new Error('stored value is not a UI settings envelope');\n }\n const entries = parsed.entries.filter(isStoredEntryRecord);\n return { entries, issues: [] };\n } catch (error) {\n return { entries: [], issues: [corruptedEnvelopeIssue(storageKey, error)] };\n }\n}\n\nfunction persistEnvelope(\n storage: Storage,\n storageKey: string,\n cardinality: UiSettingCardinality,\n valueVersion: number,\n entries: readonly StoredEntryRecord[],\n): { ok: true } | { ok: false; issue: UiSettingsIssue } {\n const envelope: StoredEnvelope = {\n formatVersion: ENVELOPE_FORMAT_VERSION,\n cardinality,\n valueVersion,\n entries,\n };\n try {\n storage.setItem(storageKey, JSON.stringify(envelope));\n return { ok: true };\n } catch (error) {\n return { ok: false, issue: writeFailedIssue(error) };\n }\n}\n\nfunction resolveStorage(options: LocalStorageUiSettingsAdapterOptions): Storage | undefined {\n if (options.storage !== undefined) return options.storage;\n if (typeof window === 'undefined') return undefined;\n try {\n return window.localStorage;\n } catch {\n return undefined;\n }\n}\n\nfunction sameEntries(a: readonly StoredEntryRecord[], b: readonly StoredEntryRecord[]): boolean {\n return a.length === b.length && JSON.stringify(a) === JSON.stringify(b);\n}\n\nfunction openCollection(\n input: UiSettingsAdapterOpenInput,\n options: LocalStorageUiSettingsAdapterOptions,\n): UiSettingsAdapterCollection {\n const storageKey = computeStorageKey(input.typeId, input.params);\n const listeners = new Set<() => void>();\n let disposed = false;\n let entries: StoredEntryRecord[] = [];\n let issues: readonly UiSettingsIssue[] = [];\n let currentSnapshot: UiSettingsAdapterSnapshot;\n\n function commit(nextEntries: StoredEntryRecord[], nextIssues: readonly UiSettingsIssue[]): void {\n entries = nextEntries;\n issues = nextIssues;\n currentSnapshot = buildSnapshot(entries, issues);\n }\n\n function notify(): void {\n for (const listener of Array.from(listeners)) listener();\n }\n\n /** Re-reads storage and, only on an actual content change, updates the snapshot and notifies. */\n function resync(): void {\n const storage = resolveStorage(options);\n if (storage === undefined) return;\n const loaded = readEnvelope(storage, storageKey);\n if (\n sameEntries(loaded.entries, entries) &&\n JSON.stringify(loaded.issues) === JSON.stringify(issues)\n )\n return;\n commit(loaded.entries, loaded.issues);\n notify();\n }\n\n // SSR-safe initial snapshot: always empty and ready, SYNCHRONOUSLY — this\n // is exactly what a server render produces (no `window`). `useUiSettings`\n // (Task 6, `use-ui-settings.ts:211`) passes THIS SAME `getSnapshot` as\n // both the live snapshot getter AND the `getServerSnapshot` argument to\n // `useSyncExternalStore`. If real `localStorage` content were read\n // synchronously right here, the client's hydration-matching render could\n // return something DIFFERENT from what the server rendered — React reports\n // that as a hydration content mismatch. So the real first read is\n // deferred by one microtask tick (below) — after hydration-matching has\n // already happened — and arrives as an ordinary async update (commit +\n // notify), exactly like a live cross-tab storage-event resync. Mutations\n // are NOT affected: `create`/`update`/`set`/`remove` still commit\n // synchronously, since those only ever run after mount, never during a\n // render pass.\n commit([], []);\n // `queueMicrotask` exists in Node too, so this also runs on the server —\n // harmlessly: `resync`'s own `resolveStorage` guard is a no-op there,\n // since there is no `window` (and no injected `options.storage`, in the\n // real no-adapter-fallback path) to read from.\n queueMicrotask(() => {\n if (disposed) return;\n resync();\n });\n\n function onStorageEvent(event: StorageEvent): void {\n if (event.key !== null && event.key !== storageKey) return;\n resync();\n }\n\n const hasDom = typeof window !== 'undefined';\n if (hasDom) {\n window.addEventListener('storage', onStorageEvent);\n }\n\n /**\n * Shared write tail for every mutator below: persist `nextEntries`, and\n * only on a successful write commit the new snapshot + notify subscribers\n * (a failed write leaves the last good snapshot's object identity intact —\n * see the quota-exceeded tests).\n */\n function persistAndCommit(\n storage: Storage,\n nextEntries: StoredEntryRecord[],\n ): { ok: true } | { ok: false; issue: UiSettingsIssue } {\n const persisted = persistEnvelope(\n storage,\n storageKey,\n input.cardinality,\n input.valueVersion,\n nextEntries,\n );\n if (!persisted.ok) return persisted;\n commit(nextEntries, []);\n notify();\n return persisted;\n }\n\n async function create(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as { scopeId: string; label?: string; value: unknown };\n if (parsed.scopeId !== LOCAL_USER_SCOPE_ID)\n return rejected([invalidScopeIssue(parsed.scopeId)]);\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const now = nowIso();\n const record: StoredEntryRecord = {\n id: newLocalId(),\n ...(parsed.label === undefined ? {} : { label: parsed.label }),\n value: parsed.value,\n revision: newLocalId(),\n createdAt: now,\n updatedAt: now,\n };\n const nextEntries = [...entries, record];\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: 'created', entry: toPublicEntry(record) };\n }\n\n async function update(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as {\n id: string;\n label?: string;\n value: unknown;\n expectedRevision?: string;\n };\n const existing = entries.find((candidate) => candidate.id === parsed.id);\n if (existing === undefined) return rejected([entryNotFoundIssue(parsed.id)]);\n if (parsed.expectedRevision !== undefined && parsed.expectedRevision !== existing.revision) {\n return { status: 'conflict', current: toPublicEntry(existing) };\n }\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const updated: StoredEntryRecord = {\n ...existing,\n ...(parsed.label === undefined ? {} : { label: parsed.label }),\n value: parsed.value,\n revision: newLocalId(),\n updatedAt: nowIso(),\n };\n const nextEntries = entries.map((candidate) =>\n candidate.id === parsed.id ? updated : candidate,\n );\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: 'updated', entry: toPublicEntry(updated) };\n }\n\n async function set(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as { scopeId: string; value: unknown; expectedRevision?: string };\n if (parsed.scopeId !== LOCAL_USER_SCOPE_ID)\n return rejected([invalidScopeIssue(parsed.scopeId)]);\n // Singleton invariant: at most one entry ever exists for this collection.\n const existing = entries[0];\n if (\n existing !== undefined &&\n parsed.expectedRevision !== undefined &&\n parsed.expectedRevision !== existing.revision\n ) {\n return { status: 'conflict', current: toPublicEntry(existing) };\n }\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const now = nowIso();\n const record: StoredEntryRecord =\n existing === undefined\n ? {\n id: newLocalId(),\n value: parsed.value,\n revision: newLocalId(),\n createdAt: now,\n updatedAt: now,\n }\n : { ...existing, value: parsed.value, revision: newLocalId(), updatedAt: now };\n const nextEntries = [record];\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: existing === undefined ? 'created' : 'updated', entry: toPublicEntry(record) };\n }\n\n async function remove(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as { id: string; expectedRevision?: string };\n const existing = entries.find((candidate) => candidate.id === parsed.id);\n // Removing an already-absent entry is idempotent success — nothing left to reject.\n if (existing === undefined) return { status: 'removed' };\n if (parsed.expectedRevision !== undefined && parsed.expectedRevision !== existing.revision) {\n return { status: 'conflict', current: toPublicEntry(existing) };\n }\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const nextEntries = entries.filter((candidate) => candidate.id !== parsed.id);\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: 'removed' };\n }\n\n const shared = {\n getSnapshot(): UiSettingsAdapterSnapshot {\n return currentSnapshot;\n },\n subscribe(listener: () => void): () => void {\n if (disposed) return () => {};\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n refresh(): void {\n if (disposed) return;\n resync();\n },\n dispose(): void {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n if (hasDom) window.removeEventListener('storage', onStorageEvent);\n },\n remove,\n };\n\n return input.cardinality === 'collection' ? { ...shared, create, update } : { ...shared, set };\n}\n\n/**\n * Creates the default browser `localStorage`-backed `UiSettingsAdapter`.\n * One collection is opened per canonical `typeId`/`params` pair (Task 3's\n * `createUiSettingsStore` already deduplicates opens sharing a key, so this\n * factory never sees two live collections for the same key at once); each\n * one owns its own `localStorage` key and its own cross-tab `storage`\n * listener, independent of every other open collection.\n */\nexport function createLocalStorageUiSettingsAdapter(\n options: LocalStorageUiSettingsAdapterOptions = {},\n): UiSettingsAdapter {\n return {\n open(input: UiSettingsAdapterOpenInput): UiSettingsAdapterCollection {\n return openCollection(input, options);\n },\n };\n}\n","import type { UiSettingsStore } from '@burojs/core';\nimport { createContext } from 'react';\n\n/**\n * Holds exactly one caller-owned `UiSettingsStore` (see `@burojs/core`).\n * `null` means no `UiSettingsProvider` is mounted above — `useUiSettings`\n * turns that into a thrown, actionable error rather than a silent no-op.\n *\n * The provider never disposes the store it receives (same convention as\n * `DataRuntimeContext`/`DataRuntimeLease`): construction and disposal stay\n * the caller's responsibility. The default local-storage-backed store lands\n * in Task 7 — this context only ever carries what a caller explicitly\n * supplies.\n */\nexport const UiSettingsStoreContext = createContext<UiSettingsStore | null>(null);\n","import type { UiSettingsStore } from '@burojs/core';\nimport type { ReactElement, ReactNode } from 'react';\nimport { UiSettingsStoreContext } from './context.js';\n\nexport interface UiSettingsProviderProps {\n /**\n * Externally owned live UI settings store (`createUiSettingsStore` from\n * `@burojs/core`). This provider only attaches it to the React tree —\n * it never disposes it, matching `DataRuntimeProvider`'s treatment of a\n * caller-owned `DataRuntimeLease`.\n */\n readonly store: UiSettingsStore;\n readonly children: ReactNode;\n}\n\n/**\n * Attaches a caller-owned `UiSettingsStore` to the React tree so\n * `useUiSettings` can resolve it. Mount one of these per app/runtime\n * boundary — two providers with two different stores never share entries,\n * subscriptions, or mutations, since each `UiSettingsStore` instance owns\n * its own adapter collections.\n */\nexport function UiSettingsProvider({ store, children }: UiSettingsProviderProps): ReactElement {\n return (\n <UiSettingsStoreContext.Provider value={store}>{children}</UiSettingsStoreContext.Provider>\n );\n}\n","import type { UIActivationContext, UIActivationSurface, UIPresentationRuntime } from '@burojs/core';\nimport { createContext, useContext, type ReactNode } from 'react';\n\n/**\n * What a component presented via `useUIPresent` sees about itself: the\n * runtime-assigned id, a way to close itself, and the activation it was\n * launched with (captured once, at present-time, by the runtime — see\n * `@burojs/core`'s `presentation-runtime.ts`).\n */\nexport interface UIInstance {\n readonly id: string;\n dismiss(): void;\n readonly activation: UIActivationContext;\n}\n\n/** The subset of `UIInstance` a component only needs for a close affordance. */\nexport interface UIPresentationLifecycle {\n dismiss(): void;\n}\n\nconst UIInstanceContext = createContext<UIInstance | null>(null);\nconst UIPresentationContext = createContext<UIPresentationLifecycle | undefined>(undefined);\nconst UIActivationSurfaceContext = createContext<UIActivationSurface | undefined>(undefined);\nconst UIPresentationRuntimeContext = createContext<UIPresentationRuntime | null>(null);\n\n/**\n * Frames the activation surface (the \"why\" behind a presentation) for\n * everything rendered underneath — e.g. a resource show page wraps its tree\n * so any `useUIPresent()` call inside picks up `{ type: 'item', ... }`\n * without every call site having to repeat it.\n */\nexport function UIActivationSurfaceProvider({\n surface,\n children,\n}: {\n readonly surface: UIActivationSurface;\n readonly children: ReactNode;\n}) {\n return (\n <UIActivationSurfaceContext.Provider value={surface}>\n {children}\n </UIActivationSurfaceContext.Provider>\n );\n}\n\n/** The nearest `UIActivationSurfaceProvider` frame, or `undefined` outside one. */\nexport function useOptionalUIActivationSurface(): UIActivationSurface | undefined {\n return useContext(UIActivationSurfaceContext);\n}\n\n/** Supplies the `UIPresentationRuntime` instance `useUIPresent` presents into. */\nexport function UIPresentationRuntimeProvider({\n runtime,\n children,\n}: {\n readonly runtime: UIPresentationRuntime;\n readonly children: ReactNode;\n}) {\n return (\n <UIPresentationRuntimeContext.Provider value={runtime}>\n {children}\n </UIPresentationRuntimeContext.Provider>\n );\n}\n\n/** The runtime supplied by the nearest `UIPresentationRuntimeProvider`; throws otherwise. */\nexport function useUIPresentationRuntime(): UIPresentationRuntime {\n const runtime = useContext(UIPresentationRuntimeContext);\n if (runtime === null) {\n throw new Error('useUIPresent must be used within a UIPresentationRuntimeProvider.');\n }\n return runtime;\n}\n\n/** The current `UIInstance`; throws when called outside a presented component. */\nexport function useUIInstance(): UIInstance {\n const instance = useOptionalUIInstance();\n if (instance === null) {\n throw new Error('useUIInstance must be used inside a component presented via useUIPresent.');\n }\n return instance;\n}\n\n/** The current `UIInstance`, or `null` when not inside a presented component. */\nexport function useOptionalUIInstance(): UIInstance | null {\n return useContext(UIInstanceContext);\n}\n\n/** The current dismiss-only lifecycle, or `undefined` when not inside a presented component. */\nexport function useOptionalUIPresentation(): UIPresentationLifecycle | undefined {\n return useContext(UIPresentationContext);\n}\n\n/**\n * Wraps a presented component's tree with its `UIInstance` (and, optionally,\n * a narrower dismiss-only `presentation` lifecycle for children that only\n * need a close affordance). The host renderer that turns a\n * `UIPresentationDescriptor` into a mounted component (Task 4+) is the\n * expected — not the only possible — caller.\n */\nexport function UIInstanceProvider({\n instance,\n presentation,\n children,\n}: {\n readonly instance: UIInstance;\n readonly presentation?: UIPresentationLifecycle;\n readonly children: ReactNode;\n}) {\n return (\n <UIInstanceContext.Provider value={instance}>\n <UIPresentationContext.Provider value={presentation}>\n {children}\n </UIPresentationContext.Provider>\n </UIInstanceContext.Provider>\n );\n}\n","import { useContext } from 'react';\nimport { ComponentsContext } from '../context.js';\n\n/**\n * `slot` is optional so that a caller computing a key conditionally can say\n * \"no slot\" directly. Without it the natural spelling is a sentinel string,\n * which the registry would dutifully look up — `undefined` would resolve the\n * literal key `\"undefined\"`, and `''` a key nothing can register.\n */\nexport function useComponent<T = unknown>(slot: string | undefined): T | undefined {\n const components = useContext(ComponentsContext);\n if (slot === undefined || slot === '') return undefined;\n return components[slot] as T | undefined;\n}\n\n/**\n * useDefaultComponent — placeholder for default-component lookup.\n * Real implementation requires the provider to track defaults separately\n * from overrides. For v0.1, we just look up the same slot.\n */\nexport function useDefaultComponent<T = unknown>(slot: string): T | undefined {\n return useComponent<T>(slot);\n}\n","import type { UIPresentationDescriptor, UIPresentationRuntime } from '@burojs/core';\nimport { type ComponentType, type ReactElement, useMemo, useSyncExternalStore } from 'react';\nimport { useComponent } from '../hooks/use-component.js';\nimport { type UIInstance, UIInstanceProvider, useUIPresentationRuntime } from './context.js';\n\n/**\n * What a concrete host (dialog/sheet chrome, supplied by the app — e.g.\n * ui-shadcn) receives for one active presentation: the already-resolved\n * component plus the portable `props`/`options` off the descriptor. The\n * host decides how to frame it (title, width, side, ...); dismissal is read\n * via `useOptionalUIPresentation()` from inside the host or the presented\n * component, since both render under the matching `UIInstanceProvider`.\n */\nexport interface UIPresentationHostProps {\n readonly component: ComponentType<Record<string, unknown>>;\n readonly props: Readonly<Record<string, unknown>>;\n readonly options: Readonly<Record<string, unknown>>;\n}\n\n/**\n * What a host declares it understands about its `options` record: a flat\n * `key → primitive type` map, all keys optional. Anything the host does not\n * list is refused once `useUIPresent` sees the schema. No nesting, no\n * unions, no custom validators — the real vocabulary today is three string\n * keys and one boolean, so a flat map is all this needs to be.\n */\nexport type UIPresentationOptionsSchema = Readonly<Record<string, 'string' | 'boolean' | 'number'>>;\n\n/**\n * A host component keyed by `UIPresentationDescriptor['host']`. May carry an\n * `optionsSchema` static describing the `options` keys it reads; a host\n * without one accepts any options, since hosts are injected by the adopter\n * and third-party hosts have no obligation to describe themselves.\n *\n * Deliberately `ComponentType<...>`, not a bare function-component call\n * signature: a class component, a `React.memo(...)` result, or a\n * `forwardRef(...)` result all satisfy `ComponentType` (and can all carry a\n * static `optionsSchema`), and all three were valid hosts before this type\n * existed. A narrower call-signature alias would silently drop that support\n * at the type level while runtime behaviour stayed identical.\n */\nexport type UIPresentationHost = ComponentType<UIPresentationHostProps> & {\n optionsSchema?: UIPresentationOptionsSchema;\n};\n\n/**\n * Host components keyed by `UIPresentationDescriptor['host']`. Injected, not\n * imported — this keeps `packages/react` DOM-free and independent of any\n * concrete component library. A descriptor whose host has no entry here\n * simply renders nothing (no crash, no console noise): that is the expected\n * shape for an app that has not wired concrete hosts (yet).\n */\nexport type UIPresentationHosts = Readonly<\n Partial<Record<UIPresentationDescriptor['host'], UIPresentationHost>>\n>;\n\nexport interface UIPresentationsProps {\n readonly hosts: UIPresentationHosts;\n}\n\n/**\n * Framework-owned overlay mount. Subscribes to the app's\n * `UIPresentationRuntime` and renders every active descriptor through its\n * injected host, resolving `descriptor.component` from the same registry\n * `useComponent` reads (the `components` map on `BuroProvider`, plus any\n * plugin-contributed `ui-component` capabilities).\n *\n * Unlike the legacy single-slot overlay controller this replaces — which\n * silently rendered `null` for an unresolved component key — an unregistered\n * key here is a loud\n * `console.error` naming the descriptor and its component key, because a\n * `present()` call that can never render anything is an app bug, not a\n * legitimate steady state.\n */\nexport function UIPresentations({ hosts }: UIPresentationsProps): ReactElement {\n const runtime = useUIPresentationRuntime();\n const descriptors = useSyncExternalStore(\n runtime.subscribe,\n runtime.getSnapshot,\n runtime.getSnapshot,\n );\n return (\n <>\n {descriptors.map((descriptor) => (\n <UIPresentationInstance\n key={descriptor.id}\n descriptor={descriptor}\n runtime={runtime}\n hosts={hosts}\n />\n ))}\n </>\n );\n}\n\nfunction UIPresentationInstance({\n descriptor,\n runtime,\n hosts,\n}: {\n readonly descriptor: UIPresentationDescriptor;\n readonly runtime: UIPresentationRuntime;\n readonly hosts: UIPresentationHosts;\n}): ReactElement | null {\n const Component = useComponent<ComponentType<Record<string, unknown>>>(descriptor.component);\n // Rebuilding this object every render gave every open overlay a new\n // `UIInstanceProvider` value on ANY stack change (a sibling presentation\n // opening/closing re-renders `<UIPresentations/>`, which re-ran this for\n // every existing instance too), re-rendering every open overlay's subtree\n // even though nothing about THIS instance changed. Memoized on the pieces\n // that can actually change per-descriptor identity: `dismiss`/`runtime`\n // stay referentially stable in practice (dismiss closes over `runtime` +\n // the stable `descriptor.id`), so this settles to one stable identity for\n // the instance's whole lifetime.\n //\n // Computed unconditionally, ABOVE both early returns below: hooks must run\n // in the same order every render, and `Component`/`Host` resolution can\n // flip between defined/undefined across renders (registry or `hosts` prop\n // changes), so a conditional `useMemo` after either early return would be\n // a hook-order violation.\n const instance: UIInstance = useMemo(\n () => ({\n id: descriptor.id,\n dismiss: () => runtime.dismiss(descriptor.id),\n activation: descriptor.activation,\n }),\n [descriptor.id, descriptor.activation, runtime],\n );\n if (Component === undefined) {\n console.error(\n `UIPresentations: no component registered for key \"${descriptor.component}\" (presentation \"${descriptor.id}\", host \"${descriptor.host}\"). Register it in the \\`components\\` map passed to BuroProvider (or via a plugin's \\`ui-component\\` capability).`,\n );\n return null;\n }\n\n const Host = hosts[descriptor.host];\n if (Host === undefined) return null;\n\n return (\n <UIInstanceProvider instance={instance} presentation={instance}>\n <Host component={Component} props={descriptor.props} options={descriptor.options} />\n </UIInstanceProvider>\n );\n}\n","import {\n type ReactElement,\n type ReactNode,\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n} from 'react';\nimport { type UIPresentationHosts, UIPresentations } from './ui-presentations.js';\n\n/**\n * Who renders the presentation stack.\n *\n * `'framework'` (default) — `BuroProvider` mounts it beside `{children}`,\n * inside every framework provider. Presented components reach field\n * implementations, i18n, UI settings and the doc panel, but NOT providers the\n * app mounts inside `{children}` (dispatch, relation aggregator, link\n * component): those render strictly below the framework's own mount.\n *\n * `'app'` — the app renders `<BuroPresentationOutlet/>` itself, typically as\n * the last child of its own provider stack. Presented components then render\n * inside BOTH the framework's providers and the app's, sharing the very same\n * instances instead of a second copy.\n */\nexport type PresentationsMode = 'framework' | 'app';\n\n/**\n * Tracks the single app-owned outlet, so `useUIPresent()` can refuse loudly\n * when the app asked for `presentations=\"app\"` and then forgot to render one.\n */\nexport interface PresentationOutletRegistry {\n /** Registers the outlet and returns its release. Throws if one is already mounted. */\n claim(): () => void;\n isMounted(): boolean;\n}\n\nexport function createPresentationOutletRegistry(): PresentationOutletRegistry {\n let claimed = false;\n return {\n claim() {\n if (claimed) {\n throw Object.assign(\n new Error(\n 'Only one <BuroPresentationOutlet/> may be mounted per BuroProvider. ' +\n 'Two outlets would race over which one renders the presentation stack.',\n ),\n { kind: 'configuration' as const, code: 'presentation-outlet-duplicate' as const },\n );\n }\n claimed = true;\n return () => {\n claimed = false;\n };\n },\n isMounted() {\n return claimed;\n },\n };\n}\n\n/** What `BuroProvider` hands down so an app-owned outlet can render the stack. */\nexport interface PresentationMount {\n readonly mode: PresentationsMode;\n readonly hosts: UIPresentationHosts;\n readonly registry: PresentationOutletRegistry;\n}\n\nconst PresentationMountContext = createContext<PresentationMount | null>(null);\n\nexport function PresentationMountProvider({\n mount,\n children,\n}: {\n readonly mount: PresentationMount;\n readonly children: ReactNode;\n}): ReactElement {\n return (\n <PresentationMountContext.Provider value={mount}>{children}</PresentationMountContext.Provider>\n );\n}\n\n/** The mount contract from the nearest `BuroProvider`, or `null` outside one. */\nexport function useOptionalPresentationMount(): PresentationMount | null {\n return useContext(PresentationMountContext);\n}\n\n// `useLayoutEffect` warns during server render; the outlet is a client-side\n// mount either way, so fall back to `useEffect` when there is no DOM.\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\n/**\n * App-owned mount point for the presentation stack. Render it inside your own\n * provider stack when `BuroProvider` is given `presentations=\"app\"`; presented\n * components then see the same app-level context instances the rest of the app\n * does, instead of a re-mounted copy.\n */\nexport function BuroPresentationOutlet(): ReactElement {\n const mount = useOptionalPresentationMount();\n const registry = mount?.registry;\n // A layout effect, not a plain effect: it runs before paint and long before\n // any user interaction can call present(), so a correctly wired app never\n // observes a spurious `outlet-missing`.\n useIsomorphicLayoutEffect(() => registry?.claim(), [registry]);\n if (mount === null) {\n throw Object.assign(\n new Error('<BuroPresentationOutlet/> must be rendered inside a BuroProvider.'),\n { kind: 'configuration' as const, code: 'presentation-outlet-orphan' as const },\n );\n }\n if (mount.mode !== 'app') {\n throw Object.assign(\n new Error(\n '<BuroPresentationOutlet/> requires <BuroProvider presentations=\"app\">; ' +\n 'in framework mode BuroProvider mounts the presentation stack itself.',\n ),\n { kind: 'configuration' as const, code: 'presentation-outlet-unexpected' as const },\n );\n }\n return <UIPresentations hosts={mount.hosts} />;\n}\n","import type { UIActivationContext, UIPresentRequest, UIPresentResult } from '@burojs/core';\nimport { useCallback, useContext, useSyncExternalStore } from 'react';\nimport { ResolverContext } from '../context.js';\nimport { useOptionalUIActivationSurface, useUIPresentationRuntime } from './context.js';\nimport { useOptionalPresentationMount } from './mount.js';\nimport type { UIPresentationOptionsSchema } from './ui-presentations.js';\n\nconst GLOBAL_SURFACE = Object.freeze({ type: 'global' as const });\nconst EMPTY_SLICES: Readonly<Record<string, unknown>> = Object.freeze({});\n\n/**\n * Reads the current activation: the surface from the nearest\n * `UIActivationSurfaceProvider` (defaulting to `{ type: 'global' }` when\n * there isn't one) plus a live snapshot of the app's resolver slices, if a\n * `BuroProvider` is mounted above. Outside one, `slices` is `{}` — this\n * hook (and `useUIPresent`, which is built on it) works standalone, e.g. in\n * a unit test that only wires up `UIPresentationRuntimeProvider`.\n */\nexport function useCurrentUIActivation(): UIActivationContext {\n const resolver = useContext(ResolverContext);\n const subscribe = useCallback(\n (listener: () => void) => (resolver === null ? () => undefined : resolver.subscribe(listener)),\n [resolver],\n );\n const getSnapshot = useCallback(\n () =>\n resolver === null ? EMPTY_SLICES : (resolver.snapshot() as Readonly<Record<string, unknown>>),\n [resolver],\n );\n const slices = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const surface = useOptionalUIActivationSurface() ?? GLOBAL_SURFACE;\n return Object.freeze({ slices, surface });\n}\n\n/** An imperative present request; `activation` is captured automatically and need not (usually) be supplied. */\nexport type UIPresentInput = Omit<UIPresentRequest, 'activation'> & {\n readonly activation?: Partial<UIActivationContext>;\n};\n\nexport type UIPresent = (request: UIPresentInput) => UIPresentResult;\n\n/**\n * Checks `options` against a host's declared `optionsSchema`, returning a\n * loud, specific message — naming the component, the key(s), the host, and\n * (for a type mismatch) both the expected and received type — or `null`\n * when every key is known and correctly typed. `schema === undefined` is\n * not represented here: the caller skips the check entirely in that case,\n * since a host with no schema accepts anything.\n *\n * Every offending key is collected and reported together in one message\n * (and one `console.error`) rather than stopping at the first, so three\n * typos cost one fix-and-rerun cycle, not three.\n *\n * A key present with value `undefined` is treated as absent for the type\n * check: `Object.entries` yields explicitly-`undefined` keys same as any\n * other, but every reader downstream of `options` (e.g. ui-shadcn's\n * `copy.ts`, which already treats a non-string `description` as \"not\n * supplied\") cannot tell an omitted key from one set to `undefined` — so\n * refusing the latter would punish an ordinary `{ description: maybeUndef }`\n * spread for a distinction nothing reads. An *unknown* key set to\n * `undefined` is still a typo and is still refused below.\n */\nfunction findInvalidOptionsMessage(\n component: string,\n host: string,\n schema: UIPresentationOptionsSchema,\n options: Readonly<Record<string, unknown>> | undefined,\n): string | null {\n if (options === undefined) return null;\n const issues: string[] = [];\n for (const [key, value] of Object.entries(options)) {\n const expected = schema[key];\n if (expected === undefined) {\n const known = Object.keys(schema);\n issues.push(\n `option \"${key}\" was refused — host \"${host}\" does not declare it in its ` +\n `optionsSchema. ${known.length > 0 ? `Known keys: ${known.join(', ')}.` : 'It declares no keys at all.'}`,\n );\n continue;\n }\n if (value === undefined) continue;\n const received = typeof value;\n if (received !== expected) {\n issues.push(\n `option \"${key}\" was refused — host \"${host}\" expects type \"${expected}\" ` +\n `but received \"${received}\".`,\n );\n }\n }\n if (issues.length === 0) return null;\n return `useUIPresent: present(\"${component}\") was refused — ${issues.join(' ')}`;\n}\n\n/**\n * Returns a `present` function that captures the current activation\n * (surface + resolver slices) at call time and forwards the request to the\n * `UIPresentationRuntime` supplied by the nearest `UIPresentationRuntimeProvider`.\n * A caller may override `surface` and/or `slices` explicitly via the\n * `activation` field of the request; anything left unset falls back to the\n * captured activation.\n */\nexport function useUIPresent(): UIPresent {\n const runtime = useUIPresentationRuntime();\n const activation = useCurrentUIActivation();\n const mount = useOptionalPresentationMount();\n return useCallback(\n (request: UIPresentInput): UIPresentResult => {\n // An app that asked to own the mount and then never rendered the outlet\n // would otherwise register descriptors nothing can ever render. Refuse\n // before touching the runtime, so the stack keeps no ghost entries.\n if (mount !== null && mount.mode === 'app' && !mount.registry.isMounted()) {\n console.error(\n `useUIPresent: present(\"${request.component}\") was refused — BuroProvider is in presentations=\"app\" mode but no <BuroPresentationOutlet/> is mounted. Render <BuroPresentationOutlet/> inside your provider stack, or drop presentations=\"app\" to let the framework mount the stack itself.`,\n );\n return Object.freeze({ ok: false, code: 'outlet-missing' as const });\n }\n // The options schema belongs to the host, not to the core runtime: core\n // knows the host NAMES (`host: 'dialog' | 'sheet'` — see `VALID_HOSTS`\n // in presentation-runtime.ts) but never learns their option\n // VOCABULARIES, which is what makes this decidable only here, the same\n // layer that owns `outlet-missing`, before the request ever reaches\n // `runtime.present()`.\n const schema = mount?.hosts[request.host]?.optionsSchema;\n if (schema !== undefined) {\n const message = findInvalidOptionsMessage(\n request.component,\n request.host,\n schema,\n request.options,\n );\n if (message !== null) {\n console.error(message);\n return Object.freeze({ ok: false, code: 'invalid-options' as const });\n }\n }\n const { activation: overrides, ...rest } = request;\n const resolvedActivation: UIActivationContext =\n overrides === undefined\n ? activation\n : Object.freeze({\n surface: overrides.surface ?? activation.surface,\n slices: overrides.slices ?? activation.slices,\n });\n return runtime.present({ ...rest, activation: resolvedActivation });\n },\n [runtime, activation, mount],\n );\n}\n","import type { Resolver, SliceDefinition } from '@burojs/context';\nimport {\n createUiSettingsStore,\n createUIPresentationRuntime,\n type AppRuntime,\n type Audit,\n type AuthProvider,\n type DocsConfig,\n type UiSettingsStore,\n} from '@burojs/core';\nimport type { I18nFacade } from '@burojs/i18n-core';\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport {\n Suspense,\n use,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { AuditContext } from './audit/context.js';\nimport { useNavAudit } from './audit/use-nav-audit.js';\nimport { DataRuntimeProvider } from './data/context.js';\nimport type { DataRuntimeLease } from './data/runtime.js';\nimport { AuthRuntimeProvider } from './auth/context.js';\nimport { DocsProvider } from './hooks/use-doc-panel.js';\nimport { FieldImplementationProvider } from './fields/provider.js';\nimport type { FieldImplementationCatalog } from './fields/definitions.js';\nimport {\n createManifestHydrationScope,\n hydrateManifest,\n type InitialManifest,\n type ManifestHydration,\n type ManifestHydrationScope,\n} from './runtime/manifest-hydration.js';\nimport { BuroRuntimeProvider } from './runtime.js';\nimport { createLocalStorageUiSettingsAdapter } from './ui-settings/local-storage-adapter.js';\nimport { UiSettingsProvider } from './ui-settings/provider.js';\nimport {\n UIPresentationRuntimeProvider,\n UIPresentations,\n createPresentationOutletRegistry,\n PresentationMountProvider,\n type PresentationsMode,\n type UIPresentationHosts,\n} from './ui/index.js';\nimport { AppContext, ComponentsContext, I18nContext, ResolverContext } from './context.js';\n\nconst NO_PRESENTATION_HOSTS: UIPresentationHosts = Object.freeze({});\n\nexport interface BuroProviderProps<\n TSlices extends Record<string, SliceDefinition> = Record<string, SliceDefinition>,\n> {\n app: AppRuntime;\n /**\n * Externally owned native data-runtime lease installed into this React tree.\n * Optional: omitting it never creates a fallback lease or data context,\n * so consumers that don't use the data-runtime-backed hooks\n * (`useResourceList`, relation aggregation, etc.) don't need to wire one.\n */\n dataRuntime?: DataRuntimeLease;\n /** Optional native auth provider; auth remains UI- and router-independent. */\n authProvider?: AuthProvider;\n /**\n * Externally owned live UI settings store (`createUiSettingsStore` from\n * `@burojs/core`). Omitting it does NOT leave `useUiSettings`\n * unresolvable: exactly one default browser `localStorage`-backed store\n * (`createLocalStorageUiSettingsAdapter`) is created per mounted provider\n * tree and provided instead, so `useUiSettings` always resolves. Passing\n * an explicit store suppresses that default entirely — no local store is\n * created, and nothing is ever mirrored to `localStorage`. The provider\n * never disposes a store it is given (explicit or default).\n */\n uiSettings?: UiSettingsStore;\n /**\n * The resolver built by `createResolver(defineContextSlices(...))`, with\n * whatever slice map the adopter declared.\n *\n * ⚠️ This used to be typed `Resolver<never>`, which is unsatisfiable: a\n * concrete `Resolver<{ env: … }>` is not assignable to it (`setSlice`'s key\n * parameter is contravariant, and `never` has no keys), so EVERY adopter had\n * to write `resolver as never` at their provider — the framework's own test\n * helpers each shipped a `providerResolver()` laundering function for it.\n * The provider is generic now and infers the slice map from this prop.\n *\n * The widening still has to happen — the context is shared by consumers that\n * cannot know the adopter's slice map — but it happens once, here, instead of\n * at every call site.\n */\n resolver: Resolver<TSlices>;\n i18n: I18nFacade;\n components: Record<string, unknown>;\n /**\n * Immutable, host-provided React field implementations. They are scoped to\n * this provider tree and are intentionally outside AppRuntime/manifests.\n */\n fieldImplementations?: FieldImplementationCatalog;\n /**\n * Article bodies for the documentation panel — the map of lazy loaders plus\n * an optional fallback locale.\n *\n * Lives here rather than on `defineApp` because it is React-layer data, the\n * same class of thing as `components`. Plugins can contribute named trusted\n * UI components, while this prop remains the direct application override. Omit it and the\n * contextual tier still works; only the panel and the browser disappear.\n */\n docs?: DocsConfig;\n /**\n * A portable server manifest plus the static definition used to reconstruct\n * it. Runtime services and request context stay exclusively on `app`.\n */\n initialManifest?: InitialManifest;\n /** Optional host/request scope shared by a matching server/client handoff. */\n manifestHydrationScope?: ManifestHydrationScope;\n /**\n * Concrete dialog/sheet host components for the framework-mounted\n * `<UIPresentations/>` overlay stack, keyed by `UIPresentationDescriptor['host']`.\n * `packages/react` stays DOM-free — these are always host-supplied (e.g.\n * ui-shadcn's dialog/sheet wrappers), never imported here. Omitting this\n * prop does not disable `useUIPresent()`/the presentation runtime: `present()`\n * calls still register and are reflected in `getSnapshot()`, they simply\n * have nothing to render into, matching a genuinely un-wired app.\n */\n presentationHosts?: UIPresentationHosts;\n /**\n * Who renders the overlay stack. `'framework'` (default) keeps today's\n * behavior: `BuroProvider` mounts `<UIPresentations/>` beside `{children}`.\n * `'app'` hands the mount to the app, which must render\n * `<BuroPresentationOutlet/>` inside its own provider stack — the only way a\n * presented component can reach app-level providers (dispatch, relation\n * aggregator, link component) as the SAME instances the app tree uses.\n */\n presentations?: PresentationsMode;\n /**\n * The application's audit emitter, from `createAudit({ onEvent })`.\n *\n * The application constructs it — not this provider — because\n * `currentCorrelationId()` has to be readable from the application's own\n * data-provider wrapper, which is composed outside the React tree and cannot\n * read a context.\n *\n * Omitted → no events are emitted and no emission site does any work.\n */\n audit?: Audit;\n children: ReactNode;\n}\n\nexport function BuroProvider<TSlices extends Record<string, SliceDefinition>>({\n app,\n dataRuntime,\n authProvider,\n uiSettings,\n resolver,\n i18n,\n components,\n fieldImplementations,\n docs,\n initialManifest,\n manifestHydrationScope,\n presentationHosts,\n presentations,\n audit,\n children,\n}: BuroProviderProps<TSlices>): ReactElement {\n if (authProvider !== undefined && dataRuntime === undefined) {\n throw Object.assign(new Error('BuroProvider authProvider requires dataRuntime.'), {\n kind: 'configuration' as const,\n code: 'auth-provider-data-runtime-required',\n });\n }\n if (dataRuntime !== undefined && dataRuntime.app !== app) {\n throw Object.assign(new Error('BuroProvider app must match dataRuntime.app.'), {\n kind: 'configuration' as const,\n code: 'data-runtime-app-mismatch',\n });\n }\n return (\n <Suspense fallback={null}>\n {dataRuntime === undefined ? (\n <ReadyBuroProvider\n app={app}\n uiSettings={uiSettings}\n resolver={resolver}\n i18n={i18n}\n components={components}\n fieldImplementations={fieldImplementations}\n docs={docs}\n initialManifest={initialManifest}\n manifestHydrationScope={manifestHydrationScope}\n presentationHosts={presentationHosts}\n presentations={presentations}\n audit={audit}\n >\n {children}\n </ReadyBuroProvider>\n ) : (\n <ReadyDataBuroProvider\n app={app}\n dataRuntime={dataRuntime}\n authProvider={authProvider}\n uiSettings={uiSettings}\n resolver={resolver}\n i18n={i18n}\n components={components}\n fieldImplementations={fieldImplementations}\n docs={docs}\n initialManifest={initialManifest}\n manifestHydrationScope={manifestHydrationScope}\n presentationHosts={presentationHosts}\n presentations={presentations}\n audit={audit}\n >\n {children}\n </ReadyDataBuroProvider>\n )}\n </Suspense>\n );\n}\n\ntype ReadyBuroProviderProps<TSlices extends Record<string, SliceDefinition>> = Omit<\n BuroProviderProps<TSlices>,\n 'dataRuntime' | 'authProvider'\n>;\n\nfunction ReadyBuroProvider<TSlices extends Record<string, SliceDefinition>>({\n app,\n uiSettings,\n resolver,\n i18n,\n components,\n fieldImplementations,\n docs,\n initialManifest,\n manifestHydrationScope,\n presentationHosts,\n presentations,\n audit,\n children,\n}: ReadyBuroProviderProps<TSlices>): ReactElement {\n // Every non-ready state observes the barrier. In particular, a settled\n // failed/disposed runtime rethrows its startup error instead of mounting an\n // invalid provider tree.\n if (app.readiness.status === 'disposed') {\n throw app.readiness.error ?? new Error(`Buro app '${app.name}' is disposed.`);\n }\n if (app.readiness.status === 'failed') throw app.readiness.error;\n if (app.readiness.status === 'pending') use(app.ready);\n useNavAudit(app, audit ?? null);\n const manifestRuntime = useRef<\n | {\n readonly appRuntime: AppRuntime;\n readonly definition: InitialManifest['definition'];\n readonly manifest: InitialManifest['manifest'];\n readonly runtime: AppRuntime['runtime'];\n readonly hydration: ManifestHydration;\n }\n | undefined\n >(undefined);\n const defaultScope = useRef<ManifestHydrationScope | undefined>(undefined);\n const scope = manifestHydrationScope ?? (defaultScope.current ??= createManifestHydrationScope());\n let runtime = app.runtime;\n let hydration: ManifestHydration | undefined;\n if (initialManifest !== undefined) {\n const prior = manifestRuntime.current;\n if (\n prior?.appRuntime === app &&\n prior.definition === initialManifest.definition &&\n prior.manifest === initialManifest.manifest\n ) {\n runtime = prior.runtime;\n hydration = prior.hydration;\n } else {\n hydration = hydrateManifest(app.runtime, initialManifest, scope);\n runtime = hydration.runtime;\n manifestRuntime.current = {\n appRuntime: app,\n definition: initialManifest.definition,\n manifest: initialManifest.manifest,\n runtime,\n hydration,\n };\n }\n }\n useEffect(() => {\n hydration?.activate();\n return () => hydration?.dispose();\n }, [hydration]);\n // No-adapter fallback (Task 7): exactly one default local store per\n // mounted provider tree, built once via `useState`'s lazy initializer —\n // it runs a single time at mount, so a later render passing/removing\n // `uiSettings` never creates a second local store, and no store at all is\n // constructed when the caller supplies one from the start. Reading\n // `localStorage` only happens once something actually opens a collection\n // through it (`UiSettingsAdapter.open`, not `createUiSettingsStore`\n // itself), so this stays SSR-safe on its own even though `useState`'s\n // initializer runs during server render too.\n const [defaultUiSettings] = useState<UiSettingsStore | undefined>(() =>\n uiSettings === undefined\n ? createUiSettingsStore(createLocalStorageUiSettingsAdapter())\n : undefined,\n );\n const effectiveUiSettings = uiSettings ?? defaultUiSettings;\n // Framework-owned imperative overlay runtime: exactly one per mounted\n // provider tree, built once via `useState`'s lazy initializer — the same\n // exactly-once construction as the default UI settings store above, and\n // for the same reason (a later render must not silently swap the instance\n // every `useUIPresent()` call site or `<UIPresentations/>` is holding a\n // reference to). Never disposed here, mirroring the settings store: this\n // component's own unmount is the runtime's end of life.\n const [presentationRuntime] = useState(() => createUIPresentationRuntime());\n // One registry per mounted provider tree, built exactly once — same\n // reasoning as the runtime above: `useUIPresent()` closes over it.\n const [outletRegistry] = useState(() => createPresentationOutletRegistry());\n const presentationMode: PresentationsMode = presentations ?? 'framework';\n const presentationMount = useMemo(\n () => ({\n mode: presentationMode,\n hosts: presentationHosts ?? NO_PRESENTATION_HOSTS,\n registry: outletRegistry,\n }),\n [presentationMode, presentationHosts, outletRegistry],\n );\n const resolvedComponents = useMemo(\n () =>\n new Proxy(components, {\n get(target, key, receiver) {\n if (typeof key !== 'string' || Object.prototype.hasOwnProperty.call(target, key)) {\n return Reflect.get(target, key, receiver);\n }\n return app.getPluginCapability('ui-component', key);\n },\n has(target, key) {\n return (\n Reflect.has(target, key) ||\n (typeof key === 'string' && app.getPluginCapability('ui-component', key) !== undefined)\n );\n },\n }),\n [app, components],\n );\n // Framework-owned overlay mount. `presentationHosts` is the only injection\n // point: packages/react never imports a concrete dialog/sheet\n // implementation (ui-shadcn supplies them at the app), so omitting the\n // prop leaves the runtime fully functional (`useUIPresent()` still\n // records presentations) with nothing rendered for them — the correct\n // default-off behavior for an app that hasn't wired hosts yet.\n //\n // It is mounted as the LAST CHILD inside the deepest framework provider,\n // adjacent to `{children}`, not as a sibling above the provider chain:\n // presented components (modals/sheets) must render in the SAME framework\n // context as the rest of the app so they can use `FieldImplementationProvider`\n // field inputs, `useUiSettings`, `useDocPanel`, `useT`/i18n, etc. A mount\n // above `BuroRuntimeProvider`/`FieldImplementationProvider` would put\n // presented components outside all of that. `UIPresentationRuntimeProvider`\n // still wraps both `{children}` and this mount, since both need the runtime.\n //\n // App-level providers (dispatch/relation-aggregator/link-component) live\n // inside `{children}` and are out of reach in this mode by construction. An\n // app that needs them switches to `presentations=\"app\"` and renders\n // `<BuroPresentationOutlet/>` inside its own stack.\n const frameworkPresentations =\n presentationMode === 'framework' ? (\n <UIPresentations hosts={presentationHosts ?? NO_PRESENTATION_HOSTS} />\n ) : null;\n return (\n <AppContext.Provider value={app}>\n <AuditContext.Provider value={audit ?? null}>\n <ResolverContext.Provider value={resolver as unknown as Resolver<never>}>\n <I18nContext.Provider value={i18n}>\n <ComponentsContext.Provider value={resolvedComponents}>\n <UIPresentationRuntimeProvider runtime={presentationRuntime}>\n <PresentationMountProvider mount={presentationMount}>\n <BuroRuntimeProvider runtime={runtime}>\n <FieldImplementationProvider fieldImplementations={fieldImplementations}>\n {effectiveUiSettings === undefined ? (\n <DocsProvider config={docs}>\n {children}\n {frameworkPresentations}\n </DocsProvider>\n ) : (\n <UiSettingsProvider store={effectiveUiSettings}>\n <DocsProvider config={docs}>\n {children}\n {frameworkPresentations}\n </DocsProvider>\n </UiSettingsProvider>\n )}\n </FieldImplementationProvider>\n </BuroRuntimeProvider>\n </PresentationMountProvider>\n </UIPresentationRuntimeProvider>\n </ComponentsContext.Provider>\n </I18nContext.Provider>\n </ResolverContext.Provider>\n </AuditContext.Provider>\n </AppContext.Provider>\n );\n}\n\nfunction ReadyDataBuroProvider<TSlices extends Record<string, SliceDefinition>>({\n dataRuntime,\n authProvider,\n ...contentProps\n}: BuroProviderProps<TSlices> & { readonly dataRuntime: DataRuntimeLease }): ReactElement {\n useSyncExternalStore(\n dataRuntime.dataSession.subscribe,\n dataRuntime.dataSession.getState,\n dataRuntime.dataSession.getState,\n );\n return (\n <QueryClientProvider client={dataRuntime.queryClient}>\n {authProvider === undefined ? (\n <DataRuntimeProvider value={dataRuntime}>\n <ReadyBuroProvider {...contentProps} />\n </DataRuntimeProvider>\n ) : (\n <AuthRuntimeProvider runtime={dataRuntime} provider={authProvider}>\n <ReadyBuroProvider {...contentProps} />\n </AuthRuntimeProvider>\n )}\n </QueryClientProvider>\n );\n}\n","import { fieldSensitivity, type AuditFieldDiff } from '@burojs/core';\n\nexport interface BuildFormDiffArgs {\n /** Values as they were when the form opened (its baseline). */\n readonly before: Readonly<Record<string, unknown>>;\n /** Values at submit time. */\n readonly after: Readonly<Record<string, unknown>>;\n /** The form's field definitions, keyed by field name — the source of `sensitive`. */\n readonly fields: Readonly<Record<string, unknown>>;\n}\n\n/**\n * A cheap structural fingerprint used only to decide whether a value actually\n * changed. File-aware on purpose, mirroring `valueKey` in\n * `hooks/file/use-file-field.ts`: plain `JSON.stringify` renders a `File` as\n * `{}` (no enumerable own properties), so two genuinely DIFFERENT Files would\n * otherwise fingerprint identically and a real edit would silently vanish\n * from the diff — audit blindness, not a leak, but the same trap this\n * codebase already hit once in the file-field hook.\n */\nfunction fingerprint(value: unknown): string {\n const seen = new WeakSet<object>();\n return (\n JSON.stringify(value, (_k, v) => {\n if (typeof File !== 'undefined' && v instanceof File) {\n return `File:${v.name}:${v.size}:${v.lastModified}`;\n }\n if (v && typeof v === 'object') {\n if (seen.has(v)) return '[circular]';\n seen.add(v);\n }\n return v;\n }) ?? 'undefined'\n );\n}\n\n/** JSON-stable (File-aware) comparison: a rebuilt-but-equal array/object is not a user edit. */\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;\n try {\n return fingerprint(a) === fingerprint(b);\n } catch {\n // Cannot prove equality (e.g. a BigInt or other unstringifiable value) —\n // treat as changed. Conservative in the safe direction: this only ever\n // widens what gets reported, and a changed value still goes through the\n // sensitivity branch below, so it cannot leak more than an honest diff would.\n return false;\n }\n}\n\n/**\n * Field kinds whose value is a container the caller cannot vouch for the\n * inside of: `buildFormDiff` only ever sees the PARENT form's field defs, so\n * for a `children` field (a nested resource's rows, e.g. `f.children('people', …)`)\n * or a `json` field (arbitrary adopter-shaped data) there is no declaration\n * to consult for what is nested inside it. An unmarked field of either kind\n * is redacted by default; the fact that it changed still survives. An\n * adopter who wants content in the diff supplies `sensitive: (v) => ...` on\n * that field, same escape hatch as any other field, which forces them to\n * decide explicitly what they expose.\n *\n * `file` joins this set for the same reason, not a weaker one. The in-memory\n * value of a `file` field is `FileRef | FileRef[]` (`packages/file-storage/src/types.ts`),\n * and `FileRef.raw` is documented there as \"Opaque to the framework\" — the\n * original backend media object, whatever shape that backend gives it —\n * while `FileRef.pending` holds the actual unsent `File` (raw bytes). Neither\n * is something `buildFormDiff` can vouch for. Emitting a `{ from, to }` pair\n * built from these objects raw does two bad things at once: a sink that\n * structured-clones or persists the event retains the user's uploaded\n * document, and every retained event pins that blob in memory for as long as\n * the event lives. `fingerprint()` above already has a safe display string for\n * a bare `File` (used only for change detection, never for emission) — it was\n * considered as the emitted value here too, but a production `file` field's\n * value is a `FileRef`, not a bare `File`, and a descriptor built from\n * `FileRef.raw` would just move the same \"cannot vouch for it\" problem one\n * level down. Full redaction is the version of this that stays correct\n * regardless of what a given storage adapter puts in `raw`.\n */\nconst REDACT_BY_DEFAULT_KINDS: ReadonlySet<string> = new Set(['children', 'json', 'file']);\n\nfunction isRedactByDefaultKind(def: unknown): boolean {\n if (typeof def !== 'object' || def === null) return false;\n const kind = (def as { kind?: unknown }).kind;\n return typeof kind === 'string' && REDACT_BY_DEFAULT_KINDS.has(kind);\n}\n\n/**\n * Build the `diff` of a `form.submit` audit event.\n *\n * Shared by both form hosts (`useDeclarativeForm` and `<ResourceForm>`) on\n * purpose: two copies of the redaction branch is how a sensitive field ends up\n * redacted on one path and not the other.\n *\n * A field the caller did not declare is redacted rather than emitted — an\n * unknown field cannot be proven non-sensitive, and a create form can carry\n * values for fields seeded from outside the declaration. `fields` is caller\n * data too (its keys can be attacker-influenced the same way `before`/\n * `after` can), so the lookup uses `Object.hasOwn` rather than an\n * `=== undefined` check: a key like `toString` or `constructor` is NOT\n * \"undefined\" on a plain object — it resolves through the prototype chain to\n * a built-in function — and treating that as \"known\" would emit whatever\n * value rode in under that name raw.\n */\nexport function buildFormDiff(args: BuildFormDiffArgs): Record<string, AuditFieldDiff> {\n const diff: Record<string, AuditFieldDiff> = {};\n const names = new Set([...Object.keys(args.before), ...Object.keys(args.after)]);\n\n for (const name of names) {\n const from = args.before[name];\n const to = args.after[name];\n if (sameValue(from, to)) continue;\n\n if (!Object.hasOwn(args.fields, name)) {\n diff[name] = { redacted: true };\n continue;\n }\n const def = args.fields[name];\n\n const sensitivity = fieldSensitivity(def);\n if (sensitivity === true) {\n diff[name] = { redacted: true };\n } else if (typeof sensitivity === 'function') {\n try {\n diff[name] = { from: sensitivity(from), to: sensitivity(to) };\n } catch {\n // A mask that throws must fall back to full redaction, never to the\n // raw value.\n diff[name] = { redacted: true };\n }\n } else if (isRedactByDefaultKind(def)) {\n diff[name] = { redacted: true };\n } else {\n diff[name] = { from, to };\n }\n }\n\n return diff;\n}\n","'use client';\nimport type { AuditFieldDiff } from '@burojs/core';\nimport { useCallback, useMemo } from 'react';\nimport { useAudit } from './context.js';\nimport { buildFormDiff } from './form-diff.js';\n\n/**\n * `errorCode` on a degraded `form.submit` event — `buildFormDiff` itself\n * threw (e.g. malformed `fields`/`before`/`after` from a caller) rather than\n * one field's own redaction failing. `outcome` still reflects what the host\n * reported about the actual submit; this code only says the audit machinery\n * could not describe what changed.\n */\nconst DIFF_BUILD_FAILED = 'audit-diff-build-failed';\n\nexport interface FormSubmitAuditArgs {\n /** Values as the form opened — captured BEFORE the write, since a host may re-baseline after it. */\n readonly before: Readonly<Record<string, unknown>>;\n readonly after: Readonly<Record<string, unknown>>;\n readonly fields: Readonly<Record<string, unknown>>;\n readonly outcome: 'success' | 'error' | 'invalid';\n readonly resource?: string;\n readonly recordId?: string;\n readonly view?: 'create' | 'edit';\n /**\n * A backend-reported error code (e.g. `'backend-500'`, design doc §4.1) —\n * plumbing for a host to report WHY an `'error'` outcome happened, distinct\n * from `audit-diff-build-failed` below (which means the audit machinery\n * itself, not the submit, failed). Ignored on any other outcome.\n */\n readonly errorCode?: string;\n}\n\nexport interface FormSubmitAudit {\n /**\n * False when the app configured no sink. Hosts check it before copying their\n * values — that check is what makes an unaudited app pay nothing.\n */\n readonly enabled: boolean;\n readonly emit: (args: FormSubmitAuditArgs) => void;\n}\n\n/**\n * The single place a `form.submit` event is constructed.\n *\n * Buro has two independent form hosts (`useDeclarativeForm` here and\n * `<ResourceForm>` in `@burojs/ui-shadcn`). They share this hook rather than a\n * copied block so the redaction branch cannot drift between them, and so a\n * third host does not become a third copy.\n */\nexport function useFormSubmitAudit(): FormSubmitAudit {\n const audit = useAudit();\n\n const emit = useCallback(\n (args: FormSubmitAuditArgs): void => {\n if (!audit) return;\n\n // `buildFormDiff` guards every FIELD-level failure internally (a\n // throwing mask redacts, an unknown field redacts), but it can still\n // throw as a whole on a malformed call — e.g. a host passing a nullish\n // `fields`/`before`/`after`. `buildFormDiff` is itself a public\n // `@burojs/react` export an adopter's own code can call directly, so\n // this construction site cannot assume a well-formed call reached it.\n // `createAudit` already guards every app-supplied callback (the sink,\n // the actor getter) on the same principle — observability must never\n // break the UI — and this is the one step of `emit` that was left\n // unguarded. On failure the event still goes out, with an empty diff\n // and `errorCode` marking it degraded, rather than silently dropping\n // the action or falling back to raw values.\n // The caller's own `errorCode` (a backend diagnostic) is the default;\n // a `buildFormDiff` crash overrides it below rather than the reverse,\n // because at that point the event ALSO cannot honestly describe what\n // changed — that is the more urgent fact for whoever reads this event,\n // and it must not be silently dropped in favour of the backend code.\n let diff: Readonly<Record<string, AuditFieldDiff>>;\n let errorCode: string | undefined = args.errorCode;\n try {\n diff = buildFormDiff({\n before: args.before,\n after: args.after,\n fields: args.fields,\n });\n } catch {\n diff = {};\n errorCode = DIFF_BUILD_FAILED;\n }\n\n audit.emit(\n {\n type: 'form.submit',\n outcome: args.outcome,\n resource: args.resource,\n recordId: args.recordId,\n view: args.view,\n diff,\n errorCode,\n },\n { initiates: true },\n );\n },\n [audit],\n );\n\n // Memoized: this return value lands in `handleSubmit`'s dependency array in\n // both form hosts, so a fresh object identity on every render would\n // invalidate that `useCallback` every render too — defeating the point of\n // memoizing `handleSubmit` at all.\n return useMemo(() => ({ enabled: audit !== null, emit }), [audit, emit]);\n}\n","import {\n DEFAULT_COMPILER_LIMITS,\n type UiSettingCardinality,\n type UiSettingCollection,\n type UiSettingHandle,\n type UiSettingSingleton,\n type UiSettingTypeDefinition,\n type UiSettingsSnapshot,\n type UiSettingsStore,\n clonePortableValue,\n} from '@burojs/core';\nimport { useContext, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';\nimport { UiSettingsStoreContext } from './context.js';\n\n/**\n * What `useUiSettings` returns for a `collection` definition: the typed\n * mutation/refresh operations plus the live snapshot. `getSnapshot`,\n * `subscribe`, and `dispose` are deliberately NOT re-exposed — the hook\n * already routes them through `useSyncExternalStore` and owns disposal of\n * its own lease (see the effect below), so handing them to the caller would\n * let a component dispose a lease the hook still depends on.\n */\nexport type UseUiSettingsCollectionResult<TValue> = Pick<\n UiSettingCollection<TValue>,\n 'create' | 'update' | 'remove' | 'refresh'\n> & {\n readonly snapshot: UiSettingsSnapshot<TValue>;\n};\n\n/** The `singleton` counterpart of {@link UseUiSettingsCollectionResult}. */\nexport type UseUiSettingsSingletonResult<TValue> = Pick<\n UiSettingSingleton<TValue>,\n 'set' | 'remove' | 'refresh'\n> & {\n readonly snapshot: UiSettingsSnapshot<TValue>;\n};\n\n/** Picks the cardinality-specific result shape, mirroring `UiSettingHandle`. */\nexport type UseUiSettingsResult<\n TValue,\n TCardinality extends UiSettingCardinality,\n> = TCardinality extends 'collection'\n ? UseUiSettingsCollectionResult<TValue>\n : UseUiSettingsSingletonResult<TValue>;\n\n/** This hook instance's currently-open lease and the identity it was opened for. */\ninterface AcquiredLease<TParams, TValue, TCardinality extends UiSettingCardinality> {\n readonly store: UiSettingsStore;\n readonly definition: UiSettingTypeDefinition<TParams, TValue, TCardinality>;\n readonly key: string;\n readonly handle: UiSettingHandle<TValue, TCardinality>;\n}\n\nfunction sortedClone(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortedClone);\n if (value !== null && typeof value === 'object') {\n const sortedEntries = Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([entryKey, entryValue]) => [entryKey, sortedClone(entryValue)] as const);\n return Object.fromEntries(sortedEntries);\n }\n return value;\n}\n\n/**\n * A stable, key-order-independent string for `params`. This is a purely\n * LOCAL memoization aid for one hook instance across its own re-renders —\n * it decides whether the params passed THIS render still match the ones the\n * currently-open lease was opened for, so a re-render with a fresh-but-equal\n * params object does not close and reopen a lease.\n *\n * Tries `clonePortableValue` first — the SAME canonicalization\n * `createUiSettingsStore` uses internally (deeply frozen, codepoint-sorted\n * object keys; both exported from `@burojs/core`'s root) — so this hook's\n * local memoization key agrees with the store's own canonical key on every\n * portable-value `params` shape, rather than merely approximating it via a\n * separate `sortedClone`. Falls back to that local best-effort\n * canonicalization only if `clonePortableValue` throws (raw, not-yet-\n * `parseParams`-validated `params` containing something non-portable, e.g. a\n * function) — a throw here must never propagate out of render, since this\n * key is computed on every render, not just at mutation time.\n */\nfunction stableParamsKey(params: unknown): string {\n try {\n return JSON.stringify(clonePortableValue(params, DEFAULT_COMPILER_LIMITS));\n } catch {\n return JSON.stringify(sortedClone(params));\n }\n}\n\nfunction buildResult<TValue>(\n cardinality: UiSettingCardinality,\n handle: UiSettingCollection<TValue> | UiSettingSingleton<TValue>,\n snapshot: UiSettingsSnapshot<TValue>,\n): UseUiSettingsCollectionResult<TValue> | UseUiSettingsSingletonResult<TValue> {\n if (cardinality === 'collection') {\n const collection = handle as UiSettingCollection<TValue>;\n return {\n create: collection.create,\n update: collection.update,\n remove: collection.remove,\n refresh: collection.refresh,\n snapshot,\n };\n }\n const singleton = handle as UiSettingSingleton<TValue>;\n return {\n set: singleton.set,\n remove: singleton.remove,\n refresh: singleton.refresh,\n snapshot,\n };\n}\n\n/**\n * One handle's disposal bookkeeping for the StrictMode guard below:\n * `scheduled` is true from the moment a cleanup defers this handle's real\n * `dispose()` call until either the deferred check runs it for real, or a\n * later setup for the SAME handle cancels it.\n */\ninterface PendingDisposal<TValue, TCardinality extends UiSettingCardinality> {\n readonly handle: UiSettingHandle<TValue, TCardinality>;\n scheduled: boolean;\n}\n\n/**\n * Opens (and keeps open) a live lease on `definition` at `params` against\n * the `UiSettingsStore` provided by the nearest `UiSettingsProvider`, and\n * subscribes this component to it.\n *\n * - Two components calling this with the same definition and structurally\n * equal params each get their OWN lease, but `store.open` dedups them onto\n * one underlying adapter collection (see `@burojs/core`'s\n * `createUiSettingsStore`) — so there is exactly one live subscription to\n * the adapter, and both components re-render off the same snapshot.\n * - A re-render with a new-but-equal `params` object reuses the already-open\n * lease; only a genuine change (new canonical params, or a new\n * `definition`) releases the old lease and opens a new one.\n * - Unmounting (or a query change) disposes ONLY this hook's own lease. The\n * underlying adapter collection is disposed by the store once every lease\n * sharing it has been released — this hook never disposes the store\n * itself.\n *\n * **StrictMode safety.** React's development `<StrictMode>` mounts effects\n * as setup → cleanup → setup, with NO render in between (see\n * `examples/marketplace-ops/src/main.tsx` and `examples/vite/src/main.tsx`,\n * both of which wrap the whole app in it and both of which mount the default\n * store, so this is a live path, not a hypothetical one — the application\n * this note originally cited, `apps/playground`, left with SP9). A\n * `UiSettingLease` from core is single-shot: once\n * `dispose()` runs, it never becomes usable again (`store.ts`'s\n * `disposed` flag is permanent), so disposing on every cleanup would let the\n * phantom cleanup permanently kill a lease that was never actually meant to\n * go away, and the very next `getSnapshot()` call would throw. The effect\n * below defers the real `handle.dispose()` call by one microtask tick; a\n * StrictMode phantom re-setup for the SAME handle (nothing else changed —\n * still no render happened) cancels it before it ever fires, so the\n * original lease and its subscription survive the whole phantom cycle\n * untouched — no reopen, no resubscription, no swapped handle for callers\n * to worry about. A genuine unmount, or a genuine params/definition change\n * (a DIFFERENT handle), has nothing left to cancel it, so the deferred\n * dispose runs for real.\n */\nexport function useUiSettings<TParams, TValue, TCardinality extends UiSettingCardinality>(\n definition: UiSettingTypeDefinition<TParams, TValue, TCardinality>,\n params: TParams,\n): UseUiSettingsResult<TValue, TCardinality> {\n const store = useContext(UiSettingsStoreContext);\n if (store === null) {\n throw new Error('[useUiSettings] must be used within a UiSettingsProvider.');\n }\n\n const key = `${definition.id} ${stableParamsKey(params)}`;\n const acquiredRef = useRef<AcquiredLease<TParams, TValue, TCardinality> | undefined>(undefined);\n const acquired = acquiredRef.current;\n if (\n acquired === undefined ||\n acquired.store !== store ||\n acquired.definition !== definition ||\n acquired.key !== key\n ) {\n acquiredRef.current = { store, definition, key, handle: store.open(definition, params) };\n }\n // Non-null: the block above always assigns before this line runs.\n const handle = (acquiredRef.current as AcquiredLease<TParams, TValue, TCardinality>).handle;\n\n const pendingDisposalRef = useRef<PendingDisposal<TValue, TCardinality> | null>(null);\n useEffect(() => {\n // Reuse the existing bookkeeping record when this setup's `handle` is\n // the SAME object a moment-ago cleanup just scheduled for disposal —\n // that can only be a StrictMode phantom re-setup (a genuine params/\n // definition change always produces a NEW handle, from the render-phase\n // block above, before this effect ever sees it). Cancel the pending\n // dispose either way: a brand-new handle has nothing scheduled yet\n // (no-op), and a StrictMode-survived handle must not be torn down.\n const reused =\n pendingDisposalRef.current !== null && pendingDisposalRef.current.handle === handle\n ? pendingDisposalRef.current\n : null;\n const record = reused ?? { handle, scheduled: false };\n pendingDisposalRef.current = record;\n record.scheduled = false;\n\n return () => {\n record.scheduled = true;\n queueMicrotask(() => {\n if (!record.scheduled) return; // Cancelled by an immediate resetup for this same handle.\n handle.dispose();\n });\n };\n }, [handle]);\n\n const snapshot = useSyncExternalStore(handle.subscribe, handle.getSnapshot, handle.getSnapshot);\n\n return useMemo(\n () => buildResult(definition.cardinality, handle, snapshot),\n [definition.cardinality, handle, snapshot],\n ) as UseUiSettingsResult<TValue, TCardinality>;\n}\n","import {\n createMutationDescriptor,\n createQueryDescriptor,\n type ActionDataAccess,\n type CustomMutationHandle,\n type CustomQueryHandle,\n type InferCreateInput,\n type InferCustomInput,\n type InferCustomOutput,\n type InferId,\n type InferUpdateInput,\n type Pagination,\n type ResourceHandle,\n} from '@burojs/core';\n\nimport { executeMutation } from './mutation-options.js';\nimport { executeQuery } from './query-execution.js';\nimport type { DataRuntimeContextValue } from './runtime.js';\n\ntype AnyResource = ResourceHandle<any, any, any, any>;\n\n/** Runtime-owned action DI. Descriptor identity always comes from the current lease. */\nexport function createRuntimeActionDataAccess(runtime: DataRuntimeContextValue): ActionDataAccess {\n async function resourceBase(resource: AnyResource) {\n const session = await runtime.waitUntilReady();\n const projection = runtime.app.registry.get(resource);\n if (projection === undefined)\n throw {\n kind: 'configuration',\n code: 'action-data-resource-unavailable',\n message: `Resource '${resource.ref.namespace}:${resource.ref.id}' is unavailable.`,\n };\n const binding = runtime.app.resolveDataBinding(resource);\n return {\n providerId: binding.providerId,\n ref: binding.ref,\n resource: binding.resource,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n bindingRevision: runtime.app.runtime.getSnapshot().manifest.snapshotId,\n idField: projection.data?.idField ?? 'id',\n ...(projection.data?.providerOptions === undefined\n ? {}\n : { providerOptions: projection.data.providerOptions }),\n };\n }\n async function resourceQuery(resource: AnyResource, input: Record<string, unknown>) {\n return executeQuery({\n descriptor: createQueryDescriptor({ ...(await resourceBase(resource)), ...input } as never),\n runtime,\n signal: new AbortController().signal,\n });\n }\n async function resourceMutation(resource: AnyResource, input: Record<string, unknown>) {\n return executeMutation({\n descriptor: createMutationDescriptor({\n ...(await resourceBase(resource)),\n ...input,\n } as never),\n runtime,\n });\n }\n async function customQuery(handle: CustomQueryHandle<unknown, unknown>, input: unknown) {\n const session = await runtime.waitUntilReady();\n const snapshot = runtime.app.runtime.getSnapshot();\n const projection = snapshot.getProjection(handle);\n if (projection === undefined || projection.kind !== 'custom-query')\n throw {\n kind: 'configuration',\n code: 'action-data-custom-query-unavailable',\n message: 'Custom query handle is unavailable.',\n };\n const binding = (\n projection.value as {\n binding?: {\n provider?: string;\n resource?: string;\n operation?: string;\n providerOptions?: unknown;\n };\n }\n ).binding;\n if (!binding?.provider || !binding.operation)\n throw {\n kind: 'configuration',\n code: 'action-data-custom-binding-invalid',\n message: 'Custom query binding is invalid.',\n };\n return executeQuery({\n descriptor: createQueryDescriptor({\n kind: 'custom',\n providerId: binding.provider,\n ref: handle.ref,\n resource: binding.resource ?? handle.ref.id,\n operation: binding.operation,\n input,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n bindingRevision: snapshot.manifest.snapshotId,\n ...(binding.providerOptions === undefined\n ? {}\n : { providerOptions: binding.providerOptions }),\n } as never),\n runtime,\n signal: new AbortController().signal,\n });\n }\n async function customMutation(handle: CustomMutationHandle<unknown, unknown>, input: unknown) {\n const session = await runtime.waitUntilReady();\n const snapshot = runtime.app.runtime.getSnapshot();\n const projection = snapshot.getProjection(handle);\n if (projection === undefined || projection.kind !== 'custom-mutation')\n throw {\n kind: 'configuration',\n code: 'action-data-custom-mutation-unavailable',\n message: 'Custom mutation handle is unavailable.',\n };\n const value = projection.value as {\n binding?: {\n provider?: string;\n resource?: string;\n operation?: string;\n providerOptions?: unknown;\n };\n replay?: unknown;\n };\n const binding = value.binding;\n if (!binding?.provider || !binding.operation)\n throw {\n kind: 'configuration',\n code: 'action-data-custom-binding-invalid',\n message: 'Custom mutation binding is invalid.',\n };\n return executeMutation({\n descriptor: createMutationDescriptor({\n kind: 'custom',\n providerId: binding.provider,\n ref: handle.ref,\n resource: binding.resource ?? handle.ref.id,\n operation: binding.operation,\n input,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n bindingRevision: snapshot.manifest.snapshotId,\n ...(binding.providerOptions === undefined\n ? {}\n : { providerOptions: binding.providerOptions }),\n ...(value.replay === undefined ? {} : { replay: value.replay }),\n } as never),\n runtime,\n });\n }\n return Object.freeze({\n one: <R extends AnyResource>(resource: R, { id }: { id: InferId<R> }) =>\n resourceQuery(resource, { kind: 'one', id }),\n list: <R extends AnyResource>(\n resource: R,\n args: { pagination?: Pagination; filter?: unknown; sort?: unknown } = {},\n ) => resourceQuery(resource, { kind: 'list', ...args }),\n many: <R extends AnyResource>(resource: R, { ids }: { ids: readonly InferId<R>[] }) =>\n resourceQuery(resource, { kind: 'many', ids }),\n createOne: <R extends AnyResource>(resource: R, { input }: { input: InferCreateInput<R> }) =>\n resourceMutation(resource, { kind: 'createOne', input }),\n updateOne: <R extends AnyResource>(\n resource: R,\n { id, input }: { id: InferId<R>; input: InferUpdateInput<R> },\n ) => resourceMutation(resource, { kind: 'updateOne', id, input }),\n deleteOne: <R extends AnyResource>(resource: R, { id }: { id: InferId<R> }) =>\n resourceMutation(resource, { kind: 'deleteOne', id }),\n query: <H extends CustomQueryHandle<unknown, unknown>>(handle: H, input: InferCustomInput<H>) =>\n customQuery(handle, input) as Promise<InferCustomOutput<H>>,\n mutate: <H extends CustomMutationHandle<unknown, unknown>>(\n handle: H,\n input: InferCustomInput<H>,\n ) => customMutation(handle, input) as Promise<InferCustomOutput<H>>,\n } as ActionDataAccess);\n}\n\n/**\n * Stand-in `ActionDataAccess` for a DI consumer (`useChecks`/`useCheckGate`)\n * mounted with no native data runtime (`useOptionalDataRuntime()` returned\n * `null` — see `../data/context.tsx`). Every method rejects with `reason`\n * rather than being unavailable outright: a check/rule that never touches\n * `di.data` must keep working normally, and one that DOES gets a clear,\n * named diagnostic instead of a generic \"cannot read properties of null\"\n * crash. `evaluateChecks` already treats a throwing/rejecting predicate as a\n * `check.exception` warning issue (`@burojs/core`'s `evaluate.ts`), so this\n * degrades to a visible, non-blocking \"check failed to run\" rather than\n * silently vanishing or crashing the host form.\n */\nexport function createUnavailableActionDataAccess(reason: string): ActionDataAccess {\n // Typed `() => Promise<never>` (not cast away) so the object literal below\n // is actually checked structurally against `ActionDataAccess` — a fewer-\n // parameter function is assignable to each of the interface's specific\n // (more-parameter) method signatures, and `Promise<never>` is assignable\n // to every method's own `Promise<...>` return type, so this catches a\n // shape drift (a renamed/added/removed method) at compile time instead of\n // silently no-op'ing behind a cast.\n const fail = (): Promise<never> => Promise.reject(new Error(reason));\n return Object.freeze({\n one: fail,\n list: fail,\n many: fail,\n createOne: fail,\n updateOne: fail,\n deleteOne: fail,\n query: fail,\n mutate: fail,\n });\n}\n","import type { RegistryResource, ResourceRefInput } from '@burojs/core';\nimport { useApp } from './use-app.js';\n\nexport function useResource(ref: ResourceRefInput): RegistryResource | undefined {\n const app = useApp();\n return app.registry.get(ref);\n}\n","import type {\n FieldDeclaration,\n FieldOption,\n ValidationIssue,\n ValidationIssues,\n} from '@burojs/core';\nimport { createElement, type ComponentType, type ReactElement, useMemo } from 'react';\nimport { useFieldImplementationCatalog } from './provider.js';\nimport type { FieldImplementationCatalog } from './definitions.js';\nimport type {\n CollectionDisplayProps,\n CollectionInputProps,\n FieldAccessibilityIds,\n FieldImplementationAttempt,\n FieldImplementationComponent,\n FieldImplementationLayout,\n FieldRenderSurface,\n FieldTestIds,\n FieldUiHints,\n ResolvedFieldImplementation,\n ScalarDisplayProps,\n ScalarInputProps,\n UseFieldImplementationArgs,\n} from './types.js';\n\nconst EMPTY_LAYOUT: FieldImplementationLayout = Object.freeze({});\nconst EMPTY_META = Object.freeze({});\nconst EMPTY_UI = Object.freeze({});\nconst EMPTY_OPTIONS = Object.freeze([]);\n\ntype RuntimeField = {\n readonly type: string;\n readonly format?: string;\n readonly items?: FieldDeclaration;\n readonly meta?: Readonly<Record<string, unknown>>;\n readonly ui?: FieldUiHints;\n readonly options?: readonly FieldOption[];\n};\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction ui(value: unknown): FieldUiHints | undefined {\n return isRecord(value) ? (value as FieldUiHints) : undefined;\n}\n\n/** Accept a raw declaration or a native FieldDefBase that carries one. */\nfunction canonicalField(input: UseFieldImplementationArgs['field']): RuntimeField {\n if (!isRecord(input)) throw new TypeError('A field implementation requires a field declaration.');\n const nested = isRecord(input.declaration) ? input.declaration : undefined;\n const type = typeof input.type === 'string' ? input.type : nested?.type;\n if (typeof type !== 'string' || type.length === 0) {\n throw new TypeError('A field implementation requires a canonical field type.');\n }\n const format =\n typeof input.format === 'string'\n ? input.format\n : typeof nested?.format === 'string'\n ? nested.format\n : undefined;\n const items = isRecord(input.items)\n ? (input.items as unknown as FieldDeclaration)\n : isRecord(nested?.items)\n ? (nested.items as unknown as FieldDeclaration)\n : undefined;\n const meta = isRecord(input.meta) ? input.meta : isRecord(nested?.meta) ? nested.meta : undefined;\n const fieldUi = ui(input.ui) ?? ui(nested?.ui);\n return Object.freeze({\n type,\n ...(format === undefined ? {} : { format }),\n ...(items === undefined ? {} : { items }),\n ...(meta === undefined ? {} : { meta }),\n ...(fieldUi === undefined ? {} : { ui: fieldUi }),\n ...(Array.isArray(input.options)\n ? { options: input.options as readonly FieldOption[] }\n : Array.isArray(nested?.options)\n ? { options: nested.options as readonly FieldOption[] }\n : {}),\n });\n}\n\nfunction component(\n catalog: FieldImplementationCatalog,\n id: string | undefined,\n surface: FieldRenderSurface,\n collection: boolean,\n): FieldImplementationComponent | undefined {\n if (id === undefined) return undefined;\n const implementation = catalog[id];\n if (implementation === undefined) return undefined;\n const value = collection\n ? surface === 'input'\n ? implementation.CollectionInput\n : implementation.CollectionDisplay\n : surface === 'input'\n ? implementation.Input\n : implementation.Display;\n return value as FieldImplementationComponent | undefined;\n}\n\nfunction layout(\n catalog: FieldImplementationCatalog,\n id: string | undefined,\n): FieldImplementationLayout {\n return id === undefined ? EMPTY_LAYOUT : (catalog[id]?.layout ?? EMPTY_LAYOUT);\n}\n\nfunction explicitId(field: RuntimeField, surface: FieldRenderSurface): string | undefined {\n const candidate = surface === 'input' ? field.ui?.input : field.ui?.display;\n return typeof candidate === 'string' && candidate.length > 0 ? candidate : undefined;\n}\n\nfunction trace(field: RuntimeField, attempts: readonly FieldImplementationAttempt[]) {\n return Object.freeze({\n ...(field.format === undefined\n ? {}\n : { rawFormat: field.format, resolvedFormat: field.format }),\n attempts: Object.freeze([...attempts]),\n });\n}\n\nfunction missing(\n field: RuntimeField,\n surface: FieldRenderSurface,\n multiple: boolean,\n attempts: readonly FieldImplementationAttempt[],\n): ResolvedFieldImplementation {\n const resolution = trace(field, attempts);\n return Object.freeze({\n multiple,\n source: 'fallback',\n layout: EMPTY_LAYOUT,\n trace: resolution,\n diagnostic: Object.freeze({\n code: 'missing-field-implementation',\n fieldType: field.type,\n ...(field.format === undefined ? {} : { format: field.format, resolvedFormat: field.format }),\n surface,\n attempts: resolution.attempts,\n }),\n });\n}\n\nfunction lookup(\n catalog: FieldImplementationCatalog,\n attempts: FieldImplementationAttempt[],\n stage: FieldImplementationAttempt['stage'],\n id: string | undefined,\n surface: FieldRenderSurface,\n collection: boolean,\n): FieldImplementationComponent | undefined {\n attempts.push(\n Object.freeze({\n stage,\n capability: collection ? `collection-${surface}` : surface,\n ...(id === undefined ? {} : { id }),\n }),\n );\n return component(catalog, id, surface, collection);\n}\n\nfunction scalar(\n catalog: FieldImplementationCatalog,\n field: RuntimeField,\n surface: FieldRenderSurface,\n): ResolvedFieldImplementation {\n const attempts: FieldImplementationAttempt[] = [];\n const explicit = explicitId(field, surface);\n const explicitComponent = lookup(catalog, attempts, 'explicit', explicit, surface, false);\n if (explicitComponent !== undefined)\n return Object.freeze({\n Component: explicitComponent,\n multiple: false,\n source: 'explicit',\n layout: layout(catalog, explicit),\n trace: trace(field, attempts),\n });\n const formatComponent = lookup(catalog, attempts, 'format', field.format, surface, false);\n if (formatComponent !== undefined)\n return Object.freeze({\n Component: formatComponent,\n multiple: false,\n source: 'format',\n layout: layout(catalog, field.format),\n trace: trace(field, attempts),\n });\n const base = lookup(catalog, attempts, 'base', field.type, surface, false);\n if (base !== undefined)\n return Object.freeze({\n Component: base,\n multiple: false,\n source: 'base',\n layout: layout(catalog, field.type),\n trace: trace(field, attempts),\n });\n return missing(field, surface, false, attempts);\n}\n\nfunction collection(\n catalog: FieldImplementationCatalog,\n field: RuntimeField,\n surface: FieldRenderSurface,\n): ResolvedFieldImplementation {\n const attempts: FieldImplementationAttempt[] = [];\n const explicit = explicitId(field, surface);\n const explicitComponent = lookup(catalog, attempts, 'explicit', explicit, surface, true);\n if (explicitComponent !== undefined)\n return Object.freeze({\n Component: explicitComponent,\n multiple: true,\n source: 'explicit',\n layout: layout(catalog, explicit),\n trace: trace(field, attempts),\n });\n const ownFormat = lookup(catalog, attempts, 'own-collection-format', field.format, surface, true);\n if (ownFormat !== undefined)\n return Object.freeze({\n Component: ownFormat,\n multiple: true,\n source: 'collection-format',\n layout: layout(catalog, field.format),\n trace: trace(field, attempts),\n });\n const item = canonicalField(field.items!);\n const itemFormat = lookup(\n catalog,\n attempts,\n 'item-collection-format',\n item.format,\n surface,\n true,\n );\n if (itemFormat !== undefined)\n return Object.freeze({\n Component: itemFormat,\n multiple: true,\n source: 'collection-format',\n layout: layout(catalog, item.format),\n trace: trace(field, attempts),\n });\n const itemResolved = scalar(catalog, item, surface);\n attempts.push(\n ...itemResolved.trace.attempts.map((attempt) =>\n Object.freeze({ ...attempt, stage: 'item-scalar' as const }),\n ),\n );\n if (itemResolved.Component !== undefined)\n return Object.freeze({\n Component: (surface === 'input'\n ? GenericArrayInput\n : GenericArrayDisplay) as FieldImplementationComponent,\n multiple: true,\n source: 'array-shell',\n layout: itemResolved.layout,\n item: itemResolved,\n trace: trace(field, attempts),\n });\n const base = lookup(catalog, attempts, 'base', field.type, surface, true);\n if (base !== undefined)\n return Object.freeze({\n Component: base,\n multiple: true,\n source: 'base',\n layout: layout(catalog, field.type),\n trace: trace(field, attempts),\n });\n return missing(field, surface, true, attempts);\n}\n\n/** Resolve host-provided code without consulting an app runtime or module global. */\nexport function resolveFieldImplementation(\n catalog: FieldImplementationCatalog,\n input: UseFieldImplementationArgs,\n): ResolvedFieldImplementation {\n const field = canonicalField(input.field);\n if (field.type === 'array') {\n if (field.items === undefined)\n throw new TypeError('An array field implementation requires an items declaration.');\n return collection(catalog, field, input.surface);\n }\n return scalar(catalog, field, input.surface);\n}\n\nexport function useFieldImplementation(\n input: UseFieldImplementationArgs,\n): ResolvedFieldImplementation {\n const catalog = useFieldImplementationCatalog();\n return useMemo(() => resolveFieldImplementation(catalog, input), [catalog, input]);\n}\n\nfunction indexedIds<T extends FieldAccessibilityIds | FieldTestIds>(input: T, index: number): T {\n return Object.freeze(\n Object.fromEntries(\n Object.entries(input).map(([key, value]) => [\n key,\n typeof value === 'string' && value.length > 0 ? `${value}-${index}` : value,\n ]),\n ),\n ) as T;\n}\n\nfunction itemIssues(issues: ValidationIssues, index: number): ValidationIssues {\n return Object.freeze(\n issues\n .filter((issue) => issue.path[0] === index)\n .map((issue) =>\n Object.freeze({ ...issue, path: Object.freeze(issue.path.slice(1)) }),\n ) as ValidationIssue[],\n );\n}\n\nfunction itemContext<T extends CollectionInputProps<unknown> | CollectionDisplayProps<unknown>>(\n parent: T,\n field: FieldDeclaration,\n index: number,\n) {\n const item = canonicalField(field);\n return Object.freeze({\n ...parent,\n field,\n path: Object.freeze([...parent.path, index]),\n meta: item.meta ?? EMPTY_META,\n ui: item.ui ?? EMPTY_UI,\n options: item.options ?? EMPTY_OPTIONS,\n issues: itemIssues(parent.issues, index),\n accessibility: indexedIds(parent.accessibility, index),\n testIds: indexedIds(parent.testIds, index),\n });\n}\n\nfunction GenericArrayInput(props: CollectionInputProps<unknown>): ReactElement | null {\n const field = canonicalField(props.field);\n if (field.type !== 'array' || field.items === undefined) return null;\n return createElement(\n 'div',\n { 'data-buro-array-shell': 'input' },\n props.value.map((value, index) =>\n createElement(GenericArrayItemInput, {\n key: index,\n field: field.items!,\n parent: props,\n value,\n index,\n }),\n ),\n );\n}\n\nfunction GenericArrayItemInput({\n field,\n parent,\n value,\n index,\n}: {\n readonly field: FieldDeclaration;\n readonly parent: CollectionInputProps<unknown>;\n readonly value: unknown;\n readonly index: number;\n}): ReactElement | null {\n const resolved = useFieldImplementation({ field, surface: 'input' });\n if (resolved.Component === undefined) return null;\n const Component = resolved.Component as ComponentType<ScalarInputProps<unknown>>;\n return createElement(Component, {\n ...itemContext(parent, field, index),\n multiple: false,\n value,\n onChange: (next: unknown) =>\n parent.onChange?.(\n parent.value.map((entry, itemIndex) => (itemIndex === index ? next : entry)),\n ),\n } as ScalarInputProps<unknown>);\n}\n\nfunction GenericArrayDisplay(props: CollectionDisplayProps<unknown>): ReactElement | null {\n const field = canonicalField(props.field);\n if (field.type !== 'array' || field.items === undefined) return null;\n return createElement(\n 'div',\n { 'data-buro-array-shell': 'display' },\n props.value.map((value, index) =>\n createElement(GenericArrayItemDisplay, {\n key: index,\n field: field.items!,\n parent: props,\n value,\n index,\n }),\n ),\n );\n}\n\nfunction GenericArrayItemDisplay({\n field,\n parent,\n value,\n index,\n}: {\n readonly field: FieldDeclaration;\n readonly parent: CollectionDisplayProps<unknown>;\n readonly value: unknown;\n readonly index: number;\n}): ReactElement | null {\n const resolved = useFieldImplementation({ field, surface: 'display' });\n if (resolved.Component === undefined) return null;\n const Component = resolved.Component as ComponentType<ScalarDisplayProps<unknown>>;\n return createElement(Component, {\n ...itemContext(parent, field, index),\n multiple: false,\n value,\n } as ScalarDisplayProps<unknown>);\n}\n","import { defineFieldDeclaration, type FieldDeclaration } from '@burojs/core';\nimport { composeFieldImplementations, type FieldImplementationCatalog } from './definitions.js';\nimport type { FieldImplementation } from './types.js';\n\ntype FieldDeclarationOverrides<TMeta extends Readonly<Record<string, unknown>>> = Omit<\n FieldDeclaration,\n 'type' | 'format' | 'meta'\n> & { readonly meta?: TMeta };\n\nexport interface DefinedField<\n TMeta extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>,\n> {\n (overrides?: FieldDeclarationOverrides<TMeta>): FieldDeclaration & { readonly meta?: TMeta };\n readonly declaration: FieldDeclaration;\n readonly catalog: FieldImplementationCatalog;\n}\n\n/**\n * Application-local authoring sugar. It makes a portable field declaration\n * helper and a separate, immutable catalog contribution once at module setup;\n * each helper call returns data only and never registers implementation code.\n */\nexport function defineFieldWithImplementation<\n TMeta extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>,\n>(\n declaration: FieldDeclaration,\n implementation: FieldImplementation<any, TMeta>,\n): DefinedField<TMeta> {\n const base = defineFieldDeclaration(declaration as FieldDeclaration);\n const id = base.format ?? base.type;\n const catalog = composeFieldImplementations({ [id]: implementation });\n const field = ((overrides: FieldDeclarationOverrides<TMeta> = {}) =>\n defineFieldDeclaration({\n ...base,\n ...overrides,\n type: base.type,\n ...(base.format === undefined ? {} : { format: base.format }),\n } as FieldDeclaration) as FieldDeclaration & { readonly meta?: TMeta }) as DefinedField<TMeta>;\n return Object.freeze(\n Object.assign(field, {\n declaration: base,\n catalog,\n }),\n );\n}\n","import { type DocContent, resolveDoc } from '@burojs/core';\nimport { useMemo } from 'react';\nimport { useI18nCaps } from './use-t.js';\n\n/**\n * Contextual documentation for one address, resolved at render time.\n *\n * `useI18nCaps()` re-derives on a locale change, so this memo recomputes when\n * the language flips — the popover's text follows the live language switch\n * without a reload, like every other content slot in the app.\n *\n * Returns `undefined` when there is nothing to show, which is exactly the\n * condition for rendering no affordance at all: density is authored in the\n * bundle, not imposed by the framework.\n */\nexport function useDoc(address: string | undefined): DocContent | undefined {\n const caps = useI18nCaps();\n return useMemo(() => (address ? resolveDoc(caps, address) : undefined), [caps, address]);\n}\n","import type { RegistryResource } from '@burojs/core';\nimport { useContext } from 'react';\nimport { ResourceContext } from '../context.js';\nimport { useApp } from './use-app.js';\n\nexport function useCurrentResource(): RegistryResource | null {\n const ctx = useContext(ResourceContext);\n const app = useApp();\n if (!ctx.resource) return null;\n return app.registry.get(ctx.resource) ?? null;\n}\n","import { useCallback, useContext, useSyncExternalStore } from 'react';\nimport { ResolverContext } from '../context.js';\n\nexport function useCtx<T>(selector: (s: never) => T): T {\n const resolver = useContext(ResolverContext);\n if (!resolver) throw new Error('[useCtx] must be used within a BuroProvider');\n\n const subscribe = useCallback((onChange: () => void) => resolver.subscribe(onChange), [resolver]);\n // ⚠️ The THIRD argument is not optional in practice. Omit it and React throws\n // \"Missing getServerSnapshot, which is required for server-rendered content.\n // Will revert to client rendering.\" the moment a component calling this is\n // rendered on the server — and its own wording names the consequence: the\n // boundary silently degrades to client-only instead of failing loudly.\n //\n // This was missing here, and only here: `use-t.ts:77` and\n // `use-doc-panel.tsx:166,377` all pass three. It went unnoticed because\n // nothing in this repository had ever server-rendered a component that reads\n // context — every consumer sits under a provider whose bootstrap returns\n // `null` during SSR, so this body never ran there. The reach is not small:\n // `useCtx` feeds `useAvailability`, `useCapability` and `usePermissions`, and\n // through them every list and every form in `@burojs/ui-shadcn`.\n //\n // The server snapshot is the SAME function as the client one, which is correct\n // rather than a shortcut: the resolver's snapshot is synchronously available\n // and identical on both sides, so there is nothing for a separate server\n // implementation to do differently.\n const getSnapshot = useCallback(\n () => selector(resolver.snapshot() as never),\n [resolver, selector],\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","import type { AppContext, PermissionMap } from '@burojs/core';\nimport { useCallback, useContext, useSyncExternalStore } from 'react';\nimport { ResolverContext } from '../context.js';\nimport { useCtx } from './use-ctx.js';\n\n/**\n * Read the current `permissions` slice from AppContext.\n *\n * Returns `undefined` when no `permissions` slice has been wired (default —\n * adopters opt INTO permissions by registering a slice that emits a\n * PermissionMap value). Callers MUST handle the undefined case; the\n * convention is fail-closed (treat missing permissions as \"deny\" inside\n * `visible(ctx)` predicates) — see `evaluateVisible` in `@burojs/core`.\n */\nexport function usePermissions(): PermissionMap | undefined {\n return useCtx((ctx: AppContext) => ctx.permissions);\n}\n\n/**\n * Read the current `scope` slice from AppContext.\n *\n * Returns `undefined` when no `scope` slice has been wired (default — the\n * scope slot is opt-in). The slot is intentionally typed as\n * `Record<string, unknown>` so adopters define the shape (PG, location,\n * warehouse, tenant…) and read keys with `ctx.scope?.<key>` inside their\n * `visible(ctx)` predicates.\n */\nexport function useScopeCtx(): Record<string, unknown> | undefined {\n return useCtx((ctx: AppContext) => ctx.scope);\n}\n\n/**\n * Build a snapshot of the AppContext suitable for passing to `evaluateVisible`.\n *\n * Aggregates every built-in slot the framework consumes for visibility\n * predicates: `{ permissions, scope, user }`.\n *\n * ⚠️ `user` was MISSING here, and the omission was silent and unsafe. It is a\n * documented built-in slot (`AppContext.user`, \"consumed by the\n * capability-rules engine so predicates can gate on `ctx.user.roles`\"), and\n * `useCapabilityResolver` reads all three — so the same predicate behaved\n * differently depending on whether it was written as a `rules:` entry (worked)\n * or as a field/resource/action `visible` (saw `undefined`).\n *\n * The failure mode is data exposure, because the natural phrasing fails OPEN:\n *\n * visible: (ctx) => !ctx.user?.roles.includes('external_auditor')\n * // ctx.user === undefined → !undefined → TRUE → shown to the auditor\n *\n * and the mirror phrasing (`?? false`) hides the field from everyone including\n * the users who should see it. Both compile, neither warns.\n *\n * This docblock previously claimed call sites \"pick up new built-in slots\n * automatically when they are added\" — which is exactly what did not happen.\n */\nexport function useVisibilityCtx(): AppContext {\n const permissions = usePermissions();\n const scope = useScopeCtx();\n const user = useCtx((c: AppContext) => c.user);\n return { permissions, scope, user };\n}\n\nconst EMPTY_APP_CONTEXT: AppContext = Object.freeze({});\n\n/**\n * Like `useVisibilityCtx`, but tolerant of a missing `BuroProvider` —\n * returns `{}` instead of throwing outside one.\n *\n * Mirrors `useCurrentUIActivation`'s (`../ui/use-ui-present.ts`) \"works\n * standalone\" precedent: a headless hook meant to be instantiable via a bare\n * `renderHook(() => useX(...))`, with no wrapper, needs graceful\n * degradation rather than `useCtx`'s hard `must be used within a\n * BuroProvider` throw. `useDeclarativeForm` (`../forms/use-declarative-\n * form.ts`, Task 4) is the first consumer: a form with no conditional\n * (`visible`/predicate `required`/`disabled`) fields must not need a full\n * app `BuroProvider` tree just to mount and be unit-tested — Task 3's\n * `renderHook(() => useDeclarativeForm(...))` tests (no wrapper) must keep\n * passing once the controller starts reading a visibility ctx.\n *\n * Inside a real `BuroProvider`, this reads the same live resolver snapshot\n * `useVisibilityCtx` does (including reactivity to slice updates), just\n * without narrowing it down to `{ permissions, scope, user }` first — the\n * one behavioral difference is that other app-defined slices ride along\n * too, which is harmless for a predicate `ctx` argument that only ever\n * reads `ctx.permissions`/`ctx.scope`/`ctx.user`.\n */\nexport function useOptionalVisibilityCtx(): AppContext {\n const resolver = useContext(ResolverContext);\n const subscribe = useCallback(\n (onChange: () => void) => (resolver === null ? () => undefined : resolver.subscribe(onChange)),\n [resolver],\n );\n const getSnapshot = useCallback(\n () => (resolver === null ? EMPTY_APP_CONTEXT : (resolver.snapshot() as AppContext)),\n [resolver],\n );\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","import { resolveVisibleTemplates, type DocumentTemplate } from '@burojs/core';\nimport { useMemo } from 'react';\nimport { useApp } from './use-app.js';\nimport { useVisibilityCtx } from './use-permissions.js';\n\n/**\n * The document types a user may be offered for `resource` right now.\n *\n * `templates.items` filtered by each entry's `visible` predicate against the\n * live app context (`{ permissions, scope, user }`) — the seam that makes a\n * type set follow scope. The hook re-runs when the context slices move, so a\n * picker built on it narrows the moment the user switches market, tenant or\n * role, with no code in the picker that knows about any of them.\n *\n * Returns `[]` for an unknown resource and for a resource that declares no\n * `templates` — \"no types on offer\", which is the honest answer for a resource\n * that has none, and lets a caller render its picker unconditionally.\n *\n * ⚠️ **This is the OFFER, not an authorization boundary.** A type hidden here\n * is still renderable by a record that already carries it (a row that exists\n * has to stay readable) and still reachable by a hand-typed create URL — the\n * page-level guard remains the host's, exactly as `ResourceConfig.visible`\n * gates navigation rather than routes. Use a capability rule where the\n * boundary has to hold.\n */\nexport function useVisibleTemplates(resource: string): DocumentTemplate[] {\n const app = useApp();\n const ctx = useVisibilityCtx();\n const def = app.registry.get(resource);\n // `ctx` is a fresh object every render (`useVisibilityCtx` builds a snapshot),\n // so this memo re-runs on every render by identity. That is deliberate and\n // cheap — the alternative, keying on the slice VALUES, would go stale the\n // first time a predicate read a slot this hook did not think to list.\n return useMemo(() => (def ? resolveVisibleTemplates(def, ctx) : []), [def, ctx]);\n}\n","import type { AppContext, Capability, CapabilityDecision, RuleContext } from '@burojs/core';\nimport { resolveCapability } from '@burojs/core';\nimport { useCallback } from 'react';\nimport { useApp } from './use-app.js';\nimport { useCtx } from './use-ctx.js';\n\nexport interface UseCapabilityArgs {\n /** Resource whose rules apply. */\n resource: string;\n target: { kind: string; name?: string };\n /** The record under consideration. Omit while creating. */\n record?: unknown;\n mode?: RuleContext['mode'];\n /**\n * Fallback when no rule matches. `edit`/`view` default OPEN (a field is\n * editable unless a rule says otherwise); gate capabilities like `run`\n * should pass `false`.\n */\n defaultAllowed?: boolean;\n}\n\nexport type CapabilityResolver = (\n capability: Capability,\n target: { kind: string; name?: string },\n defaultAllowed?: boolean,\n) => CapabilityDecision;\n\n/**\n * A single resolver bound to one (resource, record, mode) — the right primitive\n * when many targets are checked in one render (a form iterating its fields).\n * Calling the per-target `useCapability` in that loop would violate the Rules\n * of Hooks; this hoists the hook calls to one fixed set and returns a plain\n * function.\n *\n * The context is assembled from the built-in AppContext slots (`scope`, `user`,\n * `permissions`) plus `record`/`mode`, so a predicate can combine any of them.\n * Rules come through `app.ruleSource` — the MERGED source (application rules\n * from `defineApp({ rules })` + the resource's own), not a direct `def.rules`\n * read — so an app-wide policy governs form fields exactly as it governs\n * buttons, and a backend source can be composed in later without touching call\n * sites.\n *\n * ⚠️ `mode` defaults to `'edit'` here while `useAvailabilityResolver` defaults\n * to `'list'`. Deliberate: this resolver's caller is a form deciding field\n * editability, that one's is a list deciding what to draw per row. A rule that\n * branches on `ctx.mode` therefore sees different defaults from the two hooks —\n * pass `mode` explicitly whenever the two must agree (see `ActionButton`, which\n * derives its mode from its surface for exactly this reason).\n */\nexport function useCapabilityResolver(\n resource: string,\n record?: unknown,\n mode: RuleContext['mode'] = 'edit',\n): CapabilityResolver {\n const app = useApp();\n const scope = useCtx((c: AppContext) => c.scope);\n const user = useCtx((c: AppContext) => c.user);\n const permissions = useCtx((c: AppContext) => c.permissions);\n\n return useCallback(\n (capability, target, defaultAllowed = true) => {\n // The merged source, so an application-level rule is not invisible here.\n // The empty shortcut stays — the merged source returns `[]` only when\n // NEITHER half has a rule, which is the case it was there to make cheap.\n const rules = app.ruleSource.rules(resource);\n if (rules.length === 0) return { allowed: defaultAllowed };\n const ctx: RuleContext = {\n record,\n resource,\n mode,\n scope: scope ?? {},\n // An unauthenticated context has no roles AND says so, so a predicate\n // never has to infer \"signed out\" from an empty id.\n user: user\n ? { id: user.id, roles: user.roles, authenticated: true }\n : { id: '', roles: [], authenticated: false },\n permissions,\n };\n return resolveCapability(rules, capability, target, ctx, defaultAllowed);\n },\n [app.ruleSource, resource, record, mode, scope, user, permissions],\n );\n}\n\n/**\n * Decide a single capability at one call site (a button, a tab). Built on\n * {@link useCapabilityResolver}.\n */\nexport function useCapability(capability: Capability, args: UseCapabilityArgs): CapabilityDecision {\n const resolve = useCapabilityResolver(args.resource, args.record, args.mode);\n return resolve(capability, args.target, args.defaultAllowed ?? true);\n}\n","'use client';\nimport type { AppContext, Availability, RuleContext } from '@burojs/core';\nimport { resolveAvailability } from '@burojs/core';\nimport { useCallback } from 'react';\nimport { useApp } from './use-app.js';\nimport { useCtx } from './use-ctx.js';\n\n/**\n * One resolver bound to a resource, for callers that ask about MANY operations\n * or many records in one render — a list building a link per row, a menu\n * filtering its items. Calling `useAvailability` in such a loop would violate\n * the Rules of Hooks; this hoists the hook calls to a fixed set.\n *\n * ⚠️ `mode` defaults to `'list'` while `useCapabilityResolver` defaults to\n * `'edit'`. Deliberate — this hook's typical caller is a list drawing a row,\n * that one's is a form deciding field editability — but it means a rule\n * branching on `ctx.mode` gets different answers from the two hooks unless the\n * caller passes `mode`. A container and its children must therefore agree\n * explicitly: `ActionOverflow` and `ActionButton` both derive theirs from the\n * surface via `modeForSurface`, because when they did not, a menu rendered and\n * its only item then vanished.\n */\nexport function useAvailabilityResolver(\n resource: string,\n mode: RuleContext['mode'] = 'list',\n): (operation: string, record?: unknown) => Availability {\n const gate = useAvailabilityGate(mode);\n return useCallback((operation, record) => gate(resource, operation, record), [gate, resource]);\n}\n\n/**\n * The same gate with the resource as a PARAMETER rather than a binding — for\n * the few surfaces that ask about many different resources in one render.\n *\n * The command palette's Create group asks every registered resource whether it\n * can be created; a relation picker asks about its target, not about the\n * resource whose form it sits on. Neither can call `useAvailabilityResolver`\n * per resource without breaking the Rules of Hooks, and building the\n * `RuleContext` by hand at each such call site is how the synthesized\n * `{ id: '', roles: [], authenticated: false }` for a signed-out visitor ends\n * up written three slightly different ways.\n */\nexport function useAvailabilityGate(\n mode: RuleContext['mode'] = 'list',\n): (resource: string, operation: string, record?: unknown) => Availability {\n const app = useApp();\n const scope = useCtx((c: AppContext) => c.scope);\n const user = useCtx((c: AppContext) => c.user);\n const permissions = useCtx((c: AppContext) => c.permissions);\n\n return useCallback(\n (resource, operation, record) => {\n const ctx: RuleContext = {\n record,\n resource,\n mode,\n scope: scope ?? {},\n user: user\n ? { id: user.id, roles: user.roles, authenticated: true }\n : { id: '', roles: [], authenticated: false },\n permissions,\n };\n return resolveAvailability(app.ruleSource, app.registry, resource, operation, ctx);\n },\n [app.ruleSource, app.registry, mode, scope, user, permissions],\n );\n}\n\n/** Decide one operation at one call site. */\nexport function useAvailability(\n resource: string,\n operation: string,\n record?: unknown,\n): Availability {\n const resolve = useAvailabilityResolver(resource);\n return resolve(operation, record);\n}\n","'use client';\nimport { APP_ACTION_RESOURCE, canonicalEntityNodeKey } from '@burojs/core';\nimport { useMemo } from 'react';\nimport { useApp } from './use-app.js';\nimport { useAvailabilityGate } from './use-availability.js';\n\nexport interface AppActionEntry {\n readonly name: string;\n readonly label: { single: string; plural?: string };\n readonly kind: 'modal' | 'link';\n readonly component?: string;\n readonly props?: Readonly<Record<string, unknown>>;\n readonly surface?: 'dialog' | 'sheet';\n readonly to?: string;\n readonly icon?: string;\n /** Present when a rule allows it but disables it; the rule's own reason. */\n readonly disabledReason?: string;\n}\n\n/**\n * Every app-level action (`defineAppAction`, `registerAppAction`) the\n * registry knows about, filtered and annotated by the same deny-wins rule\n * engine that gates resource actions.\n *\n * An app action belongs to no resource — there is no `resource.rules` for it\n * to live in — so it is asked about at the reserved address\n * `APP_ACTION_RESOURCE` (`'buro:app-actions'`, from `@burojs/core`). This is\n * not a typo and not a real resource: it is a fixed rule address\n * (`{ resource: APP_ACTION_RESOURCE, operation: <action name> }`) that gives\n * rule authors a stable, predictable place to target app actions\n * (`{ target: { kind: 'action', name: 'incident.collect' } }` in an\n * app-level rule, which — like all app-level rules — applies regardless of\n * the resource argument) without inventing a second gating engine next to\n * `useAvailabilityGate`.\n *\n * Rule-hidden (or absent) actions are dropped from the list entirely; a rule\n * that allows-but-disables an action keeps it in the list with its\n * `disabledReason` set so a caller can render it inert instead of missing.\n */\nexport function useAppActions(): readonly AppActionEntry[] {\n const app = useApp();\n const gate = useAvailabilityGate();\n const list = app.registry.appActions.list();\n\n return useMemo(() => {\n const entries: AppActionEntry[] = [];\n for (const action of list) {\n // `action.name` is the raw, possibly-namespace-dropping id the\n // projection stores (`projectAppAction` keeps `ref.id`, same as pages/\n // groups/sections) — a plugin-registered `'incidents:collect'` lands\n // there as the lossy `'collect'`. `canonicalEntityNodeKey` is the same\n // helper `canonicalNavKey` uses for nav nodes: default-namespace\n // actions keep their short id, a namespaced one gets its qualified\n // `ns:id` form back, which is exactly the string the registry's\n // `appActionByRef` map (and a rule author's `{ name: 'incidents:collect' }`)\n // was keyed on. Gating on the lossy `action.name` here means the gate\n // can never resolve a namespaced action.\n const name = canonicalEntityNodeKey(action);\n const availability = gate(APP_ACTION_RESOURCE, name);\n if (availability.state === 'absent' || availability.state === 'hidden') continue;\n entries.push({\n name,\n label: action.label,\n kind: action.kind,\n component: action.component,\n props: action.props,\n surface: action.surface,\n to: action.to,\n icon: action.icon,\n disabledReason: availability.state === 'disabled' ? availability.reason : undefined,\n });\n }\n return entries;\n }, [list, gate]);\n}\n","import { useCallback, useContext } from 'react';\nimport { ResolverContext } from '../context.js';\n\nexport function useSetSlice<TName extends string = string>(name: TName): (value: unknown) => void {\n const resolver = useContext(ResolverContext);\n if (!resolver) throw new Error('[useSetSlice] must be used within a BuroProvider');\n\n return useCallback(\n (value) => {\n resolver.setSlice(name as never, value);\n },\n [resolver, name],\n );\n}\n","import { useMemo } from 'react';\n\nexport interface TestIdBuilder {\n navMenuItem: (resource: string) => string;\n navGroup: (name: string) => string;\n navBreadcrumb: (resource: string, id?: string) => string;\n /**\n * A sidebar entry for an adopter-declared custom page (`<NavMain>`), keyed\n * by the page key rather than a resource name — the one nav entry that has\n * no resource behind it.\n */\n sidebarCustomPage: (pageKey: string) => string;\n contextPicker: (sliceName: string) => string;\n contextPickerOption: (sliceName: string, value: string) => string;\n\n /**\n * The header language switcher and one locale inside it\n * (`<LanguageSwitch>`). The trigger additionally carries\n * `data-language-state=\"<code>\"`, which is how a test reads the ACTIVE\n * locale without opening the menu.\n */\n languageSwitch: () => string;\n languageSwitchOption: (localeCode: string) => string;\n\n /**\n * `<LoginForm>`'s three controls. Argument-less because the login form is a\n * singleton screen with no resource, record or view to key on — they are\n * factories anyway so that a test never spells the string, which is the\n * whole point of this builder.\n */\n loginEmail: () => string;\n loginPassword: () => string;\n loginSubmit: () => string;\n\n pageList: (resource: string) => string;\n listToolbar: (resource: string) => string;\n listAction: (resource: string, actionName: string) => string;\n listSearch: (resource: string) => string;\n listFilter: (resource: string, fieldName: string) => string;\n listTable: (resource: string) => string;\n listRow: (resource: string, recordId: string) => string;\n listCell: (resource: string, recordId: string, fieldName: string) => string;\n listRowAction: (resource: string, recordId: string, actionName: string) => string;\n /** The list-row overflow (`…`) menu trigger — present when a row has ≥2 actions. */\n listRowActionsMenu: (resource: string, recordId: string) => string;\n listRowCheckbox: (resource: string, recordId: string) => string;\n listPaginationPrev: (resource: string) => string;\n listPaginationNext: (resource: string) => string;\n listPaginationPage: (resource: string, n: number) => string;\n listEmpty: (resource: string) => string;\n listBulkBar: (resource: string) => string;\n bulkAction: (resource: string, actionName: string) => string;\n resourceAction: (resource: string, actionName: string) => string;\n /**\n * `<ExportDialog>`'s root testid (`@burojs/ui-shadcn`). The dialog's own\n * internal controls (format selector, columns toggle, start/download/\n * cancel buttons, the close-while-running confirm) compose off this same\n * id with a `:` suffix rather than each getting their own factory entry —\n * they have no meaning outside one mounted dialog, unlike e.g. `bulkAction`.\n */\n exportDialog: (resource: string) => string;\n /** The list-toolbar Export button (Task 8) — opens `<ExportDialog>` with the current filter/sort scope. */\n exportButton: (resource: string) => string;\n /**\n * The bulk-bar Export item (Task 8) — opens `<ExportDialog>` with the\n * selected ids. A DISTINCT factory from {@link bulkAction} on purpose: a\n * resource may declare its own custom bulk action literally named\n * `'export'` (see `bulk-action-toolbar.test.tsx`), and this built-in entry\n * point must never collide with that testid.\n */\n exportBulkAction: (resource: string) => string;\n\n pageShow: (resource: string, recordId: string) => string;\n pageEdit: (resource: string, recordId: string) => string;\n pageCreate: (resource: string) => string;\n\n /**\n * The panel a detail surface renders in place of a field set when\n * `ResourceConfig.templates.fallback: 'unsupported'` refuses an unrecognised\n * document type. Keyed by RESOURCE and not by the offending value: the value\n * is by definition one the application does not know, so a testid built from\n * it could not be written down in advance by the test that looks for it.\n */\n unsupportedDocumentType: (resource: string) => string;\n\n resourceTab: (resource: string, tabKey: string, recordId?: string) => string;\n\n subresourceTabs: (parentResource: string) => string;\n subresourceTab: (tabKey: string) => string;\n subresourceBody: (childResource: string) => string;\n\n form: (resource: string, view: string, recordId?: string) => string;\n /**\n * One declared field GROUP (`views.fields` as sections) — the `<section>`\n * (or, when `collapsed`, the `<details>`) `<ResourceForm>` wraps each group\n * in.\n *\n * ⚠️ Renamed from `formSection`, which composed `form-section:…` and had\n * **no producer** — the component has always emitted `form-group:…` (SP9\n * task 5, the same sweep that found the whole `picker-*` family addressing\n * nothing).\n */\n formGroup: (resource: string, view: string, groupKey: string) => string;\n formField: (resource: string, view: string, fieldName: string) => string;\n formFieldInput: (resource: string, view: string, fieldName: string) => string;\n formFieldError: (resource: string, view: string, fieldName: string) => string;\n formFieldLocked: (resource: string, view: string, fieldName: string) => string;\n /**\n * A field's help text — the hint under the input, resolved from the i18n\n * `hint` slot or from `meta.description`.\n *\n * ⚠️ This one was the other way round: the id was spelled identically on\n * both sides and simply never rendered. `<ResourceForm>` drew the hint\n * paragraph with an `id` (for `aria-describedby`) and no `data-testid`, so\n * `form.field(x).help()` had matched nothing since it was written. The\n * producer was added at SP9 task 5, which is what lets a browser test assert\n * that `aria-describedby` points at THIS element and that it yields to an\n * error.\n */\n formFieldHelp: (resource: string, view: string, fieldName: string) => string;\n /**\n * Per-field async-validation pending indicator (B2). Rendered next to\n * the field label while a per-field async validator is in flight.\n */\n formFieldValidating: (resource: string, view: string, fieldName: string) => string;\n formSubmit: (resource: string, view: string) => string;\n formCancel: (resource: string, view: string) => string;\n formAction: (resource: string, view: string, actionName: string) => string;\n /** The show/edit toolbar overflow (`…`) menu trigger — present when there are unpinned actions. */\n formActionsMenu: (resource: string, view: string) => string;\n /**\n * Form-level async-validation pending indicator (B2). Rendered near\n * the submit button while the resource-level cross-field validate is\n * in flight.\n */\n formValidating: (resource: string, view: string) => string;\n /**\n * Auto-save / draft-found banner (B7.1). Rendered above the form's\n * field stack on mount when a non-stale localStorage draft exists.\n */\n formDraftBanner: (resource: string, view: string) => string;\n /** Restore button inside the draft banner (B7.1). */\n formDraftRestore: (resource: string, view: string) => string;\n /** Discard button inside the draft banner (B7.1). */\n formDraftDiscard: (resource: string, view: string) => string;\n\n /**\n * THE RELATION PICKER — and why every one of these is spelled\n * `relation-picker:…` rather than `picker-…` (SP9 task 5).\n *\n * ⚠️ **This family used to name a vocabulary nothing emitted.** Seven\n * factories spelled `picker-trigger:` / `picker-dialog:` / `picker-popover:`\n * / `picker-search:` / `picker-option:` / `picker-clear:` /\n * `picker-quickcreate:`, and `@burojs/test-helpers`' `createPickerObject`\n * spelled the same seven — while `@burojs/ui-shadcn`'s\n * `fields/relation-picker.tsx` and `fields/relation-picker-dialog.tsx` have\n * always emitted `relation-picker:<target>:…` and\n * `relation-picker-dialog:<target>:…`. Measured: **zero producers** for any\n * of the seven, anywhere in the repository.\n *\n * The reason it survived is worth more than the fix. `examples/marketplace-\n * ops/tests/page-object-vocabulary.test.tsx` exists precisely to stop these\n * two hand-written copies drifting, and it was green — because it compared\n * the page object with THIS file and nothing compared either with the\n * component. Two copies of a wrong convention agree perfectly. The producer\n * side is now pinned by `packages/ui-shadcn/tests/relation-picker-\n * testids.test.tsx`, which renders the real picker and reads the ids off the\n * DOM, so the agreement has a third party that can disagree.\n *\n * `quickCreate` is gone rather than re-spelled: the picker's quick-create is\n * deferred to v2 and no element exists to address. `popover` is gone because\n * the popover CONTENT carries no id of its own — {@link pickerList} is the\n * element inside it that does.\n *\n * The trigger takes the TARGET resource, not (resource, view, field): the\n * component composes it from `to`. Inside a `<ResourceForm>` the trigger's\n * id is overridden with `formFieldInput(resource, view, field)` — the form\n * passes its own `testid` prop so a field's input is addressable the same\n * way whatever its kind — while every child of the popover keeps the\n * per-target prefix below. Both facts are asserted in that same test.\n */\n pickerTrigger: (targetResource: string) => string;\n /** The popover's search box. */\n pickerSearch: (targetResource: string) => string;\n /** The popover's result list (the popover content itself carries no id). */\n pickerList: (targetResource: string) => string;\n /** One result row, keyed by the target record's id. */\n pickerOption: (targetResource: string, value: string) => string;\n /** The \"No results.\" row. */\n pickerEmpty: (targetResource: string) => string;\n /** The Clear link — rendered only when `clearable` and a value is set. */\n pickerClear: (targetResource: string) => string;\n /** The \"Advanced search\" link, which escalates to the modal below. */\n pickerAdvanced: (targetResource: string) => string;\n /** The \"Open list\" link to the target resource's own list page. */\n pickerViewAll: (targetResource: string) => string;\n /** The escalation modal (`<RelationPickerDialog>`). */\n pickerDialog: (targetResource: string) => string;\n /** The escalation modal's own search box. */\n pickerDialogSearch: (targetResource: string) => string;\n /** The disabled trigger rendered when the target resource is unregistered. */\n pickerUnregistered: (targetResource: string) => string;\n\n actionConfirmDialog: (\n resource: string,\n scope: string,\n actionName: string,\n recordId?: string,\n ) => string;\n actionConfirmYes: (resource: string, scope: string, actionName: string) => string;\n actionConfirmNo: (resource: string, scope: string, actionName: string) => string;\n\n formModal: (resource: string, scope: string, actionName: string, recordId?: string) => string;\n formModalSubmit: (resource: string, scope: string, actionName: string) => string;\n formModalCancel: (resource: string, scope: string, actionName: string) => string;\n\n childrenTable: (resource: string, view: string, fieldName: string) => string;\n childrenRow: (resource: string, view: string, fieldName: string, index: number) => string;\n childrenAdd: (resource: string, view: string, fieldName: string) => string;\n childrenRemove: (resource: string, view: string, fieldName: string, index: number) => string;\n\n /**\n * `<TaskRunPanel>` (`@burojs/ui-shadcn`) — the surface that reports progress\n * and partial failure for work long enough to watch. Keyed by the RUN's own\n * name (the app names the run: `'stock'`, `'import'`, …), not by a resource:\n * a task run has no resource in the general case — a bulk run spans a\n * selection and a long server-side operation has no record at all.\n *\n * The root carries `data-state=\"idle|running|succeeded|failed|cancelled\"`, so\n * a test reads the outcome without matching translated text — the same device\n * `<LanguageSwitch>`'s `data-language-state` uses.\n */\n taskRun: (name: string) => string;\n /** The bar itself (`role=\"progressbar\"`), whose `aria-valuenow` is the count. */\n taskRunProgress: (name: string) => string;\n /**\n * One named unit that did not succeed — a refused row, or the step a run\n * stopped at. Keyed by SUBJECT because that is the half a reader needs:\n * three entries all reading \"failed\" name nothing.\n */\n taskRunFailure: (name: string, subject: string) => string;\n\n notification: (type: 'success' | 'error' | 'progress' | 'info') => string;\n notificationClose: (type: string) => string;\n}\n\nfunction withId(parts: Array<string | number | undefined>): string {\n return parts.filter((p) => p !== undefined && p !== '').join(':');\n}\n\nexport function useTestIds(): TestIdBuilder {\n return useMemo<TestIdBuilder>(\n () => ({\n navMenuItem: (resource) => `nav-menu-item:${resource}`,\n navGroup: (name) => `nav-group:${name}`,\n navBreadcrumb: (resource, id) => withId(['nav-breadcrumb', resource, id]),\n sidebarCustomPage: (pageKey) => `sidebar-custompage:${pageKey}`,\n contextPicker: (slice) => `context-picker:${slice}`,\n contextPickerOption: (slice, value) => `context-picker-option:${slice}:${value}`,\n\n languageSwitch: () => 'language-switch',\n languageSwitchOption: (localeCode) => `language-switch:${localeCode}`,\n\n loginEmail: () => 'login-email',\n loginPassword: () => 'login-password',\n loginSubmit: () => 'login-submit',\n\n pageList: (r) => `page-list:${r}`,\n listToolbar: (r) => `list-toolbar:${r}`,\n listAction: (r, a) => `list-action:${r}:${a}`,\n listSearch: (r) => `list-search:${r}`,\n listFilter: (r, f) => `list-filter:${r}:${f}`,\n listTable: (r) => `list-table:${r}`,\n listRow: (r, id) => `list-row:${r}:${id}`,\n listCell: (r, id, f) => `list-cell:${r}:${id}:${f}`,\n listRowAction: (r, id, a) => `list-row-action:${r}:${id}:${a}`,\n listRowActionsMenu: (r, id) => `list-row-actions-menu:${r}:${id}`,\n listRowCheckbox: (r, id) => `list-row-checkbox:${r}:${id}`,\n listPaginationPrev: (r) => `list-pagination-prev:${r}`,\n listPaginationNext: (r) => `list-pagination-next:${r}`,\n listPaginationPage: (r, n) => `list-pagination-page:${r}:${n}`,\n listEmpty: (r) => `list-empty:${r}`,\n listBulkBar: (r) => `list-bulk-bar:${r}`,\n bulkAction: (r, a) => `bulk-action:${r}:${a}`,\n resourceAction: (r, a) => `list-action:${r}:${a}`,\n exportDialog: (r) => `export-dialog:${r}`,\n exportButton: (r) => `export-button:${r}`,\n exportBulkAction: (r) => `export-bulk-action:${r}`,\n\n pageShow: (r, id) => `page-show:${r}:${id}`,\n pageEdit: (r, id) => `page-edit:${r}:${id}`,\n pageCreate: (r) => `page-create:${r}`,\n unsupportedDocumentType: (r) => `unsupported-document-type:${r}`,\n\n resourceTab: (r, k, id) => withId(['resource-tab', r, k, id]),\n\n subresourceTabs: (r) => `subresource-tabs:${r}`,\n subresourceTab: (k) => `subresource-tab:${k}`,\n subresourceBody: (c) => `subresource-body:${c}`,\n\n form: (r, v, id) => withId(['form', r, v, id]),\n formGroup: (r, v, k) => `form-group:${r}:${v}:${k}`,\n formField: (r, v, f) => `form-field:${r}:${v}:${f}`,\n formFieldInput: (r, v, f) => `form-field-input:${r}:${v}:${f}`,\n formFieldError: (r, v, f) => `form-field-error:${r}:${v}:${f}`,\n formFieldLocked: (r, v, f) => `form-field-locked:${r}:${v}:${f}`,\n formFieldHelp: (r, v, f) => `form-field-help:${r}:${v}:${f}`,\n formFieldValidating: (r, v, f) => `form-field-validating:${r}:${v}:${f}`,\n formSubmit: (r, v) => `form-submit:${r}:${v}`,\n formCancel: (r, v) => `form-cancel:${r}:${v}`,\n formAction: (r, v, a) => `form-action:${r}:${v}:${a}`,\n formActionsMenu: (r, v) => `form-actions-menu:${r}:${v}`,\n formValidating: (r, v) => `form-validating:${r}:${v}`,\n formDraftBanner: (r, v) => `form-draft-banner:${r}:${v}`,\n formDraftRestore: (r, v) => `form-draft-restore:${r}:${v}`,\n formDraftDiscard: (r, v) => `form-draft-discard:${r}:${v}`,\n\n pickerTrigger: (t) => `relation-picker:${t}`,\n pickerSearch: (t) => `relation-picker:${t}:search`,\n pickerList: (t) => `relation-picker:${t}:list`,\n pickerOption: (t, v) => `relation-picker:${t}:option:${v}`,\n pickerEmpty: (t) => `relation-picker:${t}:empty`,\n pickerClear: (t) => `relation-picker:${t}:clear`,\n pickerAdvanced: (t) => `relation-picker:${t}:advanced`,\n pickerViewAll: (t) => `relation-picker:${t}:view-all`,\n pickerDialog: (t) => `relation-picker-dialog:${t}`,\n pickerDialogSearch: (t) => `relation-picker-dialog:${t}:search`,\n pickerUnregistered: (t) => `relation-picker:${t}:unregistered`,\n\n actionConfirmDialog: (r, s, a, id) => withId(['action-confirm-dialog', r, s, a, id]),\n actionConfirmYes: (r, s, a) => `action-confirm-yes:${r}:${s}:${a}`,\n actionConfirmNo: (r, s, a) => `action-confirm-no:${r}:${s}:${a}`,\n\n formModal: (r, s, a, id) => withId(['form-modal', r, s, a, id]),\n formModalSubmit: (r, s, a) => `form-modal-submit:${r}:${s}:${a}`,\n formModalCancel: (r, s, a) => `form-modal-cancel:${r}:${s}:${a}`,\n\n childrenTable: (r, v, f) => `children-table:${r}:${v}:${f}`,\n childrenRow: (r, v, f, i) => `children-row:${r}:${v}:${f}:${i}`,\n childrenAdd: (r, v, f) => `children-add:${r}:${v}:${f}`,\n childrenRemove: (r, v, f, i) => `children-remove:${r}:${v}:${f}:${i}`,\n\n taskRun: (name) => `task-run:${name}`,\n taskRunProgress: (name) => `task-run-progress:${name}`,\n taskRunFailure: (name, subject) => `task-run-failure:${name}:${subject}`,\n\n notification: (type) => `notification:${type}`,\n notificationClose: (type) => `notification-close:${type}`,\n }),\n [],\n );\n}\n","'use client';\nimport type { RecordTitleContext } from '@burojs/core';\nimport { resolveEnumLabel } from '@burojs/core';\nimport { useApp } from './use-app.js';\nimport { useI18nCaps } from './use-t.js';\n\n/**\n * Resolve a record's human title for breadcrumbs and detail-page headings.\n *\n * Order: `def.recordTitle(record)` → `record[def.displayField]` → `#<id>`.\n *\n * The `#<id>` fallback is deliberate rather than an empty string or a spinner:\n * a detail page knows its id immediately but not its record, so the breadcrumb\n * renders `#53` on first paint and UPGRADES in place to \"Заказ кодов №53\" once\n * the fetch lands — no layout shift, no flash of nothing, and the URL always\n * stays reconcilable with what's on screen.\n *\n * Pass `record` as undefined while loading; the hook is pure and safe to call\n * on every render.\n */\nexport function useRecordTitle(\n resource: string | undefined,\n id: unknown,\n record?: unknown,\n): string {\n const app = useApp();\n const normalizedResource = resource?.trim() ? resource : undefined;\n // Bind i18n caps to this resource so a composed `recordTitle` can translate\n // embedded enum labels (e.g. the document type) — and re-resolve on a language\n // switch (`useI18nCaps` recomputes on locale change, re-rendering this hook).\n // Keep this hook call unconditional on non-resource routes; only the registry\n // lookup is skipped when breadcrumbs have no resource identity.\n const caps = useI18nCaps(normalizedResource);\n const def = normalizedResource ? app.registry.get(normalizedResource) : undefined;\n const fallback = id == null || id === '' ? '' : `#${String(id)}`;\n\n if (record == null || typeof record !== 'object') return fallback;\n\n const titleCtx: RecordTitleContext = {\n resolveEnum: (namespace, value, inlineDefault) =>\n resolveEnumLabel(caps, namespace, value, inlineDefault),\n };\n const fromHook = def?.recordTitle?.(record as never, titleCtx);\n if (typeof fromHook === 'string' && fromHook.trim() !== '') return fromHook;\n\n const field = def?.displayField;\n if (field) {\n const value = (record as Record<string, unknown>)[field];\n if (value != null && value !== '') return String(value);\n }\n return fallback;\n}\n","import type { Action, ActionDI, Dispatcher, ResourceHandle } from '@burojs/core';\nimport { useCallback, useMemo, useState } from 'react';\nimport { createRuntimeActionDataAccess } from '../data/action-data-access.js';\nimport { useDataRuntime } from '../data/context.js';\nimport { useVisibilityCtx } from './use-permissions.js';\nimport { useOptionalT } from './use-t.js';\n\nexport interface UseActionResult {\n run: () => Promise<void>;\n isRunning: boolean;\n error: Error | null;\n}\n\nexport interface UseActionArgs<\n TRecord,\n R extends ResourceHandle<any, any, any, any> = ResourceHandle<any, any, any, any>,\n> {\n resource: R;\n record: TRecord;\n values?: Partial<TRecord>;\n dispatcher: Dispatcher;\n}\n\nexport function useAction<\n TRecord = unknown,\n R extends ResourceHandle<any, any, any, any> = ResourceHandle<any, any, any, any>,\n>(action: Action<TRecord>, args: UseActionArgs<TRecord, R>): UseActionResult {\n const [isRunning, setIsRunning] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const runtime = useDataRuntime();\n const data = useMemo(() => createRuntimeActionDataAccess(runtime), [runtime]);\n const ctx = useVisibilityCtx();\n // A handler's OWN output is text: `notify.message`, `modal.options.title`.\n // With the stub `t: (k) => k` this hook used to pass, none of it could be\n // localized — a handler could only return a literal in one language, which\n // then sat untranslated in an app whose every other string flips live.\n //\n // Bound to the action's own resource, so a handler addresses its resource\n // bundle the way `action.label` does (`resources.<name>.<key>`), and\n // provider-OPTIONAL so mounting an action without an i18n provider keeps\n // working — `useOptionalT` then returns the key, exactly what the old stub\n // did, so no existing call site changes behavior.\n const translate = useOptionalT();\n const resourceName = args.resource.ref.id;\n\n const run = useCallback(async () => {\n setIsRunning(true);\n setError(null);\n try {\n const di: ActionDI<TRecord, R> = {\n resource: args.resource,\n record: args.record,\n values: args.values ?? ({} as Partial<TRecord>),\n ctx,\n t: (key, params, defaultValue) =>\n translate(key, { resource: resourceName, params, defaultValue }),\n get: () => undefined,\n data,\n };\n await args.dispatcher.dispatch(action, di);\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsRunning(false);\n }\n }, [action, args, ctx, data, translate, resourceName]);\n\n return { run, isRunning, error };\n}\n","import {\n type TaskRunEvent,\n type TaskRunFailure,\n type TaskRunReport,\n IDLE_TASK_RUN,\n applyTaskRunEvent,\n} from '@burojs/core';\nimport { useCallback, useEffect, useReducer, useRef } from 'react';\n\n/**\n * DRIVES ONE PIECE OF WORK AND KEEPS A {@link TaskRunReport} A VIEW CAN RENDER.\n *\n * The hook knows nothing about what the work IS. It hands the task a\n * {@link TaskRunReporter} and an `AbortSignal` and gets out of the way — the\n * task can poll an RPC endpoint for a step count, loop over a selection, walk\n * pages of a file upload, or anything else, and this hook's job is only to keep\n * what it says in a report and stop listening once the run is over.\n *\n * That is deliberate and it is what makes this not an operations affordance.\n * The two callers this framework already has for it are a polled server-side\n * run and a client-side `for` loop over selected rows (`BulkActionHandler`\n * hand-rolls its own summary today) — nothing about a poll or a loop appears\n * anywhere below.\n */\n\n/** What a running task tells the report. Handed to the task; never held afterwards. */\nexport interface TaskRunReporter {\n /**\n * How far the work has got, ABSOLUTE — `{ completed: 2, total: 3 }`, not\n * \"+1\". A snapshot from a poll and an index from a loop are both absolute;\n * a delta would need the task to keep its own copy of the count.\n */\n advance(update: {\n readonly completed: number;\n readonly total?: number;\n readonly unit?: string;\n }): void;\n /**\n * One unit that will not be done, while the rest carries on. The bulk case:\n * three of eleven rows are not shippable and the other eight still ship.\n * A task that cannot continue at all THROWS instead — that ends the run.\n */\n refuse(failure: TaskRunFailure): void;\n}\n\nexport interface UseTaskRunOptions {\n /** Known up front, when it is. Reported as the run's `total` before the first `advance`. */\n readonly total?: number;\n /**\n * Turns whatever the task threw into the failure that ended the run.\n *\n * **The default deliberately drops the message.** A thrown `Error`'s text is\n * written for a developer and can carry a URL, a token or a row of somebody's\n * data, and a failure list is precisely the thing that gets screenshotted.\n * Only the caller knows which of its own errors are safe to show, so the\n * default reports a stable code and nothing else, and an app that wants its\n * own domain messages on screen maps them here explicitly.\n */\n readonly mapError?: (error: unknown) => TaskRunFailure;\n}\n\nexport interface TaskRunController {\n readonly report: TaskRunReport;\n readonly isRunning: boolean;\n /**\n * Runs `task`. Resolves when the run is over, whichever way it ended — this\n * hook reports failures rather than rethrowing them, because the report IS\n * the error channel and a caller that also had to catch would have two.\n *\n * A second call while a run is in flight is refused (and reported as such by\n * the resolved promise's `false`): two runs sharing one report would\n * interleave counts into nonsense.\n */\n start(\n task: (reporter: TaskRunReporter, signal: AbortSignal) => Promise<unknown>,\n ): Promise<boolean>;\n /** Asks the in-flight task to stop, through its `AbortSignal`. */\n cancel(): void;\n /** Back to `idle`. Refused while a run is in flight. */\n reset(): void;\n}\n\n/** No message, on purpose — see {@link UseTaskRunOptions.mapError}. */\nfunction defaultMapError(): TaskRunFailure {\n return { subject: 'run', code: 'task-run/failed' };\n}\n\n/**\n * `reset` is this hook's own event, not the model's. `applyTaskRunEvent`\n * describes ONE run and refuses to move a terminal report — correctly, since a\n * late poll must not resurrect a finished run. Emptying the slot the report\n * sits in is a different act, and it belongs to whoever holds the slot.\n */\ntype TaskRunSlotEvent = TaskRunEvent | { readonly kind: 'reset' };\n\nfunction reduce(report: TaskRunReport, event: TaskRunSlotEvent): TaskRunReport {\n return event.kind === 'reset' ? IDLE_TASK_RUN : applyTaskRunEvent(report, event);\n}\n\nexport function useTaskRun(options: UseTaskRunOptions = {}): TaskRunController {\n const [report, dispatch] = useReducer(reduce, IDLE_TASK_RUN);\n const controllerRef = useRef<AbortController | null>(null);\n const mountedRef = useRef(true);\n // Read through a ref so a caller re-creating `mapError` inline on every\n // render does not change `start`'s identity — an effect or a memo depending\n // on it would then re-run on every keystroke elsewhere on the page.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n // A run outlives its screen otherwise: the task keeps polling into a\n // report nobody renders, and every report is a state update on an\n // unmounted tree.\n controllerRef.current?.abort();\n controllerRef.current = null;\n };\n }, []);\n\n const start = useCallback<TaskRunController['start']>(async (task) => {\n if (controllerRef.current !== null) return false;\n\n const controller = new AbortController();\n controllerRef.current = controller;\n const live = (): boolean => mountedRef.current && controllerRef.current === controller;\n\n dispatch({ kind: 'start', total: optionsRef.current.total });\n\n const reporter: TaskRunReporter = {\n advance: (update) => {\n if (!live()) return;\n dispatch({ kind: 'advance', ...update });\n },\n refuse: (failure) => {\n if (!live()) return;\n dispatch({ kind: 'refuse', failure });\n },\n };\n\n try {\n const result = await task(reporter, controller.signal);\n if (live()) dispatch({ kind: 'finish', result });\n } catch (error) {\n // A cancelled run is not a failed one, and the two must not render the\n // same. `controller.signal.aborted` is the check and not the shape of\n // the thrown value: a task may abandon its work with any error at all\n // once its signal fires, including one this hook has never seen.\n if (!live()) {\n // Unmounted, or superseded — nothing left to report to.\n } else if (controller.signal.aborted) {\n dispatch({ kind: 'cancel' });\n } else {\n dispatch({ kind: 'fail', error: (optionsRef.current.mapError ?? defaultMapError)(error) });\n }\n } finally {\n if (controllerRef.current === controller) controllerRef.current = null;\n }\n return true;\n }, []);\n\n const cancel = useCallback(() => {\n const controller = controllerRef.current;\n if (controller === null) return;\n controller.abort();\n // Reported here rather than only in `start`'s catch: a task that ignores\n // its signal and resolves normally would otherwise report `succeeded` for\n // a run the operator stopped. The reducer's terminal rule makes the later\n // `finish` a no-op.\n dispatch({ kind: 'cancel' });\n }, []);\n\n const reset = useCallback(() => {\n if (controllerRef.current !== null) return;\n dispatch({ kind: 'reset' });\n }, []);\n\n return { report, isRunning: report.state === 'running', start, cancel, reset };\n}\n","import {\n evaluateChecks,\n filterInlineIssues,\n type CheckOutcome,\n type CheckSurface,\n type ValidationIssues,\n} from '@burojs/core';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createRuntimeActionDataAccess,\n createUnavailableActionDataAccess,\n} from '../data/action-data-access.js';\nimport { useOptionalDataRuntime } from '../data/context.js';\nimport { useApp } from '../hooks/use-app.js';\nimport { useVisibilityCtx } from '../hooks/use-permissions.js';\nimport { useLocale, useT } from '../hooks/use-t.js';\n\nexport interface UseChecksOptions {\n readonly resource: string;\n readonly surface: CheckSurface;\n readonly values: Record<string, unknown>;\n readonly saved?: Record<string, unknown>;\n readonly record?: Record<string, unknown>;\n readonly touched?: Record<string, boolean>;\n readonly submitAttempted?: boolean;\n /** Default 300ms, matching `def.validate`. 0 disables debouncing. */\n readonly debounceMs?: number;\n readonly enabled?: boolean;\n readonly actionName?: string;\n}\n\nexport interface UseChecksResult {\n readonly inlineIssues: ValidationIssues;\n readonly outcome: CheckOutcome | null;\n readonly isChecking: boolean;\n /**\n * Un-debounced authoritative pass. Call at submit / before dispatch.\n *\n * ⚠️ Can resolve with an outcome flagged `aborted: true` (the host unmounted,\n * or a second `runNow()` superseded this one). Its three issue lists are then\n * empty because nothing was evaluated — a caller MUST NOT read that as\n * \"nothing fired\" and proceed. Check `outcome.aborted` before\n * `outcome.blockers`.\n */\n readonly runNow: () => Promise<CheckOutcome>;\n}\n\nconst EMPTY: ValidationIssues = Object.freeze([]);\nconst EMPTY_OUTCOME: CheckOutcome = Object.freeze({\n issues: EMPTY,\n blockers: EMPTY,\n confirmable: EMPTY,\n});\n\nexport function useChecks(options: UseChecksOptions): UseChecksResult {\n const app = useApp();\n // Tolerant of a missing native data runtime (`useOptionalDataRuntime`,\n // `../data/context.js`) — unlike `useAction`, a check that never touches\n // `di.data` must still evaluate normally with no runtime mounted (the\n // common case: most `<ResourceForm>` hosts in tests, and any adopter that\n // hasn't wired the native runtime, render checkless resources through the\n // exact same code path). A check whose predicate DOES call `di.data.*`\n // gets a rejecting stub instead — `evaluateChecks` turns that into a\n // visible `check.exception` warning rather than crashing the form.\n const runtime = useOptionalDataRuntime();\n const data = useMemo(\n () =>\n runtime === null\n ? createUnavailableActionDataAccess(\n `Check evaluation for \"${options.resource}\" needs a data runtime; none is mounted.`,\n )\n : createRuntimeActionDataAccess(runtime),\n [runtime, options.resource],\n );\n const ctx = useVisibilityCtx();\n const translate = useT();\n const locale = useLocale();\n // `CheckDI.t` is `(key, params?: Record<string, unknown>) => string`; `useT`'s\n // translator takes `(key, { resource?, params? })`. Wrap so predicate/message\n // interpolation params land under `.params` correctly — unlike `useAction`\n // (which stubs `t: (k) => k`), checks get the REAL translator: check messages\n // are adopter-authored and localizable, not internal plumbing.\n const t = useCallback(\n (key: string, params?: Record<string, unknown>) => translate(key, { params }),\n [translate],\n );\n // `ctx` is a fresh `{ permissions, scope, user }` object literal every render\n // (see the `latest` ref comment below) — but a check predicate CAN legitimately\n // read `di.ctx.permissions`/`di.ctx.user`, and a genuine change to either (a\n // permission grant landing, the session's user rotating) must re-evaluate.\n // Fingerprint its CONTENT — same technique as `valuesKey` below — so the\n // debounce effect reacts to what changed, not to the literal's identity.\n const ctxKey = useMemo(() => JSON.stringify(ctx), [ctx]);\n\n const [outcome, setOutcome] = useState<CheckOutcome | null>(null);\n const [isChecking, setIsChecking] = useState(false);\n\n // Monotonic seq + live controllers: the same race discipline `def.validate`\n // uses. Only the newest run may paint; older ones of the SAME kind are\n // aborted and dropped.\n const seq = useRef(0);\n // TWO controller slots, deliberately. The debounced inline pass and the\n // authoritative `runNow()` pass are different jobs with different consumers,\n // and sharing one slot let the cheap one kill the important one:\n //\n // 1. a host awaits `runNow()` and gates its WRITE on the result\n // (`<ResourceForm>`: `if (outcome.blockers.length > 0) return;`);\n // 2. anything in the debounce effect's dependency list changes while that\n // pass is still in flight (see below for what actually can);\n // 3. the effect re-arms, its timer fires, and `evaluate()` aborted the\n // single shared `controller.current` — the SUBMIT's controller;\n // 4. `evaluateChecks` returned early, so `runNow()` handed its caller an\n // outcome with no blockers in it;\n // 5. the host read `blockers.length === 0` as permission and wrote the\n // record — past a `severity: 'error'` check, which then painted inline\n // moments later, AFTER the write.\n //\n // WHAT CAN ACTUALLY RE-ARM THE EFFECT MID-PASS. Not a keystroke into\n // `<ResourceForm>`: its `handleSubmit` calls `setIsSubmitting(true)` on its\n // FIRST line (the double-submit guard, `resource-form.tsx`), and its fields\n // render `disabled={!editable || isSubmitting}` — verified, `userEvent.type`\n // is correctly refused for the whole duration of the pass. The reachable\n // triggers are the effect's other dependencies:\n // - `valuesKey` — a CUSTOM field renderer that ignores `disabled`, or an\n // async default / picker / relation resolving into `setFieldValue`;\n // - `ctxKey` — a permission slice landing, or the session's user rotating;\n // - `locale` — a live language switch (this framework ships one).\n // And `useChecks` is public API: a host that does NOT disable its inputs\n // during submit has the plain keystroke version of this.\n //\n // No StrictMode needed — this is a production path, and the window is\n // `debounceMs` (300ms by default) against check latency. A best-effort\n // inline pass has no business cancelling the authoritative one, so it no\n // longer can: each kind supersedes only its own. `seq` stays shared because\n // it governs PAINTING (newest values win), which is genuinely one job.\n const controller = useRef<AbortController | null>(null);\n const authoritativeController = useRef<AbortController | null>(null);\n const mounted = useRef(true);\n // `ctx` (useVisibilityCtx) and `t` (wrapped useT) are fresh identities EVERY\n // render, even when their content hasn't changed: useVisibilityCtx returns a\n // new `{ permissions, scope, user }` object literal each call, and useT\n // returns a new closure each call. Reading them off a ref updated every\n // render — rather than putting them in `evaluate`'s dependency array — keeps\n // `evaluate` (and therefore the debounce effect below) stable across renders\n // that don't touch values/surface/resource. Depending on the raw `ctx`/`t`\n // identities directly would re-fire the debounce effect on every render\n // `evaluate` itself causes (via setOutcome/setIsChecking), which re-fires\n // `evaluate`, which re-renders — an infinite loop. `data` is already stable\n // (memoized on `runtime`), and `options` uses the same ref technique for the\n // same reason. This ref only prevents TEARING inside the async callback —\n // it does not drive re-evaluation. Liveness to a genuine ctx/locale change is\n // `ctxKey`/`locale` below, in the debounce effect's own dependency array.\n const latest = useRef({ options, ctx, t, data });\n latest.current = { options, ctx, t, data };\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n controller.current?.abort();\n authoritativeController.current?.abort();\n };\n }, []);\n\n const evaluate = useCallback(\n async (kind: 'debounced' | 'authoritative'): Promise<CheckOutcome> => {\n const current = latest.current;\n const mySeq = seq.current + 1;\n seq.current = mySeq;\n // Supersede only the same KIND — see the two-slot note above.\n const slot = kind === 'authoritative' ? authoritativeController : controller;\n slot.current?.abort();\n const ownController = new AbortController();\n slot.current = ownController;\n if (mounted.current) setIsChecking(true);\n try {\n // Inside the `try`: a `CheckSource` is caller-supplied (app + resource\n // merged) and can throw. Looking it up outside this block would skip the\n // `finally` below entirely, leaving `isChecking` stuck `true` forever.\n const checks = app.checkSource.checks(current.options.resource);\n const next = await evaluateChecks({\n checks,\n surface: current.options.surface,\n resource: current.options.resource,\n values: current.options.values,\n saved: current.options.saved ?? {},\n record: current.options.record,\n ctx: current.ctx,\n t: current.t,\n data: current.data,\n signal: ownController.signal,\n ...(current.options.actionName === undefined\n ? {}\n : { actionName: current.options.actionName }),\n });\n // An ABORTED pass evaluated nothing, so it must never be painted NOR\n // handed back as if it were a verdict. `runNow()`'s return value is\n // authoritative for `<ResourceForm>`'s submit gate, so an unflagged\n // empty outcome here is a straight bypass of every `severity: 'error'`\n // check. `evaluateChecks` flags this itself (`CheckOutcome.aborted`,\n // `@burojs/core`); pass the flag through untouched rather than\n // laundering it into a clean-looking empty result.\n if (next.aborted === true) return next;\n // Complete, but a newer pass owns the paint (or we unmounted): the\n // VERDICT is still honest — this pass ran every applicable check\n // against the values it was given — so the caller gets it. Only the\n // state write is skipped.\n if (seq.current !== mySeq || !mounted.current) return next;\n setOutcome(next);\n return next;\n } finally {\n if (seq.current === mySeq && mounted.current) setIsChecking(false);\n }\n },\n [app],\n );\n\n const debounceMs = options.debounceMs ?? 300;\n const enabled = options.enabled ?? true;\n // Memoized on the values OBJECT, not recomputed every render: a host that\n // mounts this hook unconditionally (`<ResourceForm>` does) would otherwise\n // pay a full `JSON.stringify` of the record on every single render,\n // including the renders this hook's own `setIsChecking`/`setOutcome`\n // cause. Skipped entirely while disabled — a resource with no checks has\n // no reason to serialize anything.\n //\n // Two caveats a caller has to know about, one pre-existing and one\n // introduced by the memo:\n //\n // 1. (pre-existing) `JSON.stringify` collapses a `File` to `{}`, so\n // swapping one file for another in a file field produces the same key\n // and does not retrigger the pass. True before the memo and after it —\n // memoizing changes WHEN the call runs, not what it produces.\n //\n // 2. (new, and a real narrowing of this hook's public contract)\n // `options.values` is now compared by IDENTITY. Before the memo the\n // stringify ran every render, so a host that MUTATED its values object\n // in place — `values.amount = 5` rather than `setValues({ ...values,\n // amount: 5 })` — still produced a changed key and still retriggered\n // the debounced pass. It no longer does: an in-place mutation keeps\n // the same object reference, the memo does not recompute, and the pass\n // does not re-run. Pass a NEW object on every change (which every\n // React state update already does, and which `<ResourceForm>` — whose\n // `values` is state — has always done). Recorded in the changeset.\n const valuesKey = useMemo(\n () => (enabled ? JSON.stringify(options.values) : ''),\n [enabled, options.values],\n );\n // The pending debounced timer, so `runNow()` can cancel it (see below) —\n // without this a submit-time `runNow()` call would leave the old timer alive\n // to fire a redundant, already-superseded evaluation afterwards.\n const pendingTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n if (debounceMs === 0) {\n void evaluate('debounced');\n return;\n }\n const timer = setTimeout(() => {\n pendingTimer.current = null;\n void evaluate('debounced');\n }, debounceMs);\n pendingTimer.current = timer;\n return () => {\n clearTimeout(timer);\n if (pendingTimer.current === timer) pendingTimer.current = null;\n };\n }, [enabled, debounceMs, evaluate, valuesKey, options.surface, options.resource, ctxKey, locale]);\n\n // Same signature as `evaluate` (`() => Promise<CheckOutcome>`); wrapped\n // rather than exposing `evaluate` directly so a submit-time call also\n // cancels a still-pending debounced run instead of leaving it to fire a\n // redundant evaluation afterwards. `evaluate` itself is untouched — the\n // debounce effect above still calls it directly.\n const runNow = useCallback((): Promise<CheckOutcome> => {\n if (pendingTimer.current !== null) {\n clearTimeout(pendingTimer.current);\n pendingTimer.current = null;\n }\n // `enabled: false` means \"this host has nothing to evaluate\" (typically\n // a resource that declares no checks at all), so the authoritative\n // submit-time pass has nothing to do either — running it would reinstate\n // exactly the work `enabled` exists to avoid. Resolves with the same\n // shape a real empty pass produces, so a caller reading\n // `.blockers`/`.confirmable` needs no special case.\n if (!enabled) return Promise.resolve(EMPTY_OUTCOME);\n return evaluate('authoritative');\n }, [evaluate, enabled]);\n\n const inlineIssues = useMemo(\n () =>\n outcome === null\n ? EMPTY\n : filterInlineIssues(outcome.issues, {\n touched: options.touched ?? {},\n submitAttempted: options.submitAttempted ?? false,\n }),\n [outcome, options.touched, options.submitAttempted],\n );\n\n return { inlineIssues, outcome, isChecking, runNow };\n}\n","import {\n evaluateChecks,\n type CheckOutcome,\n type CheckSurface,\n type ValidationIssues,\n} from '@burojs/core';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n createRuntimeActionDataAccess,\n createUnavailableActionDataAccess,\n} from '../data/action-data-access.js';\nimport { useOptionalDataRuntime } from '../data/context.js';\nimport { useApp } from '../hooks/use-app.js';\nimport { useVisibilityCtx } from '../hooks/use-permissions.js';\nimport { useT } from '../hooks/use-t.js';\n\nexport interface CheckGateRequest {\n readonly surface: CheckSurface;\n readonly values?: Record<string, unknown>;\n readonly saved?: Record<string, unknown>;\n readonly record?: Record<string, unknown>;\n readonly actionName?: string;\n /** An existing `action.confirm` message; becomes the dialog header. */\n readonly header?: string | null;\n}\n\nexport interface CheckGateState {\n /**\n * The resource whose checks this gate evaluates. Carried in the state so the\n * dialog rendering it can bind its translations to the same resource the\n * rules came from: a check message's i18n key is `checks.<id>`, which only\n * reaches the per-resource entry `resources.<name>.checks.<id>` when a\n * resource is bound.\n *\n * It must travel WITH the state rather than being passed to the dialog\n * separately — the ambient `ResourceContext` is not a substitute. Only\n * `<ResourceShow>` and `<ResourceForm>` mount one, so an action gated from a\n * LIST ROW has no ambient resource at all, and the same check would render\n * translated on a show page and untranslated in the list. (Exactly the bug\n * `useResolvedLabel` in `action-button.tsx` carries a comment about.)\n *\n * Optional because a resource-less host — `<DeclarativeForm>` builds this\n * shape by hand — genuinely has no resource to name.\n */\n readonly resource?: string;\n readonly open: boolean;\n readonly busy: boolean;\n readonly header: string | null;\n readonly blockers: ValidationIssues;\n readonly confirmable: ValidationIssues;\n readonly proceed: () => void;\n readonly cancel: () => void;\n}\n\nexport interface UseCheckGateResult {\n readonly run: (request: CheckGateRequest) => Promise<'proceed' | 'cancel'>;\n readonly state: CheckGateState;\n}\n\nconst EMPTY: ValidationIssues = Object.freeze([]);\n\n/**\n * Imperative pre-flight gate. `run()` evaluates the resource's checks for the\n * surface, and resolves immediately with 'proceed' when there is nothing to say.\n * Otherwise it opens (the host renders the dialog off `state`) and resolves once\n * the user decides. One dialog: an existing `action.confirm` becomes its header\n * rather than a second prompt.\n */\nexport function useCheckGate(resource: string): UseCheckGateResult {\n const app = useApp();\n // Tolerant of a missing native data runtime — see `useChecks` (`./use-\n // checks.js`) for the full rationale. `run()` must still evaluate and open\n // for a `data`-free check with no runtime mounted; a check that DOES touch\n // `di.data` degrades to a `check.exception` warning instead of throwing.\n const runtime = useOptionalDataRuntime();\n const data = useMemo(\n () =>\n runtime === null\n ? createUnavailableActionDataAccess(\n `Check evaluation for \"${resource}\" needs a data runtime; none is mounted.`,\n )\n : createRuntimeActionDataAccess(runtime),\n [runtime, resource],\n );\n const ctx = useVisibilityCtx();\n const translate = useT();\n // Same wrapping as `useChecks`: `CheckDI.t` is `(key, params?) => string`;\n // `useT`'s translator takes `(key, { resource?, params? })`.\n const t = useCallback(\n (key: string, params?: Record<string, unknown>) => translate(key, { params }),\n [translate],\n );\n\n const [open, setOpen] = useState(false);\n const [busy, setBusy] = useState(false);\n const [header, setHeader] = useState<string | null>(null);\n const [blockers, setBlockers] = useState<ValidationIssues>(EMPTY);\n const [confirmable, setConfirmable] = useState<ValidationIssues>(EMPTY);\n const decide = useRef<((decision: 'proceed' | 'cancel') => void) | null>(null);\n const controller = useRef<AbortController | null>(null);\n const mounted = useRef(true);\n\n // Read off a ref inside the async callback — captured ONCE before the first\n // `await` — same technique `use-checks.ts` uses: `ctx`/`t` are fresh\n // identities every render (`useVisibilityCtx`/`useT` return new object\n // literals / closures each call). `run` is imperative (called on click, not\n // driven by an effect), so there is no debounce loop to break here, but\n // putting `ctx`/`t` straight in `run`'s own dependency array would still\n // recreate `run` itself on every render — this ref keeps `run`'s identity\n // stable while every invocation still reads the LATEST ctx/t/data.\n const latest = useRef({ ctx, t, data });\n latest.current = { ctx, t, data };\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n controller.current?.abort();\n decide.current?.('cancel');\n decide.current = null;\n };\n }, []);\n\n const close = useCallback((decision: 'proceed' | 'cancel') => {\n setOpen(false);\n setBlockers(EMPTY);\n setConfirmable(EMPTY);\n setHeader(null);\n const resolve = decide.current;\n decide.current = null;\n resolve?.(decision);\n }, []);\n\n const run = useCallback(\n async (request: CheckGateRequest): Promise<'proceed' | 'cancel'> => {\n // A second `run()` while one is open supersedes the first: abort its\n // evaluation and resolve its promise so it never dangles. `close()`\n // both resolves the pending decision AND resets `open`/`header`/\n // `blockers`/`confirmable` — without the reset, a superseding run that\n // ends up with nothing to confirm (the early return below) would leave\n // the dialog visually open showing the FIRST, already-cancelled call's\n // stale content, wired to a null `decide.current`.\n controller.current?.abort();\n close('cancel');\n const own = new AbortController();\n controller.current = own;\n const current = latest.current;\n setBusy(true);\n let outcome: CheckOutcome;\n try {\n outcome = await evaluateChecks({\n checks: app.checkSource.checks(resource),\n surface: request.surface,\n resource,\n values: request.values ?? {},\n saved: request.saved ?? {},\n record: request.record,\n ctx: current.ctx,\n t: current.t,\n data: current.data,\n signal: own.signal,\n ...(request.actionName === undefined ? {} : { actionName: request.actionName }),\n });\n } catch (error) {\n // `evaluateChecks` itself never rejects — a throwing check predicate\n // becomes a `check.exception` warning issue (see `evaluate.ts`) — but\n // `checkSource.checks(resource)` is caller-supplied (app + resource\n // merged; `source.ts` anticipates a future backend-pulled source) and\n // CAN throw. `run()`'s contract is `Promise<'proceed' | 'cancel'>`,\n // never a rejection: a Task 8/9/10 caller awaiting it must always see\n // it settle. A check engine that cannot run must not silently wave\n // the user through, so this resolves 'cancel' rather than 'proceed'.\n console.error(\n `[buro] useCheckGate(\"${resource}\") failed to evaluate checks; treating as cancel.`,\n error,\n );\n return 'cancel';\n } finally {\n if (mounted.current && controller.current === own) setBusy(false);\n }\n // ABORTED means this run never reached a verdict — it is NOT a verdict\n // of \"nothing to confirm\".\n //\n // `evaluateChecks` answers an aborted signal with an empty outcome\n // (flagged `aborted`, precisely so this is decidable). The two guards\n // below — still mounted, still the current controller — do NOT catch\n // the case that matters, because React StrictMode tears this hook down\n // and re-mounts it synchronously: by the time the aborted evaluation\n // resolves, `mounted.current` has been set back to `true` by the second\n // mount effect and `controller.current` is still THIS run's own\n // controller (nothing else started one). Both guards pass, the empty\n // lists read as \"no blockers, no confirmable\", and `run()` answered\n // 'proceed' — dispatching a check-gated action with no dialog at all.\n // Development builds only, which is where every adopter works.\n //\n // A gate whose evaluation did not complete must never wave the caller\n // through. Re-RUNNING is the caller's job (it owns the click that\n // started this); refusing to proceed is ours.\n if (own.signal.aborted || outcome.aborted === true) return 'cancel';\n // Unmounted, or superseded by a later `run()`: don't paint state or\n // resolve — either the unmount cleanup already resolved 'cancel', or\n // the newer `run()` owns `decide.current` now.\n if (!mounted.current || controller.current !== own) return 'cancel';\n const requestHeader = request.header ?? null;\n if (\n outcome.blockers.length === 0 &&\n outcome.confirmable.length === 0 &&\n requestHeader === null\n ) {\n return 'proceed';\n }\n setHeader(requestHeader);\n setBlockers(outcome.blockers);\n setConfirmable(outcome.confirmable);\n setOpen(true);\n return new Promise<'proceed' | 'cancel'>((resolve) => {\n decide.current = resolve;\n });\n },\n [app, resource, close],\n );\n\n return {\n run,\n state: {\n resource,\n open,\n busy,\n header,\n blockers,\n confirmable,\n // `blockers.length > 0` means an 'error'-severity check fired: Task 7's\n // dialog is expected to omit the proceed button in that case, but this\n // guard means a mis-wired host cannot bypass a blocking check by\n // calling `proceed()` directly — a no-op (dialog stays open) rather\n // than resolving 'proceed' OR silently resolving 'cancel' out from\n // under the caller.\n proceed: () => {\n if (blockers.length > 0) return;\n close('proceed');\n },\n cancel: () => close('cancel'),\n },\n };\n}\n","import type {\n Action,\n ActionDI,\n ActionResult,\n BulkActionDI,\n BulkActionHandler,\n Dispatcher,\n ResourceHandle,\n} from '@burojs/core';\nimport { useCallback, useMemo, useState } from 'react';\nimport { createRuntimeActionDataAccess } from '../data/action-data-access.js';\nimport { useDataRuntime } from '../data/context.js';\nimport { useVisibilityCtx } from './use-permissions.js';\nimport { useOptionalT } from './use-t.js';\n\nexport interface UseBulkActionResult {\n /** Resolves with the dispatched result, or `undefined` if the dispatch itself failed. */\n run: () => Promise<ActionResult | undefined>;\n isRunning: boolean;\n error: Error | null;\n}\n\nexport interface UseBulkActionArgs<\n TRecord,\n R extends ResourceHandle<any, any, any, any> = ResourceHandle<any, any, any, any>,\n> {\n resource: R;\n records: TRecord[];\n /** Every selected id — see {@link BulkActionDI.ids}. */\n ids: string[];\n dispatcher: Dispatcher;\n}\n\n/**\n * Bulk variant of {@link useAction}. Wraps a `BulkActionHandler` so its\n * result flows through the host dispatcher's effects pipeline (notify,\n * clearSelection, refetch, redirect). Mirrors `useAction` API surface\n * (`{ run, isRunning, error }`) so call sites stay symmetric.\n *\n * The dispatcher's `Action` union doesn't currently include\n * `BulkActionHandler` (single-record vs bulk DI shape), but at runtime\n * both share `kind: 'handler'` and an identical handler-returning-result\n * contract. We cast at the dispatcher boundary so the runtime `kind`\n * guard still passes; the dispatcher itself doesn't read the DI shape\n * — handlers do — so the cast is sound.\n */\nexport function useBulkAction<\n TRecord = unknown,\n R extends ResourceHandle<any, any, any, any> = ResourceHandle<any, any, any, any>,\n>(action: BulkActionHandler<TRecord>, args: UseBulkActionArgs<TRecord, R>): UseBulkActionResult {\n const [isRunning, setIsRunning] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const runtime = useDataRuntime();\n const data = useMemo(() => createRuntimeActionDataAccess(runtime), [runtime]);\n const ctx = useVisibilityCtx();\n // Same resource-bound, provider-optional translator `useAction` passes — a\n // bulk handler's `notify.message` is text too, and the stub it replaced\n // could not localize it.\n const translate = useOptionalT();\n const resourceName = args.resource.ref.id;\n\n const run = useCallback(async () => {\n setIsRunning(true);\n setError(null);\n try {\n const di: BulkActionDI<TRecord, R> = {\n resource: args.resource,\n records: args.records,\n ids: args.ids,\n ctx,\n t: (key, params) => translate(key, { resource: resourceName, params }),\n data,\n };\n return await args.dispatcher.dispatch(\n action as unknown as Action<TRecord>,\n di as unknown as ActionDI<TRecord>,\n );\n } catch (e) {\n setError(e instanceof Error ? e : new Error(String(e)));\n return undefined;\n } finally {\n setIsRunning(false);\n }\n }, [action, args, ctx, data, translate, resourceName]);\n\n return { run, isRunning, error };\n}\n","import { useCallback, useEffect, useState } from 'react';\n\n/**\n * SSR-safe localStorage hook.\n *\n * Returns `[value, setValue]`. Hydrates from `localStorage` on mount —\n * `value` is `undefined` during SSR and the initial render to avoid\n * hydration mismatches; on mount it switches to the stored value (or the\n * provided `initial` if no stored value exists).\n *\n * Setter accepts `undefined` to clear the key. Storage write errors\n * (quota / private mode) are swallowed — UI continues to reflect the\n * in-memory state.\n *\n * @example\n * const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('theme', 'light');\n * const [companyId, setCompanyId] = useLocalStorage<number>('selected-company');\n */\nexport function useLocalStorage<T>(\n key: string,\n initial?: T,\n): [T | undefined, (value: T | undefined) => void] {\n const [value, setStateValue] = useState<T | undefined>(undefined);\n\n // Hydrate from storage on mount\n useEffect(() => {\n if (typeof window === 'undefined') return;\n try {\n const raw = window.localStorage.getItem(key);\n if (raw == null) {\n setStateValue(initial);\n return;\n }\n // Try JSON.parse first; if it fails, fall back to the raw string\n // (handles legacy plain-string values like '1' or 'dark').\n try {\n setStateValue(JSON.parse(raw) as T);\n } catch {\n setStateValue(raw as unknown as T);\n }\n } catch {\n setStateValue(initial);\n }\n // intentionally only on mount — caller treats `key` as stable\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const setValue = useCallback(\n (next: T | undefined) => {\n setStateValue(next);\n if (typeof window === 'undefined') return;\n try {\n if (next === undefined) {\n window.localStorage.removeItem(key);\n } else {\n window.localStorage.setItem(key, typeof next === 'string' ? next : JSON.stringify(next));\n }\n } catch {\n // ignore storage write errors\n }\n },\n [key],\n );\n\n return [value, setValue];\n}\n","'use client';\nimport { useEffect, useState } from 'react';\n\n/**\n * Returns a debounced reflection of `value`. The returned value lags\n * behind the input by `ms` milliseconds: each change resets a pending\n * timer; only the latest value paints once the timer settles.\n *\n * Typical use: gate a network request on a user input that may change\n * rapidly (cmdk search box, free-form filter input). Pair this with the\n * source state and feed only the debounced value into the request hook\n * so rapid keystrokes don't fire one request per character.\n *\n * Edge cases:\n * - On mount: the debounced value initialises to the current `value`\n * so the first render does NOT fire an extra \"change\" through the\n * debounce — adopters can use the result on first paint without a\n * conditional `if (debouncedValue === undefined)` guard.\n * - On unmount: the pending timer is cleared in the effect cleanup\n * (no setState-after-unmount warning).\n * - On `ms === 0`: the timer fires synchronously next tick (setTimeout\n * semantics) — adopters who want truly synchronous behaviour should\n * pass the source value directly without the hook.\n *\n * SSR: `useState` + `useEffect` are SSR-safe. The initial render uses\n * the source value so server-rendered HTML matches the first client\n * paint exactly.\n */\nexport function useDebouncedValue<T>(value: T, ms: number): T {\n const [debounced, setDebounced] = useState<T>(value);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setDebounced(value);\n }, ms);\n return () => clearTimeout(timer);\n }, [value, ms]);\n\n return debounced;\n}\n","import {\n FILE_STORAGE_SERVICE,\n type FileStorageAdapter,\n type FileStorageRegistry,\n} from '@burojs/file-storage';\nimport { useApp } from '../use-app.js';\n\n/** Resolve a registered storage by name. Throws with the registered names. */\nexport function useFileStorage(name?: string): FileStorageAdapter {\n const app = useApp();\n const registry = app.getService<FileStorageRegistry>(FILE_STORAGE_SERVICE);\n if (!registry) {\n throw new Error(\n 'No file storage registered — add fileStoragePlugin({ default: … }) to defineApp',\n );\n }\n return registry.get(name);\n}\n\n/**\n * Same resolution, but reports failure instead of throwing.\n *\n * `useFileStorage` throwing is right where a throw stays local — a form field\n * that cannot be configured should fail loudly at the developer. It is wrong\n * in a READ path: a list renders one file cell per row, all of them inside the\n * DataGrid's single render, so one misspelled `ui.fileStorage` doesn't blank a\n * cell, it takes down the entire table (and anything else in that subtree)\n * with no error boundary between them. A record's data is fine; only the\n * config naming its storage is wrong.\n *\n * Returns the reason rather than a bare `undefined` so the caller can show\n * WHICH name failed and what was registered, instead of an anonymous blank.\n */\nexport function useOptionalFileStorage(\n name?: string,\n): { adapter: FileStorageAdapter; error?: undefined } | { adapter?: undefined; error: string } {\n const app = useApp();\n const registry = app.getService<FileStorageRegistry>(FILE_STORAGE_SERVICE);\n if (!registry) {\n return {\n error: 'No file storage registered — add fileStoragePlugin({ default: … }) to defineApp',\n };\n }\n // `has` before `get`, because `get` is the thing that throws.\n if (name != null && !registry.has(name)) {\n return { error: `Unknown file storage '${name}'. Registered: ${registry.names().join(', ')}.` };\n }\n return { adapter: registry.get(name) };\n}\n","'use client';\nimport type { FileRef } from '@burojs/file-storage';\nimport * as React from 'react';\nimport { useFileStorage } from './use-file-storage.js';\n\nexport type FileItemStatus =\n | 'deferred'\n | 'queued'\n | 'uploading'\n | 'uploaded'\n | 'failed'\n | 'rejected';\n\nexport interface FileItem {\n ref: FileRef;\n status: FileItemStatus;\n /** 0..1 while uploading; 1 once done. */\n progress?: number;\n error?: string;\n}\n\nexport interface UseFileFieldArgs {\n resource: string;\n field: string;\n multiple?: boolean;\n value: unknown;\n onChange: (columnValue: unknown) => void;\n record?: Record<string, unknown>;\n storage?: string;\n defer?: boolean;\n orphans?: 'best-effort' | 'keep';\n accept?: string[];\n maxSize?: number;\n /** Uploads in flight at once. Default 3. */\n concurrency?: number;\n}\n\nexport interface UseFileFieldResult {\n items: FileItem[];\n add: (files: File[]) => void;\n remove: (localId: string) => void;\n retry: (localId: string) => void;\n abort: (localId: string) => void;\n reorder: (from: number, to: number) => void;\n busy: boolean;\n}\n\n/** Match a file against HTML `accept` tokens. Empty list matches everything. */\nexport function matchesAccept(file: File, accept: string[]): boolean {\n if (accept.length === 0) return true;\n const mime = (file.type || '').toLowerCase();\n const name = file.name.toLowerCase();\n return accept.some((raw) => {\n const token = raw.trim().toLowerCase();\n if (!token) return false;\n if (token.startsWith('.')) return name.endsWith(token);\n if (token.endsWith('/*')) return mime.startsWith(token.slice(0, -1));\n return mime === token;\n });\n}\n\nexport function formatBytes(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes < 0) return `${bytes}B`;\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n if (bytes < 1024 ** 3) return `${(bytes / 1024 / 1024).toFixed(1)}MB`;\n return `${(bytes / 1024 ** 3).toFixed(2)}GB`;\n}\n\n/** Sentinel: we have not emitted anything yet, so nothing can match. */\nconst NOTHING_EMITTED = Symbol('buro.fileField.nothingEmitted');\n\n/**\n * A cheap structural fingerprint of a column value, used only to decide\n * whether an EXTERNAL change arrived. A controlled form hands back a fresh\n * literal every render, so reference identity alone would reseed forever.\n *\n * ⚠️ File-aware on purpose. `JSON.stringify` renders a File as `{}`, so two\n * genuinely different Files fingerprint identically — and in the fused\n * pipeline a column value really can carry raw Files. Without this branch a\n * newly picked file silently fails to appear.\n */\nfunction valueKey(value: unknown): string {\n const seen = new WeakSet<object>();\n try {\n return (\n JSON.stringify(value, (_k, v) => {\n if (typeof File !== 'undefined' && v instanceof File) {\n return `File:${v.name}:${v.size}:${v.lastModified}`;\n }\n if (v && typeof v === 'object') {\n if (seen.has(v)) return '[circular]';\n seen.add(v);\n }\n return v;\n }) ?? 'undefined'\n );\n } catch {\n // Never let fingerprinting break a render.\n return String(value);\n }\n}\n\nexport function useFileField(args: UseFileFieldArgs): UseFileFieldResult {\n const adapter = useFileStorage(args.storage);\n // `defer: true` is only meaningful for a fused-pipeline storage: there the\n // raw File rides inside the record mutation itself (`withFileStorage`\n // encodes it at submit time), so \"hold the bytes until submit\" is simply\n // what the pipeline already does — the flag changes nothing.\n //\n // For an immediate/handshake/resumable pipeline there is no equivalent.\n // Nothing on this branch flushes a deferred ref through `adapter.upload`\n // before the form's mutation runs — `runUpload` only fires for\n // `status === 'queued'`, and every mapper's `write` (scalarHandle included)\n // omits a handle-less ref rather than writing a placeholder. Silently\n // honouring `defer: true` here would upload nothing, emit no error, and\n // hand the mutation a column value with the file quietly missing. Fail\n // loudly at declaration time instead of shipping that.\n if (args.defer === true && adapter.pipeline !== 'fused') {\n throw new Error(\n `f.file({ defer: true }): not implemented for storage \"${args.storage ?? 'default'}\" (pipeline: \"${adapter.pipeline}\"). Deferred upload only works for a fused-pipeline storage (e.g. inline, PocketBase), where the file rides inside the record mutation itself. There is no form-submit integration on this branch that flushes a deferred ref through adapter.upload before the mutation runs, so honouring this flag would silently drop the file. Remove \\`defer: true\\` from this field — immediate/handshake/resumable pipelines already upload on pick.`,\n );\n }\n const deferred = adapter.pipeline === 'fused';\n const orphanPolicy = args.orphans ?? adapter.orphans ?? 'best-effort';\n const concurrency = args.concurrency ?? 3;\n\n // The normalized domain FileRef[] is the source of truth for what is SAVED;\n // provider mapping and canonical codecs have already run outside React.\n // `items` tracks the\n // in-flight world on top of it. Reading the column on every render would\n // discard upload state, so it seeds state once per distinct incoming value.\n //\n // \"Distinct\" is judged structurally, not referentially: a controlled form\n // typically hands back a brand-new array/object each render even when the\n // logical value hasn't changed (`value: []` in the caller re-creates that\n // array every time). Comparing by `Object.is` alone would treat every\n // render as a new value and reseed forever — an infinite render loop the\n // moment nothing is in flight — so the guard also checks a structural\n // fingerprint (`valueKey`). But a fingerprint match is not enough either:\n // whatever we last handed to `onChange` need not be treated as an external\n // change (`lastEmitted`).\n const [items, setItems] = React.useState<FileItem[]>(() =>\n readDomainRefs(args.value).map((ref) => ({ ref, status: 'uploaded' as const })),\n );\n const lastSeenValue = React.useRef(args.value);\n // Whatever we last handed to onChange. A controlled form hands it straight\n // back as `value`; avoid reseeding from our own output.\n const lastEmitted = React.useRef<unknown>(NOTHING_EMITTED);\n\n if (\n !Object.is(lastSeenValue.current, args.value) &&\n !Object.is(lastEmitted.current, args.value) &&\n valueKey(lastSeenValue.current) !== valueKey(args.value) &&\n !items.some(isInFlight)\n ) {\n lastSeenValue.current = args.value;\n setItems(readDomainRefs(args.value).map((ref) => ({ ref, status: 'uploaded' as const })));\n }\n\n const controllers = React.useRef(new Map<string, AbortController>());\n const pendingFiles = React.useRef(new Map<string, File>());\n // Handles uploaded during THIS editing session that the record does not own\n // yet. Cleared on submit; deleted on unmount under best-effort.\n const unsaved = React.useRef(new Set<string>());\n\n const itemsRef = React.useRef(items);\n itemsRef.current = items;\n\n // Single synchronous choke point every mutator below goes through, instead\n // of each calling `setItems` with its own ad hoc updater.\n //\n // `itemsRef.current` is updated HERE, synchronously, at the moment of the\n // mutation — not just once per render the way the top-of-body\n // `itemsRef.current = items` mirror is. That is what makes it safe for\n // `add`/`remove`/`reorder`/`runUpload`'s success handler to read\n // `itemsRef.current` as \"the current state\" and compute `next` from it\n // directly: with `concurrency > 1`, several `runUpload` calls can resolve\n // one after another with no render in between (React does not necessarily\n // re-render synchronously between two `setState` calls from two separate\n // promise continuations), so a version of `commit` that only wrote `items`\n // via `setState` and left the ref to catch up on the next render would let\n // the second resolution overwrite the first's change — a lost update\n // (`busy` never clears). Reading and writing `itemsRef.current` in the same\n // synchronous stretch of code (no `await` in between) closes that gap: JS's\n // single-threaded execution means nothing else can run between the read\n // and the write, however many async continuations are pending.\n const commit = React.useCallback((next: FileItem[]) => {\n itemsRef.current = next;\n setItems(next);\n }, []);\n\n const emit = React.useCallback(\n (next: FileItem[]) => {\n const refs = next\n .filter((i) => i.status === 'uploaded' || i.status === 'deferred')\n .map((i) => i.ref);\n // Remember it by reference so the value coming back from the form is\n // recognised as our own and never reseeds the list.\n lastEmitted.current = refs;\n args.onChange(refs);\n },\n [args.onChange],\n );\n\n const patch = React.useCallback(\n (localId: string, next: Partial<FileItem>) => {\n commit(itemsRef.current.map((i) => (i.ref.localId === localId ? { ...i, ...next } : i)));\n },\n [commit],\n );\n\n const runUpload = React.useCallback(\n async (localId: string) => {\n const file = pendingFiles.current.get(localId);\n if (!file) return;\n const controller = new AbortController();\n controllers.current.set(localId, controller);\n patch(localId, { status: 'uploading', progress: 0, error: undefined });\n try {\n const ref = await adapter.upload(file, {\n signal: controller.signal,\n onProgress: (loaded, total) =>\n patch(localId, { progress: total > 0 ? loaded / total : 0 }),\n });\n if (ref.handle) unsaved.current.add(ref.handle);\n pendingFiles.current.delete(localId);\n // Compute `next` from the ref, `commit` it, THEN `emit` — both plain\n // calls in the function body, never from inside a `setItems` updater.\n // `emit` calls `args.onChange`, which touches the PARENT form's\n // state; calling that from inside a state updater is exactly what\n // produced \"Cannot update a component while rendering a different\n // component\" — React may invoke an updater more than once\n // (StrictMode's deliberate double-invoke), which would double-fire\n // `onChange`, and it is simply not a safe place for a side effect\n // touching a different component while this one is still being\n // reconciled.\n const next = itemsRef.current.map((i) =>\n i.ref.localId === localId\n ? { ref: { ...ref, localId }, status: 'uploaded' as const, progress: 1 }\n : i,\n );\n commit(next);\n emit(next);\n } catch (e) {\n const err = e as Error;\n patch(localId, {\n status: err.name === 'AbortError' ? 'rejected' : 'failed',\n error: err.message,\n });\n } finally {\n controllers.current.delete(localId);\n }\n },\n [adapter, commit, emit, patch],\n );\n\n // Pump the queue: start uploads until `concurrency` are in flight.\n React.useEffect(() => {\n const uploading = items.filter((i) => i.status === 'uploading').length;\n const slots = concurrency - uploading;\n if (slots <= 0) return;\n for (const item of items.filter((i) => i.status === 'queued').slice(0, slots)) {\n void runUpload(item.ref.localId);\n }\n }, [items, concurrency, runUpload]);\n\n const add = React.useCallback(\n (files: File[]) => {\n const additions: FileItem[] = files.map((file) => {\n const localId = `local-${Math.random().toString(36).slice(2)}-${file.name}`;\n const shared = { localId, name: file.name, mime: file.type || undefined, size: file.size };\n\n if (args.maxSize != null && file.size > args.maxSize) {\n return {\n ref: shared,\n status: 'rejected',\n error: `File exceeds the maximum size of ${formatBytes(args.maxSize)} (got ${formatBytes(file.size)})`,\n };\n }\n if (args.accept?.length && !matchesAccept(file, args.accept)) {\n return {\n ref: shared,\n status: 'rejected',\n error: `This file type isn't accepted. Accepted: ${args.accept.join(', ')}`,\n };\n }\n if (deferred) {\n return { ref: { ...shared, pending: file }, status: 'deferred' };\n }\n pendingFiles.current.set(localId, file);\n return { ref: shared, status: 'queued' };\n });\n\n const next = args.multiple ? [...itemsRef.current, ...additions] : additions.slice(-1);\n commit(next);\n if (additions.some((a) => a.status === 'deferred')) emit(next);\n },\n [args.accept, args.maxSize, args.multiple, deferred, commit, emit],\n );\n\n const remove = React.useCallback(\n (localId: string) => {\n const target = itemsRef.current.find((i) => i.ref.localId === localId);\n controllers.current.get(localId)?.abort();\n pendingFiles.current.delete(localId);\n // Removing a file the record never owned: drop it from storage too,\n // since nothing else will ever point at it.\n if (target?.ref.handle && unsaved.current.has(target.ref.handle)) {\n unsaved.current.delete(target.ref.handle);\n if (orphanPolicy === 'best-effort') void adapter.remove?.(target.ref).catch(() => {});\n }\n const next = itemsRef.current.filter((i) => i.ref.localId !== localId);\n commit(next);\n emit(next);\n },\n [adapter, commit, emit, orphanPolicy],\n );\n\n const retry = React.useCallback(\n (localId: string) => {\n patch(localId, { status: 'queued', error: undefined });\n },\n [patch],\n );\n\n const abort = React.useCallback((localId: string) => {\n controllers.current.get(localId)?.abort();\n }, []);\n\n const reorder = React.useCallback(\n (from: number, to: number) => {\n const next = [...itemsRef.current];\n const [moved] = next.splice(from, 1);\n if (moved) next.splice(to, 0, moved);\n commit(next);\n emit(next);\n },\n [commit, emit],\n );\n\n // Orphan sweep. Best effort by design and documented as such: a closed tab\n // never runs this.\n React.useEffect(() => {\n return () => {\n for (const controller of controllers.current.values()) controller.abort();\n if (orphanPolicy !== 'best-effort' || !adapter.remove) return;\n for (const item of itemsRef.current) {\n if (item.ref.handle && unsaved.current.has(item.ref.handle)) {\n void adapter.remove(item.ref).catch(() => {});\n }\n }\n };\n }, [adapter, orphanPolicy]);\n\n const busy = items.some(isInFlight);\n return { items, add, remove, retry, abort, reorder, busy };\n}\n\nfunction isInFlight(item: FileItem): boolean {\n return item.status === 'queued' || item.status === 'uploading';\n}\n\nfunction readDomainRefs(value: unknown): FileRef[] {\n return isFileRefs(value) ? value : [];\n}\n\nfunction isFileRefs(value: unknown): value is FileRef[] {\n return (\n Array.isArray(value) &&\n value.every(\n (entry) =>\n entry !== null &&\n typeof entry === 'object' &&\n typeof (entry as { localId?: unknown }).localId === 'string',\n )\n );\n}\n","interface Entry {\n url: string;\n /** Epoch ms. Absent means permanent. */\n expiresAt?: number;\n}\n\nexport interface UrlCache {\n get(key: string): string | undefined;\n set(key: string, url: string, expiresAt?: number): void;\n invalidate(key: string): void;\n /** Drop every entry. Mainly for test isolation of the module-scoped cache. */\n clear(): void;\n /**\n * Epoch ms of the last `set()` for this key, or 0 if it was never resolved\n * (or was explicitly `invalidate`d/`clear`ed since).\n *\n * Kept OUTSIDE the evictable entry itself: a URL that arrives already\n * expired — a few ms of clock skew between signer and client is enough —\n * must still register as \"just resolved\" even though `get()` will evict it\n * on the very next read. Callers use this to cool down before resolving\n * the same key again, rather than resolving it forever in a tight loop.\n */\n lastResolvedAt(key: string): number;\n /**\n * True when this key currently holds a SIGNED entry (has an `expiresAt`),\n * whether or not that expiry has already passed. Does not evict — unlike\n * `get()`, checking this never has the side effect of dropping a stale\n * entry. Lets a caller skip scanning entries that can never expire (a\n * permanent, string-form `ResolvedUrl` has none) without forcing eviction\n * as a side effect of merely asking.\n */\n isSigned(key: string): boolean;\n}\n\n/** Entries less than this old are not eligible to be re-resolved. */\nexport const RESOLVE_COOLDOWN_MS = 1000;\n\n/**\n * Module-scoped so two components showing the same file resolve it once.\n *\n * An expired entry is reported as ABSENT rather than stale: a signed URL past\n * its expiry is not a slightly old URL, it is a broken image.\n */\nexport function createUrlCache(): UrlCache {\n const entries = new Map<string, Entry>();\n const resolvedAt = new Map<string, number>();\n return {\n get(key) {\n const found = entries.get(key);\n if (!found) return undefined;\n if (found.expiresAt != null && found.expiresAt <= Date.now()) {\n entries.delete(key);\n return undefined;\n }\n return found.url;\n },\n set(key, url, expiresAt) {\n entries.set(key, { url, ...(expiresAt != null ? { expiresAt } : {}) });\n resolvedAt.set(key, Date.now());\n },\n invalidate(key) {\n entries.delete(key);\n resolvedAt.delete(key);\n },\n clear() {\n entries.clear();\n resolvedAt.clear();\n },\n lastResolvedAt(key) {\n return resolvedAt.get(key) ?? 0;\n },\n isSigned(key) {\n return entries.get(key)?.expiresAt != null;\n },\n };\n}\n\nexport const sharedUrlCache = createUrlCache();\n","'use client';\nimport type { FileRef, ResolveCtx } from '@burojs/file-storage';\nimport * as React from 'react';\nimport { RESOLVE_COOLDOWN_MS, sharedUrlCache } from './url-cache.js';\nimport { useOptionalFileStorage } from './use-file-storage.js';\n\nexport interface UseFileUrlsOpts extends ResolveCtx {\n storage?: string;\n /** Set false to resolve nothing — e.g. a cell scrolled out of view. */\n enabled?: boolean;\n}\n\nexport interface UseFileUrlsResult {\n /** Keyed by `localId`. `undefined` means unresolved or unresolvable. */\n urls: Record<string, string | undefined>;\n pending: boolean;\n /** Drop the cached URL for one ref and resolve it again. */\n refresh: (localId: string) => void;\n /**\n * Set when `opts.storage` names nothing registered. Resolution is skipped\n * (every entry in `urls` stays `undefined`) rather than throwing — see the\n * note on the hook.\n */\n storageError?: string;\n}\n\nfunction cacheKey(storage: string | undefined, ref: FileRef, opts: UseFileUrlsOpts): string {\n const v = opts.variant ? `${opts.variant.width ?? ''}x${opts.variant.height ?? ''}` : '';\n return [storage ?? 'default', ref.handle, v, opts.disposition ?? '', opts.record?.id ?? ''].join(\n '|',\n );\n}\n\n/**\n * Resolve display URLs for a list of refs in ONE pass.\n *\n * ⚠️ \"One pass\" means PARALLEL, not batched — this is NOT what relation\n * aggregation does for relation cells. Fifty rows issue fifty concurrent\n * `resolveUrl` calls via `Promise.all`, deduplicated against the shared cache\n * (an already-resolved or in-flight handle costs nothing extra). A true\n * single-request batch would need a port-level `resolveUrls(refs[])` entry\n * point — `resolveUrl` is single-ref by signature, and no adapter here\n * implements anything else. Cache-dedup keeps the common case (a list\n * re-rendering with mostly-already-resolved rows) cheap; it does not turn N\n * network calls into one.\n *\n * Signed URLs are re-resolved when the cache reports them expired, and a\n * caller whose <img> failed can force one retry through `refresh`.\n *\n * An unregistered `opts.storage` REPORTS rather than throws. This is a read\n * path: callers render one of these per row, inside a single list render with\n * no error boundary between the rows, so throwing would replace a table with\n * a blank screen over one misspelled name. The caller gets `storageError` and\n * decides how loud to be.\n */\nexport function useFileUrls(refs: FileRef[], opts: UseFileUrlsOpts): UseFileUrlsResult {\n const { adapter, error: storageError } = useOptionalFileStorage(opts.storage);\n const [urls, setUrls] = React.useState<Record<string, string | undefined>>({});\n const [pending, setPending] = React.useState(false);\n const [nonce, setNonce] = React.useState(0);\n\n // Whether ANY currently-resolvable ref's cache entry is signed (carries a\n // TTL). Read by the watchdog below to skip its per-render scan entirely\n // when nothing displayed can ever expire — a list of fifty permanent URLs\n // re-rendering on every mousemove of a column-resize drag has no business\n // building fifty cache keys and doing fifty lookups per frame.\n const hasSignedRef = React.useRef(false);\n\n const resolvable = refs.filter((r) => r.handle != null);\n // A stable signature so the effect fires on real change, not on a new array.\n const signature = resolvable.map((r) => `${r.localId}:${r.handle}`).join(',');\n const optsKey = [\n opts.storage,\n opts.variant?.width,\n opts.variant?.height,\n opts.disposition,\n opts.resource,\n (opts.record as { id?: unknown } | undefined)?.id,\n ].join('|');\n\n // `signature` and `optsKey` are deliberate stand-ins for `refs`/`opts` — see\n // the comment below the dependency array. Listing the raw fields too would\n // fire this effect on every render, since `refs`/`opts` are new references\n // each time.\n // biome-ignore lint/correctness/useExhaustiveDependencies: see comment above\n React.useEffect(() => {\n // No adapter means nothing to resolve WITH — same shape as \"disabled\",\n // not an error to throw. The caller renders `storageError`.\n if (opts.enabled === false || resolvable.length === 0 || !adapter) {\n setPending(false);\n hasSignedRef.current = false;\n return;\n }\n let cancelled = false;\n\n const refreshSignedFlag = () => {\n hasSignedRef.current = resolvable.some((ref) =>\n sharedUrlCache.isSigned(cacheKey(opts.storage, ref, opts)),\n );\n };\n\n // Cache first: anything already known needs no round trip at all.\n const seeded: Record<string, string | undefined> = {};\n const misses: FileRef[] = [];\n for (const ref of resolvable) {\n const hit = sharedUrlCache.get(cacheKey(opts.storage, ref, opts));\n if (hit) seeded[ref.localId] = hit;\n else misses.push(ref);\n }\n if (Object.keys(seeded).length > 0) {\n setUrls((current) => ({ ...current, ...seeded }));\n }\n refreshSignedFlag();\n if (misses.length === 0) {\n setPending(false);\n return;\n }\n\n setPending(true);\n void Promise.all(\n misses.map(async (ref) => {\n try {\n const resolved = await adapter.resolveUrl(ref, {\n variant: opts.variant,\n disposition: opts.disposition,\n resource: opts.resource,\n record: opts.record,\n });\n const url = typeof resolved === 'string' ? resolved : resolved.url;\n const expiresAt = typeof resolved === 'string' ? undefined : resolved.expiresAt;\n sharedUrlCache.set(cacheKey(opts.storage, ref, opts), url, expiresAt);\n return [ref.localId, url] as const;\n } catch {\n // A missing or forbidden file renders a placeholder; it never throws\n // through a list of fifty rows.\n return [ref.localId, undefined] as const;\n }\n }),\n ).then((pairs) => {\n if (cancelled) return;\n setUrls((current) => ({ ...current, ...Object.fromEntries(pairs) }));\n setPending(false);\n // The freshly resolved entries just landed in the cache with their real\n // expiresAt — recompute now that we actually know.\n refreshSignedFlag();\n });\n\n return () => {\n cancelled = true;\n };\n // `signature` and `optsKey` stand in for the array and the options object,\n // both of which are new references on every render.\n }, [signature, optsKey, nonce, adapter, opts.enabled]);\n\n // The resolution effect above only re-enters on a real change to `signature`,\n // `optsKey`, `nonce` or `adapter` — none of which move on their own when a\n // signed URL's clock runs out. This watchdog runs on every render instead,\n // and only acts when a URL this hook is CURRENTLY DISPLAYING has gone stale\n // in the cache (i.e. `UrlCache.get` evicted it as expired). Clearing it and\n // bumping `nonce` hands the actual re-resolution back to the effect above,\n // so there is still exactly one code path that ever calls `resolveUrl`.\n React.useEffect(() => {\n if (opts.enabled === false) return;\n // Nothing displayed can expire — skip the per-ref cacheKey+lookup scan\n // entirely. This is the common case on every render that ISN'T about a\n // freshly (re)resolved batch, e.g. a list re-rendering during a\n // column-resize drag.\n if (!hasSignedRef.current) return;\n const stale = resolvable.filter((ref) => {\n if (urls[ref.localId] == null) return false;\n const key = cacheKey(opts.storage, ref, opts);\n // A URL that arrives already expired — a few ms of clock skew between\n // signer and client is enough — must not be evicted and re-resolved on\n // the very next render: that setUrls call is itself a render, on which\n // this watchdog would find it \"expired\" again, forever. A key inside\n // its cooldown is left alone even if the cache reports it absent; the\n // next render after the cooldown lapses will pick it up.\n if (Date.now() - sharedUrlCache.lastResolvedAt(key) < RESOLVE_COOLDOWN_MS) return false;\n return sharedUrlCache.get(key) === undefined;\n });\n if (stale.length === 0) return;\n setUrls((current) => {\n const next = { ...current };\n for (const ref of stale) next[ref.localId] = undefined;\n return next;\n });\n setNonce((n) => n + 1);\n });\n\n const refresh = React.useCallback(\n (localId: string) => {\n const ref = refs.find((r) => r.localId === localId);\n if (ref) sharedUrlCache.invalidate(cacheKey(opts.storage, ref, opts));\n setUrls((current) => ({ ...current, [localId]: undefined }));\n setNonce((n) => n + 1);\n },\n [refs, opts],\n );\n\n return { urls, pending, refresh, storageError };\n}\n","import type { EnumValue } from '@burojs/core';\nimport { useEffect, useState } from 'react';\nimport { useApp } from './use-app.js';\n\n/**\n * Result returned by `useEnumValues`. Mirrors the standard\n * `{ data | isLoading | error }` shape used by data-provider hooks.\n */\nexport interface UseEnumValuesResult {\n /** Resolved values, or `undefined` while loading or on error. */\n values: readonly EnumValue[] | undefined;\n /** True from first render until the loader resolves (or rejects). */\n isLoading: boolean;\n /** Set when the loader rejects OR when the enum is not registered. */\n error: Error | null;\n}\n\n/**\n * Resolve an enum's values from the app registry. Static enums (declared\n * with `defineEnum({ values: [...] })`) resolve synchronously on first\n * render. Loader-backed enums (declared with `defineEnum({ loader })`)\n * transition through `isLoading: true` before settling.\n *\n * Caching: backed by `app.registry.enums.getValuesAsync(name)` which is\n * single-flight per enum name. Mounting `<EnumBadge>` and `<EnumPicker>`\n * for the same enum simultaneously triggers exactly one loader call.\n *\n * Error policy: an unregistered enum surfaces as\n * `{ values: undefined, isLoading: false, error: Error('not registered') }`.\n * The bundled `<EnumBadge>` etc primitives degrade gracefully on error\n * (render the raw value as plain text) — adopters writing custom\n * primitives can do the same.\n */\nexport function useEnumValues(enumName: string): UseEnumValuesResult {\n const app = useApp();\n // Synchronous fast-path: if the enum is registered with static values\n // we can return them on the very first render with no loading flicker.\n // This matches the v0 (pre-runtime-load) behaviour of `<EnumBadge>` so\n // the regression e2e suites stay green without changes.\n const def = app.registry.enums.get(enumName);\n const initialValues = def?.values;\n\n const [values, setValues] = useState<readonly EnumValue[] | undefined>(initialValues);\n const [isLoading, setIsLoading] = useState<boolean>(initialValues === undefined);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n // If we already have static values from the synchronous path, no\n // async work needed for the static case; effect still runs in case\n // enumName changed and the new enum is loader-backed.\n const currentDef = app.registry.enums.get(enumName);\n if (currentDef?.values !== undefined) {\n setValues(currentDef.values);\n setIsLoading(false);\n setError(null);\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n setError(null);\n setValues(undefined);\n\n app.registry.enums\n .getValuesAsync(enumName)\n .then((next) => {\n if (cancelled) return;\n setValues(next);\n setIsLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setValues(undefined);\n setIsLoading(false);\n setError(err instanceof Error ? err : new Error(String(err)));\n });\n\n return () => {\n cancelled = true;\n };\n }, [app, enumName]);\n\n return { values, isLoading, error };\n}\n","'use client';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { useMany } from './data/use-many.js';\nimport { useOne } from './data/use-one.js';\n\n/**\n * A resolved relation record. Mirrors the shape used by the legacy\n * per-cell `useRelatedRecord` (see the deleted\n * `ui-shadcn/src/fields/use-related-record.ts`).\n */\nexport type RelatedRecord = { id: unknown } & Record<string, unknown>;\n\n/** Result returned by `useRelatedRecord`. Signature UNCHANGED from today. */\nexport interface UseRelatedRecordResult {\n /** Resolved record, or `undefined` while loading / on error / when id is falsy. */\n record: RelatedRecord | undefined;\n /** True from first render until the record settles. */\n isLoading: boolean;\n /** Set when resolution errors (fallback path) — the aggregator path never\n * surfaces a per-id error (a dangling FK degrades to `record: undefined`\n * instead, matching today's fail-soft display behaviour). */\n error: Error | null;\n}\n\n/**\n * `records.get(resource).get(idStr)` semantics:\n * - key absent → never requested / still in flight.\n * - value is a record → resolved.\n * - value is `null` → the batch that covered this id came back\n * without it (dangling FK / deleted row) — a CONFIRMED miss, distinct\n * from \"still loading\", so the cell can fall back to the raw id\n * immediately instead of spinning forever.\n */\ntype ResolvedEntry = RelatedRecord | null;\n\ninterface ResourceStatus {\n isLoading: boolean;\n error: Error | null;\n}\n\ninterface KeySnapshot {\n record: RelatedRecord | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n/** Stable, frozen snapshot for the \"no id\" case — never register, never fetch. */\nconst STABLE_EMPTY: KeySnapshot = Object.freeze({\n record: undefined,\n isLoading: false,\n error: null,\n});\n\nfunction keyOf(resource: string, idStr: string): string {\n return `${resource}\\u0000${idStr}`;\n}\n\n/**\n * The vanilla external store backing the relation aggregator. One instance\n * is created per `<RelationAggregatorProvider>` (via `useRef`) and shared,\n * via context, by every `useRelatedRecord` call underneath it and by the\n * provider's own `ResourceBatch` fetchers.\n *\n * Design notes (see docs/specs/relation-aggregation.md +\n * docs/superpowers/plans/2026-07-25-relation-aggregation.md Task 1):\n * - `refcounts` is mutated synchronously and O(1) on register/unregister;\n * the (possibly large) burst of registrations from mounting a\n * 1000-row list therefore costs one Map write per cell, not one React\n * state update per cell.\n * - Notifications are coalesced: a burst of register/unregister calls\n * schedules exactly ONE `fetchListeners` flush via `queueMicrotask`\n * (guarded by `flushScheduled`), so the provider re-renders once per\n * burst rather than once per row.\n * - `snapshotCache` gives `useSyncExternalStore` a STABLE object\n * reference per `(resource, id)` key: `getSnapshotKey` returns the\n * cached object until that key is explicitly invalidated by\n * `applyResults` / `setResourceStatus`, which only touch the ids that\n * were actually part of the batch that just settled. A cell whose id\n * is unaffected by another id's resolution therefore never sees its\n * snapshot reference change and never re-renders — this is what makes\n * per-cell subscriptions selective instead of \"every cell re-renders\n * whenever anything resolves\".\n */\nclass RelationAggregatorStore {\n private readonly records = new Map<string, Map<string, ResolvedEntry>>();\n private readonly status = new Map<string, ResourceStatus>();\n private readonly refcounts = new Map<string, Map<string, number>>();\n private readonly listeners = new Map<string, Set<() => void>>();\n private readonly fetchListeners = new Set<() => void>();\n private readonly snapshotCache = new Map<string, KeySnapshot>();\n\n private registeredCache: Map<string, string[]> | null = null;\n private flushScheduled = false;\n\n /** True once `resource`/`idStr` has an entry in `records` — a resolved\n * record OR a confirmed-missing `null` (dangling FK). Public so\n * `ResourceBatch` can compute its `unresolved` filter set without\n * reaching into store internals. */\n isResolved(resource: string, idStr: string): boolean {\n return this.records.get(resource)?.has(idStr) ?? false;\n }\n\n /** Refcount++. Schedules a coalesced fetch-listener notify when the id\n * transitions from unregistered → registered, or when it's genuinely\n * new work (not already resolved) so `status` reflects fresh loading. */\n register(resource: string, idStr: string): void {\n let idMap = this.refcounts.get(resource);\n if (!idMap) {\n idMap = new Map();\n this.refcounts.set(resource, idMap);\n }\n const count = idMap.get(idStr) ?? 0;\n idMap.set(idStr, count + 1);\n if (count === 0) {\n if (!this.isResolved(resource, idStr)) {\n // Fresh, unresolved work for this resource — (re-)arm loading so a\n // resource that had gone idle (previous batch settled) reports\n // isLoading again for ids ResourceBatch hasn't fetched yet.\n this.status.set(resource, { isLoading: true, error: null });\n }\n this.invalidateRegistered();\n this.scheduleFetchNotify();\n }\n }\n\n /** Refcount--. Removes the id at zero and schedules a coalesced notify. */\n unregister(resource: string, idStr: string): void {\n const idMap = this.refcounts.get(resource);\n if (!idMap) return;\n const count = idMap.get(idStr) ?? 0;\n if (count <= 1) {\n idMap.delete(idStr);\n if (idMap.size === 0) this.refcounts.delete(resource);\n this.invalidateRegistered();\n this.scheduleFetchNotify();\n } else {\n idMap.set(idStr, count - 1);\n }\n }\n\n private invalidateRegistered(): void {\n this.registeredCache = null;\n }\n\n private scheduleFetchNotify(): void {\n if (this.flushScheduled) return;\n this.flushScheduled = true;\n queueMicrotask(() => {\n this.flushScheduled = false;\n for (const cb of this.fetchListeners) cb();\n });\n }\n\n subscribeFetch = (cb: () => void): (() => void) => {\n this.fetchListeners.add(cb);\n return () => {\n this.fetchListeners.delete(cb);\n };\n };\n\n /** Stable per-call snapshot: `Map<resource, idStr[]>` of every currently\n * registered (refcount > 0) id, rebuilt only when the registered SET\n * actually changed (register/unregister at the 0↔1 boundary). */\n getRegistered = (): Map<string, string[]> => {\n if (this.registeredCache) return this.registeredCache;\n const out = new Map<string, string[]>();\n for (const [resource, idMap] of this.refcounts) {\n if (idMap.size > 0) out.set(resource, Array.from(idMap.keys()));\n }\n this.registeredCache = out;\n return out;\n };\n\n subscribeKey = (resource: string, idStr: string, cb: () => void): (() => void) => {\n const key = keyOf(resource, idStr);\n let set = this.listeners.get(key);\n if (!set) {\n set = new Set();\n this.listeners.set(key, set);\n }\n set.add(cb);\n return () => {\n set?.delete(cb);\n if (set && set.size === 0) this.listeners.delete(key);\n };\n };\n\n getSnapshotKey = (resource: string, idStr: string): KeySnapshot => {\n const key = keyOf(resource, idStr);\n const cached = this.snapshotCache.get(key);\n if (cached) return cached;\n\n const entry = this.records.get(resource)?.get(idStr);\n let snap: KeySnapshot;\n if (entry !== undefined) {\n // Resolved (a record) or confirmed-missing (null) — either way, no\n // longer loading, and never depends on resource-level status again.\n snap = { record: entry ?? undefined, isLoading: false, error: null };\n } else {\n const st = this.status.get(resource);\n snap = { record: undefined, isLoading: st?.isLoading ?? true, error: st?.error ?? null };\n }\n this.snapshotCache.set(key, snap);\n return snap;\n };\n\n private notifyKey(resource: string, idStr: string): void {\n const key = keyOf(resource, idStr);\n this.snapshotCache.delete(key);\n const set = this.listeners.get(key);\n if (!set) return;\n for (const cb of set) cb();\n }\n\n /**\n * Apply a settled `getList` batch for `resource`. `requestedIds` is the\n * EXACT set of ids that batch's `in` filter covered (captured by\n * `ResourceBatch` at query time) — only those ids' snapshots are\n * invalidated/notified, so ids resolved by an EARLIER batch (already in\n * `records`) are left untouched and never re-render their cells. Ids in\n * `requestedIds` not present in `found` are recorded as confirmed-missing\n * (`null`) — dangling FK fail-soft, same as the old per-cell `useOne`.\n */\n applyResults(resource: string, requestedIds: readonly string[], found: RelatedRecord[]): void {\n let recMap = this.records.get(resource);\n if (!recMap) {\n recMap = new Map();\n this.records.set(resource, recMap);\n }\n const byId = new Map<string, RelatedRecord>();\n for (const rec of found) {\n byId.set(String(rec.id), rec);\n }\n for (const idStr of requestedIds) {\n recMap.set(idStr, byId.get(idStr) ?? null);\n }\n this.status.set(resource, { isLoading: false, error: null });\n for (const idStr of requestedIds) this.notifyKey(resource, idStr);\n }\n\n /** A batch fetch errored. Only the ids that batch was requesting are\n * notified (they'll surface the error via resource-level `status` since\n * they still have no `records` entry); already-resolved ids elsewhere on\n * the same resource are untouched. */\n setResourceStatus(resource: string, next: ResourceStatus, requestedIds: readonly string[]): void {\n this.status.set(resource, next);\n for (const idStr of requestedIds) this.notifyKey(resource, idStr);\n }\n}\n\nconst RelationAggregatorContext = createContext<RelationAggregatorStore | null>(null);\n\ninterface ResourceBatchProps {\n resource: string;\n ids: string[];\n store: RelationAggregatorStore;\n}\n\n/**\n * One native `useMany` per resource with un-resolved registered ids — this is the\n * O(relationColumns) observer in place of the O(rows × relationColumns)\n * per-cell `useOne` fleet. Renders nothing.\n */\nfunction ResourceBatch({ resource, ids, store }: ResourceBatchProps): null {\n const unresolved = ids.filter((id) => !store.isResolved(resource, id));\n\n const query = useMany(resource, {\n ids: unresolved,\n enabled: unresolved.length > 0,\n retry: false,\n });\n\n useEffect(() => {\n if (query.error) {\n store.setResourceStatus(\n resource,\n { isLoading: false, error: query.error as unknown as Error },\n unresolved,\n );\n return;\n }\n if (query.data) {\n store.applyResults(resource, unresolved, query.data.data as RelatedRecord[]);\n }\n // `unresolved` intentionally excluded: it's a new array every render,\n // and we only want to react when the QUERY actually settles (a new\n // `data`/`error` reference from react-query). The closure still\n // captures the `unresolved` that was in scope for the render that\n // triggered THIS query, which is exactly the set that query covers.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [store, resource, query.data, query.error]);\n\n return null;\n}\n\nexport interface RelationAggregatorProviderProps {\n children?: ReactNode;\n}\n\n/**\n * Mount once inside the native data runtime around the app\n * content. Every `useRelatedRecord` call underneath registers its id here\n * instead of holding its own react-query observer; this component renders\n * one `<ResourceBatch>` per resource that currently has un-resolved\n * registered ids.\n */\nexport function RelationAggregatorProvider({\n children,\n}: RelationAggregatorProviderProps): ReactElement {\n const storeRef = useRef<RelationAggregatorStore | null>(null);\n if (!storeRef.current) storeRef.current = new RelationAggregatorStore();\n const store = storeRef.current;\n\n // 3rd arg (getServerSnapshot): `getRegistered` is itself SSR-safe (an\n // empty store just returns an empty Map), so it doubles as the server\n // snapshot — without it, SSR-rendering a 'use client' tree under this\n // provider throws \"Missing getServerSnapshot\".\n const registered = useSyncExternalStore(\n store.subscribeFetch,\n store.getRegistered,\n store.getRegistered,\n );\n\n return (\n <RelationAggregatorContext.Provider value={store}>\n {children}\n {Array.from(registered.entries()).map(([resource, ids]) => (\n <ResourceBatch key={resource} resource={resource} ids={ids} store={store} />\n ))}\n </RelationAggregatorContext.Provider>\n );\n}\n\n/**\n * Resolve a single record by `(targetResource, id)` for relation display.\n *\n * With a `<RelationAggregatorProvider>` mounted above: registers demand\n * (refcounted) and reads from the shared external store via\n * `useSyncExternalStore` — NO react-query observer per call. All calls for\n * the same resource on screen share ONE batched `getList(id in [...])`.\n *\n * Without a provider (standalone usage / tests): falls back to the\n * original per-id `useOne`-based behaviour verbatim (same options, same\n * retry/error-notification policy) — belt-and-suspenders backward safety,\n * not a required setup path.\n *\n * Rules of hooks: every hook below is called unconditionally on every\n * render; behaviour is selected by branching on VALUES (`store`, `idStr`),\n * never by skipping a hook call.\n */\nexport function useRelatedRecord(\n targetResource: string,\n id: string | number | null | undefined,\n): UseRelatedRecordResult {\n const store = useContext(RelationAggregatorContext);\n const idStr = id == null || id === '' ? null : String(id);\n\n // Fallback path — does nothing when a store is mounted (enabled: false).\n // Kept unconditional so hook order never depends on whether a provider\n // happens to be mounted.\n const fallbackEnabled = store == null && idStr != null;\n const fallbackQuery = useOne(targetResource, {\n id: fallbackEnabled ? (id as string | number) : '',\n enabled: fallbackEnabled,\n retry: false,\n });\n\n // Memoized so `useSyncExternalStore` doesn't see a NEW subscribe/getSnapshot\n // closure on every render — an unmemoized subscribe forces React to\n // unsubscribe+resubscribe the per-key listener Set on every re-render,\n // which is an avoidable O(cells) cost across a large list. `getSnapshot`\n // doubles as `getServerSnapshot` (3rd arg): both branches (`STABLE_EMPTY`\n // / the cached key snapshot) are pure reads, safe to call during SSR —\n // without a 3rd arg, SSR-rendering this 'use client' hook throws \"Missing\n // getServerSnapshot\". Same pattern as `useLocale` in use-t.ts.\n const subscribe = useCallback(\n (cb: () => void) =>\n store && idStr != null ? store.subscribeKey(targetResource, idStr, cb) : () => {},\n [store, targetResource, idStr],\n );\n const getSnapshot = useCallback(\n () => (store && idStr != null ? store.getSnapshotKey(targetResource, idStr) : STABLE_EMPTY),\n [store, targetResource, idStr],\n );\n const storeSnapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n useEffect(() => {\n if (store && idStr != null) {\n store.register(targetResource, idStr);\n return () => store.unregister(targetResource, idStr);\n }\n return undefined;\n }, [store, targetResource, idStr]);\n\n if (store != null && idStr != null) {\n return storeSnapshot;\n }\n if (idStr == null) {\n return STABLE_EMPTY;\n }\n\n // No provider mounted — mirror the old use-related-record.ts mapping.\n const error = fallbackQuery.isError ? (fallbackQuery.error as unknown as Error) : null;\n const record = fallbackQuery.data?.data as RelatedRecord | undefined;\n return { record, isLoading: fallbackQuery.isLoading, error };\n}\n","import {\n EMPTY_FILTER_GROUP,\n isFilterGroup,\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n type SortExpression,\n} from '@burojs/core';\n\ntype ResourceFilter = FilterExpression<ErasedResourceHandle>;\ntype ResourceSort = SortExpression<ErasedResourceHandle>;\n\n/**\n * Deliberate bounds for untrusted URL AST payloads. The values are large\n * enough for an interactive list, while preventing a pasted URL from making\n * server rendering or the first client render do unbounded recursive work.\n */\nexport const RESOURCE_URL_STATE_LIMITS = {\n maxEncodedBytes: 16_384,\n maxFilters: 50,\n maxFilterDepth: 16,\n maxFilterNodes: 200,\n maxSortEntries: 20,\n} as const;\n\n/** Typed, router-independent state for an interactive resource list. */\nexport interface ResourceUrlState {\n filters: readonly ResourceFilter[];\n /** The builder group. `filters` above is the PINNED slot — always ANDed. */\n filterGroup: FilterGroup;\n sort: ResourceSort;\n page: number;\n pageSize: number;\n search: string;\n visibleColumns: string[] | null;\n}\n\n/**\n * Kept temporarily as a source-level migration seam for the list controller.\n * URL AST values preserve their JSON primitive type and no longer use this\n * hint for serialization or decoding.\n */\nexport type FieldType = 'string' | 'number' | 'boolean' | 'enum' | 'relation' | 'date';\n\nexport interface CodecOptions {\n /** Resource key — used as the parameter namespace prefix. */\n resource: string;\n /** Values equal to these defaults are omitted from the URL. */\n defaults: ResourceUrlState;\n /** @deprecated AST envelopes preserve primitive value types directly. */\n fieldTypes?: Record<string, FieldType>;\n}\n\ntype JsonValue =\n | null\n | boolean\n | number\n | string\n | readonly JsonValue[]\n | { readonly [key: string]: JsonValue };\ntype JsonRecord = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(value: JsonRecord, keys: readonly string[]): boolean {\n return Object.keys(value).every((key) => keys.includes(key));\n}\n\nfunction isJsonValue(value: unknown, depth = 0): value is JsonValue {\n if (depth > RESOURCE_URL_STATE_LIMITS.maxFilterDepth) return false;\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (Array.isArray(value)) return value.every((item) => isJsonValue(item, depth + 1));\n if (!isRecord(value)) return false;\n return Object.values(value).every((item) => isJsonValue(item, depth + 1));\n}\n\nfunction isFilterExpression(\n value: unknown,\n budget: { nodes: number },\n depth = 0,\n): value is ResourceFilter {\n if (depth > RESOURCE_URL_STATE_LIMITS.maxFilterDepth || !isRecord(value)) return false;\n budget.nodes += 1;\n if (budget.nodes > RESOURCE_URL_STATE_LIMITS.maxFilterNodes) return false;\n\n if (\n typeof value.field === 'string' &&\n value.field.length > 0 &&\n typeof value.op === 'string' &&\n value.op.length > 0\n ) {\n return (\n hasOnlyKeys(value, ['field', 'op', 'value']) &&\n (!Object.hasOwn(value, 'value') || isJsonValue(value.value))\n );\n }\n\n if (Array.isArray(value.and) && hasOnlyKeys(value, ['and'])) {\n return value.and.every((child) => isFilterExpression(child, budget, depth + 1));\n }\n if (Array.isArray(value.or) && hasOnlyKeys(value, ['or'])) {\n return value.or.every((child) => isFilterExpression(child, budget, depth + 1));\n }\n return hasOnlyKeys(value, ['not']) && isFilterExpression(value.not, budget, depth + 1);\n}\n\nfunction isFilterList(\n value: unknown,\n budget: { nodes: number },\n): value is readonly ResourceFilter[] {\n if (!Array.isArray(value) || value.length > RESOURCE_URL_STATE_LIMITS.maxFilters) return false;\n return value.every((item) => isFilterExpression(item, budget));\n}\n\n/** A group row is a bare term or a nested group — never `and`/`or`/`not`. */\nfunction isGroupRow(value: unknown, budget: { nodes: number }, depth: number): boolean {\n if (!isRecord(value)) return false;\n if (Object.hasOwn(value, 'join') || Object.hasOwn(value, 'rows')) {\n return isFilterGroupValue(value, budget, depth);\n }\n return typeof value.field === 'string' && isFilterExpression(value, budget, depth);\n}\n\nfunction isFilterGroupValue(\n value: unknown,\n budget: { nodes: number },\n depth = 0,\n): value is FilterGroup {\n if (depth > RESOURCE_URL_STATE_LIMITS.maxFilterDepth || !isRecord(value)) return false;\n if (!hasOnlyKeys(value, ['join', 'rows'])) return false;\n if (value.join !== 'and' && value.join !== 'or') return false;\n if (!Array.isArray(value.rows) || value.rows.length > RESOURCE_URL_STATE_LIMITS.maxFilters)\n return false;\n // An empty group is a valid, zero-cost shape: `serializeResourceState`\n // always writes SOME `g` (substituting EMPTY_FILTER_GROUP when the panel\n // slot is unused), so charging a node here would tax every v2 envelope\n // for a group nobody populated — silently shrinking the pinned slot's\n // real budget below its documented maxFilterNodes.\n if (value.rows.length === 0) return true;\n budget.nodes += 1;\n if (budget.nodes > RESOURCE_URL_STATE_LIMITS.maxFilterNodes) return false;\n return value.rows.every((row) => isGroupRow(row, budget, depth + 1));\n}\n\nfunction isSortExpression(value: unknown): value is ResourceSort {\n return (\n Array.isArray(value) &&\n value.length <= RESOURCE_URL_STATE_LIMITS.maxSortEntries &&\n value.every(\n (item) =>\n isRecord(item) &&\n hasOnlyKeys(item, ['field', 'direction', 'nulls']) &&\n typeof item.field === 'string' &&\n item.field.length > 0 &&\n (item.direction === 'asc' || item.direction === 'desc') &&\n (item.nulls === undefined || item.nulls === 'first' || item.nulls === 'last'),\n )\n );\n}\n\nfunction encodeEnvelope(payload: unknown): string | null {\n const json = JSON.stringify(payload);\n if (typeof json !== 'string') return null;\n const bytes = new TextEncoder().encode(json);\n if (bytes.length > RESOURCE_URL_STATE_LIMITS.maxEncodedBytes) return null;\n return toBase64Url(bytes);\n}\n\nfunction decodeEnvelope(raw: string): unknown | null {\n if (\n raw.length === 0 ||\n raw.length > RESOURCE_URL_STATE_LIMITS.maxEncodedBytes ||\n !/^[A-Za-z0-9_-]+$/.test(raw)\n ) {\n return null;\n }\n try {\n const bytes = fromBase64Url(raw);\n if (bytes === null) return null;\n if (bytes.length > RESOURCE_URL_STATE_LIMITS.maxEncodedBytes) return null;\n return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));\n } catch {\n return null;\n }\n}\n\nconst BASE64_URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\n/** Browser and Node neutral; avoids relying on optional global btoa/atob. */\nfunction toBase64Url(bytes: Uint8Array): string {\n let encoded = '';\n for (let index = 0; index < bytes.length; index += 3) {\n const first = bytes[index] ?? 0;\n const second = bytes[index + 1];\n const third = bytes[index + 2];\n encoded += BASE64_URL_ALPHABET[first >> 2];\n encoded += BASE64_URL_ALPHABET[((first & 0b11) << 4) | ((second ?? 0) >> 4)];\n if (second !== undefined)\n encoded += BASE64_URL_ALPHABET[((second & 0b1111) << 2) | ((third ?? 0) >> 6)];\n if (third !== undefined) encoded += BASE64_URL_ALPHABET[third & 0b111111];\n }\n return encoded;\n}\n\nfunction fromBase64Url(encoded: string): Uint8Array | null {\n if (encoded.length % 4 === 1) return null;\n const bytes: number[] = [];\n let buffer = 0;\n let bits = 0;\n for (const char of encoded) {\n const value = BASE64_URL_ALPHABET.indexOf(char);\n if (value < 0) return null;\n buffer = (buffer << 6) | value;\n bits += 6;\n while (bits >= 8) {\n bits -= 8;\n bytes.push((buffer >> bits) & 0xff);\n }\n buffer = bits === 0 ? 0 : buffer & ((1 << bits) - 1);\n }\n // Base64url has no padding here, but its remaining bits must be zero for a\n // canonical encoding. Reject aliases such as a final non-zero pad sextet.\n if (bits > 0 && (buffer & ((1 << bits) - 1)) !== 0) return null;\n return Uint8Array.from(bytes);\n}\n\nfunction sameJson(left: unknown, right: unknown): boolean {\n return JSON.stringify(left) === JSON.stringify(right);\n}\n\n/** Serialize one resource's URL slice. AST state is versioned JSON/base64url. */\nexport function serializeResourceState(\n state: ResourceUrlState,\n opts: CodecOptions,\n): URLSearchParams {\n const params = new URLSearchParams();\n const resource = opts.resource;\n\n if (state.page !== opts.defaults.page) params.set(`${resource}.page`, String(state.page));\n if (state.pageSize !== opts.defaults.pageSize)\n params.set(`${resource}.size`, String(state.pageSize));\n if (state.search !== opts.defaults.search && state.search !== '')\n params.set(`${resource}.q`, state.search);\n\n const writeBudget = { nodes: 0 };\n const hasPinned =\n isFilterList(state.filters, writeBudget) &&\n state.filters.length > 0 &&\n !sameJson(state.filters, opts.defaults.filters);\n const groupPopulated = isFilterGroup(state.filterGroup) && state.filterGroup.rows.length > 0;\n // The group comes from the (SP2) filter-panel builder, which — unlike the\n // pinned slot's fixed, adopter-declared control set — has no upper bound\n // on how many rows a user can add. A shallow shape check is not enough\n // here: `deserializeResourceState` re-validates with the STRICT\n // `isFilterGroupValue` (maxFilters per level, maxFilterDepth, and this\n // SAME shared node budget), so a group that fails it would write a URL\n // this app cannot read back. Re-running that exact validator against the\n // exact same budget object — continuing from wherever `isFilterList` above\n // left it, exactly like the read path does — is what keeps \"whatever this\n // writes, it can read back\" true.\n const hasGroup = groupPopulated && isFilterGroupValue(state.filterGroup, writeBudget);\n if (groupPopulated && !hasGroup) {\n // Drop the group but KEEP the pinned slot. Atomic reset is the right\n // call on READ for attacker-supplied/tampered input; applying it here,\n // to input the app itself just produced, would silently throw away a\n // perfectly valid pinned slot alongside the oversized group.\n console.warn(\n `[serializeResourceState] dropping the filter group for resource \"${resource}\": it exceeds the URL-state limits ` +\n `(maxFilters=${RESOURCE_URL_STATE_LIMITS.maxFilters} per level, maxFilterDepth=${RESOURCE_URL_STATE_LIMITS.maxFilterDepth}, ` +\n `or the shared maxFilterNodes=${RESOURCE_URL_STATE_LIMITS.maxFilterNodes} budget with the pinned slot) and would not survive a reload.`,\n );\n }\n if (hasPinned || hasGroup) {\n const encoded = encodeEnvelope({\n v: 2,\n p: hasPinned ? state.filters : [],\n g: hasGroup ? state.filterGroup : EMPTY_FILTER_GROUP,\n });\n if (encoded) params.set(`${resource}.filters`, encoded);\n }\n // ⚠️ Compare against the DEFAULT, not against emptiness. `state.sort.length\n // > 0` used to gate this write, which made \"no sort\" and \"matches the\n // default\" the same condition — harmless while every default was `[]`\n // (both were empty), but once a resource declares a non-empty\n // `defaults.sort` (`views.list.defaultSort`, `@burojs/core`) the two\n // diverge: clearing the sort (`state.sort = []`) no longer matches the\n // default, so it MUST write a param (an empty envelope), or the very next\n // decode falls through to `opts.defaults.sort` and the clear silently\n // undoes itself. `sameJson([], [])` still elides for the ordinary case —\n // an undeclared resource writes no `.sort` param for an empty sort,\n // exactly as before.\n if (isSortExpression(state.sort) && !sameJson(state.sort, opts.defaults.sort)) {\n const encoded = encodeEnvelope({ v: 1, sort: state.sort });\n if (encoded) params.set(`${resource}.sort`, encoded);\n }\n\n if (state.visibleColumns !== null && state.visibleColumns.length > 0) {\n const safeColumns = state.visibleColumns.filter((column) => !column.includes(','));\n const matchesDefaults =\n opts.defaults.visibleColumns !== null &&\n opts.defaults.visibleColumns !== undefined &&\n sameJson(safeColumns, opts.defaults.visibleColumns);\n if (safeColumns.length > 0 && !matchesDefaults)\n params.set(`${resource}.cols`, safeColumns.join(','));\n }\n return params;\n}\n\n/** Decode one resource's URL slice; malformed AST envelopes reset atomically. */\nexport function deserializeResourceState(\n params: URLSearchParams,\n opts: CodecOptions,\n): ResourceUrlState {\n const prefix = `${opts.resource}.`;\n const out: ResourceUrlState = {\n filters: [],\n filterGroup: EMPTY_FILTER_GROUP,\n // Unlike `filters`/`filterGroup` (which have no non-empty default in\n // practice today), `sort` DOES: `views.list.defaultSort`\n // (`@burojs/core`) flows in here as `opts.defaults.sort`. Falling back\n // to a literal `[]` instead — as this used to — meant a declared\n // default sort was silently ignored on every cold load / URL-carries-\n // none render, because the branch below only ever runs when the `sort`\n // param IS present.\n //\n // `?? []` guards `deserializeResourceState`'s public-API surface: the\n // `CodecOptions['defaults']` type says `sort` is a required, complete\n // `ResourceSort`, but callers pass a spread `Partial` at both merge\n // sites (`use-resource-url-state.ts`'s `codecOpts`, and every hand-built\n // `CodecOptions` a test constructs), and `exactOptionalPropertyTypes`\n // is off — so an adopter passing `{ sort: undefined }` would otherwise\n // get `out.sort = undefined` where the old hardcoded `[]` used to\n // shield them by construction.\n sort: opts.defaults.sort ?? [],\n page: opts.defaults.page,\n pageSize: opts.defaults.pageSize,\n search: opts.defaults.search,\n visibleColumns: opts.defaults.visibleColumns ?? null,\n };\n\n const single = (suffix: string): string | null | undefined => {\n const values = params.getAll(`${prefix}${suffix}`);\n return values.length === 0 ? undefined : values.length === 1 ? values[0]! : null;\n };\n const page = single('page');\n if (page !== undefined && page !== null) {\n const parsed = Number(page);\n out.page = Number.isFinite(parsed) ? Math.max(1, Math.floor(parsed)) : opts.defaults.page;\n }\n const pageSize = single('size');\n if (pageSize !== undefined && pageSize !== null) {\n const parsed = Number(pageSize);\n out.pageSize =\n Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : opts.defaults.pageSize;\n }\n const search = single('q');\n if (search !== undefined && search !== null) out.search = search;\n const columns = single('cols');\n if (columns !== undefined && columns !== null) {\n const parsed = columns\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean);\n out.visibleColumns = parsed.length > 0 ? parsed : (opts.defaults.visibleColumns ?? null);\n }\n const filters = single('filters');\n if (filters !== undefined) {\n const envelope = filters === null ? null : decodeEnvelope(filters);\n const budget = { nodes: 0 };\n if (isRecord(envelope) && envelope.v === 2 && hasOnlyKeys(envelope, ['v', 'p', 'g'])) {\n const pinnedOk = isFilterList(envelope.p, budget);\n const groupOk = isFilterGroupValue(envelope.g, budget);\n // Atomic: a half-valid envelope is a tampered or truncated link, and\n // restoring half of it would silently show a different result set.\n if (pinnedOk && groupOk) {\n out.filters = envelope.p as readonly ResourceFilter[];\n out.filterGroup = envelope.g as FilterGroup;\n }\n } else if (\n isRecord(envelope) &&\n envelope.v === 1 &&\n hasOnlyKeys(envelope, ['v', 'filters']) &&\n isFilterList(envelope.filters, budget)\n ) {\n out.filters = envelope.filters;\n }\n }\n const sort = single('sort');\n if (sort !== undefined) {\n const envelope = sort === null ? null : decodeEnvelope(sort);\n out.sort =\n isRecord(envelope) &&\n hasOnlyKeys(envelope, ['v', 'sort']) &&\n envelope.v === 1 &&\n isSortExpression(envelope.sort)\n ? envelope.sort\n : [];\n }\n return out;\n}\n","import {\n EMPTY_FILTER_GROUP,\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n} from '@burojs/core';\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useRouterAdapter } from '../router/router-adapter.js';\nimport {\n type CodecOptions,\n type FieldType,\n type ResourceUrlState,\n deserializeResourceState,\n serializeResourceState,\n} from './codec.js';\n\nconst HOOK_DEFAULTS: ResourceUrlState = {\n filters: [],\n filterGroup: EMPTY_FILTER_GROUP,\n sort: [],\n page: 1,\n pageSize: 10,\n search: '',\n visibleColumns: null,\n};\n\n/**\n * History mode for a single setter call. `'push'` creates a new browser\n * history entry (back-button returns the user to the prior URL).\n * `'replace'` overwrites the current entry (back-button skips the\n * change). See {@link DEFAULT_HISTORY_MODE} for per-setter defaults and\n * adopter-override semantics.\n */\nexport type HistoryMode = 'push' | 'replace';\n\n/**\n * Per-setter default {@link HistoryMode}. The policy splits setters\n * into two groups by interaction frequency / intent:\n *\n * - **`push`** for intentional, low-frequency mutations the user\n * expects to back-out one click at a time:\n * - `setFilters` (chip add/edit/remove)\n * - `setSort` (header click)\n * - `setVisibleColumns` (column-toggle)\n * - **`replace`** for high-frequency or implicit mutations that\n * would flood the back-stack:\n * - `setPage` (next/prev pagination clicks)\n * - `setPageSize` (rare but typically combined with setPage(1))\n * - `setSearch` (per-keystroke writes)\n *\n * Same-tick batching: when multiple setters fire synchronously\n * (e.g. via `applyViewToUrlState`), the URL change uses `push` if ANY\n * of the called setters defaults (or is overridden) to push. The first\n * push in the tick wins; subsequent setters cannot downgrade. This\n * yields the desired behaviour for saved-view application (one push\n * entry covering all six setters) and for clear-all\n * (`setSearch + setFilters + setPage + setVisibleIds` → push because\n * `setFilters` defaults to push).\n *\n * Adopter override: each setter accepts an optional second argument\n * `{ historyMode?: 'push' | 'replace' }`. Useful for adopter-controlled\n * flows where the default isn't right (e.g. an \"auto-suggest\" filter\n * that should NOT push because the user didn't explicitly opt into the\n * mutation):\n *\n * ```ts\n * setFilters(filters, { historyMode: 'replace' }); // override\n * setSort(sort); // default 'push'\n * ```\n */\nexport const DEFAULT_HISTORY_MODE = {\n filters: 'push',\n filterGroup: 'push',\n sort: 'push',\n visibleColumns: 'push',\n page: 'replace',\n pageSize: 'replace',\n search: 'replace',\n} as const satisfies Record<string, HistoryMode>;\n\n/**\n * Optional second argument accepted by every setter returned from\n * {@link useResourceUrlState}. Override the per-setter default\n * {@link HistoryMode} for explicit adopter control. Pass nothing /\n * undefined to use the default for that setter (see\n * {@link DEFAULT_HISTORY_MODE}).\n */\nexport interface SetterOptions {\n historyMode?: HistoryMode;\n}\n\n/**\n * Foundation hook for URL-state sync of a list page's interactive state.\n *\n * Mirrors `{ filters, sort, page, pageSize, search, visibleColumns }`\n * into the router's search params (via {@link useRouterAdapter}) under the\n * `?<resource>.<key>=<value>` namespace.\n *\n * **Browser history semantics (A5).** Setters use a hybrid policy:\n * intentional low-frequency mutations (`setFilters`, `setSort`,\n * `setVisibleColumns`) call `router.push` so back-button returns the\n * user to the prior URL; high-frequency mutations (`setPage`,\n * `setPageSize`, `setSearch`) call `router.replace` to avoid flooding\n * the back-stack with micro-edits. Same-tick batching: when multiple\n * setters fire synchronously, the URL change is `push` if ANY of the\n * called setters defaults (or is overridden) to push. See\n * {@link DEFAULT_HISTORY_MODE} for the full policy and the per-setter\n * adopter override pattern (`{ historyMode }` second arg).\n *\n * Cross-resource isolation: params NOT prefixed with `<resource>.` are\n * preserved verbatim on every update. Two list views on the same page\n * (subresource tabs / embedded lists) can each call this hook for their\n * own resource without colliding.\n *\n * Cold deep links: the initial render reads the router adapter's\n * `searchParams` synchronously, so an AST envelope produces the filtered\n * view on first paint with no flash-of-unfiltered-rows.\n *\n * Returned setters are stable across renders (memoized via `useCallback`).\n *\n * **Stable-reference requirement.** Keep `opts.defaults` stable across\n * renders (module scope or `useMemo`) so setter identities remain stable.\n * Filter values are serialized as JSON AST, therefore their primitive types\n * do not need per-field URL coercion hints.\n *\n * **`opts.defaults.search` should remain `''` for v0.2.** A non-empty\n * default for `search` does not round-trip cleanly: the encoder elides\n * the param when `state.search === defaults.search` AND when\n * `state.search === ''`, which means clearing search to empty when the\n * default is non-empty produces a URL that re-decodes back to the\n * non-empty default. If you need a non-empty initial search value, set\n * it once at mount via `setSearch(...)` rather than via `defaults`.\n *\n * @example\n * const { filters, sort, page, search,\n * setFilters, setSort, setPage, setSearch } =\n * useResourceUrlState('document_document');\n */\nexport function useResourceUrlState(\n resource: string,\n opts?: {\n defaults?: Partial<ResourceUrlState>;\n fieldTypes?: Record<string, FieldType>;\n },\n): ResourceUrlState & {\n setFilters: (\n filters: readonly FilterExpression<ErasedResourceHandle>[],\n options?: SetterOptions,\n ) => void;\n setFilterGroup: (group: FilterGroup, options?: SetterOptions) => void;\n setSort: (sort: ResourceUrlState['sort'], options?: SetterOptions) => void;\n setPage: (page: number, options?: SetterOptions) => void;\n setPageSize: (size: number, options?: SetterOptions) => void;\n setSearch: (q: string, options?: SetterOptions) => void;\n /**\n * Replace the user-toggled visible-column set in the URL.\n *\n * Elision rules (URL stays clean for the canonical defaults view):\n * - `setVisibleColumns(null)` resets to defaults: drops the\n * `?<r>.cols=` param and the next deserialize returns\n * `defaults.visibleColumns ?? null`.\n * - `setVisibleColumns([])` is treated as `null` (empty arrays\n * collapse so the canonical defaults state is reachable from a\n * single sentinel).\n * - `setVisibleColumns(arr)` where `arr` matches `defaults.visibleColumns`\n * set-equality (same length AND same ids in the same order) ALSO\n * elides — the codec compares directly so a \"manual reset\" via\n * `setVisibleColumns([...defaults])` produces the same clean URL\n * as `setVisibleColumns(null)`.\n * - Any other non-empty array writes the URL.\n *\n * Constraint: column ids MUST NOT contain a comma (`,`). The codec\n * uses `,` as the wire-format separator; an embedded comma would\n * corrupt the parse. The serializer defensively skips offending ids\n * and emits a console.warn — rename the column id to fix.\n *\n * The codec stores ONLY the user-toggled set; the page is responsible\n * for unioning with `requiredColumns` at render time. This keeps the\n * URL compact (typically 2-3 short ids) and means a malformed URL\n * omitting a required column still renders that column.\n */\n setVisibleColumns: (cols: string[] | null, options?: SetterOptions) => void;\n} {\n const router = useRouterAdapter();\n const searchParams = router.searchParams;\n const pathname = router.pathname;\n\n // ---------------------------------------------------------------\n // Same-tick batching refs.\n //\n // These two refs accumulate state across SYNCHRONOUS setter calls\n // within a single React commit cycle. Both are reset in the next\n // render's `useMemo` body (below) — a fresh `searchParams` value is\n // our signal that a commit happened and the in-flight tick is done.\n //\n // Lifecycle:\n // 1. First setter in tick reads `pendingQsRef === null`, computes a\n // new URL from `searchParams`, writes it, stores the qs in the\n // ref so the next synchronous setter sees the merged state.\n // 2. Second setter reads the ref, layers its patch on top, writes.\n // 3. React commits → `searchParams` changes → `useMemo` reruns and\n // resets both refs to null. Next tick starts fresh.\n //\n // Concurrent-React caveat (known limitation). If React 18+ cancels\n // a render mid-flight (concurrent mode rebasing on higher-priority\n // work), a setter's mode contribution could be \"dropped\" — e.g. a\n // push setter fired in a cancelled render leaves the resolved tick\n // mode at replace. In practice this is exceedingly rare for synchronous\n // event handlers (which is the only context where two URL setters\n // fire same-tick today). Adopters who need bulletproof behaviour can\n // pass an explicit `{ historyMode: 'push' }` to the setter that MUST\n // produce a back entry — that override is observed on every call.\n //\n // Why a ref and not state: state would trigger a re-render between\n // the two setter calls, defeating same-tick batching entirely.\n // ---------------------------------------------------------------\n const pendingQsRef = useRef<string | null>(null);\n\n // Tracks the \"highest\" history mode requested this tick. Push beats\n // replace — once a push has been requested in this tick, subsequent\n // replace calls cannot downgrade. Reset alongside `pendingQsRef`.\n const pendingHistoryModeRef = useRef<HistoryMode | null>(null);\n\n // Build the codec options once per render. Defaults are the merged\n // hook-defaults + caller-supplied overrides.\n const codecOpts = useMemo<CodecOptions>(() => {\n const merged: ResourceUrlState = {\n ...HOOK_DEFAULTS,\n ...(opts?.defaults as Partial<ResourceUrlState> | undefined),\n };\n return {\n resource,\n defaults: merged,\n fieldTypes: opts?.fieldTypes,\n };\n // We intentionally deep-spread `defaults` and `fieldTypes` from opts;\n // adopter code is expected to keep these stable across renders. Re-running\n // the memo when the identity changes is fine (rare).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resource, opts?.defaults, opts?.fieldTypes]);\n\n // Derived: current state from URL. Reading `searchParams` here also\n // resets the same-tick batching caches: a fresh render means React\n // has committed the latest URL, so any in-flight pendingQsRef /\n // pendingHistoryModeRef is stale.\n const state = useMemo<ResourceUrlState>(() => {\n pendingQsRef.current = null;\n pendingHistoryModeRef.current = null;\n const params = new URLSearchParams(searchParams.toString());\n return deserializeResourceState(params, codecOpts);\n }, [searchParams, codecOpts]);\n\n /**\n * Apply a partial patch to the URL: deserialize this resource's slice,\n * merge the patch, re-serialize, then combine with all OTHER params\n * (other resources + non-prefixed) preserved verbatim. Calls\n * `router.push` or `router.replace` based on the resolved history\n * mode for this tick (push wins same-tick).\n */\n const applyPatch = useCallback(\n (patch: Partial<ResourceUrlState>, mode: HistoryMode) => {\n // Choose the most-recently-known URL: the same-tick cache wins\n // (so two synchronous setters merge), then `searchParams` from\n // the current render (covers deep links + external nav). We\n // intentionally avoid `window.location.search` because some\n // routers update it asynchronously, which would race with our\n // own writes in the same tick.\n const live = pendingQsRef.current ?? searchParams.toString();\n const liveParams = new URLSearchParams(live);\n\n // Decode this resource's current state, apply patch.\n const current = deserializeResourceState(liveParams, codecOpts);\n const next: ResourceUrlState = { ...current, ...patch };\n\n // Re-encode this resource's slice, then preserve everything else.\n const ownParams = serializeResourceState(next, codecOpts);\n const prefix = `${codecOpts.resource}.`;\n const merged = new URLSearchParams();\n for (const [k, v] of liveParams.entries()) {\n if (!k.startsWith(prefix)) merged.append(k, v);\n }\n for (const [k, v] of ownParams.entries()) {\n merged.append(k, v);\n }\n\n const qs = merged.toString();\n pendingQsRef.current = qs;\n const url = qs.length > 0 ? `${pathname}?${qs}` : pathname;\n\n // Resolve the history mode for this tick: push wins. The first\n // setter sets the mode; subsequent setters can upgrade to push\n // but cannot downgrade.\n const prior = pendingHistoryModeRef.current;\n const resolved: HistoryMode = prior === 'push' || mode === 'push' ? 'push' : 'replace';\n pendingHistoryModeRef.current = resolved;\n\n // A same-tick push must create one history entry, not one per setter.\n // Once that entry exists, replace its URL with subsequent merged\n // patches. A prior replace may be upgraded by the first push; a later\n // push never needs another entry in the same batch.\n if (resolved === 'push' && prior !== 'push') {\n router.push(url);\n } else {\n router.replace(url);\n }\n },\n [pathname, router, searchParams, codecOpts],\n );\n\n const setFilters = useCallback(\n (filters: readonly FilterExpression<ErasedResourceHandle>[], options?: SetterOptions) => {\n if (filters === undefined) {\n throw new Error(\n '[useResourceUrlState] setFilters(undefined) is invalid — pass [] to clear filters.',\n );\n }\n const mode = options?.historyMode ?? DEFAULT_HISTORY_MODE.filters;\n applyPatch({ filters }, mode);\n },\n [applyPatch],\n );\n\n const setFilterGroup = useCallback(\n (group: FilterGroup, options?: SetterOptions) => {\n const mode = options?.historyMode ?? DEFAULT_HISTORY_MODE.filterGroup;\n applyPatch({ filterGroup: group }, mode);\n },\n [applyPatch],\n );\n\n const setSort = useCallback(\n (sort: ResourceUrlState['sort'], options?: SetterOptions) => {\n const mode = options?.historyMode ?? DEFAULT_HISTORY_MODE.sort;\n applyPatch({ sort }, mode);\n },\n [applyPatch],\n );\n\n const setPage = useCallback(\n (page: number, options?: SetterOptions) => {\n const safe = Number.isFinite(page) && page >= 1 ? Math.floor(page) : 1;\n const mode = options?.historyMode ?? DEFAULT_HISTORY_MODE.page;\n applyPatch({ page: safe }, mode);\n },\n [applyPatch],\n );\n\n const setPageSize = useCallback(\n (size: number, options?: SetterOptions) => {\n const safe =\n Number.isFinite(size) && size > 0 ? Math.floor(size) : codecOpts.defaults.pageSize;\n const mode = options?.historyMode ?? DEFAULT_HISTORY_MODE.pageSize;\n applyPatch({ pageSize: safe }, mode);\n },\n [applyPatch, codecOpts.defaults.pageSize],\n );\n\n const setSearch = useCallback(\n (q: string, options?: SetterOptions) => {\n const mode = options?.historyMode ?? DEFAULT_HISTORY_MODE.search;\n applyPatch({ search: q ?? '' }, mode);\n },\n [applyPatch],\n );\n\n const setVisibleColumns = useCallback(\n (cols: string[] | null, options?: SetterOptions) => {\n // Empty arrays collapse to null so the canonical \"use defaults\"\n // state is reachable from a single sentinel — the codec's\n // serializer also elides empty arrays, so this is just defence\n // in depth + a clearer return-shape contract.\n const next = cols !== null && cols.length > 0 ? cols : null;\n const mode = options?.historyMode ?? DEFAULT_HISTORY_MODE.visibleColumns;\n applyPatch({ visibleColumns: next }, mode);\n },\n [applyPatch],\n );\n\n return {\n ...state,\n setFilters,\n setFilterGroup,\n setSort,\n setPage,\n setPageSize,\n setSearch,\n setVisibleColumns,\n };\n}\n","import { EMPTY_FILTER_GROUP } from '@burojs/core';\nimport {\n type CodecOptions,\n type FieldType,\n type ResourceUrlState,\n deserializeResourceState,\n} from './codec.js';\n\n/**\n * SSR-friendly helper that decodes a list page's URL state from raw\n * searchParams without React. Useful in Next App Router server\n * components, getServerSideProps, RSC route handlers, or anywhere a\n * `URLSearchParams`/plain-object map is available before render.\n *\n * Mirrors the runtime decoding done inside `useResourceUrlState`\n * — both call the same codec under the hood, so an SSR-prefetched\n * `useList({ filters, sorters })` will hit the same query as the\n * client renders without a refetch on hydration.\n *\n * @example\n * // Next App Router server component\n * export default async function DocumentsPage({ searchParams }) {\n * const { filters, sort, page, pageSize } = getResourceParams(\n * 'docs',\n * searchParams,\n * { fieldTypes: { status: 'enum' } }\n * );\n * const data = await fetchDocs({ filters, sort, page, pageSize });\n * return <DocList initialData={data} />;\n * }\n *\n * @example\n * // Next pages-router getServerSideProps\n * export async function getServerSideProps({ query }) {\n * const state = getResourceParams('docs', query);\n * return { props: { state } };\n * }\n *\n * @param resource Resource id used as the URL namespace prefix.\n * @param searchParams Raw URL search params. Accepts:\n * - `URLSearchParams` (e.g. from `request.nextUrl.searchParams`)\n * - Plain object map `{ key: string | string[] | undefined }` (the\n * shape Next App Router passes to server-component `searchParams`\n * props and that pages-router `getServerSideProps` exposes via\n * `context.query`). Array values are appended in order so range\n * filters (e.g. `?docs.price=gt:10&docs.price=lt:100`) round-trip\n * correctly.\n * - `undefined` / `null` → returns defaults verbatim.\n * @param opts.defaults Override the framework defaults that govern\n * default-elision. Same rules as `useResourceUrlState`'s\n * `opts.defaults` — values matching defaults are NOT serialized.\n * @param opts.fieldTypes Deprecated migration seam. Versioned AST envelopes\n * retain JSON primitive types, so no per-field coercion is needed.\n * @returns The decoded `ResourceUrlState` — same shape as\n * `useResourceUrlState`'s return (minus the setters).\n */\nexport function getResourceParams(\n resource: string,\n searchParams: URLSearchParams | Record<string, string | string[] | undefined> | undefined | null,\n opts?: {\n defaults?: Partial<ResourceUrlState>;\n fieldTypes?: Record<string, FieldType>;\n },\n): ResourceUrlState {\n const params = normalizeSearchParams(searchParams);\n const merged: ResourceUrlState = {\n filters: [],\n filterGroup: EMPTY_FILTER_GROUP,\n sort: [],\n page: 1,\n pageSize: 10,\n search: '',\n visibleColumns: null,\n ...(opts?.defaults as Partial<ResourceUrlState> | undefined),\n };\n const codecOpts: CodecOptions = {\n resource,\n defaults: merged,\n fieldTypes: opts?.fieldTypes,\n };\n return deserializeResourceState(params, codecOpts);\n}\n\n/**\n * Coerce all supported `searchParams` input shapes into a uniform\n * `URLSearchParams`. Array-valued plain-object entries (the form Next\n * pages-router uses for repeated query keys) are `append()`ed in\n * order so range filters with two values for the same field survive.\n */\nfunction normalizeSearchParams(\n raw: URLSearchParams | Record<string, string | string[] | undefined> | undefined | null,\n): URLSearchParams {\n if (raw == null) return new URLSearchParams();\n if (raw instanceof URLSearchParams) {\n return new URLSearchParams(raw.toString());\n }\n // Plain-object form (Next App Router pattern, getServerSideProps).\n const out = new URLSearchParams();\n for (const [key, value] of Object.entries(raw)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const v of value) {\n out.append(key, v);\n }\n } else {\n out.append(key, value);\n }\n }\n return out;\n}\n","import type {\n ErasedResourceHandle,\n FilterExpression,\n FilterGroup,\n SortExpression,\n} from '@burojs/core';\nimport { defineUiSetting, isFilterGroup } from '@burojs/core';\n\n/**\n * The first built-in UI setting type (spec\n * `docs/superpowers/specs/2026-08-02-ui-config-catalog-design.md` §12):\n * `buro/saved-view`, a `collection` keyed by `{ resource }`.\n *\n * `use-saved-views.ts` is the ONLY intended consumer — it projects this\n * setting's live collection into the pre-existing `useSavedViews` compat\n * surface (`adopterViews` / `userViews` / `entries` / the mutators). This\n * module owns just the typed contract: params, value, and validation.\n */\n\n/**\n * Params selecting one saved-view collection: one per resource, matching\n * the legacy `buro:saved-views:<resource>` `localStorage` key's own\n * granularity.\n */\nexport interface SavedViewSettingParams {\n readonly resource: string;\n}\n\n/**\n * Portable value persisted for one saved-view entry: everything needed to\n * REPLACE the list page's URL state on apply, except `page`.\n *\n * A view describes list *configuration*, not a position within one query's\n * results — applying a view always opens page one (spec §12; see\n * `apply-view-to-url-state.ts`). `page` is therefore not a field of this\n * value at all; `parseValue` below tolerates (and drops) a legacy stored\n * value that still carries one rather than rejecting it, so an as-is\n * legacy `SavedViewDef.state` read from `localStorage` can be handed\n * straight to `create()` during migration with no separate stripping\n * step.\n *\n * Filters and sort are the SAME portable, provider-facing \"wire form\"\n * `ResourceUrlState` itself uses — no domain conversion happens at this\n * boundary. Field codecs, once introduced, apply between the wire form and\n * the domain form elsewhere; a saved view is never rewritten just because\n * a codec is added later (spec §12).\n */\nexport interface SavedViewSettingValue {\n readonly filters?: readonly FilterExpression<ErasedResourceHandle>[];\n /**\n * The filter-builder group (Task 7, SP1). Absent on a view saved before\n * the builder shipped — `applyViewToUrlState` substitutes\n * `EMPTY_FILTER_GROUP` for a missing value, so no migration is needed;\n * this setting simply passes through whatever `buildCleanState` gives it.\n */\n readonly filterGroup?: FilterGroup;\n readonly sort?: SortExpression<ErasedResourceHandle>;\n readonly pageSize?: number;\n readonly search?: string;\n readonly visibleColumns?: string[] | null;\n}\n\nfunction parseSavedViewParams(input: unknown): SavedViewSettingParams {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n throw new TypeError('[buro/saved-view] params must be an object with a \"resource\" string.');\n }\n const resource = (input as Record<string, unknown>).resource;\n if (typeof resource !== 'string' || resource.length === 0) {\n throw new TypeError('[buro/saved-view] params.resource must be a non-empty string.');\n }\n return { resource };\n}\n\n/**\n * Validates and normalizes a raw candidate into a `SavedViewSettingValue`.\n *\n * Shallow validation only — same posture the legacy hook's `isSavedViewDef`\n * already used: the outer shape of `filters` / `sort` is checked (must be\n * an array), but the AST entries inside are not deeply validated here (the\n * portable clone boundary run by the store bounds and sanitizes the full\n * value regardless, and a malformed nested filter surfaces via the\n * existing render-time guards, same as before this task).\n *\n * Unknown keys — most notably a legacy `page` carried over from a\n * pre-migration `SavedViewDef.state` — are silently DROPPED, never\n * rejected. Never throws for a well-formed-but-unfamiliar shape; only a\n * non-object input, or a KNOWN key with the wrong runtime type, is\n * rejected (which the store turns into a `rejected` mutation result, never\n * a thrown error reaching a caller — see `store.ts`'s\n * `parseMutationValue`).\n */\nfunction parseSavedViewValue(input: unknown): SavedViewSettingValue {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n throw new TypeError('[buro/saved-view] value must be an object.');\n }\n const raw = input as Record<string, unknown>;\n const value: {\n filters?: readonly FilterExpression<ErasedResourceHandle>[];\n filterGroup?: FilterGroup;\n sort?: SortExpression<ErasedResourceHandle>;\n pageSize?: number;\n search?: string;\n visibleColumns?: string[] | null;\n } = {};\n\n if (raw.filters !== undefined) {\n if (!Array.isArray(raw.filters)) {\n throw new TypeError('[buro/saved-view] value.filters must be an array.');\n }\n value.filters = raw.filters as readonly FilterExpression<ErasedResourceHandle>[];\n }\n if (raw.filterGroup !== undefined) {\n if (!isFilterGroup(raw.filterGroup)) {\n throw new TypeError('[buro/saved-view] value.filterGroup must be a {join, rows} group.');\n }\n value.filterGroup = raw.filterGroup;\n }\n if (raw.sort !== undefined) {\n if (!Array.isArray(raw.sort)) {\n throw new TypeError('[buro/saved-view] value.sort must be an array.');\n }\n value.sort = raw.sort as SortExpression<ErasedResourceHandle>;\n }\n if (raw.pageSize !== undefined) {\n if (typeof raw.pageSize !== 'number') {\n throw new TypeError('[buro/saved-view] value.pageSize must be a number.');\n }\n value.pageSize = raw.pageSize;\n }\n if (raw.search !== undefined) {\n if (typeof raw.search !== 'string') {\n throw new TypeError('[buro/saved-view] value.search must be a string.');\n }\n value.search = raw.search;\n }\n if (raw.visibleColumns !== undefined) {\n if (raw.visibleColumns !== null && !Array.isArray(raw.visibleColumns)) {\n throw new TypeError('[buro/saved-view] value.visibleColumns must be an array or null.');\n }\n value.visibleColumns = raw.visibleColumns as string[] | null;\n }\n // `page` (legacy) and any other unrecognized key are intentionally NOT\n // copied through — dropped, never rejected. See the module doc above.\n\n return value;\n}\n\nexport const savedViewSetting = defineUiSetting({\n id: 'buro/saved-view',\n cardinality: 'collection' as const,\n currentVersion: 1,\n parseParams: parseSavedViewParams,\n parseValue: parseSavedViewValue,\n});\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n SavedViewDef,\n UiSettingEntryPermissions,\n UiSettingMutationResult,\n UiSettingScope,\n UiSettingsIssue,\n} from '@burojs/core';\nimport { useApp } from '../use-app.js';\nimport type { ResourceUrlState } from '../url-state/codec.js';\nimport { LOCAL_USER_SCOPE_ID } from '../../ui-settings/local-storage-adapter.js';\nimport { useUiSettings } from '../../ui-settings/use-ui-settings.js';\nimport { savedViewSetting, type SavedViewSettingValue } from './saved-view-setting.js';\n\n/**\n * `useSavedViews` — compatibility PROJECTION over the universal UI settings\n * store (Task 8, spec §12). This hook is the ONLY place `SavedViewDef`\n * (the `@burojs/core` type) is ever constructed from an adapter entry —\n * everywhere else in the framework talks either raw adopter config\n * (`def.views.list.savedViews`) or the typed `savedViewSetting` collection.\n *\n * ### What moved, and what didn't\n *\n * User-saved views used to live directly in `localStorage`, read/written\n * synchronously by this hook. They now live in a `buro/saved-view`\n * collection opened through `useUiSettings` — by default backed by the\n * SAME browser `localStorage`, via the default local-storage\n * `UiSettingsAdapter` that `@burojs/react` auto-wires when a\n * `BuroProvider` has no `uiSettings` prop (Task 7).\n * An adopter supplying an explicit adapter (a backend, a multi-scope\n * aggregator, …) becomes the sole mutable authority for saved views —\n * nothing here writes to `localStorage` in that case, see \"Legacy\n * migration\" below.\n *\n * `adopterViews` — the static, read-only views declared on\n * `def.views.list.savedViews` — are UNCHANGED: they never went through\n * `localStorage` and don't go through the settings store either. They\n * continue to sit ALONGSIDE whatever the store returns, exactly as before.\n *\n * ### Legacy migration\n *\n * Entries previously written under `buro:saved-views:<resource>` (this\n * hook's pre-Task-8 format) must not vanish the moment an app upgrades.\n * The migration contract (spec §12):\n *\n * 1. **Visible before migration.** While a legacy entry hasn't been\n * migrated yet, it still appears in `userViews` (merged with whatever\n * the store already has).\n * 2. **Migrates on the first successful new-format persistence.** The\n * first call to `saveCurrentAsView` / `renameUserView` /\n * `deleteUserView` that reaches this hook first replays every\n * still-pending legacy entry into the store via `create()`, THEN\n * performs the caller's own operation. A legacy `page` field (if\n * present) is silently dropped by `savedViewSetting.parseValue` — see\n * that module's doc.\n * 3. **Old data is never deleted before the new write succeeds.** Each\n * legacy entry is removed from the `localStorage` envelope only\n * immediately AFTER its own `create()` call reports `created` /\n * `updated` — never speculatively, and never in a batch that could\n * leave a gap if the process is interrupted midway. If a migration\n * `create()` is `rejected` / `conflict`, migration stops there; the\n * untouched remainder (that entry and everything after it) stays in\n * `localStorage` for a retry on the next mutation.\n * 4. **Never mirrored back.** Once an entry is migrated, this hook never\n * writes it (or anything else) back to the legacy `localStorage` key\n * — the settings store is the sole mutable copy from then on.\n *\n * Migration only ever runs against the FRAMEWORK's own default local\n * scope (`LOCAL_USER_SCOPE_ID` — see `isLocalScope` below). When an\n * adopter mounts an explicit `uiSettings` store whose write scopes don't\n * include it, legacy `localStorage` data is left untouched — read, shown,\n * or migrated by nobody. Silently pushing a user's private local browser\n * data into a newly-mounted, possibly shared/backend adapter without an\n * explicit adopter-authored migration would be a far more surprising\n * failure mode than leaving inert bytes on disk; the adopter's own\n * explicit adapter is \"the only mutable settings authority\" (spec §12).\n *\n * ### Async mutation surface\n *\n * `saveCurrentAsView` / `renameUserView` / `deleteUserView` / `forkUserView`\n * are all `Promise`-returning: they `await` the store's mutation outcome and\n * throw (i.e. reject) on `rejected` / `conflict`, mirroring the old\n * contract's synchronous throw-on-quota-exceeded as closely as an\n * inherently async boundary allows. `saveCurrentAsView` still throws\n * synchronously-as-a-rejection for an empty label (defensive\n * belt-and-braces, unchanged from before).\n *\n * ### Scope/permission surface (Task 9)\n *\n * `entries` carries each store entry's `scope`/`permissions`; `writeScopes`\n * is the store's own answer to \"where may the current user create a NEW\n * entry\" (spec §5); `issues` and `pending` are the store's own\n * `snapshot.issues`/`snapshot.pending`, passed through unchanged. None of\n * these three are specific to migration or to any one adapter — they are\n * plain projections of the live `UiSettingsSnapshot`, present regardless of\n * whether legacy `localStorage` migration ever runs.\n */\n\nconst LEGACY_STORAGE_KEY_PREFIX = 'buro:saved-views:';\nconst LEGACY_STORAGE_VERSION = 1 as const;\n\n/** Wrapped legacy persisted shape — unchanged from the pre-Task-8 format. */\ninterface LegacyStoredEnvelope {\n version: typeof LEGACY_STORAGE_VERSION;\n views: SavedViewDef[];\n}\n\n/**\n * Validates a single legacy `localStorage` entry. Returns `null` for\n * malformed shapes so the caller can drop them silently. Unchanged from\n * the pre-Task-8 reader: id + label are required strings, `state` must be\n * a plain object; a legacy `state.page` is NOT checked for here — it is\n * tolerated all the way through to `savedViewSetting.parseValue`, which\n * drops it during migration.\n */\nfunction isLegacySavedViewDef(v: unknown): v is SavedViewDef {\n if (typeof v !== 'object' || v === null) return false;\n const o = v as Record<string, unknown>;\n if (typeof o.id !== 'string' || o.id.length === 0) return false;\n if (typeof o.label !== 'string') return false;\n if (typeof o.state !== 'object' || o.state === null || Array.isArray(o.state)) {\n return false;\n }\n return true;\n}\n\n/**\n * Reads + validates the legacy `buro:saved-views:<resource>` entries.\n * Handles the same three shapes the pre-Task-8 hook did (current `{\n * version: 1, views }` envelope, a defensive bare-array v0 shape, and a\n * silently-dropped future `version`). Any parse failure degrades to `[]`\n * — never throws, so stale/corrupted legacy data can never brick the page.\n */\nfunction readLegacyUserViews(resource: string): SavedViewDef[] {\n if (typeof window === 'undefined') return [];\n try {\n const raw = window.localStorage.getItem(`${LEGACY_STORAGE_KEY_PREFIX}${resource}`);\n if (raw == null) return [];\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n return parsed.filter(isLegacySavedViewDef);\n }\n if (typeof parsed === 'object' && parsed !== null) {\n const env = parsed as Record<string, unknown>;\n const version = env.version;\n if (typeof version !== 'number') return [];\n if (version > LEGACY_STORAGE_VERSION) return [];\n const views = env.views;\n if (!Array.isArray(views)) return [];\n return views.filter(isLegacySavedViewDef);\n }\n return [];\n } catch {\n return [];\n }\n}\n\n/** Rewrites the legacy envelope with a SHRUNKEN `views` list — used mid-migration, one successfully-migrated entry at a time (see the module doc's point 3). Never throws; a failed write just leaves the previous envelope in place. */\nfunction writeLegacyUserViews(resource: string, views: SavedViewDef[]): void {\n if (typeof window === 'undefined') return;\n try {\n const envelope: LegacyStoredEnvelope = { version: LEGACY_STORAGE_VERSION, views };\n window.localStorage.setItem(\n `${LEGACY_STORAGE_KEY_PREFIX}${resource}`,\n JSON.stringify(envelope),\n );\n } catch {\n // Best-effort — if this write fails, the (already-migrated-into-the-\n // store) entry simply gets re-attempted on the next mutation. The\n // ONLY consequence of a failed shrink-write is a possible duplicate\n // retry, never data loss (the store-side create already succeeded).\n }\n}\n\n/** Removes the legacy key entirely — called once every pending entry has migrated. Never throws. */\nfunction clearLegacyUserViews(resource: string): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.removeItem(`${LEGACY_STORAGE_KEY_PREFIX}${resource}`);\n } catch {\n // Best-effort — see writeLegacyUserViews.\n }\n}\n\n/**\n * Defensively coerces a raw (possibly adapter-supplied, possibly\n * pre-Task-8-legacy) value into `SavedViewDef['state']`, reusing\n * `savedViewSetting`'s own validator so there is exactly one definition of\n * \"what a saved-view value looks like\". Never throws: a malformed value\n * degrades to `{}` rather than crashing the page, matching the legacy\n * reader's posture.\n */\nfunction toSavedViewState(rawValue: unknown): SavedViewDef['state'] {\n try {\n return savedViewSetting.parseValue(rawValue) as SavedViewDef['state'];\n } catch {\n return {};\n }\n}\n\n/** Strips `page` (never persisted — see `saved-view-setting.ts`) and undefined keys from a URL-state snapshot on its way into `create()`/`update()`. */\nfunction buildCleanState(state: Partial<ResourceUrlState>): SavedViewSettingValue {\n // Built through a locally-mutable shape (`SavedViewSettingValue`'s own\n // fields are `readonly`, by design — see that module's doc) and handed\n // back as the public readonly-fielded type at the `return`, which is a\n // structural (not a mutability) check.\n const cleanState: {\n filters?: SavedViewSettingValue['filters'];\n filterGroup?: SavedViewSettingValue['filterGroup'];\n sort?: SavedViewSettingValue['sort'];\n pageSize?: SavedViewSettingValue['pageSize'];\n search?: SavedViewSettingValue['search'];\n visibleColumns?: SavedViewSettingValue['visibleColumns'];\n } = {};\n if (state.filters !== undefined) cleanState.filters = state.filters;\n if (state.filterGroup !== undefined) cleanState.filterGroup = state.filterGroup;\n if (state.sort !== undefined) cleanState.sort = state.sort;\n if (state.pageSize !== undefined) cleanState.pageSize = state.pageSize;\n if (state.search !== undefined) cleanState.search = state.search;\n if (state.visibleColumns !== undefined) cleanState.visibleColumns = state.visibleColumns;\n // `state.page` is intentionally never copied through.\n return cleanState;\n}\n\n/** Throws for `rejected` / `conflict`; a no-op for every other status. Shared by rename/delete, which never need to return an entry. */\nfunction throwIfMutationFailed(\n result: UiSettingMutationResult<SavedViewSettingValue>,\n resource: string,\n): void {\n if (result.status === 'conflict') {\n throw Object.assign(\n new Error(\n `[useSavedViews] Saved view was modified elsewhere (resource=\"${resource}\"); reload and try again.`,\n ),\n { kind: 'conflict' as const, current: result.current },\n );\n }\n if (result.status === 'rejected') {\n throw Object.assign(\n new Error(\n `[useSavedViews] Failed to persist saved view (resource=\"${resource}\"): ${\n result.issues.map((issue) => issue.message).join('; ') || 'rejected by the settings store'\n }`,\n ),\n { kind: 'rejected' as const, issues: result.issues },\n );\n }\n}\n\n/** `create()`'s success path, converted back to a `SavedViewDef`. Throws (via `throwIfMutationFailed`) on failure. */\nfunction resultToSavedViewDef(\n result: UiSettingMutationResult<SavedViewSettingValue>,\n resource: string,\n): SavedViewDef {\n throwIfMutationFailed(result, resource);\n if (result.status === 'created' || result.status === 'updated') {\n return {\n id: result.entry.id,\n label: result.entry.label ?? '',\n state: toSavedViewState(result.entry.value),\n };\n }\n // 'removed' is unreachable here in practice (no well-behaved adapter\n // returns it from create/update) — the shared `UiSettingMutationResult`\n // union just doesn't narrow per-method. Fail loudly rather than\n // fabricate a view out of nothing.\n throw new Error(\n `[useSavedViews] Unexpected mutation result status \"${result.status}\" while saving a view (resource=\"${resource}\").`,\n );\n}\n\n/**\n * One adapter-backed saved view, WITH the scope/permission/label metadata\n * new UI (Task 9) needs — unlike the plain `SavedViewDef` shape\n * `adopterViews` / `userViews` expose for old callers. Static\n * `def.views.list.savedViews` entries are intentionally NOT represented\n * here (they carry no scope or per-entry permissions — they're a single\n * read-only application source, not a settings-store entry).\n */\nexport interface SavedViewEntry {\n readonly id: string;\n readonly label: string;\n readonly state: SavedViewDef['state'];\n readonly scope: UiSettingScope;\n readonly permissions: UiSettingEntryPermissions;\n}\n\nexport interface UseSavedViewsResult {\n /**\n * Adopter-defined views from the resource config\n * (`def.views.list.savedViews`). Read-only, unaffected by this task's\n * migration — same source and shape as before.\n */\n adopterViews: SavedViewDef[];\n /**\n * The union of settings-store entries (adapter-backed) and any\n * still-pending legacy migration, with any entry whose id collides with\n * an `adopterViews` id FILTERED OUT (adopter config wins — see\n * `getViewById`) — preserved for pre-Task-8 callers exactly as before.\n * Does NOT itself contain `adopterViews`; those are a separate,\n * read-only source callers combine with this one when rendering.\n */\n userViews: SavedViewDef[];\n /**\n * The settings-store entries alone (no legacy merge, no collision\n * filter), WITH scope/permission metadata — for new UI (Task 9). Empty\n * while nothing has been saved/migrated yet.\n */\n entries: SavedViewEntry[];\n /**\n * Scopes the current user may create a NEW view in (spec §5), straight\n * from the store's `snapshot.writeScopes` — Task 9. Empty means saving is\n * unavailable; exactly one means the UI writes there without asking;\n * more than one means the UI must ask \"for whom?\" and pass the chosen\n * scope id into {@link saveCurrentAsView} / {@link forkUserView}.\n */\n writeScopes: readonly UiSettingScope[];\n /**\n * Adapter-reported issues for this collection (spec §13) — Task 9. An\n * issue never hides otherwise-valid entries; it is rendered alongside\n * them (e.g. \"some views could not be loaded\"), straight from the\n * store's `snapshot.issues`.\n */\n issues: readonly UiSettingsIssue[];\n /**\n * True until the underlying collection has produced its first settled\n * snapshot (spec §6) — Task 9. Entries already present (a synchronous\n * local adapter, or a remote adapter's cached local entries) remain\n * usable while this is true; it is not a \"hide the list\" signal.\n */\n pending: boolean;\n /**\n * Persist the current url-state snapshot as a new user view. Migrates\n * any still-pending legacy entries first (see the module doc). Resolves\n * with the persisted view (its store-assigned id).\n *\n * `scopeId` (Task 9) picks WHICH of `writeScopes` the view is created\n * in. Omit it to keep the original single-scope default: the framework's\n * own local scope when `isLocalScope`, otherwise `writeScopes[0]` — a\n * heuristic only ever appropriate when `writeScopes.length <= 1`. A\n * caller offering a real choice among several write scopes MUST pass the\n * user's selection explicitly; this hook never re-derives \"who\".\n *\n * Rejects with:\n * - `Error('[useSavedViews] label cannot be empty')` if\n * `label.trim().length === 0`.\n * - a `rejected`/`conflict`-tagged `Error` (see `throwIfMutationFailed`)\n * on a failed store mutation (quota exceeded, permission denied, no\n * writable scope, …).\n */\n saveCurrentAsView: (\n label: string,\n state: Partial<ResourceUrlState>,\n scopeId?: string,\n ) => Promise<SavedViewDef>;\n /**\n * Rename a user view by id. Adopter-view ids — and any id this hook\n * doesn't recognize — are silently ignored (a resolved no-op), matching\n * the pre-Task-8 behaviour.\n */\n renameUserView: (id: string, newLabel: string) => Promise<void>;\n /** Delete a user view by id. Adopter-view ids are silently ignored (a resolved no-op). */\n deleteUserView: (id: string) => Promise<void>;\n /**\n * Fork an existing entry into `scopeId` (spec §5: \"moving an entry\n * between scopes … is expressed as fork/copy into a writable scope\n * followed by an optional deletion when permitted\") — Task 9. Copies the\n * source entry's stored state (never the live URL state — that is\n * `saveCurrentAsView`'s job) into a brand-new, independent entry tagged\n * `forkedFrom: { entryId: id }`; the fork never receives later changes\n * from its origin. `label` defaults to the source entry's own label.\n *\n * Unlike rename/delete, an unknown `id` REJECTS rather than resolving as\n * a no-op: a fork with no source to copy from is always a caller\n * mistake, never a legitimate \"nothing to do here\" (static adopter\n * views, which have no per-entry permissions, are not forkable through\n * this method — the UI never offers Fork for them in the first place).\n */\n forkUserView: (id: string, scopeId: string, label?: string) => Promise<SavedViewDef>;\n /**\n * Resolve a view by id from either source. Adopter views win on a\n * collision (adopter config is the canonical source) — unchanged.\n */\n getViewById: (id: string) => SavedViewDef | null;\n}\n\n/**\n * Hook returning the union of adopter-defined views (from the resource\n * config) and user-saved views (from the universal UI settings store),\n * plus async mutators for the user-view set. See the module doc above for\n * the legacy-migration and async-mutation contracts.\n *\n * @example\n * const { adopterViews, userViews, saveCurrentAsView } = useSavedViews('document_document');\n */\nexport function useSavedViews(resource: string): UseSavedViewsResult {\n const app = useApp();\n\n // Adopter views from the registry — unchanged from before this task.\n const adopterViews = useMemo<SavedViewDef[]>(() => {\n const def = app.registry.get(resource);\n return (def?.views?.list?.savedViews ?? []) as SavedViewDef[];\n }, [app, resource]);\n\n const { snapshot, create, update, remove } = useUiSettings(savedViewSetting, { resource });\n\n // Whether the CURRENTLY resolved store is the framework's own default\n // local-storage adapter (Task 7) — the only scenario legacy migration\n // ever runs in. See the module doc's \"Legacy migration\" section for why\n // an adopter-supplied adapter is deliberately excluded. Stable across\n // renders for a given store: the default adapter publishes\n // `writeScopes: [LOCAL_USER_SCOPE]` synchronously from its very first\n // snapshot, so there is no mount-time flicker between the two branches.\n const isLocalScope = snapshot.writeScopes.some((s) => s.id === LOCAL_USER_SCOPE_ID);\n\n // Legacy `localStorage` reads. Hydrated in an effect (never during\n // render) for the same SSR-safety reason the pre-Task-8 hook used one:\n // `[]` on the server and on the first client render avoids a hydration\n // mismatch, and the real content arrives one tick later.\n //\n // `legacyRef` mirrors `legacyViews` synchronously so `migrateLegacyIfNeeded`\n // (below) always reads the CURRENT pending set even when called twice\n // back-to-back before a re-render lands.\n const [legacyViews, setLegacyViews] = useState<SavedViewDef[]>([]);\n const legacyRef = useRef<SavedViewDef[]>([]);\n // Single-flight guard for `migrateLegacyIfNeeded` — see its doc below.\n const migrationPromiseRef = useRef<Promise<Map<string, SavedViewEntry>> | null>(null);\n useEffect(() => {\n if (!isLocalScope) {\n legacyRef.current = [];\n setLegacyViews([]);\n return;\n }\n const initial = readLegacyUserViews(resource);\n legacyRef.current = initial;\n setLegacyViews(initial);\n }, [resource, isLocalScope]);\n\n // Settings-store entries, converted to the richer `SavedViewEntry` shape\n // (Step 3 — scope/permissions/label for new UI).\n const entries = useMemo<SavedViewEntry[]>(\n () =>\n snapshot.entries.map((entry) => ({\n id: entry.id,\n label: entry.label ?? '',\n state: toSavedViewState(entry.value),\n scope: entry.scope,\n permissions: entry.permissions,\n })),\n [snapshot.entries],\n );\n\n // `userViews` — store entries PLUS whatever legacy views haven't\n // migrated yet, minus the same adopter-id collision filter the\n // pre-Task-8 hook applied (adopter config is canonical; a colliding\n // user/legacy view is hidden with a one-time warning).\n const warnedIdsRef = useRef<Set<string>>(new Set());\n const userViews = useMemo<SavedViewDef[]>(() => {\n const combined: SavedViewDef[] = [\n ...entries.map((entry) => ({ id: entry.id, label: entry.label, state: entry.state })),\n ...legacyViews,\n ];\n if (combined.length === 0 || adopterViews.length === 0) return combined;\n const adopterIds = new Set(adopterViews.map((v) => v.id));\n const out: SavedViewDef[] = [];\n for (const v of combined) {\n if (adopterIds.has(v.id)) {\n if (!warnedIdsRef.current.has(v.id)) {\n warnedIdsRef.current.add(v.id);\n // eslint-disable-next-line no-console\n console.warn(\n `[useSavedViews] user view id \"${v.id}\" collides with an adopter-defined view; the user copy is hidden until the collision is resolved.`,\n );\n }\n continue;\n }\n out.push(v);\n }\n return out;\n }, [entries, legacyViews, adopterViews]);\n\n /**\n * The actual migration batch — one pass over `pending`, replaying every\n * view into the settings store via `create()` and shrinking (then\n * clearing) the legacy `localStorage` envelope as each one lands\n * successfully (module doc, point 3).\n *\n * `legacyRef`/`legacyViews` are committed INCREMENTALLY, right after\n * each successful `create()` — not just once at the end — so a\n * still-in-progress batch never leaves `userViews` showing a view\n * that's already landed in the store AND still sitting in the legacy\n * list (a transient double-count that a purely end-of-loop commit would\n * otherwise produce for however long the remaining entries take).\n *\n * ONLY ever called from `migrateLegacyIfNeeded`'s single-flight guard\n * below — never call this directly, or two concurrent callers can each\n * start their own pass over the SAME `pending` array and double-`create()`\n * every view.\n */\n async function runLegacyMigration(pending: SavedViewDef[]): Promise<Map<string, SavedViewEntry>> {\n const migrated = new Map<string, SavedViewEntry>();\n let remaining = pending;\n for (const view of pending) {\n const result = await create({\n scopeId: LOCAL_USER_SCOPE_ID,\n label: view.label,\n value: view.state as SavedViewSettingValue,\n });\n if (result.status !== 'created' && result.status !== 'updated') {\n // Stop here — leave this entry and everything after it in legacy\n // storage for a retry on the next mutation (data safety over\n // completeness; see the module doc, point 3).\n break;\n }\n migrated.set(view.id, {\n id: result.entry.id,\n label: result.entry.label ?? view.label,\n state: toSavedViewState(result.entry.value),\n scope: result.entry.scope,\n permissions: result.entry.permissions,\n });\n remaining = remaining.filter((v) => v !== view);\n writeLegacyUserViews(resource, remaining);\n legacyRef.current = remaining;\n setLegacyViews(remaining);\n }\n if (remaining.length === 0) {\n clearLegacyUserViews(resource);\n }\n return migrated;\n }\n\n /**\n * Single-flight guard around `runLegacyMigration`: ensures the pending\n * legacy set migrates AT MOST ONCE even when multiple mutations are\n * concurrently in-flight — e.g. two quick clicks on the manage dialog's\n * delete button, each independently calling `deleteUserView` before the\n * first click's own migration pass has resolved. Without this guard,\n * BOTH calls would read the SAME `legacyRef.current`, both loop\n * `create()` over the SAME pending views, and the store would assign a\n * fresh id to each — duplicate store entries (data duplication, not\n * loss, but still wrong).\n *\n * The FIRST caller to find legacy work starts `runLegacyMigration` and\n * publishes the in-flight promise via `migrationPromiseRef`; every\n * concurrent caller sees that ref already set and `await`s the SAME\n * promise instead of re-reading `legacyRef.current` and re-running the\n * loop. Both therefore resolve against the SAME `migratedFor` map, so\n * each can independently look up its OWN target id — two concurrent\n * deletes of two DIFFERENT pending legacy rows both succeed. The ref is\n * cleared once settled (guarded by identity, in case a brand-new\n * migration already replaced it by the time this one's `finally` runs).\n *\n * A no-op (empty map, no store call, no ref churn) when there is\n * nothing pending, or when the resolved store isn't the framework's own\n * default local scope — see the module doc.\n */\n async function migrateLegacyIfNeeded(): Promise<Map<string, SavedViewEntry>> {\n if (migrationPromiseRef.current !== null) {\n return migrationPromiseRef.current;\n }\n if (!isLocalScope) return new Map();\n const pending = legacyRef.current;\n if (pending.length === 0) return new Map();\n\n const promise = runLegacyMigration(pending);\n migrationPromiseRef.current = promise;\n try {\n return await promise;\n } finally {\n if (migrationPromiseRef.current === promise) {\n migrationPromiseRef.current = null;\n }\n }\n }\n\n async function saveCurrentAsView(\n label: string,\n state: Partial<ResourceUrlState>,\n scopeId?: string,\n ): Promise<SavedViewDef> {\n const trimmedLabel = label.trim();\n if (trimmedLabel.length === 0) {\n // Defensive belt-and-braces: the playground UI's Save button is\n // already disabled when the input is empty, but adopters wiring the\n // hook to a different surface deserve a clear failure mode.\n throw new Error('[useSavedViews] label cannot be empty');\n }\n await migrateLegacyIfNeeded();\n // Task 9: an explicit `scopeId` (the UI's own \"for whom?\" answer) always\n // wins. Only when the caller doesn't supply one do we fall back to the\n // original single-scope heuristic — correct exactly when there is at\n // most one writable scope to begin with.\n const targetScopeId =\n scopeId ?? (isLocalScope ? LOCAL_USER_SCOPE_ID : snapshot.writeScopes[0]?.id);\n if (targetScopeId === undefined) {\n throw new Error(\n `[useSavedViews] No writable scope is available to save a view for resource \"${resource}\".`,\n );\n }\n const result = await create({\n scopeId: targetScopeId,\n label: trimmedLabel,\n value: buildCleanState(state),\n });\n return resultToSavedViewDef(result, resource);\n }\n\n async function renameUserView(id: string, newLabel: string): Promise<void> {\n const migratedFor = await migrateLegacyIfNeeded();\n const current = migratedFor.get(id) ?? entries.find((entry) => entry.id === id);\n // Unknown id (never saved) or an adopter-view id: silently ignored —\n // the adopter config is canonical, matching the pre-Task-8 behaviour.\n if (current === undefined) return;\n const result = await update({\n id: current.id,\n label: newLabel,\n value: current.state as SavedViewSettingValue,\n });\n throwIfMutationFailed(result, resource);\n }\n\n async function deleteUserView(id: string): Promise<void> {\n const migratedFor = await migrateLegacyIfNeeded();\n const current = migratedFor.get(id) ?? entries.find((entry) => entry.id === id);\n if (current === undefined) return;\n const result = await remove({ id: current.id });\n throwIfMutationFailed(result, resource);\n }\n\n async function forkUserView(id: string, scopeId: string, label?: string): Promise<SavedViewDef> {\n const migratedFor = await migrateLegacyIfNeeded();\n const source = migratedFor.get(id) ?? entries.find((entry) => entry.id === id);\n if (source === undefined) {\n // Unlike rename/delete, there is no sensible \"nothing to do\" reading\n // of forking a view that doesn't exist — reject loudly instead of\n // silently resolving (see the field doc on `forkUserView`).\n throw new Error(\n `[useSavedViews] Cannot fork unknown view id \"${id}\" for resource \"${resource}\".`,\n );\n }\n const trimmedLabel = label?.trim();\n const result = await create({\n scopeId,\n label: trimmedLabel && trimmedLabel.length > 0 ? trimmedLabel : source.label,\n value: source.state as SavedViewSettingValue,\n forkedFrom: { entryId: source.id },\n });\n return resultToSavedViewDef(result, resource);\n }\n\n function getViewById(id: string): SavedViewDef | null {\n // Adopter wins on collision (canonical source of truth) — unchanged.\n const adopterHit = adopterViews.find((v) => v.id === id);\n if (adopterHit) return adopterHit;\n const userHit = userViews.find((v) => v.id === id);\n return userHit ?? null;\n }\n\n return {\n adopterViews,\n userViews,\n entries,\n writeScopes: snapshot.writeScopes,\n issues: snapshot.issues,\n pending: snapshot.pending,\n saveCurrentAsView,\n renameUserView,\n deleteUserView,\n forkUserView,\n getViewById,\n };\n}\n","import {\n EMPTY_FILTER_GROUP,\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n type SavedViewDef,\n} from '@burojs/core';\nimport type { ResourceUrlState } from '../url-state/codec.js';\n\n/**\n * Optional defaults supplied to `applyViewToUrlState`. When the view's\n * `state.<field>` is `undefined`, the corresponding setter receives the\n * default from this object instead — and if the default is also unset,\n * falls back to the framework-level defaults documented per setter\n * below.\n *\n * Use this when the call site has page-level defaults that differ from\n * the framework defaults — e.g. the playground uses `pageSize: 10`\n * while the framework default is also 10 (no override needed). An\n * adopter rendering a 25-row default would pass `{ pageSize: 25 }`.\n *\n * `page` is deliberately excluded from `defaults`: applying a view\n * always hardcodes page one (see `applyViewToUrlState`'s doc below), so\n * a `defaults.page` would silently be ignored rather than honored — the\n * type admits only the fields the implementation actually reads.\n */\nexport interface ApplyViewToUrlStateOptions {\n defaults?: Omit<Partial<ResourceUrlState>, 'page'>;\n}\n\n/**\n * Subset of the `useResourceUrlState` return value the helper needs.\n * Defined explicitly (not as `Pick<ReturnType<...>>`) so the helper\n * accepts both:\n * - the strongly-typed return of `useResourceUrlState()` (the playground\n * call site), AND\n * - lightweight test mocks built around `vi.fn()` shapes.\n *\n * Persisted views and URL state share the core portable AST, so this helper\n * passes the typed value through without an adapter cast.\n */\nexport interface ApplyViewUrlStateSetters {\n setFilters: (filters: readonly FilterExpression<ErasedResourceHandle>[]) => void;\n setFilterGroup: (group: FilterGroup) => void;\n setSort: (sort: ResourceUrlState['sort']) => void;\n setPage: (page: number) => void;\n setPageSize: (size: number) => void;\n setSearch: (q: string) => void;\n setVisibleColumns: (cols: string[] | null) => void;\n}\n\n/**\n * Apply a `SavedViewDef` to a `useResourceUrlState` return — REPLACE\n * pattern. Each setter is called once per tick (the hook's\n * `pendingQsRef` batches them into a single router call), so the URL\n * ends in a deterministic state matching the view's declared `state`\n * exactly. Missing fields fall back to `options.defaults`, then to the\n * framework defaults:\n *\n * **Browser history (A5).** The same-tick push wins: because\n * `setFilters`, `setFilterGroup`, `setSort`, and `setVisibleColumns` all\n * default to push, applying a view always produces ONE new history entry\n * covering the combined patch. The user can `back` once to return to\n * whatever filter/sort/columns they had before applying the view.\n *\n * - filters → []\n * - filterGroup → EMPTY_FILTER_GROUP\n * - sort → []\n * - page → 1 (ALWAYS — see below, not defaulted from the view)\n * - pageSize → 10\n * - search → ''\n * - visibleColumns → null\n *\n * **Page is not part of a saved view (spec §12).** `SavedViewDef.state`\n * has no `page` field — a view describes list *configuration*, not a\n * position within one particular query's results. Applying ANY view\n * therefore always resets to page one, unconditionally; there is no\n * `defaults.page` override for this setter (unlike every other field).\n *\n * Use this in the page's `onApply` handler:\n *\n * ```tsx\n * const urlState = useResourceUrlState(resource, { ... });\n * const applyView = useCallback((view: SavedViewDef) => {\n * applyViewToUrlState(view, urlState);\n * }, [urlState]);\n * ```\n *\n * The helper is intentionally pure — it owns no state and surfaces no\n * effects beyond the seven setter calls (filters, filterGroup, sort, page,\n * pageSize, search, visibleColumns). That keeps it trivially unit-testable\n * with a mock urlState.\n */\nexport function applyViewToUrlState(\n view: SavedViewDef,\n urlState: ApplyViewUrlStateSetters,\n options?: ApplyViewToUrlStateOptions,\n): void {\n const d = options?.defaults ?? {};\n urlState.setFilters(view.state.filters ?? d.filters ?? []);\n // Legacy views (saved before the builder shipped) carry no group; REPLACE\n // semantics mean an absent field clears, not preserves.\n urlState.setFilterGroup(view.state.filterGroup ?? d.filterGroup ?? EMPTY_FILTER_GROUP);\n urlState.setSort(view.state.sort ?? d.sort ?? []);\n // Unconditional — see the module doc's \"Page is not part of a saved\n // view\" note. No `view.state.page` to read (the field is gone from\n // `SavedViewDef.state`) and no `d.page` fallback either.\n urlState.setPage(1);\n urlState.setPageSize(view.state.pageSize ?? d.pageSize ?? 10);\n urlState.setSearch(view.state.search ?? d.search ?? '');\n // visibleColumns: `null` is a meaningful value (= \"use defaults\"),\n // so we only fall back when the view literally omits the key.\n // `view.state.visibleColumns ?? d.visibleColumns ?? null` works\n // because `null ?? X` returns X — i.e. an explicit null in the view\n // would fall through to `d.visibleColumns` and then `null`. That's\n // the desired behaviour (null === defaults at both layers).\n //\n // History note: the urlState hook resolves the same-tick history\n // mode to `push` because at least one of the called setters\n // (setFilters / setSort / setVisibleColumns) defaults to push. The\n // helper does NOT pass an explicit `{ historyMode }` because the\n // implicit \"push wins\" resolution is exactly the desired UX.\n urlState.setVisibleColumns(view.state.visibleColumns ?? d.visibleColumns ?? null);\n}\n","'use client';\nimport { useCallback, useEffect, useState } from 'react';\n\n/**\n * Return shape of `useCommandPalette()`.\n *\n * - `open` — current open state (controlled by the hook).\n * - `setOpen` — set the open state directly (e.g. to close on item select).\n * - `toggle` — flip the open state. Used by the ⌘/Ctrl+K shortcut.\n */\nexport interface UseCommandPaletteResult {\n open: boolean;\n setOpen: (next: boolean) => void;\n toggle: () => void;\n}\n\n/**\n * Options for `useCommandPalette()`.\n */\nexport interface UseCommandPaletteOptions {\n /**\n * Disable the global ⌘K / Ctrl+K shortcut. Default `false` (enabled).\n * When true the hook returns the same `{ open, setOpen, toggle }` API\n * but no global keyboard listener is attached — callers can drive the\n * palette open/close from their own UI affordances.\n */\n disableShortcut?: boolean;\n}\n\n/**\n * State + keyboard wiring for the command palette.\n *\n * Returns `{ open, setOpen, toggle }`. By default attaches a window-level\n * `keydown` listener that toggles the palette on ⌘K (mac) / Ctrl+K\n * (others) and cleans up on unmount.\n *\n * Why ⌘K is safe inside inputs:\n *\n * The spec calls for \"Skip when input/textarea focused UNLESS modifier\n * held.\" Since ⌘/Ctrl+K REQUIRES a modifier, the rule is satisfied\n * by construction: the shortcut always fires, regardless of focus.\n * Any future bare-key shortcut (e.g. `/` to focus the palette input)\n * would need an explicit input-focus skip — but the v0.2 design is\n * modifier-only.\n *\n * Esc-to-close is handled by the underlying `<CommandDialog>` (Radix\n * Dialog calls `onOpenChange(false)` on Esc), so we don't need to\n * intercept Esc here. This keeps cmdk's own Esc handling intact for\n * cases where the palette has a typeahead that should clear on Esc.\n *\n * Multiple instances:\n *\n * Each `useCommandPalette()` call has its own `open` state and (unless\n * `disableShortcut: true`) its own keydown listener. Mounting two of\n * them simultaneously means ⌘K toggles BOTH — which is almost never\n * what you want. For v0.2 the recommendation is one palette per app\n * shell. Adopters that need a secondary palette (e.g. a context-scoped\n * sub-palette) should pass `disableShortcut: true` and wire opening\n * from their own UI.\n *\n * SSR:\n *\n * The keydown listener is attached inside `useEffect`, so `window` is\n * never touched during render. Safe in any RSC/SSR context.\n */\nexport function useCommandPalette(opts?: UseCommandPaletteOptions): UseCommandPaletteResult {\n const [open, setOpen] = useState(false);\n const toggle = useCallback(() => setOpen((o) => !o), []);\n const disableShortcut = opts?.disableShortcut ?? false;\n\n useEffect(() => {\n if (disableShortcut) return;\n const handler = (e: KeyboardEvent) => {\n // ⌘K (mac) or Ctrl+K (everywhere else). Modifier is required, so\n // this never fires from a bare keypress inside an input/textarea.\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n e.preventDefault();\n toggle();\n }\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [toggle, disableShortcut]);\n\n return { open, setOpen, toggle };\n}\n","'use client';\nimport { useEffect } from 'react';\n\n/**\n * Storage shape for one entry in the \"recently visited\" list.\n *\n * - `resource` — registry name of the resource (e.g. `document_document`).\n * - `id` — record id, always coerced to string for stable storage shape\n * even when adopters use numeric ids.\n * - `label` — human-readable display label resolved at write time\n * (alias → name → title → label → fallback to id). Captured at write\n * so the Recent group survives even if the record is later deleted\n * server-side; the navigation will 404 but the entry still renders\n * and identifies which record it referenced.\n * - `visitedAt` — ISO timestamp of the most-recent visit. Updated on\n * each call to `useTrackRecentRecord`.\n */\nexport interface RecentRecord {\n resource: string;\n id: string;\n label: string;\n visitedAt: string; // ISOString\n}\n\n/**\n * Persisted envelope. Mirrors the saved-views envelope (A4 pattern) so\n * future schema changes can bump `version` without crashing older tabs.\n *\n * Reads accept three shapes (see `parseRecentEnvelope`):\n * 1. Current v1 envelope `{ version: 1, items: RecentRecord[] }`.\n * 2. Legacy / defensive bare-array form (migrated on next write).\n * 3. Anything else / parse failure → treated as empty list.\n */\nexport interface RecentEnvelope {\n version: 1;\n items: RecentRecord[];\n}\n\n/**\n * Default cap for the Recent list. Keeps localStorage payload small —\n * 5 × ~200 bytes per entry ≈ 1 KB, well under any quota concern.\n */\nconst DEFAULT_LIMIT = 5;\n\nconst STORAGE_PREFIX = 'buro:recent:';\nconst SINGLETON_KEY = 'singleton';\n\n/**\n * Resolve the localStorage key for a given user. Multi-user installs\n * scope the list per-user so logging out + back in as a different user\n * doesn't leak the previous user's history. Single-user / unauthenticated\n * adopters pass `undefined` and share a singleton bucket.\n */\nfunction storageKeyFor(userId: string | undefined | null): string {\n return `${STORAGE_PREFIX}${userId == null || userId === '' ? SINGLETON_KEY : userId}`;\n}\n\nfunction isValidRecent(x: unknown): x is RecentRecord {\n if (typeof x !== 'object' || x === null) return false;\n const r = x as Record<string, unknown>;\n return (\n typeof r.resource === 'string' &&\n typeof r.id === 'string' &&\n typeof r.label === 'string' &&\n typeof r.visitedAt === 'string'\n );\n}\n\n/**\n * Defensive parse: accept the current envelope, accept a bare legacy\n * array, drop anything else (forward-compat for `version > 1`,\n * malformed JSON, wrong top-level shape) so a stale write never bricks\n * the palette.\n */\nfunction parseRecentEnvelope(raw: string | null): RecentEnvelope {\n if (raw == null) return { version: 1, items: [] };\n try {\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n // Legacy bare-array migration — wrap on next write.\n return { version: 1, items: parsed.filter(isValidRecent) };\n }\n if (typeof parsed === 'object' && parsed !== null) {\n const env = parsed as Record<string, unknown>;\n if (env.version === 1 && Array.isArray(env.items)) {\n return { version: 1, items: (env.items as unknown[]).filter(isValidRecent) };\n }\n }\n return { version: 1, items: [] };\n } catch {\n return { version: 1, items: [] };\n }\n}\n\n/**\n * Insert / move-to-front the given entry. Dedup by `(resource, id)`:\n * revisiting the same record updates its `visitedAt` instead of creating\n * a duplicate. FIFO eviction at `limit` — oldest entries fall off the\n * tail.\n */\nfunction upsertRecent(items: RecentRecord[], next: RecentRecord, limit: number): RecentRecord[] {\n const filtered = items.filter((it) => !(it.resource === next.resource && it.id === next.id));\n return [next, ...filtered].slice(0, limit);\n}\n\nfunction stringOrUndefined(x: unknown): string | undefined {\n return typeof x === 'string' && x.length > 0 ? x : undefined;\n}\n\n/**\n * Resolve a human-readable label for a record. Falls back through the\n * conventional display field names adopters tend to use, ending with\n * the stringified id when nothing else is set. The label is captured\n * at write-time so the Recent entry survives later deletions.\n */\nfunction resolveLabel(record: { id?: unknown; [key: string]: unknown }): string {\n return (\n stringOrUndefined(record.alias) ??\n stringOrUndefined(record.name) ??\n stringOrUndefined(record.title) ??\n stringOrUndefined(record.label) ??\n String(record.id ?? '')\n );\n}\n\n/**\n * Options for `useTrackRecentRecord`.\n */\nexport interface UseTrackRecentRecordOptions {\n /**\n * Maximum entries to keep. Default 5 (matches v0.2 spec C3.3). Older\n * entries fall off the tail when a new one is upserted.\n */\n limit?: number;\n /**\n * Caller-supplied user id used as the localStorage key suffix. Multi-\n * user installs pass `auth.user?.id`; single-user / unauthenticated\n * adopters omit and share a `'singleton'` bucket.\n *\n * The framework's core `App` does not yet expose a built-in user\n * slot (per the `AppContext` open interface — adopters declare their\n * own `user` slice), so this is plumbed as an explicit option rather\n * than read from `useApp()`. See `useApp` / `AppContext` for the\n * declaration-merging extension point.\n */\n userId?: string | null;\n isCurrentData?: boolean;\n}\n\n/**\n * Records a \"recently visited\" entry for the given `(resource, record)`\n * pair into `localStorage`.\n *\n * Storage contract:\n * `localStorage[\"buro:recent:<userId|singleton>\"]` →\n * `JSON.stringify({ version: 1, items: RecentRecord[] })`\n *\n * Behaviour:\n *\n * - Fires on mount and re-fires whenever `record.id` changes — a\n * single component instance navigating between two records still\n * produces two entries.\n * - Dedupes by `(resource, id)`: revisiting the same record bumps its\n * `visitedAt` and moves it to the front instead of creating a\n * duplicate.\n * - FIFO-evicts the oldest entry when the list exceeds `limit`\n * (default 5).\n * - Waits for a real record before writing — calling with\n * `record === undefined | null` (typical loading state) is a no-op.\n * - SSR-safe: a missing `window` short-circuits before any storage\n * call, so the hook is safe to import from server components.\n * - Storage write errors (quota / private mode) are swallowed silently;\n * the palette continues to function with whatever the last successful\n * write left behind.\n *\n * Companion reader: `getRecentRecords(userId)` is the synchronous\n * equivalent for the palette's Recent group — the palette re-reads on\n * every render (cheap; a localStorage read is sub-microsecond).\n *\n * Example:\n * ```tsx\n * function DocumentShowPage({ params }: { params: { id: string } }) {\n * const { record } = useFetchRecord('document_document', params.id);\n * useTrackRecentRecord('document_document', record);\n * return <ResourceShow record={record} />;\n * }\n * ```\n */\nexport function useTrackRecentRecord(\n resource: string,\n record: { id?: unknown; [key: string]: unknown } | null | undefined,\n opts?: UseTrackRecentRecordOptions,\n): void {\n const limit = opts?.limit ?? DEFAULT_LIMIT;\n const userId = opts?.userId;\n const isCurrentData = opts?.isCurrentData ?? true;\n // Pull a few primitive deps out of the record so the effect's deps\n // stay stable (passing `record` directly would re-run on every render\n // because each fetch returns a new object identity).\n const recordId = record?.id;\n // Reject ids that aren't string-coercible to something stable. Anything\n // outside `string | number` (objects, arrays, booleans, etc.) is\n // treated as \"no id\" — the hook is a no-op rather than persisting\n // garbage. Numeric ids are stringified before storage so the on-disk\n // shape stays uniform.\n const recordIdValid = typeof recordId === 'string' || typeof recordId === 'number';\n // Capture the label at the same render the effect sees so re-runs\n // pick up renamed records too.\n const label = record && recordIdValid ? resolveLabel(record) : undefined;\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n if (!isCurrentData || !record) return;\n if (!recordIdValid) return;\n if (recordId === '' || recordId === null || recordId === undefined) return;\n if (label === undefined || label === '') return;\n\n const key = storageKeyFor(userId ?? null);\n try {\n const envelope = parseRecentEnvelope(window.localStorage.getItem(key));\n const next = upsertRecent(\n envelope.items,\n {\n resource,\n id: String(recordId),\n label,\n visitedAt: new Date().toISOString(),\n },\n limit,\n );\n window.localStorage.setItem(\n key,\n JSON.stringify({ version: 1, items: next } satisfies RecentEnvelope),\n );\n } catch {\n // localStorage may be unavailable (private mode, quota, disabled).\n // Silently drop — the rest of the UI keeps working.\n }\n // Intentionally dep on the primitives, not `record`, so a re-fetch\n // with identical values doesn't re-write.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resource, recordId, recordIdValid, label, userId, limit, isCurrentData]);\n}\n\n/**\n * Synchronous read of the Recent list for the given user. Safe to call\n * during render; SSR-safe (returns `[]` when `window` is undefined).\n *\n * Typical use: the palette's Recent group calls this on every render\n * to populate its rows. localStorage reads are sub-microsecond so the\n * cost is negligible; we don't subscribe to storage events.\n */\nexport function getRecentRecords(userId: string | null | undefined): RecentRecord[] {\n if (typeof window === 'undefined') return [];\n try {\n const raw = window.localStorage.getItem(storageKeyFor(userId ?? null));\n return parseRecentEnvelope(raw).items;\n } catch {\n return [];\n }\n}\n\n/**\n * Clear the Recent list for the given user. Used by adopters that want\n * to wire a \"Clear recent\" affordance (out of scope for v0.2 but cheap\n * to expose). Returns `true` when the key was removed (or already\n * absent), `false` when localStorage threw.\n */\nexport function clearRecentRecords(userId: string | null | undefined): boolean {\n if (typeof window === 'undefined') return false;\n try {\n window.localStorage.removeItem(storageKeyFor(userId ?? null));\n return true;\n } catch {\n return false;\n }\n}\n","'use client';\nimport {\n type Action,\n type ActionDI,\n type ActionDataAccess,\n type ItemActionPlacement,\n type ResourceHandle,\n type RuleContext,\n normalizeEntityRef,\n planItemActions,\n} from '@burojs/core';\nimport { useMemo } from 'react';\nimport { useApp } from './use-app.js';\nimport { useAvailabilityResolver } from './use-availability.js';\n\n/**\n * One item action, resolved for a single record on a single surface.\n *\n * Inherits `placement` (`'standalone'` | `'menu'`) and `density`\n * (`'compact'` | `'regular'` | `null`, null exactly when `placement ===\n * 'menu'`) from `ItemActionPlacement` — the render surface renders its own\n * control for `'standalone'` entries and collects `'menu'` entries into an\n * overflow menu; `density` tells a `'standalone'` control whether to show\n * just its icon or the icon plus label.\n */\nexport interface ResolvedItemAction extends ItemActionPlacement {\n variant: 'default' | 'destructive';\n disabled: boolean;\n disabledReason?: string;\n}\n\n/**\n * `data` stub for the render-time DIs used to evaluate synchronous action\n * predicates (visible / enabled / confirm message / link.to / modal.props).\n *\n * Those predicates run during render and must NOT reach the backend — the real\n * backend-capable `data` is injected at dispatch time by the mounted native\n * runtime. Calling any method here throws loudly so the misuse surfaces\n * instead of silently hitting `undefined`.\n *\n * MOVED here from `@burojs/ui-shadcn`'s `actions/render-di.ts` (Task 6): this\n * hook needs the identical stub to build the identical `ActionDI` shape\n * `<ActionButton>` builds — see `buildDI` below. `render-di.ts` now re-exports\n * this so its existing importers (`action-button.tsx`, `bulk-action-toolbar.tsx`)\n * keep compiling unchanged.\n */\nfunction unavailableActionData(): never {\n throw new Error(\n 'buro: action `data` is not available in render-time predicates (visible/enabled/confirm/link/modal); it is only injected at dispatch time',\n );\n}\n\nexport const RENDER_TIME_DATA: ActionDataAccess = {\n one: unavailableActionData,\n list: unavailableActionData,\n many: unavailableActionData,\n createOne: unavailableActionData,\n updateOne: unavailableActionData,\n deleteOne: unavailableActionData,\n query: unavailableActionData,\n mutate: unavailableActionData,\n};\n\n/**\n * Build a minimal ActionDI for evaluating action callbacks (link.to, modal.props,\n * confirm message, `visible`, etc.). Mirrors `useAction` but without dispatcher\n * coupling — link/modal kinds never hit the dispatcher.\n *\n * MOVED here from `@burojs/ui-shadcn`'s `action-button.tsx` (Task 6), which\n * defined this identically as a package-private function. `useItemActions` and\n * `<ActionButton>` must evaluate `visible` off the SAME DI shape: if they built\n * two slightly different ones, a rule or predicate reading e.g. `di.ctx` could\n * answer differently between them, and this hook's list would disagree with\n * what the button actually renders for each entry — an item that appears in\n * the menu and then vanishes. `action-button.tsx` now imports this instead of\n * keeping its own copy.\n *\n * `t` defaults to the identity stub (`(key) => key`) so every EXISTING caller\n * — `visible` predicates here and in `<ActionButton>` — keeps evaluating off\n * the same render-time shape it always has. A caller evaluating a message\n * meant to reach the SCREEN (a `confirm` predicate, in particular) must pass a\n * real translator explicitly: the framework's built-in `delete` declares\n * `confirm: (di) => di.t('confirm.delete')`, and the stub used to make that\n * render the literal string `\"confirm.delete\"` instead of translated text.\n */\nexport function buildDI<TRecord>(\n resource: ResourceHandle,\n record: TRecord,\n t?: (key: string, params?: Record<string, unknown>, defaultValue?: string) => string,\n): ActionDI<TRecord> {\n return {\n resource,\n record,\n values: {} as Partial<TRecord>,\n ctx: {} as never,\n t: t ?? ((k) => k),\n get: () => undefined,\n // Render-time predicate DI: backend access is dispatch-time only.\n data: RENDER_TIME_DATA,\n };\n}\n\n/**\n * Rule-engine mode for a render surface. Container and children MUST agree:\n * when they did not, a menu rendered and its only item then vanished, because\n * a rule branching on `ctx.mode` answered the two differently.\n *\n * MOVED here from `@burojs/ui-shadcn`'s `actions/action-surface.ts` (Task 6),\n * which now re-exports this so its existing importers keep working. Widened\n * from that file's closed `ActionSurface` union to a plain `string`: surfaces\n * are an open vocabulary (`ActionSurfaces` is declaration-merged, not a fixed\n * union), and this hook's callers pass whatever surface name their own panel\n * is.\n */\nexport function modeForSurface(surface: string): RuleContext['mode'] {\n return surface === 'show' || surface === 'edit' ? surface : 'list';\n}\n\n/**\n * The single resolved list of item actions for one record on one surface.\n *\n * Hidden and denied actions are ABSENT; denied-but-shown actions arrive with\n * `disabled: true` and a reason. Order and pinning are already applied. What\n * this hook deliberately does NOT do is dispatch: label resolution, icons, the\n * confirm/checks gate and per-kind execution stay in `<ActionButton>`, which\n * every surface still uses to render one entry. A second implementation of\n * that machinery here would fork the i18n precedence rules and the checks gate.\n */\nexport function useItemActions(args: {\n resource: string;\n record: { id: string } & Record<string, unknown>;\n surface: string;\n}): readonly ResolvedItemAction[] {\n const { resource, record, surface } = args;\n const app = useApp();\n const def = app.registry.get(resource);\n const gate = useAvailabilityResolver(resource, modeForSurface(surface));\n const items = (def?.actions?.item ?? []) as Action<unknown>[];\n const resourceHandle = useMemo<ResourceHandle>(\n () => ({ kind: 'resource', ref: normalizeEntityRef(resource) }),\n [resource],\n );\n\n return useMemo(() => {\n const byName = new Map(items.map((action) => [action.name, action]));\n const out: ResolvedItemAction[] = [];\n for (const placement of planItemActions(items, surface)) {\n const action = byName.get(placement.name);\n if (!action) continue;\n const availability = gate(placement.name, record);\n if (availability.state === 'absent' || availability.state === 'hidden') continue;\n if (!isVisible(action, resourceHandle, record)) continue;\n out.push({\n ...placement,\n variant: action.variant === 'destructive' ? 'destructive' : 'default',\n disabled: availability.state === 'disabled',\n ...(availability.state === 'disabled' && availability.reason\n ? { disabledReason: availability.reason }\n : {}),\n });\n }\n return out;\n }, [items, surface, gate, record, resourceHandle]);\n}\n\n/**\n * The adopter's own secondary filter, on top of the rule engine.\n *\n * A THROWING predicate HIDES the action (fail closed) — same direction as\n * `evaluateVisible` in core and `<ActionButton>`. A predicate that crashed has\n * told us nothing, and showing a gated control on no information is the worse\n * failure.\n */\nfunction isVisible(\n action: Action<unknown>,\n resource: ResourceHandle,\n record: Record<string, unknown>,\n): boolean {\n const predicate = action.visible;\n if (predicate === false) return false;\n if (typeof predicate !== 'function') return true;\n try {\n return (predicate as (di: ActionDI<unknown>) => boolean)(buildDI(resource, record));\n } catch {\n return false;\n }\n}\n","import { isRelationField, resourceKey } from '@burojs/core';\nimport type {\n EnumDef,\n ErasedResourceHandle,\n FilterFieldKindHint,\n FilterPredicateOp,\n ResourceDef,\n Registry,\n SortExpression,\n} from '@burojs/core';\nimport type { FilterKind } from './types.js';\n\n/**\n * Pure helpers lifted out of the demo app's list controller so\n * `@burojs/react`'s future `useResourceList` (Task B1.3b) and the app\n * can share one implementation instead of two. Moved VERBATIM — only the\n * imports/type-origins changed (see each function's note). No behaviour\n * changed.\n *\n * `kindToValueKind` (`_list-body.tsx:238`) deliberately did NOT move here:\n * it fed the old operator-picker chip's value-input type. That chip\n * mechanism (and `kindToValueKind` itself) is gone — SP2 Task 8 deleted it\n * in favor of the filter-builder region's `FilterValueControl`\n * (`@burojs/ui-shadcn`'s `list-kit/filter-builder/values/`), which derives\n * its own value-input type straight from `FilterKind` below.\n *\n * See `docs/superpowers/plans/2026-07-26-cfb1-list-controller.md`,\n * Task B1.3a.\n */\n\n/**\n * Categorisation of a column's field def into the kind of filter value\n * control it needs. This drives both `filters.available` (what the\n * filter-builder panel's field picker offers) and `FilterValueControl`'s\n * per-kind render dispatch (`@burojs/ui-shadcn`).\n *\n * The categorisation is \"best-effort\" — fields that don't match any\n * supported kind are excluded from `filters.available` entirely.\n *\n * Moved verbatim from `_list-body.tsx:153-196`. The only change is the\n * `registry` parameter's type: the original derived it as\n * `ReturnType<typeof useApp>['registry']` (a hook-shaped type, awkward to\n * import into a non-hook helper); this imports `Registry` directly from\n * `@burojs/core`, which is the exact same type `useApp()['registry']`\n * resolves to.\n */\nfunction readEnumValues(\n source: { kind?: string; type?: string; values?: unknown; ui?: { values?: unknown } } | undefined,\n): readonly string[] | null {\n if (source?.kind !== 'enum' && source?.type !== 'enum') return null;\n const raw = Array.isArray(source.values) ? source.values : source.ui?.values;\n if (!Array.isArray(raw) || raw.length === 0) return null;\n return raw.every((entry) => typeof entry === 'string') ? (raw as readonly string[]) : null;\n}\n\nexport function categorizeField(\n fieldDef: unknown,\n registry: Pick<Registry, 'get'> & { enums: { get(name: string): EnumDef | undefined } },\n): FilterKind | null {\n const source = fieldDef as\n | {\n declaration?: unknown;\n type?: string;\n format?: string;\n kind?: string;\n values?: unknown;\n opts?: { enum?: string; to?: string };\n ui?: { enum?: string; values?: unknown };\n meta?: { to?: unknown; enum?: string };\n }\n | undefined;\n if (!source) return null;\n const declaration = source.declaration as\n | { type?: string; format?: string; meta?: { to?: unknown; enum?: string } }\n | undefined;\n // Canonical declarations are either the field itself (modern builders) or\n // the explicit compatibility projection. Read semantic properties only\n // from that projection; legacy members are fallback for fields not lowered\n // yet.\n const canonical =\n declaration?.type !== undefined ? declaration : source.type !== undefined ? source : undefined;\n const type = canonical?.type;\n const format = canonical?.format;\n const meta = canonical?.meta;\n const legacyKind = canonical === undefined ? source.kind : undefined;\n\n // Relation first — wins over its underlying string/number storage\n // because the picker provides a much better UX than typing an FK id.\n if (isRelationField({ type, format, kind: legacyKind })) {\n const target = canonical === undefined ? (source.meta?.to ?? source.opts?.to) : meta?.to;\n let to: string | undefined;\n try {\n to =\n target === undefined ? undefined : resourceKey(target as Parameters<typeof resourceKey>[0]);\n } catch {\n to = undefined;\n }\n if (to && registry.get(to)) return { kind: 'relation', to };\n return null; // unregistered target — exclude from the menu\n }\n // Enum-bound string column.\n const enumName = canonical === undefined ? (source.opts?.enum ?? source.ui?.enum) : meta?.enum;\n if (enumName) {\n if (registry.enums.get(enumName)) return { kind: 'enum', enumName };\n return null; // unregistered enum — exclude\n }\n const inlineValues = readEnumValues(source);\n if (inlineValues) return { kind: 'enum-values', values: inlineValues };\n // `time` is carried, not discarded: a date-time field needs a\n // `datetime-local` control and range-first operators, and by the time\n // `FilterValueControl` dispatches there is nothing left to recover it\n // from. Emitted only when true so a plain date still deep-equals the\n // bare `{kind: 'date'}` this returned before.\n if (format === 'date-time' || legacyKind === 'dateTime') {\n return { kind: 'date', time: true };\n }\n if (format === 'date' || legacyKind === 'date') {\n return { kind: 'date' };\n }\n switch (type ?? legacyKind) {\n case 'string':\n case 'text':\n case 'email':\n case 'url':\n case 'uuid':\n return { kind: 'string' };\n case 'number':\n return { kind: 'number' };\n case 'boolean':\n return { kind: 'boolean' };\n }\n\n return null;\n}\n\n/**\n * The operators the builder offers for a field kind. First entry is the\n * default a freshly added row starts on.\n *\n * Vocabulary is the portable AST's (`FILTER_PREDICATE_OPS`), NOT the\n * narrower `FilterOperator`: builder rows are AST predicates, and `groupToExpression`\n * recognises only `isNull`/`isNotNull` as valueless.\n *\n * `isNull`/`isNotNull` are offered on every kind — \"has no value\" is a\n * question worth asking about any column, and the pair renders no value\n * control at all.\n *\n * An adopter narrows or widens this per field through\n * `views.list.filters.fields: [{ field, operators }]`; this is a default,\n * not a ceiling.\n */\nexport function operatorsForKind(kind: FilterKind): FilterPredicateOp[] {\n const nullish: FilterPredicateOp[] = ['isNull', 'isNotNull'];\n switch (kind.kind) {\n case 'enum':\n case 'enum-values':\n case 'relation':\n return ['in', 'notIn', 'eq', 'neq', ...nullish];\n case 'boolean':\n return ['eq', ...nullish];\n case 'string':\n return ['contains', 'eq', 'neq', 'startsWith', 'endsWith', ...nullish];\n case 'number':\n return ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', ...nullish];\n case 'date':\n // Same set either way; the ORDER is the point, because a freshly\n // added builder row starts on `operators[0]`. On a date-TIME field an\n // `eq` matches one exact instant — seconds and milliseconds included —\n // so it can essentially never be satisfied by a minute picked out of a\n // `datetime-local` box, and defaulting a new row to it hands the user\n // an empty list and no clue why. Range operators lead there; a plain\n // calendar date keeps `eq` first, where it means what it says.\n return kind.time\n ? ['gte', 'lte', 'gt', 'lt', 'eq', 'neq', ...nullish]\n : ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', ...nullish];\n }\n}\n\n/**\n * Converts an adopter-declared {@link FilterFieldKindHint} into the\n * `FilterKind` every filter surface in this package dispatches on.\n *\n * The two types are deliberately separate: the hint is a DECLARATION and\n * lives in `@burojs/core` beside `FilterFieldRef`; `FilterKind` is what the\n * value control switches over and lives here. This is the one place they\n * meet, so a hint can never reach a control without passing through it.\n *\n * The object arm tests the VALUE of `enum`, not `'enum' in hint`. The two\n * members carry `never` markers for each other's key\n * (see `FilterFieldKindHint`), which makes `enum` a declared-but-optional\n * property on the relation member too — so `in` does not narrow, and the\n * read comes back `string | undefined`. Testing the value narrows properly\n * and needs no cast.\n */\nexport function filterKindFromHint(hint: FilterFieldKindHint): FilterKind {\n if (typeof hint !== 'string') {\n if (typeof hint.enum === 'string') return { kind: 'enum', enumName: hint.enum };\n return { kind: 'relation', to: hint.relation };\n }\n switch (hint) {\n case 'dateTime':\n return { kind: 'date', time: true };\n case 'date':\n return { kind: 'date' };\n case 'number':\n return { kind: 'number' };\n case 'boolean':\n return { kind: 'boolean' };\n default:\n return { kind: 'string' };\n }\n}\n\n/**\n * Compute the unique union of two string arrays preserving the order of\n * the first array (extras from the second array are appended in their\n * declared order). Used by `ColumnsToggle` and by `ResourceListBody` to\n * derive `allAvailable` and the effective visible column set.\n *\n * Moved verbatim from `_list-body.tsx:542-553`. No type dependencies, so\n * nothing to adapt beyond the export.\n */\nexport function unionPreservingOrder(a: string[], b: string[] | undefined): string[] {\n if (!b || b.length === 0) return a.slice();\n const seen = new Set(a);\n const out = a.slice();\n for (const x of b) {\n if (!seen.has(x)) {\n out.push(x);\n seen.add(x);\n }\n }\n return out;\n}\n\n/** Adds a stable unique ordering field without altering a declared primary order. */\nexport function withSortTiebreaker(\n sort: SortExpression<ErasedResourceHandle>,\n def: ResourceDef | undefined,\n): SortExpression<ErasedResourceHandle> {\n if (sort.length === 0) return sort;\n const declared = def?.views?.list?.sortTiebreaker;\n if (declared === false) return sort;\n const field = declared ?? (def?.fields?.id ? 'id' : undefined);\n if (!field || sort.some((entry) => entry.field === field)) return sort;\n return [...sort, { field, direction: 'desc' }];\n}\n","import {\n type AppContext,\n type FilterFieldRef,\n type FixedFilterInput,\n type ResolvedFixedFilter,\n type ResourceDef,\n lockedFilterFields,\n normalizeFixedFilters,\n resolveFieldLabel,\n} from '@burojs/core';\nimport { useCallback, useMemo } from 'react';\nimport { useApp } from '../use-app.js';\nimport { useCapabilityResolver } from '../use-capability.js';\nimport { usePermissions, useScopeCtx } from '../use-permissions.js';\nimport { useI18nCaps } from '../use-t.js';\nimport { categorizeField, filterKindFromHint, operatorsForKind } from './helpers.js';\nimport type { FilterFieldSpec } from './types.js';\n\n/**\n * Second argument to {@link useFilterFields}.\n */\nexport interface UseFilterFieldsOptions {\n /** Call-site narrowing. Its fields are hidden from the offered list unless `{lock: false}`. */\n readonly fixedFilters?: readonly FixedFilterInput[];\n /**\n * Gates the `available`/`pinnedFields` derivation — the walk that runs\n * `categorizeField` (plus `operatorsForKind`, label resolution) over every\n * candidate field of the resource. Defaults to `true`. A caller whose\n * consuming UI isn't visible yet (e.g. the relation picker's dialog before\n * it's opened, via `useDialogFilterState`) should pass `false` to skip\n * that work on every mount / `fixedFilters`-identity change; it resolves\n * to empty arrays while disabled and recomputes in full the next render\n * where this flips back to `true` — same render the caller's UI becomes\n * visible in, so nothing it shows is stale.\n */\n readonly enabled?: boolean;\n}\n\n/** Return shape of {@link useFilterFields}. */\nexport interface FilterFieldsResult {\n /** Fields the builder offers, in declared order. Empty when the config opted out. */\n readonly available: FilterFieldSpec[];\n /** Fields declared as always-visible controls. */\n readonly pinnedFields: FilterFieldSpec[];\n /** Normalized call-site filters; entries with a `label` render as undeletable badges. */\n readonly fixed: readonly ResolvedFixedFilter[];\n /** Fields the list is already narrowed on unconditionally. */\n readonly lockedFields: ReadonlySet<string>;\n}\n\n/**\n * Derives WHICH fields a filter UI may offer for a resource.\n *\n * Lifted out of `useResourceList` because the relation picker's dialog needs\n * exactly these rules — the config whitelist, the per-field operator override,\n * the locked-field hiding — for a resource that is NOT the page's. A second\n * copy of them would drift within a month.\n *\n * Deliberately free of URL state: this hook answers \"what can be filtered\",\n * never \"what is filtered\".\n */\nexport function useFilterFields(\n resource: string,\n options?: UseFilterFieldsOptions,\n): FilterFieldsResult {\n const app = useApp();\n const listCaps = useI18nCaps(resource);\n const def: ResourceDef | undefined = app.registry.get(resource);\n const enabled = options?.enabled ?? true;\n\n // Same visibility context `<ResourceList>` evaluates field `visible`\n // predicates against, so the Columns menu and the rendered table agree\n // on which columns exist in the CURRENT context (role / scope).\n //\n // ⚠️ Adapted, deliberately: the app called `useVisibilityCtx()`\n // (`_list-body.tsx:753`), which builds `{ permissions, scope }` FRESH on\n // every render. Used as a memo dep that recomputes the entire column\n // chain (`isColVisibleHere` → declared/optional/all/required/visible)\n // on every single render, which breaks this hook's identity contract at\n // the root. Rebuilding the same object from the same two slots, memoized\n // on their values, is behaviourally identical and stable.\n //\n // KEEP IN SYNC with `useVisibilityCtx` (`../use-permissions.ts`): if a\n // new built-in slot joins that snapshot, add it here too.\n const permissions = usePermissions();\n const scopeCtx = useScopeCtx();\n const visibilityCtx = useMemo<AppContext>(\n () => ({ permissions, scope: scopeCtx }),\n [permissions, scopeCtx],\n );\n\n /**\n * The call-site's fixed-filter narrowing (Task 7), normalized once. Feeds\n * both the composed `filter` below and the fields hidden from the filter\n * UI — a list locked to `pg = 'alcohol'` can only offer a tautology or an\n * empty result on `pg`, so that field is dropped from `available`.\n */\n const fixedFilters = useMemo(\n () => normalizeFixedFilters(options?.fixedFilters),\n [options?.fixedFilters],\n );\n const lockedFields = useMemo(() => lockedFilterFields(fixedFilters), [fixedFilters]);\n const capabilityFor = useCapabilityResolver(resource, undefined, 'list');\n\n /**\n * Resolve one declared filter field reference (string or `{field,\n * operators?, label?}`) into a {@link FilterFieldSpec}, or `null` when\n * the field is locked, unknown, or not categorisable. Shared by\n * `available` and `pinnedFields` below so both apply the exact same\n * exclusion rules.\n *\n * `system` is deliberately NOT one of those rules. It used to be — every\n * `system: true` field was dropped from every filter surface — but that\n * had no basis in the flag's own contract (`FieldDef.system`,\n * `@burojs/core`), which speaks only about FORMS: hidden on create,\n * read-only on edit, normal on show and in list columns. Filtering was\n * never mentioned, and the exclusion made the two most ordinary questions\n * a list can be asked — \"which rows have this id\", \"which were created\n * after this\" — unaskable, while pushing adopters into a custom toolbar\n * slot to search a `system: true` identifier (`docs/lists-guide.md`).\n * A system field is an ordinary filter candidate: offered by the implicit\n * default, honoured when declared in `fields`/`pinned`, and removable the\n * same way any other field is (declare `filters.fields` without it).\n *\n * `source` distinguishes an EXPLICIT adopter declaration\n * (`'fields'`/`'pinned'`, i.e. this `ref` came from\n * `views.list.filters.fields`/`.pinned`) from the IMPLICIT default (every\n * field on the resource, when `filters.fields` is undeclared) — `null`.\n * Only the explicit case warns: the implicit default legitimately walks\n * every field the resource has, including kinds nobody asked to filter on\n * (`f.json()`, `f.file()`, an unregistered relation target) — warning\n * there fires on every recompute of a normal resource, not on adopter\n * error. An explicit declaration naming a bad or nonexistent field IS\n * adopter error, and is exactly the typo class this warning exists to\n * catch — see Task 7 fix round 2.\n */\n const specFor = useCallback(\n (ref: FilterFieldRef, source: 'fields' | 'pinned' | null): FilterFieldSpec | null => {\n const field = typeof ref === 'string' ? ref : ref.field;\n if (lockedFields.has(field)) return null;\n if (!capabilityFor('view', { kind: 'column', name: field }).allowed) return null;\n const override = typeof ref === 'string' ? undefined : ref;\n\n // A DECLARED kind wins outright, and is the only way a relation path\n // can be filtered at all: `documents.document_id` names no field on\n // this resource, so there is nothing to look up and nothing for\n // `categorizeField` to read. Checked BEFORE the field lookup rather\n // than as a fallback after it, so a declared kind also overrides a\n // same-named field — the adopter asked for this control by name.\n if (override?.kind) {\n const declaredKind = filterKindFromHint(override.kind);\n // The same rule `categorizeField` applies to a declared field: a\n // relation whose target is not registered, or an enum nobody\n // registered, cannot render a working control. Repeated here\n // because a declared kind never reaches `categorizeField` — without\n // it a typo in the target ships a picker that can never load a\n // single option, and says nothing about why.\n const unregistered =\n declaredKind.kind === 'relation' && !app.registry.get(declaredKind.to)\n ? declaredKind.to\n : declaredKind.kind === 'enum' && !app.registry.enums.get(declaredKind.enumName)\n ? declaredKind.enumName\n : undefined;\n if (unregistered !== undefined) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}' with a kind naming '${unregistered}', which is not registered.`,\n );\n }\n return null;\n }\n return {\n field,\n label: override.label ?? resolveFieldLabel(listCaps, field),\n kind: declaredKind,\n operators: override.operators ?? operatorsForKind(declaredKind),\n options: override.options,\n };\n }\n\n // A path with no declared kind. Reported on its own terms: the\n // \"not a field on this resource\" warning below would send the reader\n // hunting for a typo instead of a missing `kind`.\n if (field.includes('.')) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}', which is a relation path and needs an explicit \\`kind\\` ` +\n `(nothing on this resource can derive one for it).`,\n );\n }\n return null;\n }\n\n const fieldDef = def?.fields?.[field] as { label?: string } | undefined;\n if (!fieldDef) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}', which is not a field on this resource.`,\n );\n }\n return null;\n }\n const kind = categorizeField(fieldDef, app.registry);\n if (!kind) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}', which is not filterable (unsupported field kind).`,\n );\n }\n return null;\n }\n return {\n field,\n label: override?.label ?? resolveFieldLabel(listCaps, field, fieldDef.label),\n kind,\n operators: override?.operators ?? operatorsForKind(kind),\n options: override?.options,\n };\n },\n [def, app.registry, listCaps, lockedFields, resource, capabilityFor],\n );\n\n /**\n * Filterable fields for the toolbar — either the declared\n * `views.list.filters.fields` whitelist (order and operator overrides\n * honored verbatim) or, by default, every field with a categorisable\n * kind in `views.list.columns` order. Fields locked by a fixed filter are\n * excluded either way; system fields are not (see `specFor`).\n *\n * Moved from `filterableColumns` (`_list-body.tsx:827-844`) and extended\n * (Task 7) to read the field whitelist/operator overrides from config\n * instead of always deriving the full column set. `false` removes the\n * filter button entirely (`declaredFields === false`).\n */\n // A bare property read used below as a `useMemo` dependency (see\n // `declaredFields`) — safe because `def` (`app.registry.get(resource)`\n // above) is a plain Map read: the registry returns the SAME object across\n // renders AND across a locale switch (nothing in `registry.ts` is\n // locale-aware), so this read is reference-stable and will never bust the\n // memo spuriously. `declaredFields` itself only carries untranslated field\n // REFS and their order, never resolved text, so it does not need to\n // recompute on a language switch either — the translated LABEL for each\n // ref is resolved downstream, per render, by `specFor` (below), whose own\n // `useCallback` deps include `listCaps` and which is what actually makes\n // `available`/`pinnedFields` re-render with fresh labels on a locale\n // change.\n const filterConfig = def?.views?.list?.filters;\n // Whether `available` below iterates an EXPLICIT `filters.fields` list\n // (warn-eligible) or the IMPLICIT every-field default (never warns —\n // see `specFor`'s doc comment).\n const fieldsExplicit = filterConfig?.fields !== undefined;\n const declaredFields = useMemo(() => {\n const declared =\n typeof filterConfig?.fields === 'function'\n ? filterConfig.fields(visibilityCtx)\n : filterConfig?.fields;\n if (declared === false) return false as const;\n return declared ?? def?.views?.list?.columns ?? Object.keys(def?.fields ?? {});\n }, [filterConfig, visibilityCtx, def]);\n\n const available = useMemo<FilterFieldSpec[]>(() => {\n // Gate FIRST, before touching `declaredFields`/`specFor` — skipping the\n // loop body is what avoids the `categorizeField` walk; see this hook's\n // `enabled` doc.\n if (!enabled) return [];\n if (declaredFields === false) return [];\n const out: FilterFieldSpec[] = [];\n for (const ref of declaredFields) {\n const spec = specFor(ref, fieldsExplicit ? 'fields' : null);\n if (spec) out.push(spec);\n }\n return out;\n }, [declaredFields, specFor, fieldsExplicit, enabled]);\n\n /**\n * Fields declared as always-visible controls beside the filter button\n * (`views.list.filters.pinned`), same resolution rules as `available`.\n */\n const pinnedFields = useMemo<FilterFieldSpec[]>(() => {\n if (!enabled) return [];\n const declared =\n typeof filterConfig?.pinned === 'function'\n ? filterConfig.pinned(visibilityCtx)\n : filterConfig?.pinned;\n if (!declared) return [];\n const out: FilterFieldSpec[] = [];\n for (const ref of declared) {\n // Always explicit — this loop only runs when the adopter declared\n // `views.list.filters.pinned` at all.\n const spec = specFor(ref, 'pinned');\n if (spec) out.push(spec);\n }\n return out;\n }, [filterConfig, visibilityCtx, specFor, enabled]);\n\n // A fresh object literal here is invisible to `useResourceList` (it\n // destructures immediately), but this hook has a second, public consumer\n // (the relation-picker dialog's `useDialogFilterState`) that may put the\n // whole result in a dependency array — which would then \"change\" every\n // render without this.\n return useMemo(\n () => ({ available, pinnedFields, fixed: fixedFilters, lockedFields }),\n [available, pinnedFields, fixedFilters, lockedFields],\n );\n}\n","import type { Availability, Registry, ResourceDef } from '@burojs/core';\nimport { hrefFor, resourceShowHref } from '@burojs/core';\n\n/**\n * Where one row points, given what its record allows.\n *\n * Extracted as a pure function so the decision is testable without a list, a\n * query client or a router.\n *\n * `disabled` collapses to the same result as `hidden`/`absent` here: a table\n * row is a LINK, and a link cannot carry a label and a toast the way a button\n * can. Dimming a whole row and hijacking its click to explain itself would be\n * worse than simply not linking it.\n */\nexport function rowHrefFor(\n registry: Pick<Registry, 'get'>,\n def: ResourceDef | undefined,\n resource: string,\n id: string,\n gate: (operation: string, record?: unknown) => Availability,\n record?: unknown,\n): string {\n if (gate('show', record).state === 'available') {\n return resourceShowHref(registry as Registry, def, resource, id);\n }\n if (gate('edit', record).state === 'available') {\n // ⚠️ Plain `hrefFor`, NOT a `resourceEditHref` — the show branch above\n // honours `routesTo.show` and this one honours nothing, because `routesTo`\n // has no `edit` key to honour. A resource that delegates its show page\n // elsewhere and then loses `show` falls back to its OWN edit page.\n return hrefFor(registry as Registry, resource, { action: 'edit', id });\n }\n return '';\n}\n","'use client';\nimport {\n type AppContext,\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n type FixedFilterInput,\n type PortableObject,\n type ResourceDef,\n type SavedViewDef,\n type SortExpression,\n EMPTY_FILTER_GROUP,\n composeListFilter,\n evaluateVisible,\n resourceCreateHref,\n} from '@burojs/core';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { applyViewToUrlState } from '../saved-views/apply-view-to-url-state.js';\nimport { useSavedViews } from '../saved-views/use-saved-views.js';\nimport type { ResourceUrlState } from '../url-state/codec.js';\nimport { useResourceUrlState } from '../url-state/use-resource-url-state.js';\nimport { useCount } from '../data/use-count.js';\nimport { useInfiniteList } from '../data/use-infinite-list.js';\nimport { useList } from '../data/use-list.js';\nimport { useApp } from '../use-app.js';\nimport { useAvailabilityResolver } from '../use-availability.js';\nimport { useCapabilityResolver } from '../use-capability.js';\nimport { usePermissions, useScopeCtx } from '../use-permissions.js';\nimport { useFilterFields } from './use-filter-fields.js';\nimport { unionPreservingOrder, withSortTiebreaker } from './helpers.js';\nimport { rowHrefFor } from './row-href.js';\nimport type { ResourceListController, RowRecord } from './types.js';\n\n/**\n * `useResourceList` — the data-connected list controller (core flexibility\n * program, Task B1.3b). Everything a list page needs that is NOT rendering:\n * URL-state sync, column math, filter composition, the `useList` call, row\n * identity, selection, saved views and routing hrefs. Adopters get a working\n * list without re-implementing ~600 lines of glue; presentational packages\n * (`@burojs/ui-shadcn`) and app code stay free of controller logic.\n *\n * The implementation is a MOVE, not a rewrite: every unit below was lifted\n * from the demo app's `ResourceListBody` and adapted only at its\n * inputs/outputs.\n * Source line references are cited per unit so the two can be diffed.\n *\n * ---------------------------------------------------------------------\n * Router coupling — resolved.\n * ---------------------------------------------------------------------\n * This hook builds on {@link useResourceUrlState}, which used to statically\n * import `next/navigation`, pulling Next into any app that imported\n * `useResourceList` even though `next` was only an optional peer dependency\n * of `@burojs/react`. That import is gone: {@link useResourceUrlState}\n * now reads/writes location through an injected `RouterAdapter`\n * (`../router/router-adapter.js`), the same pattern already used for links\n * via `LinkComponentProvider`. Any adopter supplying a `RouterAdapterProvider`\n * — Next, react-router, or otherwise — can use this hook.\n *\n * ---------------------------------------------------------------------\n * Identity contract.\n * ---------------------------------------------------------------------\n * Re-rendering with an unchanged URL and unchanged data returns the SAME\n * object for every group (`pagination`, `filters`, `columns`, …) and the\n * same function reference for every callback. Consumers may therefore use\n * any of them as a `useMemo` / `useEffect` / `React.memo` dependency\n * without churn. See \"Identity discipline\" below for how that is achieved\n * — it does NOT come for free, because `useResourceUrlState` returns a\n * fresh object on every render.\n *\n * @see docs/superpowers/plans/2026-07-26-cfb1-list-controller.md — Task B1.3b\n */\n\n/**\n * Fallback for a resource that declares NEITHER `views.list.pageSize` NOR\n * `views.list.defaultSort` (`@burojs/core`, SP0b Task 1) — `10`, no sort.\n * `pageSize: 10` matches the literal the playground has always used; the\n * other defaults (`page: 1`, `sort: []`, `search: ''`, `filters: []`) come\n * from the url-state hook itself.\n *\n * ⚠️ This is now only the FALLBACK, not the value passed to\n * {@link useResourceUrlState} directly — see `declaredDefaults` below,\n * which reads `def.views.list.pageSize` / `.defaultSort` and falls back to\n * this constant. Kept as a named constant (rather than inlining `10`\n * there) so there is exactly one place that says what \"nothing declared\"\n * means.\n *\n * Moved verbatim from `_list-body.tsx:97`.\n */\nconst URL_STATE_DEFAULTS = { pageSize: 10 };\n\n/**\n * Page-size choices surfaced as `pagination.pageSizeOptions`.\n *\n * The pre-lift app never passed `pageSizeOptions` to `<ResourceList>`, so\n * the rendered selector used that component's own default\n * (`resource-list.tsx:188`, `[10, 25, 50, 100]`). The controller now has to\n * name a value because `ResourceListController.pagination.pageSizeOptions`\n * is non-optional — this constant reproduces that default exactly, so\n * wiring `pageSizeOptions={pagination.pageSizeOptions}` in B1.3e is a\n * no-op change. Module scope keeps the array identity stable.\n *\n * ⚠️ Base list only. A resource declaring `views.list.pageSize` outside\n * this set (e.g. `30`) gets it MERGED in — see the `pageSizeOptions` memo\n * below — otherwise the size selector would offer no option matching the\n * declared default, a gap the fixed `100` in this list happened to hide\n * for the resources this feature first shipped for.\n */\nconst PAGE_SIZE_OPTIONS = [10, 25, 50, 100];\n\n/**\n * `useList` query options. Hoisted to module scope (the app had it inline,\n * `_list-body.tsx:1299-1307`) purely for stable identity — the body is\n * unchanged.\n *\n * Keeping the previous page's rows on screen while a new filter/sort/page\n * query loads avoids dropping to the skeleton on every change: `isLoading`\n * stays false once we have any data, so the list keeps rendering the\n * (stale) table until fresh rows arrive.\n */\nconst NO_PAGES: ReadonlyArray<{ readonly data: readonly unknown[] }> = [];\n\n/** Stable empty selection — avoids a fresh `[]` identity on mount. */\nconst NO_SELECTION: string[] = [];\nconst NO_ROWS: RowRecord[] = [];\nconst NO_CACHE: Record<string, RowRecord> = {};\n\n/**\n * `provider::resource` keys a data provider has already answered\n * `{ total: null }` for — \"this cannot be counted here at all\". That is a\n * property of the resource↔provider mapping (no aggregate root exists);\n * no filter, page, sort or scope can change it, so the answer is worth\n * remembering.\n *\n * Module scope, because it must outlive the hook: `getCount` is\n * presence-discovered (there is deliberately no `canCount` probe, see\n * `packages/core/src/types/data-access.ts`), so without this the dead\n * affordance would come back on every remount of an uncountable list —\n * one wasted click each time the user navigates back to it.\n *\n * ⚠️ Keyed by RESOURCE NAME, never by table. `code_document_link` and\n * `code_code_document` are the same physical table under two resource\n * names, and only the resource name decides which mapping — and therefore\n * which aggregate root — applies. Note this holds the *unavailability*\n * verdict only; the counted NUMBER is never cached here (it is per-mount\n * state keyed on the full filter tuple, see `countKey` below).\n */\n\n/**\n * Second argument to {@link useResourceList}.\n *\n * Deliberately tiny: everything else the controller needs it resolves\n * itself from the registry (`def`) or from the URL. These two exist\n * because they cannot be derived — `meta` carries app-level query scope,\n * and `onReset` is the seam to state the controller does not own.\n */\nexport interface UseResourceListOptions {\n /**\n * Extra `meta` merged into the `useList` call — and therefore into the\n * react-query cache key. This is how app-level query scope (a sidebar\n * product-group / location picker, a tenant id) becomes part of the\n * cache key instead of being invisible to react-query.\n *\n * ⚠️ **The caller MUST memoize this object.** It flows into the query\n * key; a fresh object literal every render produces a fresh key every\n * render, which means a refetch loop. The playground memoizes on\n * `[scope.productGroup, scope.locationId]`.\n *\n * Merge order: controller-owned meta keys are spread FIRST, so **caller\n * keys win** on a collision. As of Task 4 (F2) the controller DOES own\n * one such key: {@link ResourceListController.providerQuery}, a level-2\n * filters-slot's own escape hatch into this same `meta`. A key here that\n * collides with a key the slot pushes through `providerQuery.set` still\n * wins — the slot silently loses that key, not the other way round — but\n * an adopter picking a `meta` key that happens to collide should know\n * that collision is possible, not assume the merge site is unreachable.\n */\n meta?: Record<string, unknown>;\n /**\n * Fired by {@link ResourceListController.filters}`.clearAll` and by\n * {@link ResourceListController.savedViews}`.apply`.\n *\n * The seam for ephemeral UI state the controller does NOT own but that\n * must reset in step with those two actions. Concretely (the case this\n * was designed for): the playground's dynamic-filter toolbar keeps its\n * own `visibleIds` set of which chips are rendered, and the pre-lift\n * `clearAllFilters` (`_list-body.tsx:1336`) and `applyView`\n * (`_list-body.tsx:950`) both reset it. Without this callback,\n * clear-all leaves stale empty chips on screen and applying a saved\n * view leaves the PREVIOUS view's chips.\n *\n * Read through a ref, so an inline arrow here does not destabilise\n * `clearAll` / `apply` identity.\n */\n onReset?: () => void;\n /**\n * Call-site narrowing the user did not choose: the parent FK of an\n * embedded list, the resource owning a picker dialog, a tab showing one\n * slice of a collection.\n *\n * Never reaches the URL — it is derived from the render context, so a\n * serialized copy would be both forgeable and stale the moment the parent\n * changes. By default each entry also HIDES its fields from the filter UI;\n * pass `{ filter, lock: false }` to keep a field available.\n *\n * ⚠️ Memoize it: it feeds the query key.\n */\n fixedFilters?: readonly FixedFilterInput[];\n /**\n * Overrides `views.list.refetchInterval` (`@burojs/core`) for a host that\n * mounts a list by hand rather than through the level-0 nav-area page —\n * the declared route can't take props, this option is the escape hatch.\n * `false` forces polling off even when the resource declares an interval;\n * omit to use the declared value untouched.\n */\n refetchInterval?: number | false;\n}\n\n/**\n * Data-connected list controller for `resource`.\n *\n * ⚠️ **Precondition: `resource` MUST be registered.** `routing.createHref`\n * resolves through `resourceCreateHref` → `hrefFor`, which throws\n * `unknown node '<resource>'` for a name the registry doesn't know. This\n * is the pre-lift behaviour, and it is exactly why the playground's route\n * calls `notFound()` before mounting the list\n * (`app/(admin)/[resource]/page.tsx:15-22`). Resolve\n * `app.registry.get(resource)` and handle the miss BEFORE calling this\n * hook. (`ResourceListController.def` is typed `ResourceDef | undefined`\n * for that reason, but `undefined` is not reachable in practice.)\n *\n * ### Free-text search\n *\n * `filters.search` composes into the fetched filter set via core's\n * `searchToFilter` (`@burojs/core`), driven by `def.views.list.search`\n * (a `SearchDecl`):\n *\n * 1. Declarative form (`{ fields: [...] }`) ORs `contains` (or a per-field\n * `op` override) across the listed fields.\n * 2. Function form takes over completely — returning `null` means \"this\n * query searches nothing\", a deliberate answer, not an error.\n * 3. Undeclared (`views.list.search` absent) — the search string\n * contributes nothing.\n *\n * ⚠️ The framework adds NO numeric-id branch of its own. It used to\n * (`/^\\d+$/ → {field: 'id', op: 'eq'}` unconditionally on every resource,\n * `_list-body.tsx:1263-1267`), which decided the storage type of somebody\n * else's `id` column for them — a provider holding `id` as a\n * bigint-as-string rejected the numeric value outright. A resource that\n * wants that behaviour back declares a function `views.list.search`.\n *\n * See {@link ResourceListController.filters}`.group` and `.fixed` for the\n * other two slots `composeListFilter` (`@burojs/core`) folds together with\n * search — fixed (call-site narrowing) → pinned (`filters.set`) → search →\n * group (the filter-builder panel), in that order (Task 7).\n *\n * ### Pagination modes\n *\n * Offset (the default) and cursor, chosen by\n * `def.views.list.pagination` and surfaced as\n * {@link ResourceListController.cursor} (`null` ⇒ offset).\n *\n * | | offset | `'cursor'` |\n * |---|---|---|\n * | fetch | `useList` | `useInfiniteList` |\n * | `rows` | the current page | every page loaded so far, de-duplicated by id |\n * | advance | `pagination.setPage(n)` | `cursor.loadMore()` |\n * | `pagination.page` / `setPage` | live | inert |\n * | key | includes `currentPage` | no page number — cursor owned by `InfiniteListObserver` |\n *\n * Both hooks are called unconditionally; the inactive one is switched off\n * through `queryOptions.enabled`. See the comment at the call sites.\n *\n * ### Row identity\n *\n * See {@link ResourceListController.rows}. `def.rowId(record, index)` wins\n * when declared; otherwise the framework default is the first present of\n * `id`, `event_id`, `job_id`, else the row's index. The resolved value is\n * written ONTO the row as `id` — see the `rows` memo below for why.\n *\n * @param resource Registry name of the resource to list.\n * @param opts See {@link UseResourceListOptions}. Optional; `meta`\n * must be memoized when supplied.\n */\nexport function useResourceList(\n resource: string,\n opts?: UseResourceListOptions,\n): ResourceListController {\n const app = useApp();\n // Gates the row's drill-in target (see `rowHref` below) — `show` first,\n // falling back to `edit`, never a link when neither is reachable.\n const availability = useAvailabilityResolver(resource);\n\n // The resource def is resolved here rather than being passed in (the\n // pre-lift `ResourceListBody` took it as a prop, `_list-body.tsx:746`).\n // `registry.get` is a Map read, so the identity is stable.\n const def: ResourceDef | undefined = app.registry.get(resource);\n\n // Same visibility context `<ResourceList>` evaluates field `visible`\n // predicates against, so the Columns menu and the rendered table agree\n // on which columns exist in the CURRENT context (role / scope).\n //\n // ⚠️ Adapted, deliberately: the app called `useVisibilityCtx()`\n // (`_list-body.tsx:753`), which builds `{ permissions, scope }` FRESH on\n // every render. Used as a memo dep that recomputes the entire column\n // chain (`isColVisibleHere` → declared/optional/all/required/visible)\n // on every single render, which breaks this hook's identity contract at\n // the root. Rebuilding the same object from the same two slots, memoized\n // on their values, is behaviourally identical and stable.\n //\n // KEEP IN SYNC with `useVisibilityCtx` (`../use-permissions.ts`): if a\n // new built-in slot joins that snapshot, add it here too.\n const permissions = usePermissions();\n const scopeCtx = useScopeCtx();\n const visibilityCtx = useMemo<AppContext>(\n () => ({ permissions, scope: scopeCtx }),\n [permissions, scopeCtx],\n );\n\n // Accumulating selection. Ids survive page, pageSize, filter, sorters and\n // search; they are dropped only where the ROWS are dropped too — the\n // resource boundary and the scope / provider-options boundary (see the\n // reset effect below) — and on unmount.\n const [selectedIds, setSelectedIds] = useState<string[]>(NO_SELECTION);\n // Snapshot of every selected row, keyed by id. A row selected on a page the\n // user has since left is not in `rows` any more; without a snapshot a bulk\n // action would silently act on fewer records than the user picked.\n const [selectedCache, setSelectedCache] = useState<Record<string, RowRecord>>(NO_CACHE);\n\n // #17 — column-layout reset signal consumed by `<ResourceList>`.\n // Moved from `_list-body.tsx:765-768`.\n const [resetLayout, setResetLayout] = useState<{ token: number; mode: 'sizes' | 'all' }>({\n token: 0,\n mode: 'sizes',\n });\n\n // -------------------------------------------------------------------\n // Column math — moved from `_list-body.tsx:796-818`.\n //\n // Defaults preserve full backward compat: a resource without\n // `optionalColumns` shows no extras; without `requiredColumns` every\n // default column is treated as required (the conservative choice —\n // adopters opt into toggling by listing extras).\n //\n // A column only \"exists\" in this context if its field's `visible`\n // predicate holds. `<ResourceList>` filters the RENDERED columns by\n // exactly this; applying it here too keeps the Columns menu honest —\n // otherwise a field hidden by `visible` (e.g. an admin-only column)\n // shows up in the menu, checked, but never appears in the table and\n // toggling it does nothing.\n // -------------------------------------------------------------------\n /*\n ONE OF THE TWO `kind: 'column'` ENFORCEMENT CALL SITES (SP5 task 2). The\n other is `<ResourceList>`'s `visibleColumnKeys`, which filters what the\n TABLE draws; this one filters what the CONTROLLER offers — the Columns\n menu, `optionalColumns`, `requiredColumns`. Both are needed for the same\n reason the `visible` predicate is already applied in both places, recorded\n in the comment above: a column filtered out of only one of them shows up in\n the menu, checked, and never appears in the table.\n\n Before this, `{ target: { kind: 'column', name: 'total_cents' }, deny: 'view' }`\n typechecked, registered without a word, and the column rendered anyway —\n confirmed by a probe, not by reading.\n\n `mode: 'list'` and NO record: a column spans every row, so a column rule\n that branches on `ctx.record` has nothing to read. That is stated in the\n docs rather than defended here — passing one row's record would make the\n whole table's shape depend on which row happened to be first.\n */\n const capabilityFor = useCapabilityResolver(resource, undefined, 'list');\n const isColVisibleHere = useMemo(() => {\n return (col: string): boolean => {\n if (!capabilityFor('view', { kind: 'column', name: col }).allowed) return false;\n const field = def?.fields?.[col] as { visible?: unknown } | undefined;\n if (!field) return true;\n return evaluateVisible(field.visible as never, visibilityCtx);\n };\n }, [def, visibilityCtx, capabilityFor]);\n /**\n * ⚠️ A column naming a field the resource does not have is KEPT on purpose\n * (`isColVisibleHere` returns true for an unknown key so an app can list a\n * column it renders itself via `renderCell`). The cost is that a TYPO is\n * indistinguishable from that: `views.list.columns: ['aliass']` yields a\n * real column with a plausible humanized header, every cell blank, a\n * checked-but-dead entry in the Columns menu, and silent absence from the\n * filter toolbar. It reads as a data bug, not a schema bug, and an adopter\n * can lose a long time to it.\n *\n * So: warn, don't change the behaviour. Same shape as the warning\n * `<ResourceWizard>` already emits for exactly this typo class\n * (`resource-wizard.tsx:147`) — named resource, named column, deduped so a\n * re-render cannot spam the console.\n */\n const warnedUnknownColumnsRef = useRef<Set<string>>(new Set());\n const declaredColumns = useMemo<string[]>(() => {\n if (!def) return [];\n const declared = def.views?.list?.columns ?? Object.keys(def.fields ?? {});\n // Only when the app declared columns explicitly — the fallback is derived\n // FROM `fields`, so every key is known by construction.\n if (def.views?.list?.columns && def.fields) {\n for (const col of declared) {\n if (def.fields[col]) continue;\n const key = `${resource}::${col}`;\n if (warnedUnknownColumnsRef.current.has(key)) continue;\n warnedUnknownColumnsRef.current.add(key);\n // eslint-disable-next-line no-console\n console.warn(\n `[buro] Resource \"${resource}\": views.list.columns names \"${col}\", which is not a field on this resource. The column will render empty. Known fields: ${Object.keys(def.fields).join(', ')}.`,\n );\n }\n }\n return declared.filter(isColVisibleHere);\n }, [def, isColVisibleHere, resource]);\n const optionalColumns = useMemo<string[]>(\n () => (def?.views?.list?.optionalColumns ?? []).filter(isColVisibleHere),\n [def, isColVisibleHere],\n );\n const allAvailable = useMemo<string[]>(\n () => unionPreservingOrder(declaredColumns, optionalColumns),\n [declaredColumns, optionalColumns],\n );\n const requiredColumns = useMemo<string[]>(\n () => def?.views?.list?.requiredColumns ?? declaredColumns,\n [def, declaredColumns],\n );\n\n /**\n * The filterable-field derivation (declared whitelist, per-field operator\n * overrides, pinned fields, fixed-filter normalization and locked-field\n * hiding) is lifted into {@link useFilterFields} — the relation picker's\n * dialog needs exactly these rules for a resource that is NOT the page's,\n * and a second copy of them would drift within a month. See that hook's\n * doc comment for the full derivation.\n */\n const {\n available,\n pinnedFields,\n fixed: fixedFilters,\n } = useFilterFields(resource, {\n fixedFilters: opts?.fixedFilters,\n });\n\n /**\n * Per-resource defaults for {@link useResourceUrlState} — SP0b Task 2.\n * Reads `views.list.pageSize` / `views.list.defaultSort` (`@burojs/core`,\n * Task 1) so a resource that declares either gets it as the state the\n * URL falls back to when it carries none: page size on cold load, and an\n * initial sort order before the user (or a saved view) picks one.\n *\n * `sort` is only present in the object when the resource actually\n * declares `defaultSort` — an explicit `sort: []` would ALSO be a valid\n * default, but `useResourceUrlState`'s codec only omits the `?<r>.sort=`\n * param from the URL when the current sort matches the default\n * (`sameJson`), and there is nothing to omit-match against differently\n * here: `[]` is already `HOOK_DEFAULTS.sort`. Spreading conditionally\n * keeps the common (undeclared) case textually identical to \"no sort\n * override\", rather than writing out `[]` for a value that was already\n * the hook's own default.\n *\n * `def.views.list.defaultSort` shares `SortExpression<ErasedResourceHandle>`\n * with `ResourceUrlState['sort']` (both are core's erased sort AST — see\n * `views.list.defaultSort`'s JSDoc in `@burojs/core`), so this is a\n * direct assignment, not a conversion. Verified against\n * `packages/react/src/hooks/url-state/codec.ts`'s `ResourceSort` alias.\n *\n * ⚠️ `useMemo` is REQUIRED, not decorative: `useResourceUrlState`\n * memoizes its own `codecOpts` on the IDENTITY of `opts.defaults`\n * (`use-resource-url-state.ts`'s `codecOpts` memo), and that identity\n * feeds the setter callbacks. A fresh object literal here every render\n * would recreate `codecOpts` every render, which busts setter identity\n * and the codec memo — see `URL_STATE_DEFAULTS`'s docblock above for the\n * full failure mode this hook's original comment names. Keyed on the\n * declared VALUES (not on `def`), so identity survives every render that\n * doesn't actually change the declaration.\n *\n * A resource that declares neither key returns `URL_STATE_DEFAULTS`\n * ITSELF (not a byte-identical copy) — the brief's \"keep the module\n * constant as the value for nothing declared\" taken literally, which\n * also means every undeclared resource shares one stable object across\n * mounts, not just within one.\n */\n const declaredPageSize = def?.views?.list?.pageSize;\n const declaredSort = def?.views?.list?.defaultSort;\n const declaredDefaults = useMemo(\n () =>\n declaredPageSize === undefined && declaredSort === undefined\n ? URL_STATE_DEFAULTS\n : {\n pageSize: declaredPageSize ?? URL_STATE_DEFAULTS.pageSize,\n ...(declaredSort ? { sort: declaredSort } : {}),\n },\n [declaredPageSize, declaredSort],\n );\n\n /**\n * URL-state hook — source of truth for the page's interactive state\n * (filters / sort / page / pageSize / search / visibleColumns). Each\n * setter writes to the URL so cold deep-links restore the view and\n * reload preserves state.\n *\n * Selection stays in local state above (ephemeral UI). Column\n * visibility lives in the URL via `?<resource>.cols=col1,col2,col3`\n * (A3); a one-shot migration below picks up the legacy\n * `buro:columns:<resource>` localStorage value the first time a\n * given resource mounts post-upgrade.\n *\n * Moved verbatim from `_list-body.tsx:893-910`. `defaults` used to be\n * the module-level `URL_STATE_DEFAULTS` literal (deliberate — the\n * url-state hook memoizes on `opts.defaults` / `opts.fieldTypes`\n * individually); it is now `declaredDefaults` (SP0b Task 2), which is\n * stable for the same reason (see that memo's docblock above).\n */\n const urlState = useResourceUrlState(resource, {\n defaults: declaredDefaults,\n });\n const {\n page,\n sort,\n search,\n filters: urlFilters,\n filterGroup,\n visibleColumns: urlVisibleColumns,\n } = urlState;\n const pageSize = urlState.pageSize;\n\n /**\n * Saved-views integration (A4.1-A4.3). `useSavedViews` returns the union\n * of adopter-defined views (`def.views.list.savedViews`) and user-saved\n * views (localStorage). Moved from `_list-body.tsx:929-934`; the two\n * dialogs and the toast stay in the app (see `savedViews.saveCurrent`).\n */\n const {\n adopterViews,\n userViews,\n entries: savedViewEntries,\n writeScopes: savedViewWriteScopes,\n issues: savedViewIssues,\n pending: savedViewsPending,\n saveCurrentAsView,\n renameUserView,\n deleteUserView,\n forkUserView,\n } = useSavedViews(resource);\n\n // Effective visible set: required columns are always present; the user's\n // toggled set (read from the URL) supplies the rest, intersected with\n // `allAvailable` to drop stale entries from older config or unknown ids\n // from a malformed deep link. Materialized in `allAvailable` order so\n // the table layout is stable across toggles. When the URL has no\n // `?<r>.cols=` param we fall back to the resource's declared default\n // columns so initial paint matches the server-rendered shell.\n //\n // Moved verbatim from `_list-body.tsx:992-997`.\n const visibleColumns = useMemo<string[]>(() => {\n const base = urlVisibleColumns ?? declaredColumns;\n const baseSet = new Set(base);\n const requiredSet = new Set(requiredColumns);\n return allAvailable.filter((c) => baseSet.has(c) || requiredSet.has(c));\n }, [urlVisibleColumns, declaredColumns, requiredColumns, allAvailable]);\n\n // -------------------------------------------------------------------\n // ⚠️ Identity discipline — the volatile ref.\n //\n // `useResourceUrlState` returns a FRESH object every render\n // (`use-resource-url-state.ts:375-383`), and its setters are only as\n // stable as `useRouter()` / `useSearchParams()` underneath them. A\n // naive `useCallback(…, [urlState])` — or even `[setFilters]` — is\n // therefore a new function on almost every render, which propagates\n // into every group object and defeats every downstream memo.\n //\n // The repo's answer to exactly this problem is the volatile-ref\n // pattern (`ui-shadcn/src/resource/resource-list.tsx:337-347`): one ref\n // holding everything volatile, REASSIGNED during render, read only from\n // inside event-handler callbacks that themselves have empty dep lists.\n // Handlers run after commit, so `.current` is always the latest\n // committed render's value — fresh values, frozen identity.\n //\n // ⚠️ Render-time reads must NOT go through this ref (a memo reading\n // `.current` would never invalidate). Everything the render path needs\n // is destructured above as a normal value.\n // -------------------------------------------------------------------\n const volatileRef = useRef({\n urlState,\n declaredDefaults,\n visibleColumns,\n requiredColumns,\n saveCurrentAsView,\n renameUserView,\n deleteUserView,\n forkUserView,\n onReset: opts?.onReset,\n registry: app.registry,\n def,\n resource,\n availability,\n sort,\n refetch: (): void => {},\n // Cursor mode (B5.2). Assigned right after the two query hooks below —\n // `loadMore` reads all three so its own identity can stay frozen.\n hasNextPage: false as boolean | undefined,\n isFetchingNextPage: false,\n fetchNextPage: (): void => {},\n isCurrentData: false,\n requestCount: (): void => {},\n rowsById: new Map<string, RowRecord>(),\n });\n volatileRef.current.urlState = urlState;\n volatileRef.current.declaredDefaults = declaredDefaults;\n volatileRef.current.visibleColumns = visibleColumns;\n volatileRef.current.requiredColumns = requiredColumns;\n volatileRef.current.saveCurrentAsView = saveCurrentAsView;\n volatileRef.current.renameUserView = renameUserView;\n volatileRef.current.deleteUserView = deleteUserView;\n volatileRef.current.forkUserView = forkUserView;\n volatileRef.current.onReset = opts?.onReset;\n volatileRef.current.registry = app.registry;\n volatileRef.current.def = def;\n volatileRef.current.availability = availability;\n volatileRef.current.resource = resource;\n volatileRef.current.sort = sort;\n\n // One-shot migration of the pre-A3 `buro:columns:<resource>`\n // localStorage key to the URL's `?<r>.cols=` param. Runs once per\n // resource mount, BEFORE the user has a chance to interact with the\n // toolbar. The latest `urlVisibleColumns` is read via a ref so the\n // effect doesn't re-fire on every URL change.\n //\n // Behaviour:\n // - Legacy key absent → no-op.\n // - Legacy key present, URL has no cols → write to URL, delete key.\n // - Legacy key present, URL already has cols → URL wins; the legacy\n // key is still cleared (the URL is now the source of truth).\n //\n // Multi-tab race: the migration is per-tab and idempotent. Both\n // branches converge to the same end state — the legacy key is gone and\n // the URL holds either the migrated value or whatever was already\n // there. If two tabs race the same first-mount, the loser sees the\n // (already-cleared) legacy key as absent and no-ops. There is no path\n // where data is lost across tabs.\n //\n // Moved verbatim from `_list-body.tsx:1020-1051`.\n const urlVisibleColumnsRef = useRef(urlVisibleColumns);\n useEffect(() => {\n urlVisibleColumnsRef.current = urlVisibleColumns;\n }, [urlVisibleColumns]);\n useEffect(() => {\n if (typeof window === 'undefined') return;\n const legacyKey = `buro:columns:${resource}`;\n let legacy: string[] | null = null;\n try {\n const raw = window.localStorage.getItem(legacyKey);\n if (raw) {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((x) => typeof x === 'string')) {\n legacy = parsed as string[];\n }\n }\n } catch {\n // ignore — corrupted localStorage value is dropped on the floor\n }\n if (legacy === null) return;\n // URL wins if it already has cols — only seed the URL when empty.\n if (urlVisibleColumnsRef.current === null) {\n volatileRef.current.urlState.setVisibleColumns(legacy);\n }\n // Delete legacy regardless (URL is now source of truth).\n try {\n window.localStorage.removeItem(legacyKey);\n } catch {\n // ignore\n }\n }, [resource]);\n\n /**\n * Compose the filter sent to `useList` — the three-slot model (Task 7):\n * fixed (call-site narrowing) → pinned (URL-state column filters) →\n * search → group (the URL-state builder group), folded into one\n * expression by `composeListFilter` (`@burojs/core`) in that order.\n *\n * Moved from `_list-body.tsx:1254-1272`; the search resolution itself now\n * lives in core's `searchToFilter` (`views.list.search`, see the hook\n * JSDoc), and the fixed/group slots are new (Task 7).\n */\n const searchDecl = def?.views?.list?.search;\n const searchContext = useMemo(() => ({ resource, def }), [resource, def]);\n const filter = useMemo<FilterExpression<ErasedResourceHandle> | undefined>(\n () =>\n composeListFilter({\n fixed: fixedFilters,\n pinned: urlFilters,\n group: filterGroup,\n search,\n searchDecl,\n searchContext,\n }),\n [fixedFilters, urlFilters, filterGroup, search, searchDecl, searchContext],\n );\n\n /**\n * Sort, plus a UNIQUE TIEBREAKER.\n *\n * ⚠️ This used to emit the user's column alone. Sorting by a non-unique\n * column then duplicated and hid rows: SQL does not guarantee a stable order\n * among ties across separate `limit`/`offset` windows, so a row can appear on\n * two pages while another appears on none. Measured on the 2 728-row document\n * table sorted by its 9-value status column — 2 728 rows shown, only 2 152\n * distinct, 576 documents unreachable, and page 8 repeating 19 rows from\n * page 1, all while the footer asserted «Показаны 1–2 728 из 2 728».\n *\n * The tiebreaker only makes the order deterministic; it never changes which\n * rows match. Skipped when the user is already sorting by the tiebreaker\n * field, and when the resource has no such field to sort on (an append-only\n * log table need not have an `id`) — see `views.list.sortTiebreaker`.\n */\n const sorters = useMemo<SortExpression<ErasedResourceHandle>>(\n () => withSortTiebreaker(sort, def),\n [sort, def],\n );\n\n /**\n * `providerQuery` — узкий канал (Task 4 / F2), которым level-2\n * filters-слот может протолкнуть в запрос произвольный provider-блоб, не\n * имея доступа к `opts.meta` (его передаёт СТРАНИЦА, а не слот). Значение\n * непрозрачно для контроллера — он не знает и не обязан знать, что внутри.\n *\n * `undefined` по умолчанию, так и остаётся, пока слот ни разу не вызвал\n * `providerQuery.set`.\n */\n const [providerQueryValue, setProviderQueryValue] = useState<Record<string, unknown> | undefined>(\n undefined,\n );\n\n /**\n * Meta merged into the `useList` call — and therefore into the\n * react-query key. Controller-owned keys are spread FIRST so caller\n * keys win on collision: `providerQuery` (Task 4) is the first\n * controller-owned key, spread ahead of `opts.meta` below.\n * Collapses to `undefined` when empty so a caller passing nothing (and\n * a slot never touching `providerQuery`) gets the same query key it\n * would have without a meta argument at all.\n */\n const callerMeta = opts?.meta;\n const meta = useMemo<PortableObject | undefined>(() => {\n const merged = { ...providerQueryValue, ...callerMeta };\n return Object.keys(merged).length > 0 ? (merged as PortableObject) : undefined;\n }, [providerQueryValue, callerMeta]);\n\n // -------------------------------------------------------------------\n // The fetch. TWO hooks, one enabled (Task B5.2).\n //\n // ⚠️ RULES OF HOOKS — do NOT \"simplify\" this into `isCursor ? useList()\n // : useInfiniteList()`. Both hooks MUST be called on every render, in\n // this order; the inactive one is switched off through\n // `queryOptions.enabled` (see `LIST_QUERY_OPTIONS_DISABLED` /\n // `INFINITE_QUERY_OPTIONS_DISABLED`), which stops the fetch AND the\n // live-polling interval, leaving only two cheap idle observers.\n //\n // Offset and cursor descriptors are intentionally distinct: an offset\n // list owns one page while an infinite list owns an ordered page sequence.\n // Routing every list through the latter would make normal page replacement\n // and cursor accumulation indistinguishable to cache invalidation.\n //\n // Why the mode is DECLARED and not sniffed from the first response: see\n // `views.list.pagination`'s JSDoc in `@burojs/core`. Short version —\n // a single-page cursor list is indistinguishable from an offset one, and\n // flipping mode after the first response would fetch page one twice.\n // -------------------------------------------------------------------\n const isCursor = def?.views?.list?.pagination === 'cursor';\n\n /**\n * Declared live-list interval (`views.list.refetchInterval`), overridden\n * by the hook's own option for hosts that mount a list by hand.\n *\n * Cursor mode accumulates pages, so a background refetch would fight the\n * accumulator — warn once and stay static rather than silently doing\n * something the caller did not ask for.\n */\n const declaredInterval = opts?.refetchInterval ?? def?.views?.list?.refetchInterval ?? false;\n const liveInterval =\n typeof declaredInterval === 'number' && declaredInterval > 0 ? declaredInterval : null;\n const [isLivePaused, setLivePaused] = useState(false);\n const liveDisabledByCursor = liveInterval !== null && isCursor;\n useEffect(() => {\n if (liveDisabledByCursor) {\n // eslint-disable-next-line no-console\n console.warn(\n `useResourceList(\"${resource}\"): views.list.refetchInterval is ignored for a cursor list.`,\n );\n }\n }, [liveDisabledByCursor, resource]);\n const activeInterval =\n liveInterval === null || liveDisabledByCursor || isLivePaused ? false : liveInterval;\n\n // Moved verbatim from `_list-body.tsx:1293-1308` (`meta` and\n // `queryOptions` hoisted out; see `LIST_QUERY_OPTIONS`).\n //\n // ⚠️ `refetchInterval` is spread in only when a live interval is actually\n // declared (`liveInterval !== null`) — a resource that declares nothing\n // must produce a BYTE-IDENTICAL `useList` call to before this feature\n // existed, not one carrying an explicit `refetchInterval: false` (which is\n // the same value to TanStack Query, but not the same call for a test — or\n // an adopter — asserting on it).\n const offsetQuery = useList(resource, {\n pagination: { kind: 'offset', page, pageSize },\n filter,\n sort: sorters,\n providerOptionsOverride: meta,\n enabled: !isCursor,\n ...(liveInterval === null ? {} : { refetchInterval: activeInterval }),\n });\n\n /**\n * Cursor mode. The `pagination` passed to `useInfiniteList` carries no\n * page number at all (`{ kind: 'cursor', limit: pageSize }`) — the opaque\n * continuation token lives entirely inside `InfiniteListObserver`, which\n * derives it from the previous page's `pageInfo.nextCursor` and never\n * feeds it back into the descriptor. That keeps the descriptor (and its\n * query key/identity) stable across a load-more, which is what makes\n * accumulation work at all: `InfiniteListObserver` appends to its own\n * `pages` array under ONE identity instead of starting a new query per\n * token.\n *\n * ⚠️ That stability is also why the QueryClient-wide `placeholderData:\n * keepPreviousData` default cannot break this the way it broke the\n * hand-written accumulator it replaces: a placeholder is only ever\n * substituted while a query is `pending`, and a load-more never leaves\n * the current key's `success` state.\n *\n * ⚠️ `retry: false` is NOT carried over. The hand-written Schedules page\n * passed it (`schedules/page.tsx:65`); the controller has one retry\n * policy for every list it drives, which is react-query's default of 3\n * with backoff — the same policy every Hasura list in the app already\n * runs under. A cursor provider outage therefore surfaces its error\n * later than the bespoke page did. Recorded rather than papered over\n * with a `queryOptions` passthrough that would have exactly one caller.\n */\n const cursorQuery = useInfiniteList(resource, {\n pagination: { kind: 'cursor', limit: pageSize },\n filter,\n sort: sorters,\n providerOptionsOverride: meta,\n enabled: isCursor,\n });\n\n // The two results are read field-by-field rather than through a single\n // `isCursor ? cursorQuery : offsetQuery` union: TypeScript will not call\n // a method off a union of two differently-parameterised react-query\n // results, and a `refetch()` that needs a cast is a refetch nobody will\n // notice breaking.\n volatileRef.current.refetch = () => {\n if (isCursor) void cursorQuery.refetch();\n else void offsetQuery.refetch();\n };\n volatileRef.current.hasNextPage = cursorQuery.hasNextPage;\n volatileRef.current.isFetchingNextPage = cursorQuery.isFetchingNextPage;\n volatileRef.current.fetchNextPage = () => {\n void cursorQuery.fetchNextPage();\n };\n\n /**\n * The rows on screen, each coerced to `{ …record, id: string }` — the\n * current page in offset mode, **every page loaded so far** in cursor\n * mode (see {@link ResourceListController.rows}).\n *\n * ⚠️ C1 — the row-id chain. `def.rowId(record, index)` wins when\n * declared (composite identity: a Temporal workflow is\n * `${workflowId}:${runId}`, which the plain default would collide\n * across runs). Otherwise the framework default is the chain moved\n * verbatim from `_list-body.tsx:1313`: `id ?? event_id ?? job_id ??\n * String(index)`. That chain is NOT decoration — `logs_l2_job_events`\n * and `logs_l2_production_events` are ClickHouse tables with no `id`\n * column at all, so a `String(record.id)` default would render\n * `id=\"undefined\"` for every row (duplicate React keys, broken\n * selection, `list-row:…:undefined` testids) and no e2e covers them.\n *\n * The resolved value is written ONTO the row rather than exposed as a\n * separate `getRowId`, because `useBuroDataTable`'s default\n * `getRowId` (`ui-shadcn/src/data-table/use-buro-data-table.ts:159-167`)\n * reads `row.id`, and every `list-row:<resource>:<id>` /\n * `list-cell:<resource>:<id>:<col>` testid derives from it. Keeping the\n * write here is what keeps that testid surface byte-for-byte identical.\n *\n * ⚠️ Cursor mode additionally DE-DUPLICATES by resolved id, keeping the\n * first position and the last value — the exact semantics of the\n * `new Map(prev.map(…))` + `byId.set(…)` accumulator the hand-written\n * Temporal pages used (`schedules/page.tsx:79-83`). Cursor providers can\n * legitimately overlap pages when rows are inserted between fetches, and\n * a duplicate `id` here means duplicate React keys and broken selection.\n * Offset mode is deliberately left alone: no page can repeat a row, and\n * silently dropping a genuine duplicate would be a behaviour change to\n * every existing list.\n *\n * ⚠️ Both branches are inside ONE memo so the returned array identity is\n * stable while neither source changes — react-query's structural sharing\n * hands back the same `pages` array across a no-op refetch, which is what\n * keeps the controller's identity contract intact in cursor mode too.\n */\n const offsetRows = offsetQuery.data?.data;\n const cursorPages = cursorQuery.data?.pages;\n const rows = useMemo<RowRecord[]>(() => {\n const rowId = def?.rowId;\n const source: readonly unknown[] = isCursor\n ? (cursorPages ?? NO_PAGES).flatMap((p) => (p.data ?? []) as unknown[])\n : (offsetRows ?? []);\n const out: RowRecord[] = [];\n const seen = isCursor ? new Map<string, number>() : null;\n source.forEach((r, i) => {\n const rec = r as Record<string, unknown>;\n const idVal = rowId ? rowId(rec, i) : (rec.id ?? rec.event_id ?? rec.job_id ?? String(i));\n const id = String(idVal);\n const row = { ...rec, id };\n const at = seen?.get(id);\n if (at !== undefined) {\n out[at] = row;\n return;\n }\n seen?.set(id, out.length);\n out.push(row);\n });\n return out;\n }, [isCursor, offsetRows, cursorPages, def]);\n\n // Row lookup for selection: `rows` is rebuilt on every page, and both the\n // snapshot cache and `selectedRecords` need id → row without a linear scan\n // per selected id.\n const rowsById = useMemo(() => {\n const map = new Map<string, RowRecord>();\n for (const row of rows) map.set(row.id, row);\n return map;\n }, [rows]);\n volatileRef.current.rowsById = rowsById;\n\n // Selection accumulates across page, pageSize, filter, sorters and search:\n // the user is building a set, and paginating must not silently empty it.\n // It IS dropped on the two boundaries where the rows themselves are dropped:\n // a different resource, and a different scope / provider-options. A cached\n // record from another tenant must never reach a bulk action.\n //\n // ⚠️ Keyed on `callerMeta` (`opts.meta`), NOT the merged `meta` above.\n // `providerQuery` is the level-2 filters-slot's own raw-query channel — it\n // is documented as a FILTER (see `isFiltered` below and the `providerQuery`\n // JSDoc), and every other filter change preserves selection. Folding it\n // into the merged `meta` that feeds this identity would make\n // `providerQuery.set(...)` the one filter that silently drops the\n // selection, contradicting that rule. The scope boundary this identity\n // exists to catch is the CALLER's scope / provider-options — a slot's raw\n // query was never that boundary.\n const selectionIdentity = useMemo(\n () => JSON.stringify([resource, callerMeta ?? null]),\n [resource, callerMeta],\n );\n // Reset DURING RENDER, not in an effect. `rows` empty out synchronously on a\n // resource/scope change, but a passive effect would not clear the selection\n // until after the commit — and for that one committed render `records` would\n // resolve snapshots belonging to the previous tenant. React re-runs this\n // component immediately on a set-during-render, so children never observe the\n // stale set.\n const [lastSelectionIdentity, setLastSelectionIdentity] = useState(selectionIdentity);\n if (lastSelectionIdentity !== selectionIdentity) {\n setLastSelectionIdentity(selectionIdentity);\n setSelectedIds(NO_SELECTION);\n setSelectedCache(NO_CACHE);\n }\n\n // Extended from `_list-body.tsx:1318` (Task 7) to include the builder group,\n // and (Task 11) the provider-query channel: a level-2 slot's raw\n // `providerQuery.set(...)` changes what the list request MEANS just as much\n // as a structured filter does, so \"is this list filtered?\" must say yes\n // while one is in force — otherwise a raw query matching zero rows renders\n // the ordinary \"no records yet / + Create\" empty state instead of \"nothing\n // matches\", and the standard filter region's \"Clear all\" stays hidden.\n const isFiltered =\n Boolean(search.trim()) ||\n urlFilters.length > 0 ||\n filterGroup.rows.length > 0 ||\n providerQueryValue !== undefined;\n\n // Count is a normal native descriptor. A controller neither chooses a\n // provider nor probes capabilities: the runtime resolves the descriptor\n // exactly as it resolves the list. `manual` keeps the observer disabled\n // until the user asks; `auto` and `live` opt in to its normal lifecycle.\n const countPolicy = def?.views?.list?.count ?? 'provided';\n const inlineTotal = isCursor ? cursorQuery.data?.pages.at(-1)?.total : offsetQuery.data?.total;\n const countQuery = useCount(resource, {\n filter,\n providerOptionsOverride: meta,\n enabled: countPolicy === 'live' || (countPolicy === 'auto' && inlineTotal === undefined),\n });\n const [nullCountIdentity, setNullCountIdentity] = useState<string | null>(null);\n const countIdentity = useMemo(\n () => JSON.stringify([resource, filter ?? null, meta ?? null]),\n [resource, filter, meta],\n );\n const countValue = countQuery.data?.total;\n useEffect(() => {\n if (countValue === null) setNullCountIdentity(countIdentity);\n }, [countValue, countIdentity]);\n const countIsNull = nullCountIdentity === countIdentity || countValue === null;\n const countAvailable = countPolicy === 'manual' && !countIsNull;\n volatileRef.current.requestCount = () => {\n if (countPolicy !== 'manual' || countIsNull || countQuery.isFetching) return;\n void countQuery.refetch();\n };\n const requestCount = useCallback(() => volatileRef.current.requestCount(), []);\n\n // -------------------------------------------------------------------\n // Callbacks. Every one has an EMPTY dep list and reads what it needs\n // from `volatileRef` — see \"Identity discipline\" above.\n // -------------------------------------------------------------------\n\n const setPage = useCallback((next: number) => {\n volatileRef.current.urlState.setPage(next);\n }, []);\n\n /**\n * Setting the page size also anchors back to page 1: row 41 of the old\n * size may not exist under the new one, so we avoid landing the user on\n * an empty page. Moved from the `onPageSize` closure,\n * `_list-body.tsx:1569-1574`.\n */\n const setPageSize = useCallback((size: number) => {\n volatileRef.current.urlState.setPageSize(size);\n volatileRef.current.urlState.setPage(1);\n }, []);\n\n /**\n * `providerQuery.set` (Task 4 / F2). Same \"anchor back to page 1\" move as\n * `setPageSize` above, for the same reason: the new blob changes what the\n * request MEANS, so whatever page the user was on under the old meaning\n * may not exist (or may mean something else entirely) under the new one.\n * `undefined` clears the channel — also anchored to page 1, since a\n * cleared provider query is just as much a change of query meaning as a\n * set one.\n */\n const setProviderQuery = useCallback((next: Record<string, unknown> | undefined) => {\n setProviderQueryValue(next);\n volatileRef.current.urlState.setPage(1);\n }, []);\n\n /**\n * Raw filter write. Deliberately a pass-through: the pre-lift page reset\n * pagination to page 1 on a filter change from INSIDE the TanStack\n * bridge (`setColumnFilters`, `_list-body.tsx:1104-1122`, which also\n * carries the \"skip the write when nothing actually changed\" guard).\n * That bridge stays in the app until B2, so the reset stays with it —\n * B1.3e composes `filters.set(next)` + `if (pagination.page !== 1)\n * pagination.setPage(1)` exactly as the source does.\n */\n const setFilters = useCallback((next: readonly FilterExpression<ErasedResourceHandle>[]) => {\n volatileRef.current.urlState.setFilters(next);\n }, []);\n\n /**\n * Raw builder-group write (Task 7). Same stable-identity discipline as\n * `setFilters` above — reads the live url-state through the volatile ref\n * so this callback's own identity never changes.\n */\n const setGroup = useCallback((next: FilterGroup) => {\n volatileRef.current.urlState.setFilterGroup(next);\n }, []);\n\n /**\n * Raw search write.\n *\n * ⚠️ Does NOT reset the page. The pre-lift page did `setPage(1);\n * setSearch(v)` — but from the JSX (`<ListSearchInput onCommit>`,\n * `_list-body.tsx:1382-1385`), and all JSX stays in the app for B1.\n * B1.3e must keep that composition (`onCommit={(v) => {\n * pagination.setPage(1); filters.setSearch(v); }}`), otherwise\n * searching from page 3 silently keeps the user on page 3.\n */\n const setSearch = useCallback((q: string) => {\n volatileRef.current.urlState.setSearch(q);\n }, []);\n\n /**\n * Atomically clear the free-form search, every URL-state column filter,\n * the builder group (Task 7) and the page cursor, then fire\n * `opts.onReset` for app-owned ephemeral UI (chip visibility).\n *\n * Moved from `clearAllFilters` (`_list-body.tsx:1332-1337`) with\n * `setVisibleIds(new Set())` replaced by the `onReset` seam. The\n * url-state setters fire in the same tick, so the url-state hook's\n * `pendingQsRef` merges them: each successive write observes the\n * previous one and the LAST URL is the fully-cleared one.\n *\n * ⚠️ Also clears `providerQuery` (Task 11): `setProviderQueryValue` is a\n * `useState` setter, which React guarantees a stable identity for across\n * renders — the same reason `providerQuery.set` itself (below) calls it\n * directly instead of going through `volatileRef`. Without this, \"Clear\n * all\" would leave a level-2 slot's raw provider query silently in force\n * even though {@link isFiltered} (which now factors it in) just told the\n * user there was nothing left to clear.\n */\n const clearAll = useCallback(() => {\n const { urlState: u, onReset } = volatileRef.current;\n u.setSearch('');\n u.setFilters([]);\n u.setFilterGroup(EMPTY_FILTER_GROUP);\n u.setPage(1);\n setProviderQueryValue(undefined);\n onReset?.();\n }, []);\n\n const setSort = useCallback((next: ResourceUrlState['sort']) => {\n volatileRef.current.urlState.setSort(next);\n }, []);\n\n /**\n * Header-click sort handler: the 3-click toggle. Moved verbatim from\n * the `<ResourceList onSort>` closure, `_list-body.tsx:1594-1614`.\n */\n const toggleSort = useCallback((field: string, direction?: 'asc' | 'desc' | null) => {\n const { urlState: u, sort: current } = volatileRef.current;\n u.setPage(1);\n // Explicit direction from the header menu wins; `undefined` keeps the\n // legacy toggle for any caller that still relies on it.\n if (direction !== undefined) {\n u.setSort(direction === null ? [] : [{ field, direction }]);\n return;\n }\n // The url-state hook's setSort accepts a value (not an updater), so we\n // branch off the current `sort` snapshot:\n // - new field → asc\n // - same field, currently asc → desc\n // - same field, currently desc → null (3rd click clears)\n const currentEntry = current[0];\n if (currentEntry?.field !== field) {\n u.setSort([{ field, direction: 'asc' }]);\n } else if (currentEntry.direction === 'asc') {\n u.setSort([{ field, direction: 'desc' }]);\n } else {\n u.setSort([]);\n }\n }, []);\n\n const setVisible = useCallback((next: string[] | undefined) => {\n volatileRef.current.urlState.setVisibleColumns(next ?? null);\n }, []);\n\n /**\n * Header-menu «hide»: drop the column from the visible set unless it is\n * a required column. Moved verbatim from the `<ResourceList\n * onHideColumn>` closure, `_list-body.tsx:1588-1593`.\n */\n const hide = useCallback((field: string) => {\n const { requiredColumns: required, visibleColumns: visible, urlState: u } = volatileRef.current;\n if (required.includes(field)) return;\n u.setVisibleColumns(visible.filter((c) => c !== field));\n }, []);\n\n /**\n * Both Columns-menu footer actions, parameterized (see the contract note\n * on {@link ResourceListController.columns}`.restoreDefaults`):\n * - `'sizes'` → the old `onResetSizes` (`_list-body.tsx:1455`): bump\n * the token in sizes mode only.\n * - `'all'` (default) → the old `onRestoreDefaults`\n * (`_list-body.tsx:1456-1461`): sizes + pins + order via the token,\n * AND clear visibility, AND clear sort.\n */\n const restoreDefaults = useCallback((mode: 'sizes' | 'all' = 'all') => {\n setResetLayout((r) => ({ token: r.token + 1, mode }));\n if (mode === 'all') {\n volatileRef.current.urlState.setVisibleColumns(null);\n volatileRef.current.urlState.setSort([]);\n }\n }, []);\n\n const clearSelection = useCallback(() => {\n setSelectedIds(NO_SELECTION);\n setSelectedCache(NO_CACHE);\n }, []);\n\n const setSelection = useCallback((ids: string[]) => {\n setSelectedIds(ids);\n // The cache is rebuilt from the incoming set on every change: newly\n // selected ids get a snapshot from the current page, kept ids keep the\n // one they already had, and deselected ids are pruned — so the cache\n // never outgrows the selection.\n setSelectedCache((prev) => {\n const currentRowsById = volatileRef.current.rowsById;\n const next: Record<string, RowRecord> = {};\n for (const id of ids) {\n const row = currentRowsById.get(id) ?? prev[id];\n if (row) next[id] = row;\n }\n const prevKeys = Object.keys(prev);\n const unchanged =\n prevKeys.length === Object.keys(next).length &&\n prevKeys.every((key) => prev[key] === next[key]);\n return unchanged ? prev : next;\n });\n }, []);\n\n /**\n * Apply a saved view — REPLACE pattern: every URL-state field is\n * unconditionally rewritten from the view's declared state, falling\n * back to the framework defaults for fields the view doesn't mention.\n * The url-state hook's same-tick batching merges all six setters.\n *\n * Also fires `opts.onReset` so app-owned chip visibility resets in step\n * — chips for fields the new view doesn't filter on should disappear,\n * and the toolbar re-adds chips for the new filter set on its own.\n *\n * ⚠️ SP0b Task 2 — reads `volatileRef.current.declaredDefaults`, the\n * SAME object passed to `useResourceUrlState` above, not the module\n * constant `URL_STATE_DEFAULTS`. A view that doesn't mention `pageSize`\n * (most don't — it's rarely part of what a saved view is FOR) must reset\n * to the RESOURCE's declared page size, not to a hardcoded framework\n * `10`; passing a second, independently-hardcoded default here would\n * silently drop the user back to 10 rows the moment they applied any\n * view on a resource that declared 100 — a regression that surfaces\n * three clicks in (apply → observe fine → apply a plainer view → page\n * size quietly changes) and is easy to miss in review.\n *\n * Moved from `applyView`, `_list-body.tsx:939-953`\n * (`setVisibleIds(new Set())` → the `onReset` seam).\n */\n const applyView = useCallback((view: SavedViewDef) => {\n applyViewToUrlState(view, volatileRef.current.urlState, {\n defaults: volatileRef.current.declaredDefaults,\n });\n volatileRef.current.onReset?.();\n }, []);\n\n /**\n * Snapshot the CURRENT url state and persist it as a new user view. No\n * `page` in the snapshot — a saved view is never a position within a\n * query's results (spec §12); `useSavedViews().saveCurrentAsView` drops\n * it unconditionally even if it were passed.\n *\n * ⚠️ I8 — this **rejects** (Task 8: the settings store is async, so\n * this whole chain is now too). `useSavedViews().saveCurrentAsView`\n * rejects on an empty label and on a failed store mutation (quota /\n * permission denied / conflict, `use-saved-views.ts`), and that\n * propagates unchanged. The `await` + try/catch, the toast, the label\n * input and the two dialogs all stay in the app (`handleSaveConfirm`,\n * `_list-body.tsx:960-978`) — no `@burojs/ui-shadcn` `toast` import\n * may cross into this package.\n *\n * Moved from `handleSaveConfirm`, minus the toast/label/dialog handling.\n */\n const saveCurrent = useCallback((label: string, scopeId?: string): Promise<SavedViewDef> => {\n const { urlState: u, saveCurrentAsView: save } = volatileRef.current;\n return save(\n label,\n {\n filters: u.filters,\n filterGroup: u.filterGroup,\n sort: u.sort,\n pageSize: u.pageSize,\n search: u.search,\n visibleColumns: u.visibleColumns,\n },\n scopeId,\n );\n }, []);\n\n const renameUser = useCallback((id: string, label: string): Promise<void> => {\n return volatileRef.current.renameUserView(id, label);\n }, []);\n\n const deleteUser = useCallback((id: string): Promise<void> => {\n return volatileRef.current.deleteUserView(id);\n }, []);\n\n /** Fork an entry into `scopeId` (Task 9 — spec §5's \"fork/copy into a writable scope\"). */\n const forkView = useCallback(\n (id: string, scopeId: string, label?: string): Promise<SavedViewDef> => {\n return volatileRef.current.forkUserView(id, scopeId, label);\n },\n [],\n );\n\n const refetch = useCallback(() => {\n volatileRef.current.refetch();\n }, []);\n\n const pauseLive = useCallback(() => setLivePaused(true), []);\n const resumeLive = useCallback(() => setLivePaused(false), []);\n\n /**\n * Cursor-mode load-more (B5.2). Guarded here rather than at the call\n * site so a consumer can wire it straight to `onClick` — a double-click\n * or a click during the fetch is a no-op, not a second page skipped.\n *\n * `hasNextPage` (not `next !== null`) is the gate on purpose: it is\n * react-query's own verdict, computed from the REAL page array, so while\n * a new query key's first page is in flight — the window in which\n * `placeholderData` is showing the previous key's pages — it is `false`\n * and this correctly refuses to advance a cursor that belongs to a query\n * that no longer exists.\n */\n const loadMore = useCallback(() => {\n const v = volatileRef.current;\n if (!v.hasNextPage || v.isFetchingNextPage) return;\n v.fetchNextPage();\n }, []);\n\n // `availability` is read through the volatile ref for the same reason every\n // other callback here is: this function must keep a stable identity or the\n // memoized table body re-renders on every parent render.\n const rowHref = useCallback((row: RowRecord) => {\n if (!volatileRef.current.isCurrentData) return undefined;\n const { registry, def: d, resource: r, availability: gate } = volatileRef.current;\n return rowHrefFor(registry, d, r, String(row.id), gate, row);\n }, []);\n\n // -------------------------------------------------------------------\n // Groups. Each is memoized on its own state values; the callbacks above\n // are permanently stable, so a group only changes when its DATA does.\n // -------------------------------------------------------------------\n\n const isLoading = isCursor ? cursorQuery.isLoading : offsetQuery.isLoading;\n const isFetching = isCursor ? cursorQuery.isFetching : offsetQuery.isFetching;\n const isPlaceholderData = isCursor\n ? cursorQuery.isPlaceholderData\n : offsetQuery.isPlaceholderData;\n const isCurrentData = isCursor ? cursorQuery.isCurrentData : offsetQuery.isCurrentData;\n volatileRef.current.isCurrentData = isCurrentData;\n // Pre-resolved to `null` when there is no error (`_list-body.tsx:1577`).\n const rawError = isCursor ? cursorQuery.error : offsetQuery.error;\n const error = rawError ? (rawError as unknown as Error) : null;\n const queryGroup = useMemo(\n () => ({ isLoading, isFetching, isPlaceholderData, isCurrentData, error, refetch }),\n [isLoading, isFetching, isPlaceholderData, isCurrentData, error, refetch],\n );\n\n // The provider's own count when it reports one, otherwise whatever the\n // user asked for on demand. ONE field, ONE absent-sentinel — see the\n // contract note on `pagination.total`.\n //\n // In cursor mode the LAST page carries it: a token provider that can\n // count at all reports the same total on every page, and reading the\n // freshest one means a total that moves as rows are added is not frozen\n // at page one. Temporal reports none, so this is `undefined` there and\n // the unknown-total contract holds unchanged.\n const lastCursorPage = cursorPages?.[cursorPages.length - 1];\n const total =\n countPolicy === 'off'\n ? undefined\n : countPolicy === 'provided'\n ? inlineTotal\n : countValue === null\n ? undefined\n : (inlineTotal ?? countValue);\n /**\n * `PAGE_SIZE_OPTIONS` plus the declared `views.list.pageSize`, merged in\n * when it isn't already one of the four base choices — otherwise a\n * resource declaring e.g. `pageSize: 30` gets a size selector with no\n * option matching its own default. Identity stays `PAGE_SIZE_OPTIONS`\n * itself (module scope) for every resource that declares nothing, or\n * whose declared value already appears in the base list.\n */\n const pageSizeOptions = useMemo(\n () =>\n declaredPageSize !== undefined && !PAGE_SIZE_OPTIONS.includes(declaredPageSize)\n ? [...PAGE_SIZE_OPTIONS, declaredPageSize].sort((a, b) => a - b)\n : PAGE_SIZE_OPTIONS,\n [declaredPageSize],\n );\n const pagination = useMemo(\n () => ({\n page,\n pageSize,\n pageSizeOptions,\n total,\n setPage,\n setPageSize,\n }),\n [page, pageSize, pageSizeOptions, total, setPage, setPageSize],\n );\n\n /**\n * The cursor group — `null` for every offset list, which is the\n * discriminator the contract documents.\n *\n * `next` is ANDed with react-query's `hasNextPage` so the token and the\n * ability to spend it can never disagree: a consumer rendering\n * `next !== null` and calling `loadMore()` always gets a page.\n *\n * ⚠️ Memoized, and `cursor` is a dep of the root memo below. An inline\n * `{ … }` literal would return a fresh object on every render and break\n * the identity contract at the root — which\n * `use-resource-list.test.tsx`'s three-re-render `Object.is` assertion\n * would catch, but only after it had already shipped a re-render storm\n * into every consumer's `useMemo` deps.\n */\n const cursorNext =\n isCursor && cursorQuery.hasNextPage ? (lastCursorPage?.pageInfo?.nextCursor ?? null) : null;\n const isLoadingMore = isCursor && cursorQuery.isFetchingNextPage;\n const cursor = useMemo(\n () => (isCursor ? { next: cursorNext, loadMore, isLoadingMore } : null),\n [isCursor, cursorNext, loadMore, isLoadingMore],\n );\n\n /**\n * The live-polling slice — present only when an interval is both declared\n * and applicable (offset pagination). `pause`/`resume` are permanently\n * stable (see `pauseLive`/`resumeLive` above), so this group changes only\n * when `isPaused` does, and is `undefined` (not present-but-inert) for\n * every resource that doesn't opt in — see the contract note on\n * `ResourceListController.live`.\n */\n const live = useMemo(\n () =>\n liveInterval !== null && !liveDisabledByCursor\n ? { intervalMs: liveInterval, isPaused: isLivePaused, pause: pauseLive, resume: resumeLive }\n : undefined,\n [liveInterval, liveDisabledByCursor, isLivePaused, pauseLive, resumeLive],\n );\n\n // `requestCount` is permanently stable, so this group changes only when\n // the affordance's own two booleans do — an inline literal here would\n // break the controller's identity contract on every render.\n const count = useMemo(\n () => ({ available: countAvailable, isLoading: countQuery.isFetching, request: requestCount }),\n [countAvailable, countQuery.isFetching, requestCount],\n );\n\n const filtersGroup = useMemo(\n () => ({\n value: urlFilters,\n set: setFilters,\n available,\n search,\n setSearch,\n isFiltered,\n clearAll,\n group: filterGroup,\n setGroup,\n fixed: fixedFilters,\n pinnedFields,\n }),\n [\n urlFilters,\n setFilters,\n available,\n search,\n setSearch,\n isFiltered,\n clearAll,\n filterGroup,\n setGroup,\n fixedFilters,\n pinnedFields,\n ],\n );\n\n const sorting = useMemo(\n () => ({ value: sort, set: setSort, toggle: toggleSort }),\n [sort, setSort, toggleSort],\n );\n\n const providerQuery = useMemo(\n () => ({ value: providerQueryValue, set: setProviderQuery }),\n [providerQueryValue, setProviderQuery],\n );\n\n const columns = useMemo(\n () => ({\n all: allAvailable,\n visible: visibleColumns,\n required: requiredColumns,\n optional: optionalColumns,\n defaultVisible: declaredColumns,\n setVisible,\n hide,\n resetLayout,\n restoreDefaults,\n }),\n [\n allAvailable,\n visibleColumns,\n requiredColumns,\n optionalColumns,\n declaredColumns,\n setVisible,\n hide,\n resetLayout,\n restoreDefaults,\n ],\n );\n\n // Selected records: the current page's row wins (it is fresh), a snapshot\n // covers everything the user picked on a page they have since left. An id\n // with neither is kept in `ids` but has no record to contribute, so\n // `records.length` can be shorter than `ids.length`.\n const selectedRecords = useMemo(() => {\n if (selectedIds.length === 0) return NO_ROWS;\n const out: RowRecord[] = [];\n for (const id of selectedIds) {\n const row = rowsById.get(id) ?? selectedCache[id];\n if (row) out.push(row);\n }\n return out;\n }, [rowsById, selectedCache, selectedIds]);\n const selection = useMemo(\n () => ({\n ids: selectedIds,\n records: selectedRecords,\n set: setSelection,\n clear: clearSelection,\n }),\n [selectedIds, selectedRecords, setSelection, clearSelection],\n );\n\n const savedViews = useMemo(\n () => ({\n adopter: adopterViews,\n user: userViews,\n entries: savedViewEntries,\n writeScopes: savedViewWriteScopes,\n issues: savedViewIssues,\n pending: savedViewsPending,\n apply: applyView,\n saveCurrent,\n renameUser,\n deleteUser,\n forkView,\n }),\n [\n adopterViews,\n userViews,\n savedViewEntries,\n savedViewWriteScopes,\n savedViewIssues,\n savedViewsPending,\n applyView,\n saveCurrent,\n renameUser,\n deleteUser,\n forkView,\n ],\n );\n\n // `createHref` is a plain string, so value equality is identity here.\n const createHref = resourceCreateHref(app.registry, def, resource);\n const routing = useMemo(() => ({ createHref, rowHref }), [createHref, rowHref]);\n\n return useMemo(\n () => ({\n resource,\n def,\n rows,\n query: queryGroup,\n pagination,\n live,\n cursor,\n count,\n filters: filtersGroup,\n sorting,\n columns,\n selection,\n savedViews,\n routing,\n providerQuery,\n }),\n [\n resource,\n def,\n rows,\n queryGroup,\n pagination,\n live,\n cursor,\n count,\n filtersGroup,\n sorting,\n columns,\n selection,\n savedViews,\n routing,\n providerQuery,\n ],\n );\n}\n","'use client';\nimport { type ReactElement, type ReactNode, createContext, useContext } from 'react';\nimport type { ResourceListController } from './types.js';\n\n/**\n * `ResourceListProvider` + `useResourceListContext` (core flexibility\n * program, Task B1.3c). This is the seam a later sub-project's list\n * \"slots\" (search box, filter toolbar, pagination footer, column menu, …)\n * will read the controller through, instead of a prop chain threaded by\n * hand through every intermediate component.\n *\n * The reason this earns its own task rather than being folded into\n * `useResourceList` itself (B1.3b): a slot built against\n * `useResourceListContext()` can be unit-tested by mounting\n * `<ResourceListProvider value={handWrittenStub}>` around it — no\n * `BuroProvider` or other app-level provider, no data provider, no\n * `next/navigation` mock, and no real `useResourceList` call at all — the\n * provider only ever hands out whatever `value` it was given. See\n * `tests/use-resource-list-context.test.tsx` for the proof; that\n * testability is the entire point of this file.\n *\n * @see docs/superpowers/plans/2026-07-26-cfb1-list-controller.md — Task B1.3c\n */\n\n/**\n * `null` means \"no provider mounted\". Not exported: consumers go through\n * {@link ResourceListProvider} to write and {@link useResourceListContext}\n * to read, matching this package's existing provider/hook pairs (compare\n * `AppContext` / `useApp`, `../context.js`).\n */\nconst ResourceListContext = createContext<ResourceListController | null>(null);\n\nexport interface ResourceListProviderProps {\n /**\n * The controller to hand to the tree beneath — typically the return\n * value of `useResourceList(resource, opts)`, but a plain hand-written\n * object satisfying {@link ResourceListController} works exactly as\n * well (that substitutability is what makes slot unit tests cheap).\n */\n value: ResourceListController;\n children?: ReactNode;\n}\n\n/**\n * Makes a {@link ResourceListController} available to the component tree\n * beneath it via {@link useResourceListContext}.\n */\nexport function ResourceListProvider({ value, children }: ResourceListProviderProps): ReactElement {\n return <ResourceListContext.Provider value={value}>{children}</ResourceListContext.Provider>;\n}\n\n/**\n * Read the nearest {@link ResourceListController} mounted via\n * {@link ResourceListProvider}. Throws when no provider is mounted rather\n * than degrading to an optional return: a slot has nothing meaningful to\n * render without a controller, so failing loudly at the read site beats\n * every caller re-deriving its own \"is this undefined?\" guard.\n */\nexport function useResourceListContext(): ResourceListController {\n const ctx = useContext(ResourceListContext);\n if (!ctx) {\n throw new Error('[useResourceListContext] must be used within a ResourceListProvider');\n }\n return ctx;\n}\n","/**\n * Shallow merge of components objects. Overrides keys win; both inputs unchanged.\n */\nexport function mergeComponents<\n TBase extends Record<string, unknown>,\n TOver extends Record<string, unknown>,\n>(base: TBase, overrides: TOver): TBase & TOver {\n return { ...base, ...overrides };\n}\n","import {\n type AppRuntime,\n canonicalEntityNodeKey,\n leafBasePath,\n resolveStaticAvailability,\n} from '@burojs/core';\nimport type { ReactElement } from 'react';\n\n/** A resource's list/show/edit/create route. */\nexport interface ResourceRouteDescriptor {\n resource: string;\n action: 'list' | 'show' | 'edit' | 'create';\n path: string;\n}\n\n/** A custom (non-resource) page's single route. */\nexport interface CustomPageRouteDescriptor {\n page: string;\n action: 'page';\n path: string;\n}\n\nexport type RouteDescriptor = ResourceRouteDescriptor | CustomPageRouteDescriptor;\n\n/**\n * Every URL the app expects to exist, for a host that mounts routes at\n * runtime (react-router, TanStack Router) rather than from files.\n *\n * Paths come from `leafBasePath` — the SAME derivation `hrefFor` uses for the\n * sidebar. That is the whole point: a resource or page inside nav groups gets\n * a nested URL (`/settings/integrations/webhook`), and if this function\n * derived its own simpler path the sidebar would link somewhere no route was\n * registered. Under Next the two could not drift, because routes are files the\n * app author places in the nested folder by hand; a runtime host mounts\n * exactly what this returns, so the two derivations have to be one derivation.\n *\n * Custom pages are included. They are a separate registry namespace, but a\n * runtime host still needs a route for each one, and their URLs derive from\n * the same group chain.\n */\nexport function generateRouteDescriptors(app: AppRuntime): RouteDescriptor[] {\n const descriptors: RouteDescriptor[] = [];\n for (const def of app.registry.list()) {\n const ref = def.ref;\n const resourceKey = canonicalEntityNodeKey(def);\n const base = leafBasePath(app.registry, def);\n // The STATIC form: route generation has no user, no record and no scope,\n // so it can only honour what is true for everyone. A dynamic denial dims\n // affordances; it does not remove routes.\n const has = (op: string) =>\n resolveStaticAvailability(app.registry, (ref ?? def.name) as string, op).state ===\n 'available';\n\n descriptors.push({ resource: resourceKey, action: 'list', path: base });\n if (has('show'))\n descriptors.push({ resource: resourceKey, action: 'show', path: `${base}/:id` });\n if (has('edit'))\n descriptors.push({ resource: resourceKey, action: 'edit', path: `${base}/:id/edit` });\n if (has('create'))\n descriptors.push({ resource: resourceKey, action: 'create', path: `${base}/create` });\n }\n for (const page of app.registry.customPages.list()) {\n const pageKey = canonicalEntityNodeKey(page);\n descriptors.push({\n page: pageKey,\n action: 'page',\n path: leafBasePath(app.registry, page),\n });\n }\n return descriptors;\n}\n\n/** Narrowing helper — `action: 'page'` is the discriminant. */\nexport function isCustomPageRoute(d: RouteDescriptor): d is CustomPageRouteDescriptor {\n return d.action === 'page';\n}\n\n/**\n * <BuroRoutes> placeholder. In v0.1, route mounting is on the user;\n * use generateRouteDescriptors to produce route descriptors and mount via\n * react-router or Next App Router. Full integration arrives in Plan 7.\n */\nexport function BuroRoutes(): ReactElement {\n return <></>;\n}\n","export const en = {\n validation: {\n requiredHint: '(required)',\n required: 'This field is required',\n },\n actions: {\n close: 'Close',\n clearSelection: 'Clear',\n create: 'Create',\n edit: 'Edit',\n delete: 'Delete',\n show: 'Open',\n auditLog: 'Audit log',\n save: 'Save',\n cancel: 'Cancel',\n refresh: 'Refresh',\n submit: 'Submit',\n ok: 'OK',\n confirm: 'Confirm',\n back: 'Back',\n next: 'Next',\n retry: 'Retry',\n saving: 'Saving…',\n creating: 'Creating…',\n submitting: 'Submitting…',\n validating: 'Validating…',\n // Overflow-menu chrome (Workstream B — actions overflow).\n more: 'More',\n column: 'Actions',\n openMenu: 'Open row actions menu',\n },\n confirm: {\n delete: 'Are you sure you want to delete?',\n deleteMany: 'Are you sure you want to delete {{count}} records?',\n discardChanges: 'Discard unsaved changes?',\n ok: 'OK',\n confirm: 'Confirm',\n },\n checks: {\n // Already neutral across surfaces (save / action / delete) — kept\n // verbatim; see the RU bundle's note, where the save-specific wording\n // had to be fixed.\n dialogTitle: 'Please review',\n proceed: 'Continue anyway',\n back: 'Go back',\n blocked: 'Cannot continue',\n exception: 'A check failed to run',\n parseError: 'Check \"{{checkId}}\" has an invalid condition: {{detail}}',\n },\n table: {\n selectedCount: '{{count}} selected',\n empty: 'No records',\n loading: 'Loading…',\n rowsSelected: '{{count}} selected',\n selectAllRows: 'Select all rows',\n selectRow: 'Select row',\n },\n // Show-page chrome. `groups.other` names the catch-all block that collects\n // fields no `views.fields` group claimed — see `resolveFieldLayout`\n // (`@burojs/core`). Despite the `show.*` bundle key, this default is now\n // consumed by BOTH the show page and the form (resource-form.tsx reads it\n // as the shared `otherLabel` fallback) — the key predates the form\n // growing its own grouped rendering and was left in place.\n show: {\n groups: {\n other: 'Other',\n },\n },\n boolean: {\n yes: 'Yes',\n no: 'No',\n active: 'Active',\n inactive: 'Inactive',\n },\n pagination: {\n showingUnknownTotal: 'Showing {{from}}–{{to}}',\n // The on-demand row-count trigger (Task B4.3). Deliberately the ONLY new\n // key: on success the total lands in `pagination.total` and `showing`\n // above renders the answer, and while the request is in flight the label\n // is replaced by a spinner in place — so there is neither a result string\n // nor a loading string to translate.\n countRows: 'Count rows',\n // Cursor (opaque-token) pagination — `<CursorLoadMore>` (Task B5.3).\n // A token list has no page count and no last page, so there is nothing\n // to number: the only affordance is \"give me the next page\".\n loadMore: 'Load more',\n loadingMore: 'Loading…',\n emptyPage: 'No records on this page',\n pageOnly: 'Page {{page}}',\n previous: 'Previous',\n next: 'Next',\n prev: 'Prev',\n pageOf: 'Page {{page}} of {{total}}',\n showing: 'Showing {{from}}–{{to}} of {{total}}',\n rowsPerPage: 'Rows per page',\n firstPage: 'Go to first page',\n previousPage: 'Go to previous page',\n nextPage: 'Go to next page',\n lastPage: 'Go to last page',\n },\n filters: {\n // Comparison operators stay as SYMBOLS in both locales. The round-6 finding\n // was about English WORDS («contains», «starts with») leaking into a Russian\n // UI; `>` `≥` `<` `≤` are mathematical notation, not English — they need no\n // translation, they are unambiguous, and they fit a narrow filter chip where\n // «больше или равно» does not. Translating them was an over-correction.\n operators: {\n eq: 'equals',\n ne: 'not equals',\n gt: '>',\n gte: '≥',\n lt: '<',\n lte: '≤',\n in: 'in',\n nin: 'not in',\n contains: 'contains',\n ncontains: 'not contains',\n between: 'between',\n nbetween: 'not between',\n null: 'is empty',\n nnull: 'is not empty',\n startswith: 'starts with',\n endswith: 'ends with',\n // The AST predicate vocabulary (`FilterPredicateOp`, `@burojs/core`)\n // used by the filter-builder row (Task 5) — newer and differently\n // named than the `FilterOperator` set above (`ne`/`nin`/`startswith`),\n // which stays as-is because `DataTableOperatorFilter` still reads it.\n // `eq`/`gt`/`gte`/`lt`/`lte`/`in`/`contains` are shared by both sets.\n neq: 'not equals',\n notIn: 'not in',\n startsWith: 'starts with',\n endsWith: 'ends with',\n isNull: 'is empty',\n isNotNull: 'is not empty',\n },\n clearAll: 'Clear filters',\n apply: 'Apply',\n clear: 'Clear',\n // Filter-builder panel (Task 6). Distinct from `clear` above (a per-row\n // value control's own \"clear this value\" action) — `reset` empties the\n // WHOLE draft but, unlike `clearAll`, does not apply anything; the user\n // still presses `apply` to make the empty state take effect.\n reset: 'Reset',\n // Filter button label (Task 6), e.g. \"Filters\" + the applied-row count.\n title: 'Filters',\n // An `in`/`notIn` predicate's array value on an applied-filter badge\n // (Task 6) — too many picks to list, so the badge reads \"`n` selected\"\n // instead.\n selectedCount: '{{count}} selected',\n is: 'is',\n isNot: 'is not',\n contains: 'contains',\n // Generic aria-label / placeholder / empty-selection text for a builder\n // row's value control (`filter-value-control.tsx` and its four\n // implementations) — deliberately field-agnostic, unlike `operators.*`.\n value: 'Value',\n // Field-aware accessible name for the SAME value controls (SP2\n // final-review finding 7) — used instead of `value` above whenever the\n // caller has a field label to give (every builder row; every pinned\n // control). `{{field}}` interpolates `FilterFieldSpec.label`.\n valueFor: 'Value for {{field}}',\n // aria-labels for a builder row's field/operator `Select` triggers\n // (finding 7) — otherwise two adjacent comboboxes per row announce as\n // unlabelled to a screen reader, indistinguishable from each other and\n // from every other row's.\n field: 'Field',\n operator: 'Operator',\n // Filter-builder group chrome (Task 5) — `where` precedes the first\n // row, `and`/`or` label the group's join (a toggle on row 2, read-only\n // text after). Task 6's `describeRow` reuses `and`/`or` to join a\n // folded nested group's rows on an applied-filter badge.\n where: 'Where',\n and: 'and',\n or: 'or',\n // Accessible name for that toggle. Its visible text is the single word\n // `and`/`or` — in Russian a single LETTER — which names neither what the\n // control is nor what pressing it does.\n toggleJoin: 'Join: {{current}} — activate to switch to {{next}}',\n addRow: 'Add filter',\n addGroup: 'Add group',\n removeRow: 'Remove filter',\n removeGroup: 'Remove group',\n },\n errors: {\n required: 'Required',\n invalid: 'Invalid value',\n tooLong: 'No more than {{max}} characters',\n tooShort: 'At least {{min}} characters',\n failed: 'Validation failed',\n validatorFailed: 'Could not validate the form. Please try again.',\n },\n // List-page chrome (empty / loading / error states). `{{items}}` is the\n // resource plural label, `{{item}}` the singular — both interpolated by the\n // caller (already lowercased where the original literal lowercased).\n list: {\n loadingShort: 'Loading…',\n notRegistered: 'Resource not registered',\n loading: 'Loading {{items}}…',\n errorTitle: 'Something went wrong',\n errorBody: 'Failed to load data. Please try again.',\n errorDetails: 'Details',\n emptyTitle: 'No {{items}} yet',\n emptyBody: 'Get started by creating your first {{item}}.',\n emptyFilteredTitle: 'No matching {{items}}',\n emptyFilteredBody:\n 'No {{items}} match the current filter. Try clearing the filter to see everything.',\n clearFilter: 'Clear filter',\n create: '+ Create {{item}}',\n // Template-discriminator cell: the row's `type` value matches no\n // registered template (null, empty, or a token the app doesn't know).\n templateUnknown: 'Unknown',\n // Generic search-box placeholder/label for a resource whose `views.list.search`\n // is a resolver (no single field to name — see `toolbar.searchBy` for the\n // declarative-field form).\n search: 'Search',\n },\n // Synthesized detail/show \"Details\" tab label (resources that declare other\n // tabs alongside the auto details tab). Resolved via `t('tab.details')`.\n tab: {\n details: 'Details',\n },\n // `component`-tab body fallbacks (unregistered slot / crash boundary).\n tabBody: {\n empty: 'Nothing to show here yet.',\n failed: 'This tab failed to load.',\n },\n // Sidebar top-level group label.\n breadcrumbs: {\n create: 'Create',\n edit: 'Edit',\n },\n nav: {\n skipToContent: 'Skip to content',\n resources: 'Resources',\n main: 'Main navigation',\n breadcrumb: 'Breadcrumb',\n // Accessible names for two controls that shipped untranslated: the\n // language switcher (which could not itself be translated) and the\n // sidebar toggle, whose `title` also renders as a hover tooltip.\n language: 'Language',\n toggleSidebar: 'Toggle sidebar',\n label: 'Navigation',\n },\n // PageHeader back-link + computed titles.\n pageHeader: {\n backTo: 'Back to {{label}}',\n editTitle: 'Edit {{label}}',\n editTitleNamed: 'Edit {{label}}: {{name}}',\n createTitle: 'Create {{label}}',\n },\n router: {\n emptyTitle: 'Nothing here',\n emptyBody: 'This page has no registered content.',\n notFoundTitle: 'Page not found',\n notFoundBody: \"This route doesn't match any registered page.\",\n },\n notifications: {\n region: 'Notifications',\n },\n create: {\n pickType: 'Pick a type to continue.',\n unsupportedType: 'Unsupported type',\n unsupportedTypeHint: 'The type “{{type}}” is not registered for this resource.',\n backToPicker: 'Back to picker',\n },\n // `<TaskRunPanel>` — progress and partial failure for work long enough to\n // watch. `partial` is the state nothing else in this framework names: the run\n // finished and still left units behind, which is neither a success nor a\n // failure and must not be reported as either.\n taskRun: {\n idle: 'Not started',\n running: 'Running',\n complete: 'Finished',\n partial: 'Finished, with refusals',\n stopped: 'Stopped',\n cancelled: 'Cancelled',\n count: '{{completed}} of {{total}}',\n countUnknownTotal: '{{completed}} done',\n },\n // Login / auth surfaces.\n auth: {\n invalidEmail: 'Invalid email',\n passwordRequired: 'Password required',\n invalidCredentials: 'Incorrect email or password.',\n signOut: 'Sign out',\n signIn: 'Sign in',\n signingIn: 'Signing in…',\n email: 'Email',\n password: 'Password',\n },\n // List / data-table toolbar controls.\n toolbar: {\n clearAll: 'Clear all',\n clearAllAria: 'Clear {{count}} active filters',\n addFilter: 'Add filter',\n filterBy: 'Filter by',\n columns: 'Columns',\n views: 'Views',\n viewsDefaults: 'Defaults',\n // The framework's own local-user scope (`buro:local-user`, Task 9)\n // — its data-layer label is a hardcoded placeholder (\"My settings\");\n // the UI recognizes that EXACT scope id and renders this reactive key\n // instead. Also doubles as the option label in the \"for whom?\" scope\n // picker. Every OTHER (adopter-supplied) scope label renders as-provided,\n // never through this key.\n viewsMyScope: 'Just me',\n viewsSaveCurrent: 'Save current view…',\n viewsManage: 'Manage views…',\n // Saved-view dialogs rendered by `<ResourceListPage>` — the\n // save-current prompt and the manage/delete list.\n viewsSaveTitle: 'Save current view',\n viewsSaveDescription:\n 'Pick a label. The view captures the current filters, sort, search, and visible columns.',\n viewsSavePlaceholder: 'e.g. Errors this week',\n viewsSaved: 'Saved view “{{label}}”',\n viewsSaveFailed: 'Could not save view (storage full or unavailable)',\n viewsDeleteFailed: 'Could not delete view (storage full or unavailable)',\n viewsManageTitle: 'Manage saved views',\n viewsManageDescription:\n 'Delete views you no longer need. Adopter-defined defaults are not editable here.',\n viewsManageEmpty: 'No saved views yet.',\n // Scope-selection dialog (Task 9, spec §5) — shown when saving/forking\n // a view and more than one write scope is available (\"for whom?\").\n viewsScopeDialogTitle: 'Save for…',\n viewsScopeDialogDescription: 'Choose where this view should be saved.',\n // Per-entry actions (Task 9), gated by `entry.permissions`.\n viewsRename: 'Rename',\n viewsRenameTitle: 'Rename view',\n viewsRenameDescription: 'Pick a new label for this view.',\n viewsRenameFailed: 'Could not rename view (storage full or unavailable)',\n viewsFork: 'Fork',\n viewsForkFailed: 'Could not fork view (storage full or unavailable)',\n // Shown next to an entry whose permissions grant none of update/remove/\n // fork — the adapter has made it immutable for this user.\n viewsReadOnly: 'Read-only',\n // Adapter-reported issues (Task 9, spec §13) — rendered without hiding\n // the otherwise-valid entries that loaded fine.\n viewsIssuesNotice: 'Some views could not be loaded.',\n resetToDefaults: 'Reset to defaults',\n resetSizes: 'Reset column widths',\n restoreDefaults: 'Restore defaults',\n search: 'Search {{name}}…',\n searchBy: 'Search by {{name}}…',\n // Live-list pause toggle. Rendered only for a resource that declares\n // `views.list.refetchInterval` — a page that changes under the\n // operator's hands has to say so, and let them stop it.\n liveOn: 'Auto-refresh: on',\n liveOff: 'Auto-refresh: off',\n },\n // Shared field-input chrome (select / combobox / enum pickers).\n field: {\n removeFile: 'Remove file',\n pickFile: 'Pick or drop a file',\n dropHint: 'Click to pick a file or drag-and-drop',\n dismiss: 'Dismiss',\n waitingForSave: 'waiting for save',\n select: 'Select…',\n loading: 'Loading…',\n },\n // Form chrome (system-field disclosure on create/edit/show forms).\n form: {\n systemFields: 'System fields (read-only)',\n validating: 'Validating',\n wizardProgress: 'Wizard progress',\n },\n // Relation picker (typeahead combobox on edit/create forms).\n relation: {\n select: 'Select {{name}}…',\n failed: 'Failed to load options.',\n noResults: 'No results.',\n },\n // Command palette (⌘K) chrome — group headings, search placeholder, and\n // the empty-state + footer hints rendered by the `<CommandPalette*>` family\n // in @burojs/ui-shadcn. Each component falls back to these English\n // defaults when rendered outside a `BuroProvider`.\n columnMenu: {\n sortSection: 'Sort',\n sortAsc: 'Ascending',\n sortDesc: 'Descending',\n clearSort: 'Clear',\n pinSection: 'Pin',\n pinLeft: 'Left',\n pinRight: 'Right',\n unpin: 'Unpin',\n moveSection: 'Move',\n moveLeft: 'Left',\n moveRight: 'Right',\n hide: 'Hide column',\n },\n navGuard: {\n title: 'Unsaved changes',\n body: 'You have unsaved changes on this page. If you leave now, they will be lost.',\n stay: 'Stay',\n leave: 'Leave without saving',\n },\n relationPicker: {\n viewAll: 'Open list',\n clear: 'Clear',\n advancedSearch: 'Advanced search',\n title: 'Select: {{name}}',\n create: 'Create',\n select: 'Select',\n prev: 'Prev',\n next: 'Next',\n page: 'Page {{page}}',\n },\n draft: {\n found: 'Draft found from {{time}}.',\n restorePrompt: 'Restore?',\n restore: 'Restore',\n discard: 'Discard',\n timeAgoMoment: 'a moment ago',\n timeAgoMinutes: '{{n}} minutes ago',\n timeAgoHours: '{{n}} hours ago',\n timeAgoDays: '{{n}} days ago',\n timeAgoRecently: 'recently',\n },\n commandPalette: {\n title: 'Command Palette',\n description: 'Search and run actions.',\n actions: 'Actions',\n create: 'Create',\n createNew: 'Create new',\n recent: 'Recent',\n records: 'Records',\n resources: 'Resources',\n pages: 'Pages',\n search: 'Search…',\n empty: 'No matches found.',\n emptyHint: 'Try a different search or open a resource from the navigation.',\n navigate: 'Navigate',\n select: 'Select',\n close: 'Close',\n // Header trigger chip that opens the palette.\n trigger: 'Search',\n triggerHint: 'Open command palette (⌘K / Ctrl+K)',\n searchEverything: 'Search resources, pages, records, actions…',\n },\n // Rich-text editor toolbar. These are all `aria-label`s (plus the link\n // dialog), so they are announced by screen readers — user-facing text that\n // shipped hardcoded in English. Keyboard hints stay literal in both locales.\n richText: {\n loadingDisplay: 'Loading rich text display',\n loadingEditor: 'Loading rich text editor',\n toolbar: 'Rich text formatting',\n bold: 'Bold (Ctrl+B)',\n italic: 'Italic (Ctrl+I)',\n paragraph: 'Paragraph (Ctrl+Alt+0)',\n heading1: 'Heading 1 (Ctrl+Alt+1)',\n heading2: 'Heading 2 (Ctrl+Alt+2)',\n heading3: 'Heading 3 (Ctrl+Alt+3)',\n bulletList: 'Bullet list (Ctrl+Shift+8)',\n orderedList: 'Ordered list (Ctrl+Shift+7)',\n editLink: 'Edit link (Ctrl+K)',\n insertLink: 'Insert link (Ctrl+K)',\n addLinkTitle: 'Add link',\n url: 'URL',\n },\n // Contextual-documentation chrome. Namespaced `docPanel`, deliberately NOT\n // `doc`: the `resolveKey` chain falls through to `common.<key>` as its last\n // step, so a `common.doc.summary` here would make EVERY undocumented entity\n // in the app sprout a popover.\n docPanel: {\n openFor: 'Help: {{name}}',\n opensInNewTab: '(opens in a new tab)',\n readMore: 'Read more',\n title: 'Help',\n topics: 'Topics',\n back: 'Back to the list',\n close: 'Close help',\n loading: 'Loading…',\n loadFailed: 'This article could not be loaded.',\n empty: 'Nothing is documented here yet.',\n noTranslation: 'Not translated yet — showing the {{locale}} version.',\n kindExplanation: 'About',\n kindHowTo: 'How to',\n kindFaq: 'Common questions',\n kindReference: 'Reference',\n search: 'Search help',\n glossary: 'Glossary',\n areas: 'Areas',\n copyLink: 'Copy link to this section',\n linkCopied: 'Link copied',\n openForArea: 'Help for this section',\n expand: 'Expand to the full page',\n collapse: 'Collapse the panel',\n pickTopic: 'Pick a topic to read it.',\n noMatches: 'Nothing matches that.',\n },\n // The availability gate's own chrome: the generic denial toast shown when a\n // rule disables an action/field but supplies no `reason` of its own.\n availability: {\n denied: \"This action isn't available\",\n },\n // `<ExportDialog>` (`@burojs/ui-shadcn`) and its background/cancel close\n // flow.\n //\n // `export.format.<id>` is deliberately ABSENT for the format's own NAME —\n // an `ExportFormat.label` is `LocalizedText` (a plain string or a\n // `{locale: string}` map), not a bundle key, so 'CSV'/'JSON' render via\n // `resolveLocalizedText` instead (see `packages/export/src/encoders/csv.ts`).\n // That exemption covers ONLY `ExportFormat.label`. A format's OPTION FIELDS\n // are ordinary declarative-form fields whose `label` is a\n // `LocalizedMessage`, i.e. it CAN be a `{key, fallback}` reference — and\n // `csvFormat()`'s delimiter field is exactly that, so its keys live here\n // (`export.format.csv.preset.*`) like any other translatable string.\n export: {\n format: {\n csv: {\n preset: {\n label: 'Delimiter',\n option: {\n semicolon: 'Semicolon (;)',\n comma: 'Comma (,)',\n tab: 'Tab',\n },\n },\n },\n },\n dialog: {\n titleFilter: 'Export {{count}} rows by current filter',\n /** `estimatedCount` is optional on `ExportDialogProps` — shown when a filter-scope export has no known row estimate. */\n titleFilterUnknownCount: 'Export rows by current filter',\n titleSelected: 'Export {{count}} selected rows',\n /** Defensive fallback: Task 8 gates the trigger on `available` before opening, so this is only reachable from a direct/programmatic mount. */\n unavailable: 'Export is not available for this resource.',\n /** Shown in place of the format selector while a deferred exporter registration (`ExporterLoader`) is still loading. */\n loading: 'Preparing export…',\n format: 'Format',\n columns: 'Columns',\n columnsVisible: 'As on the page',\n columnsAll: 'All columns',\n sortWarning: 'Sorting is not applied to the exported file.',\n start: 'Start export',\n progressIndeterminate: 'Exporting…',\n progress: 'Exporting… {{done}}/{{total}}',\n download: 'Download',\n failed: 'Export failed',\n canceled: 'Export canceled.',\n confirmCloseTitle: 'Export in progress',\n confirmCloseMessage:\n 'The export is still running. Stop it, or let it continue in the background?',\n stop: 'Stop export',\n continue: 'Continue in background',\n },\n continuesInBackground: 'The export continues in the background.',\n /** Toolbar/bulk-bar Export entry points (Task 8). Shared by both — the same action, two scopes. */\n button: {\n label: 'Export',\n },\n /** `useExportRunWatcher()` background-completion toasts (Task 8). */\n toast: {\n succeeded: 'Export ready',\n download: 'Download',\n failed: 'Export failed: {{message}}',\n },\n },\n // Success notification for the framework-synthesized built-in item actions\n // (`withBuiltinItemActions`) — currently just `delete`.\n notify: {\n deleted: 'Record deleted',\n },\n} as const;\n","export const ru = {\n validation: {\n requiredHint: '(обязательное)',\n required: 'Обязательное поле',\n },\n actions: {\n close: 'Закрыть',\n clearSelection: 'Снять выделение',\n create: 'Создать',\n edit: 'Изменить',\n delete: 'Удалить',\n show: 'Открыть',\n auditLog: 'Журнал аудита',\n save: 'Сохранить',\n cancel: 'Отмена',\n refresh: 'Обновить',\n submit: 'Отправить',\n ok: 'ОК',\n confirm: 'Подтвердить',\n back: 'Назад',\n next: 'Далее',\n retry: 'Повторить',\n saving: 'Сохранение…',\n creating: 'Создание…',\n submitting: 'Отправка…',\n validating: 'Проверка…',\n // Overflow-menu chrome (Workstream B — actions overflow).\n more: 'Ещё',\n column: 'Действия',\n openMenu: 'Открыть меню действий',\n },\n confirm: {\n delete: 'Удалить запись?',\n deleteMany: 'Удалить {{count}} записей?',\n discardChanges: 'Отменить изменения?',\n ok: 'ОК',\n confirm: 'Подтвердить',\n },\n checks: {\n // Neutral across surfaces: the SAME dialog gates saves, actions and\n // deletes (`CheckConfirmDialog`), so a save-specific title read wrong\n // above «Удалить: X?» on the delete surface. A host that wants\n // surface-specific wording passes `title` to the dialog (the action\n // button does exactly that, with the action's own label).\n dialogTitle: 'Проверьте перед продолжением',\n proceed: 'Всё равно продолжить',\n back: 'Вернуться',\n blocked: 'Продолжить нельзя',\n exception: 'Проверка не выполнилась',\n parseError: 'Правило «{{checkId}}» задано неверно: {{detail}}',\n },\n table: {\n selectedCount: 'Выбрано: {{count}}',\n empty: 'Нет записей',\n loading: 'Загрузка…',\n rowsSelected: 'Выбрано: {{count}}',\n selectAllRows: 'Выбрать все строки',\n selectRow: 'Выбрать строку',\n },\n // Чрома страницы просмотра. `groups.other` — заголовок блока, в который\n // попадают поля, не названные ни в одной группе `views.fields` (см.\n // `resolveFieldLayout`, `@burojs/core`). Несмотря на ключ `show.*`, это\n // значение теперь используется и формой (resource-form.tsx читает его как\n // общий fallback `otherLabel`), не только страницей просмотра — ключ\n // остался от времён, когда группировка была только на show.\n show: {\n groups: {\n other: 'Прочее',\n },\n },\n boolean: {\n yes: 'Да',\n no: 'Нет',\n active: 'Активно',\n inactive: 'Неактивно',\n },\n pagination: {\n showingUnknownTotal: 'Показаны {{from}}–{{to}}',\n countRows: 'Посчитать',\n loadMore: 'Показать ещё',\n loadingMore: 'Загрузка…',\n emptyPage: 'На этой странице нет записей',\n pageOnly: 'Стр. {{page}}',\n previous: 'Назад',\n next: 'Вперёд',\n prev: 'Назад',\n pageOf: 'Стр. {{page}} из {{total}}',\n showing: 'Показаны {{from}}–{{to}} из {{total}}',\n rowsPerPage: 'Строк на странице',\n firstPage: 'В начало',\n previousPage: 'Предыдущая страница',\n nextPage: 'Следующая страница',\n lastPage: 'В конец',\n },\n filters: {\n // Comparison operators stay as SYMBOLS in both locales. The round-6 finding\n // was about English WORDS («contains», «starts with») leaking into a Russian\n // UI; `>` `≥` `<` `≤` are mathematical notation, not English — they need no\n // translation, they are unambiguous, and they fit a narrow filter chip where\n // «больше или равно» does not. Translating them was an over-correction.\n operators: {\n eq: 'равно',\n ne: 'не равно',\n gt: '>',\n gte: '≥',\n lt: '<',\n lte: '≤',\n in: 'входит в',\n nin: 'не входит в',\n contains: 'содержит',\n ncontains: 'не содержит',\n between: 'между',\n nbetween: 'не между',\n null: 'не заполнено',\n nnull: 'заполнено',\n startswith: 'начинается с',\n endswith: 'заканчивается на',\n // AST predicate vocabulary (`FilterPredicateOp`) — see the matching\n // comment in en.ts. `eq`/`gt`/`gte`/`lt`/`lte`/`in`/`contains` are\n // shared with the set above.\n neq: 'не равно',\n notIn: 'не входит в',\n startsWith: 'начинается с',\n endsWith: 'заканчивается на',\n isNull: 'не заполнено',\n isNotNull: 'заполнено',\n },\n clearAll: 'Сбросить фильтры',\n apply: 'Применить',\n clear: 'Сбросить',\n // Filter-builder panel (Task 6) — see the matching comment in en.ts:\n // empties the whole draft without applying it.\n reset: 'Сбросить',\n title: 'Фильтры',\n selectedCount: 'Выбрано: {{count}}',\n is: 'равно',\n isNot: 'не равно',\n contains: 'содержит',\n value: 'Значение',\n // See the matching comment in en.ts (SP2 final-review finding 7).\n valueFor: 'Значение для {{field}}',\n field: 'Поле',\n operator: 'Оператор',\n where: 'Где',\n and: 'и',\n or: 'или',\n // See the matching comment in en.ts.\n toggleJoin: 'Связка: {{current}} — нажмите, чтобы переключить на {{next}}',\n addRow: 'Добавить фильтр',\n addGroup: 'Добавить группу',\n removeRow: 'Удалить фильтр',\n removeGroup: 'Удалить группу',\n },\n errors: {\n required: 'Обязательное поле',\n invalid: 'Неверное значение',\n tooLong: 'Не более {{max}} символов',\n tooShort: 'Не менее {{min}} символов',\n // Fallback when an adopter validator throws, or a schema reports an issue\n // with no message of its own. Shipped as English 'Validation failed'.\n failed: 'Проверка не пройдена',\n validatorFailed: 'Не удалось проверить форму. Попробуйте ещё раз.',\n },\n // List-page chrome (empty / loading / error states). `{{items}}` is the\n // resource plural label, `{{item}}` the singular — both interpolated by the\n // caller (already lowercased where the original literal lowercased).\n list: {\n loadingShort: 'Загрузка…',\n notRegistered: 'Ресурс не зарегистрирован',\n loading: 'Загрузка…',\n errorTitle: 'Что-то пошло не так',\n errorBody: 'Не удалось загрузить данные. Попробуйте ещё раз.',\n errorDetails: 'Подробности',\n emptyTitle: 'Пока нет записей',\n emptyBody: 'Создайте первую запись, чтобы начать.',\n emptyFilteredTitle: 'Ничего не найдено',\n emptyFilteredBody:\n 'Ни одна запись не соответствует текущему фильтру. Сбросьте фильтр, чтобы увидеть все.',\n clearFilter: 'Сбросить фильтр',\n create: '+ Создать {{item}}',\n // Template-discriminator cell: the row's `type` value matches no\n // registered template (null, empty, or a token the app doesn't know).\n templateUnknown: 'Неизвестный',\n // Generic search-box placeholder/label for a resource whose `views.list.search`\n // is a resolver (no single field to name — see `toolbar.searchBy` for the\n // declarative-field form).\n search: 'Поиск',\n },\n // Synthesized detail/show \"Details\" tab label (resources that declare other\n // tabs alongside the auto details tab). Resolved via `t('tab.details')`.\n tab: {\n details: 'Основное',\n },\n // `component`-tab body fallbacks (unregistered slot / crash boundary).\n tabBody: {\n empty: 'Здесь пока ничего нет.',\n failed: 'Не удалось загрузить вкладку.',\n },\n // Sidebar top-level group label.\n breadcrumbs: {\n create: 'Создание',\n edit: 'Изменение',\n },\n nav: {\n skipToContent: 'Перейти к содержимому',\n resources: 'Ресурсы',\n main: 'Основная навигация',\n breadcrumb: 'Хлебные крошки',\n // Accessible names for two controls that shipped untranslated: the\n // language switcher (which could not itself be translated) and the\n // sidebar toggle, whose `title` also renders as a hover tooltip.\n language: 'Язык',\n toggleSidebar: 'Свернуть меню',\n // Accessible name for the mobile nav sheet (a Radix Dialog, which\n // requires a title). Screen-reader-only, and it was English.\n label: 'Навигация',\n },\n // PageHeader back-link + computed titles.\n pageHeader: {\n // Deliberately does NOT interpolate the resource label. The label is\n // nominative («Документы»), while «Назад к …» requires the dative\n // («к документам») — and a framework has no business shipping a Russian\n // declension engine to fix one link. Naming the destination generically is\n // correct in every case and reads naturally; EN keeps the label, where\n // «Back to Documents» needs no inflection.\n backTo: 'Назад к списку',\n editTitle: 'Изменить {{label}}',\n editTitleNamed: 'Изменить {{label}}: {{name}}',\n // Colon form on purpose: `label.single` is capitalised for standalone\n // headings («Документ»), so «Создать Документ» reads wrong mid-sentence,\n // and auto-lowercasing a label is not safe in general. The colon also\n // scales to a typed create — «Создать: Заказ кодов».\n createTitle: 'Создать: {{label}}',\n },\n // Fallback states rendered by the resource page router when a route\n // resolves to nothing. Both shipped as hardcoded English.\n router: {\n emptyTitle: 'Здесь пока пусто',\n emptyBody: 'Для этой страницы не зарегистрировано содержимое.',\n notFoundTitle: 'Страница не найдена',\n notFoundBody: 'Этот адрес не соответствует ни одной зарегистрированной странице.',\n },\n notifications: {\n region: 'Уведомления',\n },\n create: {\n pickType: 'Выберите тип, чтобы продолжить.',\n unsupportedType: 'Неподдерживаемый тип',\n unsupportedTypeHint: 'Тип «{{type}}» не зарегистрирован для этого ресурса.',\n backToPicker: 'Назад к выбору типа',\n },\n // `<TaskRunPanel>` — см. en.ts.\n taskRun: {\n idle: 'Не запущено',\n running: 'Выполняется',\n complete: 'Готово',\n partial: 'Готово, часть не выполнена',\n stopped: 'Остановлено',\n cancelled: 'Отменено',\n count: '{{completed}} из {{total}}',\n countUnknownTotal: 'выполнено: {{completed}}',\n },\n // Login / auth surfaces.\n auth: {\n invalidEmail: 'Некорректный адрес',\n passwordRequired: 'Введите пароль',\n invalidCredentials: 'Неверный адрес или пароль.',\n signOut: 'Выйти',\n signIn: 'Войти',\n signingIn: 'Вход…',\n email: 'Эл. почта',\n password: 'Пароль',\n },\n // List / data-table toolbar controls.\n toolbar: {\n clearAll: 'Очистить всё',\n clearAllAria: 'Очистить фильтры: {{count}}',\n addFilter: 'Добавить фильтр',\n filterBy: 'Фильтровать по',\n columns: 'Колонки',\n views: 'Представления',\n viewsDefaults: 'По умолчанию',\n // Собственный локальный скоуп фреймворка (`buro:local-user`, задача 9)\n // — на уровне данных у него плейсхолдер-лейбл (\"My settings\"); интерфейс\n // распознаёт ИМЕННО этот id скоупа и вместо него показывает этот\n // реактивный ключ. Также используется как подпись варианта в диалоге\n // выбора «для кого». Любой ДРУГОЙ (заданный адаптером) лейбл скоупа\n // выводится как есть, никогда через этот ключ.\n viewsMyScope: 'Только я',\n viewsSaveCurrent: 'Сохранить текущее…',\n viewsManage: 'Управление представлениями…',\n // Saved-view dialogs rendered by `<ResourceListPage>` — the\n // save-current prompt and the manage/delete list.\n viewsSaveTitle: 'Сохранить текущее представление',\n viewsSaveDescription:\n 'Укажите название. Представление сохранит текущие фильтры, сортировку, поиск и набор колонок.',\n viewsSavePlaceholder: 'например, Ошибки за неделю',\n viewsSaved: 'Представление «{{label}}» сохранено',\n viewsSaveFailed: 'Не удалось сохранить представление (хранилище переполнено или недоступно)',\n viewsDeleteFailed: 'Не удалось удалить представление (хранилище переполнено или недоступно)',\n viewsManageTitle: 'Управление представлениями',\n viewsManageDescription:\n 'Удалите ненужные представления. Встроенные по умолчанию здесь не редактируются.',\n viewsManageEmpty: 'Пока нет сохранённых представлений.',\n // Диалог выбора скоупа (задача 9, спецификация §5) — показывается при\n // сохранении/копировании представления, если доступно больше одного\n // скоупа для записи («для кого?»).\n viewsScopeDialogTitle: 'Сохранить для…',\n viewsScopeDialogDescription: 'Выберите, куда сохранить это представление.',\n // Действия для конкретной записи (задача 9), доступность определяется\n // `entry.permissions`.\n viewsRename: 'Переименовать',\n viewsRenameTitle: 'Переименовать представление',\n viewsRenameDescription: 'Укажите новое название для этого представления.',\n viewsRenameFailed:\n 'Не удалось переименовать представление (хранилище переполнено или недоступно)',\n viewsFork: 'Копировать себе',\n viewsForkFailed: 'Не удалось скопировать представление (хранилище переполнено или недоступно)',\n // Показывается рядом с записью, для которой запрещены все действия —\n // изменение, удаление и копирование (адаптер сделал её неизменяемой для\n // текущего пользователя).\n viewsReadOnly: 'Только для чтения',\n // Проблемы, о которых сообщил адаптер (задача 9, спецификация §13) —\n // отображаются, не скрывая остальные успешно загруженные записи.\n viewsIssuesNotice: 'Не удалось загрузить некоторые представления.',\n resetToDefaults: 'Сбросить настройки',\n resetSizes: 'Сбросить размеры колонок',\n restoreDefaults: 'Восстановить по умолчанию',\n search: 'Поиск: {{name}}…',\n searchBy: 'Поиск по: {{name}}…',\n // Live-list pause toggle. Rendered only for a resource that declares\n // `views.list.refetchInterval` — a page that changes under the\n // operator's hands has to say so, and let them stop it.\n liveOn: 'Авто-обновление: вкл',\n liveOff: 'Авто-обновление: выкл',\n },\n // Shared field-input chrome (select / combobox / enum pickers).\n field: {\n removeFile: 'Удалить файл',\n pickFile: 'Выберите файл или перетащите его сюда',\n dropHint: 'Нажмите, чтобы выбрать файл, или перетащите его сюда',\n dismiss: 'Скрыть',\n waitingForSave: 'ожидает сохранения',\n select: 'Выберите…',\n loading: 'Загрузка…',\n },\n // Form chrome (system-field disclosure on create/edit/show forms).\n form: {\n systemFields: 'Системные поля (только чтение)',\n validating: 'Проверка',\n wizardProgress: 'Ход заполнения',\n },\n // Relation picker (typeahead combobox on edit/create forms).\n relation: {\n // The field's own label sits directly above the control, so repeating it\n // inside the placeholder is redundant — and in Russian it also forces a\n // case the template cannot decline («Выберите: локация…»). Same wording as\n // `field.select` keeps every picker on the form consistent.\n select: 'Выберите…',\n failed: 'Не удалось загрузить варианты.',\n noResults: 'Ничего не найдено.',\n },\n // Command palette (⌘K) chrome — group headings, search placeholder, and\n // the empty-state + footer hints rendered by the `<CommandPalette*>` family\n // in @burojs/ui-shadcn. Each component falls back to the English defaults\n // (en.ts) when rendered outside a `BuroProvider`.\n columnMenu: {\n sortSection: 'Сортировка',\n sortAsc: 'По возрастанию',\n sortDesc: 'По убыванию',\n clearSort: 'Сбросить',\n pinSection: 'Закрепление',\n pinLeft: 'Слева',\n pinRight: 'Справа',\n unpin: 'Открепить',\n moveSection: 'Перемещение',\n moveLeft: 'Влево',\n moveRight: 'Вправо',\n hide: 'Скрыть колонку',\n },\n navGuard: {\n title: 'Несохранённые изменения',\n body: 'На этой странице есть несохранённые изменения. Если уйти сейчас, они будут потеряны.',\n stay: 'Остаться',\n leave: 'Уйти без сохранения',\n },\n relationPicker: {\n viewAll: 'Открыть список',\n clear: 'Очистить',\n advancedSearch: 'Расширенный поиск',\n title: 'Выбор: {{name}}',\n create: 'Создать',\n select: 'Выбрать',\n prev: 'Назад',\n next: 'Вперёд',\n page: 'Стр. {{page}}',\n },\n draft: {\n found: 'Найден черновик, сохранённый {{time}}.',\n restorePrompt: 'Восстановить?',\n restore: 'Восстановить',\n discard: 'Отклонить',\n timeAgoMoment: 'только что',\n timeAgoMinutes: '{{n}} мин назад',\n timeAgoHours: '{{n}} ч назад',\n timeAgoDays: '{{n}} дн назад',\n timeAgoRecently: 'недавно',\n },\n commandPalette: {\n title: 'Палитра команд',\n description: 'Поиск и запуск действий.',\n actions: 'Действия',\n create: 'Создать',\n createNew: 'Создать',\n recent: 'Недавние',\n records: 'Записи',\n resources: 'Разделы',\n pages: 'Страницы',\n search: 'Поиск…',\n empty: 'Ничего не найдено',\n emptyHint: 'Измените запрос или откройте раздел из навигации.',\n navigate: 'Навигация',\n select: 'Выбрать',\n close: 'Закрыть',\n // Header trigger chip that opens the palette.\n trigger: 'Поиск',\n triggerHint: 'Открыть командную панель (⌘K / Ctrl+K)',\n searchEverything: 'Поиск по разделам, страницам, записям и действиям…',\n },\n // Rich-text editor toolbar. These are all `aria-label`s (plus the link\n // dialog), so they are announced by screen readers — user-facing text that\n // shipped hardcoded in English. Keyboard hints stay literal in both locales.\n richText: {\n loadingDisplay: 'Загрузка форматированного текста',\n loadingEditor: 'Загрузка редактора форматированного текста',\n toolbar: 'Форматирование текста',\n bold: 'Полужирный (Ctrl+B)',\n italic: 'Курсив (Ctrl+I)',\n paragraph: 'Абзац (Ctrl+Alt+0)',\n heading1: 'Заголовок 1 (Ctrl+Alt+1)',\n heading2: 'Заголовок 2 (Ctrl+Alt+2)',\n heading3: 'Заголовок 3 (Ctrl+Alt+3)',\n bulletList: 'Маркированный список (Ctrl+Shift+8)',\n orderedList: 'Нумерованный список (Ctrl+Shift+7)',\n editLink: 'Изменить ссылку (Ctrl+K)',\n insertLink: 'Вставить ссылку (Ctrl+K)',\n addLinkTitle: 'Добавить ссылку',\n url: 'URL',\n },\n // См. комментарий в en.ts: namespace `docPanel`, а не `doc` — иначе\n // `common.doc.summary` заставил бы каждую недокументированную сущность\n // показать поповер.\n docPanel: {\n openFor: 'Справка: {{name}}',\n opensInNewTab: '(открывается в новой вкладке)',\n readMore: 'Подробнее',\n title: 'Справка',\n topics: 'Разделы',\n back: 'К списку разделов',\n close: 'Закрыть справку',\n loading: 'Загрузка…',\n loadFailed: 'Не удалось загрузить статью.',\n empty: 'Здесь пока ничего не задокументировано.',\n noTranslation: 'Перевода пока нет — показан вариант на {{locale}}.',\n kindExplanation: 'О сущности',\n kindHowTo: 'Как сделать',\n kindFaq: 'Частые вопросы',\n kindReference: 'Справочник',\n search: 'Поиск по справке',\n glossary: 'Глоссарий',\n areas: 'Разделы',\n copyLink: 'Скопировать ссылку на этот раздел',\n linkCopied: 'Ссылка скопирована',\n openForArea: 'Справка по этому разделу',\n expand: 'Развернуть на всю страницу',\n collapse: 'Свернуть панель',\n pickTopic: 'Выберите раздел, чтобы прочитать.',\n noMatches: 'Ничего не найдено.',\n },\n // Собственный чром шлюза доступности: общий текст отказа, показываемый\n // тостом, когда правило запрещает действие/поле, но не задаёт свой `reason`.\n availability: {\n denied: 'Действие недоступно',\n },\n // `<ExportDialog>` (`@burojs/ui-shadcn`) и его сценарий закрытия во время\n // выполнения экспорта.\n //\n // Ключа с НАЗВАНИЕМ формата (`export.format.<id>`) здесь намеренно нет:\n // `ExportFormat.label` это `LocalizedText` (строка или карта локалей), а не\n // ключ бандла, поэтому «CSV»/«JSON» рендерятся через `resolveLocalizedText`\n // (см. `packages/export/src/encoders/csv.ts`). Это исключение касается\n // ТОЛЬКО `ExportFormat.label`. Поля НАСТРОЕК формата — обычные поля\n // декларативной формы, их `label` это `LocalizedMessage`, то есть он МОЖЕТ\n // быть ссылкой `{key, fallback}`; поле разделителя из `csvFormat()` именно\n // такое, поэтому его ключи лежат здесь (`export.format.csv.preset.*`), как\n // любая другая переводимая строка.\n export: {\n format: {\n csv: {\n preset: {\n label: 'Разделитель',\n option: {\n semicolon: 'Точка с запятой (;)',\n comma: 'Запятая (,)',\n tab: 'Табуляция',\n },\n },\n },\n },\n dialog: {\n titleFilter: 'Экспорт {{count}} строк по текущему фильтру',\n /** `estimatedCount` необязателен в `ExportDialogProps` — показывается, когда для экспорта по фильтру нет известной оценки количества строк. */\n titleFilterUnknownCount: 'Экспорт строк по текущему фильтру',\n titleSelected: 'Экспорт {{count}} выбранных строк',\n /** Защитный резерв: Task 8 закрывает триггер по `available` до открытия, так что это достижимо только при прямом/программном монтировании. */\n unavailable: 'Экспорт недоступен для этого ресурса.',\n /** Показывается вместо выбора формата, пока загружается отложенная регистрация экспортёра (`ExporterLoader`). */\n loading: 'Подготовка экспорта…',\n format: 'Формат',\n columns: 'Колонки',\n columnsVisible: 'Как на странице',\n columnsAll: 'Все колонки',\n sortWarning: 'Сортировка не применяется к экспортируемому файлу.',\n start: 'Начать экспорт',\n progressIndeterminate: 'Экспорт…',\n progress: 'Экспорт… {{done}}/{{total}}',\n download: 'Скачать',\n failed: 'Экспорт завершился с ошибкой',\n canceled: 'Экспорт отменён.',\n confirmCloseTitle: 'Экспорт выполняется',\n confirmCloseMessage: 'Экспорт всё ещё выполняется. Остановить его или продолжить в фоне?',\n stop: 'Остановить экспорт',\n continue: 'Продолжить в фоне',\n },\n continuesInBackground: 'Экспорт продолжается в фоне.',\n /** Кнопки экспорта в тулбаре и в панели массовых действий (Task 8) — одно и то же действие, два места вызова. */\n button: {\n label: 'Экспорт',\n },\n /** Тосты `useExportRunWatcher()` о завершении экспорта в фоне (Task 8). */\n toast: {\n succeeded: 'Экспорт готов',\n download: 'Скачать',\n failed: 'Экспорт завершился с ошибкой: {{message}}',\n },\n },\n // Уведомление об успехе для встроенных действий над записью, синтезируемых\n // фреймворком (`withBuiltinItemActions`) — пока только `delete`.\n notify: {\n deleted: 'Запись удалена',\n },\n} as const;\n","import { evaluateVisible, type ErasedResourceHandle, type FilterExpression } from '@burojs/core';\nimport type { FormValues, RelationFilterOpt } from './types.js';\n\n/**\n * A field-level predicate: either a static boolean, or a function evaluated\n * against the current visibility ctx + form values. Same `(ctx, values)`\n * argument order as core's `VisiblePredicate` (`@burojs/core`'s\n * `permissions.ts:95-98`) — the existing `visible` convention this widens\n * `required`/`disabled` to match, per the design doc §4/§6\n * (`docs/superpowers/specs/2026-08-04-declarative-forms-design.md`).\n *\n * `ctx` is `unknown` here (not `AppContext`) so this module stays\n * framework-shape-agnostic; the controller passes `useOptionalVisibilityCtx()`.\n *\n * `values` is OPTIONAL in the function form's own signature — matching core's\n * `VisiblePredicate` (`values?: TValues`) exactly, which is what lets\n * `resolveFieldFlags` hand a `ConditionalFieldPredicate` straight to\n * `evaluateVisible` without a cast. It is also the empirically-required\n * shape for a `required`/`visible` predicate to type-check through the\n * `@burojs/field-types` `f` builder at all — `f.string({ required: (ctx,\n * values) => ... })` with a REQUIRED second parameter fails with TS2322\n * \"Target signature provides too few arguments\" against the builder's\n * `FieldOptsBase.required: boolean | ((d: unknown) => boolean)` (single\n * param); marking it `values?` is what the codebase's existing B3\n * conditional-fields tests already do\n * (`packages/ui-shadcn/tests/resource-form-validation.test.tsx:2187`), and\n * is required, not stylistic. At the call site, `values` is always the\n * real live values map — never actually omitted — so this widens what\n * TYPE-CHECKS without changing runtime behavior.\n *\n * Named `ConditionalFieldPredicate` (not `FieldPredicate`) to avoid a NAME\n * collision with `@burojs/core`'s already-public `FieldPredicate` — an\n * unrelated filter-expression generic (`packages/core/src/data/filters.ts`).\n * This type is local to `@burojs/react` and not re-exported from its\n * `index.ts`.\n */\nexport type ConditionalFieldPredicate = boolean | ((ctx: unknown, values?: FormValues) => boolean);\n\n/**\n * Resolve a `required`/`disabled` predicate to a boolean.\n * - `undefined` → `fallback` (the field never declared this predicate).\n * - `boolean` → itself (static form).\n * - function → called `(ctx, values)`; a throw is caught and ALSO resolves\n * to `fallback` — \"a broken predicate behaves as if it were never\n * declared\" (there is no established asymmetric-fallback convention for\n * `required`/`disabled` to mirror, unlike `visible` below).\n *\n * NOT used for `visible` — that predicate reuses core's `evaluateVisible`\n * directly (see `resolveFieldFlags`), because `evaluateVisible`'s fail\n * path is NOT symmetric with its undefined path (undefined → visible\n * `true`, but a THROW → not-visible `false`, unconditionally — fail-closed\n * on a broken predicate specifically because visibility gates what a user\n * sees). Reusing one shared `fallback` value for both paths, as this\n * function does, would make a throwing `visible` predicate fail OPEN\n * whenever its declared default is `true` — the opposite of\n * `evaluateVisible`'s actual, deliberate contract.\n */\nexport function resolvePredicate(\n p: ConditionalFieldPredicate | undefined,\n ctx: unknown,\n values: FormValues,\n fallback: boolean,\n): boolean {\n if (p === undefined) return fallback;\n if (typeof p === 'boolean') return p;\n try {\n return p(ctx, values);\n } catch {\n return fallback;\n }\n}\n\n/** The field-def keys this module resolves off a field, uniformly across shapes. */\nexport type ConditionalFieldKey = 'visible' | 'required' | 'disabled' | 'clearWhenHidden';\n\n/**\n * Read a field def's raw `visible` / `required` / `disabled` /\n * `clearWhenHidden` value — boolean, predicate function, or `undefined` —\n * checking top-level first (raw `FieldDeclaration`s, and `visible`'s native\n * home on every field def), then `.opts` (the `@burojs/field-types` `f`\n * builder's shape, e.g. `f.string({ required: ... })`, whose `opts: O`\n * carries the input object through unchanged). Mirrors the same\n * top-level-then-`.opts` fallback chain `resolveFieldStatic`\n * (`@burojs/core`'s `fields/field-static.ts`) uses for the STATIC\n * `required` boolean — generalized here to carry a function value through\n * unevaluated, since evaluating it is `resolvePredicate`'s job, and to two\n * more keys.\n *\n * `disabled` and `clearWhenHidden` have NO typed channel on the field-types\n * builder's `FieldOptsBase` at all (unlike `required`/`visible`, which the\n * builder types — see the Task 4 report's empirical findings) — they are\n * reachable today via a raw field declaration, or by spreading a builder\n * field and extending it (`{ ...f.string({...}), disabled: true }`, the\n * same pattern the Task 3 test suite already uses for `validators`). This\n * reader still resolves them uniformly regardless of which shape produced\n * the field, since `.opts` is untyped (`unknown` / `Record<string,\n * unknown>`) on the shared core field-def type — it duck-types exactly like\n * `resolveFieldStatic` already does, rather than throwing on an\n * unrecognized shape.\n */\nexport function readFieldOpt(\n fieldDef: unknown,\n key: ConditionalFieldKey,\n): ConditionalFieldPredicate | undefined {\n if (fieldDef === null || typeof fieldDef !== 'object') return undefined;\n const record = fieldDef as Record<string, unknown> & { readonly opts?: Record<string, unknown> };\n const value = record[key] !== undefined ? record[key] : record.opts?.[key];\n if (typeof value === 'boolean' || typeof value === 'function')\n return value as ConditionalFieldPredicate;\n return undefined;\n}\n\n/** A field's resolved (predicate-evaluated) visibility/required/disabled state for one values snapshot. */\nexport interface ResolvedFieldFlags {\n /** `!visible` — the `fields` getter and validation both key off this. */\n readonly hidden: boolean;\n readonly required: boolean;\n readonly disabled: boolean;\n}\n\n/**\n * Resolve one field's `hidden`/`required`/`disabled` against a ctx + values\n * snapshot.\n *\n * `hidden` is `!evaluateVisible(...)` — core's real evaluator\n * (`@burojs/core`'s `permissions.ts:121-136`), reused as-is rather than\n * reimplemented: undefined → visible (adopters opt INTO gating); a throw →\n * NOT visible, unconditionally (fail-closed). This is THE existing `visible`\n * convention every other renderer (`<ResourceList>`, `<ResourceShow>`,\n * `<ResourceForm>`) already consults — reusing it, rather than routing\n * `visible` through the more generic `resolvePredicate` below, is what\n * keeps this controller's conditional-visibility semantics identical to\n * theirs.\n *\n * `required`/`disabled` default to `false` when undeclared or on a throw\n * (`resolvePredicate`) — \"no predicate declared → behave exactly as before\n * this feature existed\".\n */\nexport function resolveFieldFlags(\n fieldDef: unknown,\n ctx: unknown,\n values: FormValues,\n): ResolvedFieldFlags {\n const visible = evaluateVisible(readFieldOpt(fieldDef, 'visible'), ctx, values);\n const required = resolvePredicate(readFieldOpt(fieldDef, 'required'), ctx, values, false);\n const disabled = resolvePredicate(readFieldOpt(fieldDef, 'disabled'), ctx, values, false);\n return { hidden: !visible, required, disabled };\n}\n\n/**\n * Whether a field opts into nulling its value when it becomes hidden.\n * Boolean-only per spec §4 (`clearWhenHidden?: boolean`) — unlike\n * `required`/`disabled`/`visible`, this is not a predicate: whether to\n * clear is a fixed per-field policy, not a condition to re-evaluate.\n */\nexport function isClearWhenHidden(fieldDef: unknown): boolean {\n return readFieldOpt(fieldDef, 'clearWhenHidden') === true;\n}\n\n/**\n * Read a field def's raw `filter` value — an array (static form), a\n * function (resolved per-render), or `undefined` — checking top-level\n * first, then `.opts` (same fallback chain `readFieldOpt` uses). Kept\n * SEPARATE from `readFieldOpt`/`ConditionalFieldKey`: that reader's type\n * guard only accepts `boolean | function` (the predicate shapes), which\n * would silently drop `filter`'s static ARRAY form.\n *\n * No typed `@burojs/field-types` builder channel exists for `filter` either\n * (`RelationFieldOpts` carries no `filter` key) — empirically the same\n * finding the Task 4 report made for `disabled`/`clearWhenHidden`. Reachable\n * today via the same spread-extension escape hatch:\n * `{ ...f.relation({ to: '...' }), filter: (values) => [...] }`.\n */\nexport function readFieldFilterOpt(fieldDef: unknown): RelationFilterOpt | undefined {\n if (fieldDef === null || typeof fieldDef !== 'object') return undefined;\n const record = fieldDef as Record<string, unknown> & { readonly opts?: Record<string, unknown> };\n const value = record.filter !== undefined ? record.filter : record.opts?.filter;\n if (Array.isArray(value) || typeof value === 'function') return value as RelationFilterOpt;\n return undefined;\n}\n\n/**\n * Resolve a field's `filter` opt against the current values snapshot\n * (design doc §5) — the value `FieldBinding.fixedFilters` carries.\n * - `undefined` declared → `undefined` (no scope; `<Field>` leaves any\n * static `meta.filters` already on the field def untouched).\n * - array (static form) → itself, unevaluated.\n * - function → called with `values`; a throw, OR a non-array return,\n * resolves to `undefined` — \"a broken filter behaves as if it were never\n * declared\", the same fail-open convention `resolvePredicate` uses for\n * `required`/`disabled` (there is no established fail-closed convention\n * for a relation scope the way `visible` has one). A THROW specifically\n * also emits a dev-only `console.warn` (gated on `NODE_ENV !==\n * 'production'`, same idiom as `RelationPicker`'s unregistered-target\n * warning in `packages/ui-shadcn/src/fields/relation-picker.tsx`) — the\n * fail-open policy stays silent-safe at runtime, but a broken filter is\n * now discoverable in dev instead of silently showing unscoped options.\n *\n * `name` is the field name, used only for the dev warning's message — it\n * does not affect resolution.\n */\nexport function resolveFieldFilter(\n fieldDef: unknown,\n values: FormValues,\n name: string,\n): readonly FilterExpression<ErasedResourceHandle>[] | undefined {\n const raw = readFieldFilterOpt(fieldDef);\n if (raw === undefined) return undefined;\n // `typeof raw === 'function'` (positive narrowing), not\n // `Array.isArray(raw)` negated — TS cannot narrow a `readonly T[] | fn`\n // union away from the readonly-array arm in the ELSE branch of an\n // `Array.isArray` check (a known limitation with `ReadonlyArray`), which\n // left `raw(values)` uncallable at the DTS build step.\n if (typeof raw !== 'function') return raw;\n try {\n const result = raw(values);\n return Array.isArray(result) ? result : undefined;\n } catch (err) {\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line no-console\n console.warn(\n `[buro] relation filter for field \"${name}\" threw; showing unscoped options`,\n err,\n );\n }\n return undefined;\n }\n}\n","import {\n type CheckOutcome,\n type CheckSurface,\n type FieldIssue,\n type ResourceFieldDefinition,\n type StandardSchemaV1,\n type ValidationContext,\n type ValidationIssue,\n evaluateChecks,\n filterInlineIssues,\n i18nPrefixToRef,\n normalizeFieldIssues,\n resolveFieldStatic,\n} from '@burojs/core';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useFormSubmitAudit } from '../audit/use-form-submit-audit.js';\nimport {\n createRuntimeActionDataAccess,\n createUnavailableActionDataAccess,\n} from '../data/action-data-access.js';\nimport { useOptionalDataRuntime } from '../data/context.js';\nimport { useOptionalVisibilityCtx } from '../hooks/use-permissions.js';\nimport { useTranslate } from '../hooks/use-t.js';\nimport {\n type ResolvedFieldFlags,\n isClearWhenHidden,\n resolveFieldFilter,\n resolveFieldFlags,\n} from './conditional.js';\nimport type {\n DeclarativeFormApi,\n FieldBinding,\n FormValues,\n ResolvedIssue,\n SubmitEventLike,\n UseDeclarativeFormOptions,\n} from './types.js';\n\n/** Duck-types a Standard Schema (`~standard.version === 1`) without importing a schema library. */\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n if (value === null || typeof value !== 'object') return false;\n const standard = (value as { readonly '~standard'?: unknown })['~standard'];\n if (standard === null || typeof standard !== 'object') return false;\n return (\n (standard as { readonly version?: unknown }).version === 1 &&\n typeof (standard as { readonly validate?: unknown }).validate === 'function'\n );\n}\n\n/** First path segment of a Standard Schema issue, as a field name — or undefined. */\nfunction pathHead(path: readonly unknown[] | undefined): string | undefined {\n const head = path?.[0];\n if (typeof head === 'string' || typeof head === 'number') return String(head);\n if (head !== null && typeof head === 'object' && 'key' in (head as Record<string, unknown>)) {\n const key = (head as { readonly key?: unknown }).key;\n if (typeof key === 'string' || typeof key === 'number') return String(key);\n }\n return undefined;\n}\n\n/** Run one Standard Schema and normalize its issues onto `defaultField`. */\nasync function runStandardSchema(\n schema: StandardSchemaV1,\n value: unknown,\n defaultField: string,\n): Promise<ValidationIssue[]> {\n const result = await schema['~standard'].validate(value);\n if (!('issues' in result) || result.issues === undefined) return [];\n const friendly: FieldIssue[] = result.issues.map((entry) => ({\n message: typeof entry.message === 'string' ? entry.message : 'Invalid',\n field: pathHead(entry.path) ?? defaultField,\n }));\n return normalizeFieldIssues(friendly, { defaultField });\n}\n\n/** Mirrors validation-runner.ts's own empty check — a required, empty value is the one built-in rule this controller enforces itself. */\nfunction isEmptyValue(value: unknown): boolean {\n return (\n value === undefined ||\n value === null ||\n value === '' ||\n (Array.isArray(value) && value.length === 0)\n );\n}\n\n/**\n * Run one field's `required` check plus its canonical validators. `required`\n * is passed in ALREADY RESOLVED by the caller — a static boolean or a\n * predicate `(ctx, values) => boolean` evaluated per `resolveFieldFlags`\n * (`./conditional.js`), fail-closed on a throw. `validators` still comes\n * from core's `resolveFieldStatic`, which reads them from whichever shape\n * produced the field (raw declaration, TS field-type builder's\n * `opts.validate`, or a hand-authored hybrid). Every validator return is\n * normalized through `normalizeFieldIssues`.\n */\nasync function runFieldValidators(\n fieldDef: ResourceFieldDefinition,\n value: unknown,\n values: FormValues,\n name: string,\n required: boolean,\n): Promise<ValidationIssue[]> {\n const out: ValidationIssue[] = [];\n const { validators } = resolveFieldStatic(fieldDef);\n if (required && isEmptyValue(value)) {\n out.push(\n ...normalizeFieldIssues(\n {\n code: 'required',\n // `validation.required` — NOT `fields.validation.*` (core's\n // reserved, deliberately-untranslated generic-diagnostic\n // namespace, `validation-runner.ts`'s own `message()` helper) —\n // because this key IS meant to resolve through the bundle:\n // `packages/react/src/locales/{en,ru}.ts` both register a\n // top-level `validation.required` string, and `<ResourceForm>`\n // already looks up the exact same bare key for the exact same\n // case (`resource-form.tsx`'s own `t('validation.required')`\n // override for a presence error). Emitting `fields.validation.\n // required` here made `resolveKey` build candidates under a\n // `fields.` ancestor the bundle never populates, so the lookup\n // always missed and this hardcoded English fallback always won —\n // in every locale, Russian included. `resolveKey`'s last-resort\n // raw-key candidate (and, once namespaced under `common.*` per\n // the app's own i18n wiring, the `common.validation.required`\n // candidate before it) is what makes the bare key resolve.\n message: { key: 'validation.required', fallback: 'This field is required.' },\n },\n { defaultField: name },\n ),\n );\n }\n const ctx: ValidationContext = { values, field: name };\n for (const validator of validators) {\n if (isStandardSchema(validator)) {\n out.push(...(await runStandardSchema(validator, value, name)));\n } else {\n const outcome = await validator(value, ctx);\n out.push(...normalizeFieldIssues(outcome, { defaultField: name }));\n }\n }\n return out;\n}\n\nfunction toResolvedIssue(issue: ValidationIssue): ResolvedIssue {\n const head = issue.path[0];\n return {\n field: typeof head === 'string' || typeof head === 'number' ? String(head) : '_form',\n severity: issue.severity,\n message: issue.message,\n // Forwarded so a renderer's bundle-translated `t(message.key, { params })`\n // call can interpolate a `{{placeholder}}` — dropping it here (as this\n // used to) is invisible for every hand-authored fallback string, but\n // silently renders the literal `{{checkId}}` etc. for any bundle entry\n // that registers `message.key` with a placeholder.\n ...(issue.params === undefined ? {} : { params: issue.params }),\n };\n}\n\n/** Shallow key-by-key equality — enough for the flat `FormValues` record. */\nfunction shallowEqualValues(a: FormValues, b: FormValues): boolean {\n if (a === b) return true;\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((key) => Object.is(a[key], b[key]));\n}\n\n/**\n * Headless controller for a declarative form: values (controlled or\n * uncontrolled), per-field + cross-field + whole-form-schema validation, the\n * error/warning partition, `canSubmit`, `isDirty`, `handleSubmit` with an\n * anti-double-submit latch, conditional visibility, predicate `required`/\n * `disabled`, and `clearWhenHidden`.\n *\n * Reads `useOptionalVisibilityCtx()` (`../hooks/use-permissions.js`) as the\n * `ctx` argument every `visible`/`required`/`disabled` predicate receives —\n * NOT `useVisibilityCtx`, which throws outside a `BuroProvider`. This\n * controller must stay instantiable via a bare\n * `renderHook(() => useDeclarativeForm(...))`, no wrapper (Task 3's own\n * suite does this, and a form with no conditional fields has no reason to\n * require the whole app's provider tree just to mount) — the optional\n * variant defaults `ctx` to `{}` outside a provider instead.\n */\nexport function useDeclarativeForm(options: UseDeclarativeFormOptions): DeclarativeFormApi {\n const controlled = options.value !== undefined;\n const [inner, setInner] = useState<FormValues>(() => options.defaultValue ?? {});\n const values = options.value ?? inner;\n const vctx = useOptionalVisibilityCtx();\n const submitAudit = useFormSubmitAudit();\n\n const valuesRef = useRef(values);\n valuesRef.current = values;\n\n // Captured once — `useRef`'s initializer argument is only honored on the\n // very first render, so this never re-baselines on later prop changes.\n const baselineRef = useRef<FormValues>(options.value ?? options.defaultValue ?? {});\n\n // ORDINARY validation issues only (field / cross-field / schema). Check\n // issues deliberately live apart, in `checkOutcome` — see\n // `checkInlineIssues` below for why the two channels cannot share one\n // state bucket.\n const [issues, setIssues] = useState<readonly ValidationIssue[]>([]);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const submittingRef = useRef(false);\n const fieldValidateSeqRef = useRef<Record<string, number>>({});\n\n // Inline-visibility state for `filterInlineIssues` (`@burojs/core`), the\n // same two inputs `<ResourceForm>` feeds `useChecks`. This controller had\n // no notion of \"touched\" at all before checks — it validates a field on\n // blur but never recorded that the blur happened — so `touched` is\n // introduced here purely to drive `trigger`. It is set on BLUR, matching\n // `<ResourceForm>`'s own `touched` (its `makeFieldBlurHandler`, not its\n // change handler), so the two hosts agree on when a `trigger: 'touched'`\n // check may paint. `submitAttempted` flips on the first `handleSubmit()`\n // call and — again mirroring `<ResourceForm>` — is never cleared except by\n // `reset()`.\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n const [submitAttempted, setSubmitAttempted] = useState(false);\n\n // ---- Conditional checks (Task 9) — DI plumbing -------------------------\n // Mirrors `useChecks`/`useCheckGate` (`@burojs/react`)'s own tolerance for\n // a missing native data runtime: a declarative form is frequently mounted\n // outside one entirely (this controller must stay instantiable via a bare\n // `renderHook`, no provider — see the docblock above), so a check that\n // never touches `di.data` must still evaluate normally, while one that\n // DOES gets a rejecting stub `evaluateChecks` turns into a visible\n // `check.exception` warning rather than a crash.\n const runtime = useOptionalDataRuntime();\n const data = useMemo(\n () =>\n runtime === null\n ? createUnavailableActionDataAccess(\n `Check evaluation for \"${options.i18nPrefix ?? 'form'}\" needs a data runtime; none is mounted.`,\n )\n : createRuntimeActionDataAccess(runtime),\n [runtime, options.i18nPrefix],\n );\n // `useTranslate()` is provider-optional (degrades to the raw key with no\n // `BuroProvider`), same as `vctx` above. Wrapped so `CheckDI.t`'s\n // `(key, params?) => string` shape matches `useTranslate`'s\n // `(key, { params }) => string` — same adaptation `useChecks` uses.\n const translate = useTranslate();\n const t = useCallback(\n (key: string, params?: Record<string, unknown>) => translate(key, { params }),\n [translate],\n );\n const [checkOutcome, setCheckOutcome] = useState<CheckOutcome | null>(null);\n // Mirrors `checkOutcome` into a ref, read by `runValidationAndChecks`\n // when a `revalidate()` pass has to skip re-EVALUATING checks (see below)\n // but must still re-merge its fresh ordinary-validation issues with\n // whatever check-sourced issues are already on screen — reading state\n // directly inside a `useCallback` would either go stale or force the\n // callback (and everything that depends on it) to be recreated on every\n // check pass; a ref sidesteps both.\n const checkOutcomeRef = useRef<CheckOutcome | null>(null);\n checkOutcomeRef.current = checkOutcome;\n // Track mount state + the in-flight check pass's own controller, the same\n // discipline `use-check-gate.ts` uses for its `run()`: never paint state\n // once unmounted (a slow `di.data` check that resolves after unmount would\n // otherwise call `setCheckOutcome`/`setIssues` on a dead component), and a\n // NEWER pass aborts an older one before starting.\n //\n // Priority between the two callers is NOT symmetric last-writer-wins —\n // `handleSubmit` and `revalidate` are semantically different: a submit's\n // result is something a user is actively waiting on, a revalidate is a\n // caller-driven live-validation seam (`types.ts`'s own doc comment on\n // `revalidate`) that fires opportunistically (a blur, a debounced change).\n // A `revalidate()` landing while `handleSubmit()`'s CHECK PASS is still in\n // flight must NOT abort or supersede it — that would silently drop the\n // user's submit with no error, no state update, nothing. This applies to\n // the CHECK pass only, never to ordinary field/cross-field/schema\n // validation: `runValidationAndChecks`'s `caller === 'revalidate'` guard\n // (below) skips calling `runChecksPass` while a submit is in flight, but\n // it still runs `runFormValidation` and paints the result every time —\n // dropping ordinary validation feedback would regress every declarative\n // form, checks or not, the moment a host wires `revalidate()` to\n // `onBlur`/`onChange` (exactly what `types.ts`'s own `revalidate` doc\n // comment recommends) and the user keeps interacting during a slow\n // `onSubmit`. A `handleSubmit()` pass, conversely, MAY abort a pending\n // `revalidate()` CHECK pass — and does, unconditionally, in\n // `runChecksPass` below — since submit always outranks it. `submittingRef`\n // is the ownership signal for \"is a submit currently in flight\" (it is set\n // before ANY `await` in `handleSubmit` and cleared in its `finally`, so it\n // spans exactly the window that matters); `checkPassControllerRef`'s own\n // identity check is the second, closing-the-gap layer for a race that\n // starts BEFORE `submittingRef` flips (a `revalidate()` check pass already\n // mid-`evaluateChecks` when a submit begins) — the submit still preempts\n // it via the unconditional abort in `runChecksPass`, and the superseded\n // `revalidate()` pass's own post-await identity check discards its result\n // once it does resolve.\n const mountedRef = useRef(true);\n const checkPassControllerRef = useRef<AbortController | null>(null);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n checkPassControllerRef.current?.abort();\n };\n }, []);\n\n // Per-field validation. Runs on blur (unconditionally) and — Bug 1 fix,\n // \"reValidateMode: onChange\" in React Hook Form's terms — on a CHANGE to a\n // field the user has already been told about (see `setValue` below).\n // Mirrors resource-form.tsx's `validateField` (:898-981) minus the\n // `def`/capability coupling: replace only this field's slice of `issues`,\n // guarded by a local sequence number so a slower, stale run can never\n // clobber a faster, newer one — a blur and a change on the same field can\n // now race, and the sequence guard is what keeps the LAST one authoritative\n // regardless of which started first.\n //\n // `valuesOverride`, not a bare read of `valuesRef.current`, is what makes\n // this safe to call from `setValue` itself: in CONTROLLED mode `setValue`\n // never adopts the new value into this hook's own state (the parent owns\n // `values` and feeds it back on a LATER render, via the `onChange` it just\n // called) — so at the moment `setValue` runs, `valuesRef.current` still\n // holds the OLD value, not the one the user just typed. Passing the\n // freshly-computed `next` map explicitly sidesteps that render lag\n // entirely, in both controlled and uncontrolled mode; a bare\n // `validateOneField(name)` (as `onBlur` below still calls it) is correct\n // there because a blur always lands on a LATER render than the `setValue`\n // that preceded it, by which point `valuesRef.current` has caught up.\n const validateOneField = useCallback(\n async (name: string, valuesOverride?: FormValues) => {\n const seq = (fieldValidateSeqRef.current[name] ?? 0) + 1;\n fieldValidateSeqRef.current[name] = seq;\n const snapshot = valuesOverride ?? valuesRef.current;\n const fieldDef = options.fields[name];\n if (!fieldDef) return;\n const { hidden, required } = resolveFieldFlags(fieldDef, vctx, snapshot);\n const fieldIssues = hidden\n ? []\n : await runFieldValidators(fieldDef, snapshot[name], snapshot, name, required);\n if (fieldValidateSeqRef.current[name] !== seq) return; // superseded by a later run\n setIssues((prev) => [...prev.filter((issue) => issue.path[0] !== name), ...fieldIssues]);\n },\n [options.fields, vctx],\n );\n\n // The raw value-commit, with NO reValidateMode side effect. Shared by the\n // public `setValue` below and by the `clearWhenHidden` effect (further\n // down), which must NOT go through revalidation — see that effect's own\n // doc comment for the infinite-loop this origin split exists to prevent.\n const commitValue = useCallback(\n (name: string, value: unknown): FormValues => {\n const next = { ...values, [name]: value };\n if (controlled) {\n options.onChange?.(next);\n } else {\n setInner(next);\n options.onChange?.(next);\n }\n return next;\n },\n [values, controlled, options],\n );\n\n const setValue = useCallback(\n (name: string, value: unknown) => {\n const next = commitValue(name, value);\n // Bug 1 fix: without this, a field's error — once shown, by a blur or\n // a failed submit — could only ever be cleared by ANOTHER blur or\n // submit. That is a dead end the instant the field with the error is\n // also the field the user is typing in: it holds focus, so it is\n // never blurred, and `canSubmit` (`errors.length === 0`) staying false\n // disables the very button that would trigger a fresh validation pass.\n // Gating on `submitAttempted || touched[name]` — never unconditional —\n // is what keeps this from becoming the noisy opposite bug: a field\n // nobody has touched or attempted to submit must not start validating\n // on every keystroke before the user has been told anything is wrong.\n // This intentionally revalidates only THIS field's own validators\n // (`validateOneField`, same scope as `onBlur` below) — deliberately\n // NOT the form-level `validate`/`schema` pass and NOT the check-gate\n // pass:\n // - `validate`/`schema` is cross-field and can be arbitrarily\n // expensive (a Standard Schema, a slow custom `validate`, real I/O\n // for a check). Running it on every keystroke of every touched\n // field — this form can have several — reintroduces the exact\n // \"background revalidation is a caller-opt-in seam, not automatic\"\n // design `revalidate()` already exists to preserve (see its own\n // doc comment). `onBlur` below has never re-run these either; a\n // change is not given a wider scope than a blur already has.\n // - This does mean a stale cross-field-sourced issue keyed to THIS\n // field can be cleared here without re-confirming the cross-field\n // rule that produced it still fails (`validateOneField` replaces\n // every issue for `name`, regardless of which channel produced it)\n // — but that is the SAME pre-existing scope `onBlur` already had;\n // this fix does not widen it. It is safe rather than a second dead\n // end because the next `handleSubmit()` (or a host's own\n // `revalidate()`) always re-runs `runFormValidation` in full\n // regardless of what this optimistic per-field pass showed —\n // nothing unsafe reaches `onSubmit`, the worst case is the submit\n // button re-enabling for a moment before a real submit attempt\n // re-blocks it.\n // - The check-gate pass (`checkOutcome`) is a separate channel\n // entirely (`checkInlineIssues`, above) already timed by\n // `filterInlineIssues`'s own `trigger`/`show` rules, not by\n // anything in `issues` — a field change was never part of its\n // re-evaluation story, and only a `severity: 'error'` check can\n // block submit, which — like ordinary cross-field validation —\n // gets a fresh, authoritative answer at the next submit regardless.\n if (submitAttempted || touched[name]) {\n void validateOneField(name, next);\n }\n },\n [commitValue, submitAttempted, touched, validateOneField],\n );\n\n // Hidden fields are skipped entirely (their own `required`/validators never\n // run), and any FORM-LEVEL `validate`/`schema` issue that happens to be\n // keyed to a now-hidden field is dropped too — `def.validate` still\n // receives the full `currentValues` map for cross-field rules that\n // reference hidden values, but a hidden field must never block submit,\n // regardless of which channel produced its issue.\n const runFormValidation = useCallback(\n async (currentValues: FormValues): Promise<ValidationIssue[]> => {\n const out: ValidationIssue[] = [];\n const hiddenNames = new Set<string>();\n for (const name of Object.keys(options.fields)) {\n const fieldDef = options.fields[name];\n if (!fieldDef) continue;\n const { hidden, required } = resolveFieldFlags(fieldDef, vctx, currentValues);\n if (hidden) {\n hiddenNames.add(name);\n continue;\n }\n out.push(\n ...(await runFieldValidators(\n fieldDef,\n currentValues[name],\n currentValues,\n name,\n required,\n )),\n );\n }\n if (options.validate) {\n const ctx: ValidationContext = { values: currentValues };\n const result = await options.validate(currentValues, ctx);\n out.push(...normalizeFieldIssues(result, { defaultField: '_form' }));\n }\n if (options.schema) {\n out.push(...(await runStandardSchema(options.schema, currentValues, '_form')));\n }\n return out.filter((issue) => {\n const head = issue.path[0];\n const name =\n typeof head === 'string' || typeof head === 'number' ? String(head) : undefined;\n return name === undefined || !hiddenNames.has(name);\n });\n },\n [options, vctx],\n );\n\n // ---- Conditional checks (Task 9) — the one evaluation, shared ----------\n // `runChecksPass` is the ONLY place `evaluateChecks` is called — both\n // `handleSubmit` and `revalidate` funnel through it (via\n // `runValidationAndChecks` below), so `checkOutcome` and the merged\n // `issues` state can never disagree about \"what did the last check pass\n // say\" (Minor 3 — `revalidate()` used to drop check issues while leaving\n // `checkOutcome` stale).\n //\n // This function itself does NOT know or care which logical caller it's\n // running for — it always takes over unconditionally. That is exactly\n // right for a `'submit'` call (submit always outranks a pending\n // `revalidate`, see the priority doc comment above) and is made SAFE for a\n // `'revalidate'` call by `runValidationAndChecks`'s own `submittingRef`\n // guard, one level up, which stops a `'revalidate'` call from ever\n // reaching this function while a submit is in flight — so the only\n // `'revalidate'` calls that DO get here are ones that started before any\n // submit did, and those correctly lose the race the instant a submit\n // begins (this function's unconditional abort-and-take-over below,\n // followed by the loser's own post-await identity check).\n //\n // Returns `{ ok: false }` when this pass was superseded by a newer one\n // (aborted via `checkPassControllerRef`) or the component unmounted while\n // awaiting — the caller must then do NOTHING further: paint no state, call\n // no callback. A newer pass — or nothing, on unmount — owns the outcome\n // now. `{ ok: true, outcome: null }` is the ordinary \"no checks configured\"\n // case, kept distinct from \"aborted\" so a caller never confuses \"there is\n // nothing to report\" with \"do not report anything from THIS call\".\n const runChecksPass = useCallback(\n async (\n currentValues: FormValues,\n ): Promise<\n { readonly ok: true; readonly outcome: CheckOutcome | null } | { readonly ok: false }\n > => {\n if (!options.checks || options.checks.length === 0) return { ok: true, outcome: null };\n // Unconditional abort-and-take-over — see the doc comment above for\n // why this is safe despite having no per-caller knowledge here.\n checkPassControllerRef.current?.abort();\n const own = new AbortController();\n checkPassControllerRef.current = own;\n // Explicit `options.surface` wins over the create/edit heuristic — see\n // its own doc comment in `types.ts` for why the heuristic alone\n // misclassifies the common \"seed a new record's defaults\" create form.\n const surface: CheckSurface =\n options.surface ??\n (options.value !== undefined || options.defaultValue !== undefined ? 'edit' : 'create');\n const outcome = await evaluateChecks({\n checks: options.checks,\n surface,\n // Diagnostic/DI label only — `CheckDI.resource` and the\n // `[buro] check \"<id>\" on \"<resource>\" threw` console.warn, NEVER a\n // routing/lookup key (declarative forms have no resource registry\n // entry at all). `i18nPrefix` (or the `'form'` default) is the\n // closest stable per-form handle, same as `binding.resource` below.\n resource: options.i18nPrefix ?? 'form',\n values: currentValues,\n saved: baselineRef.current,\n ctx: vctx,\n t,\n data,\n signal: own.signal,\n });\n // `outcome.aborted` (`@burojs/core`) closes the hole the two guards\n // beside it cannot see: they answer \"is this pass still the current\n // one\", and both can pass on a run whose evaluation was aborted (a\n // remount restores `mountedRef` and leaves `checkPassControllerRef`\n // pointing at this pass's own controller). Without it the `{ ok: true,\n // outcome }` below would hand back three empty lists off a pass that\n // evaluated nothing — which is precisely the confusion the doc comment\n // above promises this function prevents.\n if (\n !mountedRef.current ||\n checkPassControllerRef.current !== own ||\n outcome.aborted === true\n ) {\n return { ok: false };\n }\n return { ok: true, outcome };\n },\n [options, vctx, t, data],\n );\n\n /**\n * Run ordinary validation, then (Minor 4 — see below) the check pass, and\n * publish both into `issues`/`checkOutcome` together. Shared by\n * `handleSubmit` and `revalidate` — the two are the ONLY entry points that\n * ever call this, so the merge logic (and the checkOutcome/issues\n * consistency it guarantees) cannot drift between them.\n *\n * `caller` is the fix for \"revalidate can silently kill an in-flight\n * submit\": a `'revalidate'` call checks `submittingRef.current` and, if a\n * submit is already underway, skips ONLY the CHECK pass (never calls\n * `runChecksPass`, never touches the shared check-pass controller\n * `handleSubmit`'s own pass owns) — it still runs `runFormValidation` and\n * paints the result EVERY time, exactly as if this guard didn't exist.\n * Ordinary field/cross-field/schema validation is never the thing this\n * guard drops: it has no shared controller to race over in the first\n * place, and a host commonly wires `revalidate()` to `onBlur`/`onChange`\n * (`types.ts`'s own doc comment on `revalidate` recommends exactly this) —\n * silently going quiet on ordinary validation for the whole duration of a\n * slow `onSubmit` would regress every declarative form, checks or not.\n * When the check pass IS skipped, the already-visible check-sourced\n * issues simply stay visible: they are derived from `checkOutcome` (which\n * this branch leaves untouched), not stored in `issues`, so a\n * validation-only write cannot flash them away. It never re-evaluates\n * checks itself; that would be the exact race this guard exists to avoid.\n *\n * This is a deliberate policy choice for the CHECK half specifically (the\n * alternative — \"run the check pass too, just without disturbing the\n * submit's controller\" — was rejected): while a submit is in flight its\n * check outcome is authoritative and imminent, so a concurrent revalidate\n * evaluating checks a second time has nothing useful to contribute and\n * would just risk a flicker. This only closes the \"revalidate arrives\n * at/after submittingRef flips true\" window — the earlier race (revalidate\n * ALREADY mid-`evaluateChecks` when a submit begins) is closed by\n * `runChecksPass`'s unconditional abort-and-take-over for a submit pass,\n * below.\n *\n * Returns `null` when the check pass was superseded/aborted (see\n * `runChecksPass`) — the caller must stop, doing nothing further.\n * Otherwise returns the FULL merged issue list (ordinary + check) plus the\n * `CheckOutcome` that produced the check half — either freshly evaluated,\n * or (when the check pass was skipped) the same `CheckOutcome` already in\n * state — so `handleSubmit` can read `outcome.confirmable` for its own\n * gate without a second `evaluateChecks` call.\n */\n const runValidationAndChecks = useCallback(\n async (\n currentValues: FormValues,\n caller: 'submit' | 'revalidate',\n ): Promise<{\n readonly merged: readonly ValidationIssue[];\n readonly outcome: CheckOutcome | null;\n } | null> => {\n const skipCheckPass = caller === 'revalidate' && submittingRef.current;\n const freshIssues = await runFormValidation(currentValues);\n if (freshIssues.some((issue) => issue.severity === 'error')) {\n // Minor 4 (decision: SKIP) — ordinary validation already blocks, so\n // the check pass is skipped entirely rather than run and ignored.\n // Running checks against values already known invalid performs real\n // I/O (a `di.data` read, a network round trip) for a result that is\n // never read — the early return in `handleSubmit` below already\n // stops before `outcome` would matter — and risks a `when`\n // predicate written against VALID values throwing on invalid ones,\n // surfacing a `check.exception` beside the real, more actionable\n // validation error. `checkOutcome` is deliberately left UNTOUCHED\n // here (not reset to `null`) — its documented meaning is \"the last\n // check pass that actually ran\", and skipping this attempt doesn't\n // change what that was. This means the `outcome: null` returned just\n // below is ONLY \"no NEW pass ran on THIS call\" — it does NOT assert\n // the live `checkOutcome` state is (or was made) `null` too, and the\n // two are allowed to disagree here. Harmless: the sole consumer of\n // this return value, `handleSubmit`'s confirm-gate branch, is already\n // unreachable on this path (`merged` already carries the blocking\n // error), so nothing ever reads this `outcome` as \"the current\n // checkOutcome\" — code that wants that reads the `checkOutcome`\n // state directly.\n setIssues(freshIssues);\n return { merged: freshIssues, outcome: null };\n }\n if (skipCheckPass) {\n // A submit's own check pass owns the shared controller right now —\n // report what it (or an earlier pass) already established, never\n // re-evaluate. See this function's own doc comment above. Nothing\n // has to be re-merged into `issues` any more: check issues are not\n // stored there (they are derived from `checkOutcome`, which this\n // branch leaves untouched), so they cannot be dropped by a\n // validation-only write in the first place.\n const currentOutcome = checkOutcomeRef.current;\n setIssues(freshIssues);\n return {\n merged:\n currentOutcome === null ? freshIssues : [...freshIssues, ...currentOutcome.issues],\n outcome: currentOutcome,\n };\n }\n const passResult = await runChecksPass(currentValues);\n if (!passResult.ok) return null;\n setCheckOutcome(passResult.outcome);\n setIssues(freshIssues);\n // The returned `merged` is the FULL, UNFILTERED union — it exists for\n // the caller's blocking decision (`severity: 'error'`), which `show`/\n // `trigger` must never suppress. What renders inline is a separate,\n // narrower projection (`checkInlineIssues` below).\n return {\n merged:\n passResult.outcome === null\n ? freshIssues\n : [...freshIssues, ...passResult.outcome.issues],\n outcome: passResult.outcome,\n };\n },\n [runFormValidation, runChecksPass],\n );\n\n // Resolved once per (fields, values, ctx) change — the single source of\n // truth `field()`, the `fields` getter, and the clearWhenHidden/issue-\n // pruning effect below all read from, so a field's hidden/required/\n // disabled state never disagrees between them within one render.\n const resolvedFlags = useMemo(() => {\n const map: Record<string, ResolvedFieldFlags> = {};\n for (const name of Object.keys(options.fields)) {\n const fieldDef = options.fields[name];\n if (!fieldDef) continue;\n map[name] = resolveFieldFlags(fieldDef, vctx, values);\n }\n return map;\n }, [options.fields, values, vctx]);\n\n // The check half of the INLINE channel. `show` and `trigger` exist to keep\n // a fired check off the form until it is meant to be seen — a\n // `show: 'confirm'` rule belongs only in the gate dialog, a `show:\n // 'silent'` rule renders nowhere at all, and `trigger` decides the timing\n // — and `filterInlineIssues` (`@burojs/core`) is the one place that\n // decision lives. `<ResourceForm>` gets this via `useChecks`; this\n // controller used to merge `outcome.issues` into `issues` wholesale, so\n // every fired check painted regardless of what the adopter declared.\n //\n // Derived, not stored: `touched`/`submitAttempted` change AFTER a pass has\n // run (the user blurs a field, then submits), and a stored snapshot would\n // freeze the visibility decision at evaluation time. The FULL outcome is\n // untouched — `checkOutcome` and the gate handshake still see every issue,\n // including the confirm-channel ones this filter removes from the form.\n const checkInlineIssues = useMemo(\n () =>\n checkOutcome === null\n ? []\n : filterInlineIssues(checkOutcome.issues, { touched, submitAttempted }),\n [checkOutcome, touched, submitAttempted],\n );\n const visibleIssues = useMemo(\n () => (checkInlineIssues.length === 0 ? issues : [...issues, ...checkInlineIssues]),\n [issues, checkInlineIssues],\n );\n\n // Belt-and-suspenders: `runFormValidation`/`validateOneField` already\n // never PRODUCE an issue for a hidden field, and the effect below PRUNES\n // `issues` state when a field's hidden status flips — but filtering here\n // too means `errors`/`warnings` are correct for the CURRENT render even\n // in the one render between a hiding values-change and that (passive)\n // effect running.\n const errors = useMemo(\n () =>\n visibleIssues\n .filter((issue) => issue.severity === 'error')\n .map(toResolvedIssue)\n .filter((issue) => !resolvedFlags[issue.field]?.hidden),\n [visibleIssues, resolvedFlags],\n );\n const warnings = useMemo(\n () =>\n visibleIssues\n .filter((issue) => issue.severity !== 'error')\n .map(toResolvedIssue)\n .filter((issue) => !resolvedFlags[issue.field]?.hidden),\n [visibleIssues, resolvedFlags],\n );\n const canSubmit = errors.length === 0 && !isSubmitting;\n const isDirty = useMemo(() => !shallowEqualValues(values, baselineRef.current), [values]);\n\n const resource = useMemo(\n () => i18nPrefixToRef(options.i18nPrefix ?? 'form'),\n [options.i18nPrefix],\n );\n\n const field = useCallback(\n (name: string): FieldBinding => {\n const fieldDef = options.fields[name];\n if (!fieldDef) throw new Error(`useDeclarativeForm: unknown field \"${name}\"`);\n const flags = resolvedFlags[name] ?? { hidden: false, required: false, disabled: false };\n return {\n name,\n value: values[name],\n onChange: (value: unknown) => setValue(name, value),\n onBlur: () => {\n // Marks the field touched for `trigger: 'touched'` (see the\n // `touched` state's own note) as well as running its validators —\n // blur is the same moment `<ResourceForm>` records.\n setTouched((prev) => (prev[name] ? prev : { ...prev, [name]: true }));\n void validateOneField(name);\n },\n error: errors.find((issue) => issue.field === name),\n warnings: warnings.filter((issue) => issue.field === name),\n required: flags.required,\n disabled: flags.disabled,\n hidden: flags.hidden,\n resource,\n field: fieldDef,\n fixedFilters: resolveFieldFilter(fieldDef, values, name),\n };\n },\n [options.fields, values, errors, warnings, resolvedFlags, resource, setValue, validateOneField],\n );\n\n // Visible-only, in declaration order — hidden fields are not rendered.\n const fieldBindings = useMemo(\n () =>\n Object.keys(options.fields)\n .filter((name) => !resolvedFlags[name]?.hidden)\n .map((name) => field(name)),\n [options.fields, resolvedFlags, field],\n );\n\n // `clearWhenHidden`: a field that just became hidden and opts in gets its\n // value nulled via `commitValue` (routes through `onChange` in controlled\n // mode, §10) — but only when its current value isn't already null/\n // undefined, so this can never re-fire once settled (no loop). Runs in\n // the same effect as pruning `issues` for now-hidden fields, so a later\n // re-show never resurrects a stale error from before the field hid.\n //\n // Calls `commitValue`, NOT the public `setValue` — this is deliberate and\n // load-bearing, not a style choice. A REAL infinite loop shipped here\n // during the Bug 1 fix (reValidateMode on change) before this split was\n // added, confirmed by instrumentation rather than assumed:\n // 1. This effect's own dependency array includes `values` and\n // `resolvedFlags`, BOTH of which are fresh object references on every\n // render whenever the host's `value` prop isn't referentially stable\n // across renders (a very ordinary shape — e.g. `value={{...record}}`\n // computed inline) — so the effect can re-run on a render that changed\n // nothing semantically.\n // 2. Once `submitAttempted` is true (i.e. after the FIRST submit —\n // exactly the state Bug 1's fix targets), a `setValue` call —\n // including THIS effect's own bookkeeping write — triggers\n // `validateOneField`, whose `setIssues` always produces a brand-new\n // array reference and therefore always forces a re-render, even when\n // the ISSUE CONTENT didn't change.\n // 3. That re-render recreates `values`/`resolvedFlags` again (per #1),\n // re-running this effect, which calls `setValue` again, which\n // revalidates again, which re-renders again — unbounded, with no\n // value/content ever actually changing. Traced: `setValue` was called\n // 40+ times in under a second before the run was killed, each one\n // requesting the exact same `null` for the exact same field.\n // The guard below (`values[name] !== null`) cannot break this cycle on its\n // own: it reads the same (possibly never-updated, e.g. an ignored\n // controlled `onChange`) `values` prop every time, so from the effect's\n // point of view the field looks \"still not null\" on every single pass.\n // The real fix is about ORIGIN, not timing or content: this write is the\n // FRAMEWORK's own bookkeeping, never a user edit, so it must never feed\n // reValidateMode at all — `commitValue` cannot re-enter this effect no\n // matter how many times it (redundantly) fires.\n useEffect(() => {\n const hiddenNames = Object.keys(options.fields).filter((name) => resolvedFlags[name]?.hidden);\n if (hiddenNames.length === 0) return;\n\n setIssues((prev) => {\n const next = prev.filter((issue) => {\n const head = issue.path[0];\n const name =\n typeof head === 'string' || typeof head === 'number' ? String(head) : undefined;\n return name === undefined || !resolvedFlags[name]?.hidden;\n });\n return next.length === prev.length ? prev : next;\n });\n\n for (const name of hiddenNames) {\n const fieldDef = options.fields[name];\n if (\n fieldDef &&\n isClearWhenHidden(fieldDef) &&\n values[name] !== null &&\n values[name] !== undefined\n ) {\n commitValue(name, null);\n }\n }\n }, [options.fields, resolvedFlags, values, commitValue]);\n\n const handleSubmit = useCallback(\n (cb?: (values: FormValues) => unknown | Promise<unknown>) => {\n return async (e?: SubmitEventLike): Promise<void> => {\n e?.preventDefault?.();\n if (submittingRef.current) return;\n submittingRef.current = true;\n setIsSubmitting(true);\n // Before the first `await`: a `trigger: 'submit'` check must be\n // visible for THIS attempt's result, not the next one.\n setSubmitAttempted(true);\n // `before` is captured HERE, before the callback runs: a successful\n // submit re-baselines (the host commonly calls `reset()` with the\n // saved record right after `onSubmit` resolves), and reading\n // `baselineRef` any later would yield an empty (or wrong) diff.\n // `submitAudit.enabled` is the zero-cost guard — with no sink\n // configured this form never even copies its values.\n //\n // `after` is deliberately NOT captured here alongside it. Several\n // awaits separate this line from each `emitSubmit` call below\n // (`runValidationAndChecks`, the confirm gate, `onSubmit` itself), and\n // `valuesRef.current` can move during any of them — a background\n // revalidation, a controlled parent re-render, a keystroke the user\n // gets in while a slow save is in flight. Reading it fresh inside\n // `emitSubmit`, at the moment each outcome is actually decided, is\n // what keeps the recorded \"to\" the value that was truly live at that\n // moment instead of a stale snapshot from handler entry.\n const auditBefore = submitAudit.enabled ? { ...baselineRef.current } : null;\n const emitSubmit = (outcome: 'success' | 'error' | 'invalid', errorCode?: string): void => {\n if (!auditBefore) return;\n submitAudit.emit({\n before: auditBefore,\n after: { ...valuesRef.current },\n fields: options.fields as Record<string, unknown>,\n outcome,\n errorCode,\n });\n };\n try {\n // Conditional checks (Task 9) — declarative forms are resource-\n // less, so `options.checks` (a plain array) is the ONLY source;\n // there is no registry lookup the way `<ResourceForm>`'s\n // `useChecks`/`useCheckGate` key off a `resource` string.\n // `runValidationAndChecks` (shared with `revalidate`) runs\n // ordinary validation, then the check pass, and publishes both\n // `issues`/`checkOutcome` together.\n const result = await runValidationAndChecks(valuesRef.current, 'submit');\n if (result === null) return; // superseded/unmounted mid check-evaluation\n // A check's `severity: 'error'` issue flows through this SAME\n // check for free — it is already in `result.merged` with\n // `severity: 'error'`, exactly like an ordinary blocking issue.\n if (result.merged.some((issue) => issue.severity === 'error')) {\n emitSubmit('invalid');\n return;\n }\n // Ordinary + check validation both passed. A `confirmable` check\n // issue (non-error, `show` in {'both','confirm'}) never blocks on\n // its own — same as any other warning — UNLESS the host supplied\n // `onConfirmChecks` (`<DeclarativeForm>` does, wiring its own\n // `<CheckConfirmDialog>`). `'cancel'` aborts the submit here;\n // `'proceed'`, or no gate installed at all, falls through to the\n // real save below.\n if (\n result.outcome !== null &&\n result.outcome.confirmable.length > 0 &&\n options.onConfirmChecks\n ) {\n const decision = await options.onConfirmChecks(result.outcome);\n if (decision === 'cancel') return;\n }\n try {\n await (cb ?? options.onSubmit)?.(valuesRef.current);\n emitSubmit('success');\n } catch (error) {\n emitSubmit('error');\n throw error;\n }\n } finally {\n submittingRef.current = false;\n setIsSubmitting(false);\n }\n };\n },\n [runValidationAndChecks, options, submitAudit],\n );\n\n const reset = useCallback(\n (next?: FormValues) => {\n const value = next ?? options.defaultValue ?? {};\n if (controlled) {\n options.onChange?.(value);\n } else {\n setInner(value);\n options.onChange?.(value);\n }\n baselineRef.current = value;\n setIssues([]);\n setCheckOutcome(null);\n // A reset form is a fresh one: nothing has been touched and no submit\n // has been attempted, so `trigger` starts over too.\n setTouched({});\n setSubmitAttempted(false);\n },\n [controlled, options],\n );\n\n // Live-validation seam: re-run the SAME full pass `handleSubmit` runs\n // (ordinary validation + checks, via `runValidationAndChecks`) and publish\n // it to `errors`/`warnings`/`checkOutcome`, without any of submit's side\n // effects (no latch, no `onConfirmChecks` gate, no `onSubmit` call).\n // Deciding WHEN to call this (on change, debounced, ...) is the caller's\n // job — the controller never calls it itself.\n //\n // Task 9 fix (Minor 3): this used to call `runFormValidation` directly and\n // skip the check pass entirely, so a check-anchored warning could vanish\n // from `field(name).warnings` on a `revalidate()` call while `checkOutcome`\n // kept reporting it as still current — the two disagreed. Routing through\n // the same shared helper `handleSubmit` uses makes that impossible: both\n // entry points always leave `issues` and `checkOutcome` in lockstep.\n //\n // Passes `'revalidate'` as its caller tag — `runValidationAndChecks` uses\n // that to defer ONLY its check pass to an in-flight `handleSubmit()`,\n // rather than risk silently cancelling it (see the priority-ownership doc\n // comment on `checkPassControllerRef`, above, and `runChecksPass` below);\n // ordinary field/cross-field/schema validation always still runs and\n // paints, submit in flight or not.\n const revalidate = useCallback(async (): Promise<void> => {\n await runValidationAndChecks(valuesRef.current, 'revalidate');\n }, [runValidationAndChecks]);\n\n return {\n field,\n fields: fieldBindings,\n values,\n errors,\n warnings,\n canSubmit,\n isDirty,\n isSubmitting,\n checkOutcome,\n handleSubmit,\n setValue,\n reset,\n revalidate,\n };\n}\n","import type { ExportHandle } from '@burojs/core';\n\nexport interface ExportRunEntry {\n readonly runId: string;\n readonly resource: string;\n readonly exporterId: string;\n readonly formatId: string;\n readonly startedAt: number;\n /** State/subscribe/cancel/resume all live on the handle — the store only observes it. */\n readonly handle: ExportHandle;\n}\n\nlet runIdFallbackCounter = 0;\n\n/**\n * Collision-resistant run id. Prefers `crypto.randomUUID`; falls back when\n * unavailable — `crypto.randomUUID` is secure-context-only in browsers, and\n * this repo already guards it for exactly that reason (see\n * `packages/react/src/ui-settings/local-storage-adapter.ts`'s `newLocalId`,\n * `packages/file-storage/src/adapters/supabase.ts`). Exported so\n * `use-export.ts`'s `useResourceExport().start()` can call it as a\n * pre-flight probe BEFORE running the exporter (see the comment there) — an\n * id-generation failure must never leave a live, unregistered export run.\n */\nexport function createExportRunId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n runIdFallbackCounter += 1;\n return `export-run-${Date.now().toString(36)}-${runIdFallbackCounter.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Lease-scoped registry of export runs for one app (one instance per\n * `DataRuntimeContextValue` — see `getExportRunsStore` in `use-export.ts`),\n * so every consumer — the export trigger that started a run and a future\n * header indicator (REF-15) — observes the same list. It survives session\n * and scope transitions: a run started under a previous scope stays in\n * `list()` until dismissed or the lease itself is disposed — the store has\n * no session/scope awareness at all.\n *\n * The store only ever *observes* handles (`subscribe`/`getState`); it never\n * calls `set` and tolerates a handle that is already terminal when it\n * arrives (subscribing to a terminal handle is safe — see\n * `packages/export/src/handle.ts` — it simply never fires again).\n *\n * Per-entry handle subscriptions are lazy and reference-counted against the\n * store's OWN subscriber count: nothing is attached until someone is\n * listening, and everything is detached the moment nobody is. This is what\n * keeps a store with zero live consumers (e.g. between two component mounts)\n * from leaking a live subscription into every export's handle forever.\n */\nexport class ExportRunsStore {\n readonly #entries: ExportRunEntry[] = [];\n #snapshot: readonly ExportRunEntry[] | null = null;\n readonly #listeners = new Set<() => void>();\n readonly #handleUnsubscribes = new Map<string, () => void>();\n\n start = (entry: Omit<ExportRunEntry, 'runId' | 'startedAt'>): ExportRunEntry => {\n const full: ExportRunEntry = {\n ...entry,\n runId: createExportRunId(),\n startedAt: Date.now(),\n };\n this.#entries.push(full);\n if (this.#listeners.size > 0) this.#attachHandle(full);\n this.#invalidate();\n this.#notify();\n return full;\n };\n\n /** Stable snapshot: the same array identity across calls until something\n * changes (`useSyncExternalStore` requires this to avoid re-render loops).\n * Frozen so a consumer's in-place `.sort()`/`.push()` on the (typed\n * `readonly`, but not runtime-enforced without this) array can never\n * corrupt the cached snapshot silently. */\n list = (): readonly ExportRunEntry[] => {\n if (this.#snapshot === null) this.#snapshot = Object.freeze(this.#entries.slice());\n return this.#snapshot;\n };\n\n subscribe = (cb: () => void): (() => void) => {\n const wasEmpty = this.#listeners.size === 0;\n this.#listeners.add(cb);\n if (wasEmpty) {\n for (const entry of this.#entries) this.#attachHandle(entry);\n }\n return () => {\n this.#listeners.delete(cb);\n if (this.#listeners.size === 0) this.#detachAll();\n };\n };\n\n dismiss = (runId: string): void => {\n const index = this.#entries.findIndex((entry) => entry.runId === runId);\n if (index === -1) return;\n this.#entries.splice(index, 1);\n this.#detachHandle(runId);\n this.#invalidate();\n this.#notify();\n };\n\n #attachHandle(entry: ExportRunEntry): void {\n if (this.#handleUnsubscribes.has(entry.runId)) return;\n const unsubscribe = entry.handle.subscribe(() => {\n this.#invalidate();\n this.#notify();\n });\n this.#handleUnsubscribes.set(entry.runId, unsubscribe);\n }\n\n #detachHandle(runId: string): void {\n const unsubscribe = this.#handleUnsubscribes.get(runId);\n if (unsubscribe === undefined) return;\n unsubscribe();\n this.#handleUnsubscribes.delete(runId);\n }\n\n #detachAll(): void {\n for (const unsubscribe of this.#handleUnsubscribes.values()) unsubscribe();\n this.#handleUnsubscribes.clear();\n }\n\n #invalidate(): void {\n this.#snapshot = null;\n }\n\n #notify(): void {\n for (const listener of [...this.#listeners]) listener();\n }\n}\n","import {\n type AppExportConfig,\n type CountResult,\n type DataError,\n EXPORT_ERROR_CODES,\n type ErasedResourceHandle,\n type ExportFormat,\n type ExportRequest,\n type Exporter,\n type ExporterContext,\n type ExporterDataAccess,\n type ExporterLoader,\n type ListResult,\n type ResourceExportSetting,\n createQueryDescriptor,\n normalizeDataError,\n normalizeEntityRef,\n resolveDescriptorLocale,\n resolveExporter,\n} from '@burojs/core';\nimport { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../data/context.js';\nimport { executeQuery } from '../data/query-execution.js';\nimport type { DataRuntimeContextValue } from '../data/runtime.js';\nimport { useLocale } from '../hooks/use-t.js';\n\nimport { type ExportRunEntry, ExportRunsStore, createExportRunId } from './runs-store.js';\n\n/**\n * One `ExportRunsStore` per app. `useDataRuntime()` returns the SAME\n * `DataRuntimeContextValue` object for the whole tree — it is created once\n * (`createDataRuntime`) and handed to `<BuroProvider dataRuntime={...}>` at\n * the app's root — so keying this lazily-populated map by that identity\n * gives every component in the app the one shared store REF-15's future\n * header indicator depends on, without either module-global mutable state\n * outside React's control or a per-component `useMemo` (which would create\n * an independent store per mount point).\n */\nconst runsStores = new WeakMap<DataRuntimeContextValue, ExportRunsStore>();\n\nfunction getExportRunsStore(runtime: DataRuntimeContextValue): ExportRunsStore {\n let store = runsStores.get(runtime);\n if (store === undefined) {\n store = new ExportRunsStore();\n runsStores.set(runtime, store);\n }\n return store;\n}\n\n/** All export runs for the current app, live-updated as runs start, progress,\n * and finish. Backed by the one `ExportRunsStore` for this app (see above) —\n * every component calling this hook observes the same list. */\nexport function useExportRuns(): readonly ExportRunEntry[] {\n const runtime = useDataRuntime();\n const store = getExportRunsStore(runtime);\n // `store.subscribe`/`store.list` are bound arrow properties on the store\n // instance (stable per-store), so they can be passed directly — no\n // memoized wrapper closure is needed to keep useSyncExternalStore from\n // resubscribing on every render.\n return useSyncExternalStore(store.subscribe, store.list, store.list);\n}\n\n/** Removes a run from the app's shared `ExportRunsStore`. A separate hook\n * (rather than widening `useExportRuns`'s return, which the brief fixes as\n * a plain array) so the frozen `useExportRuns` surface never has to grow a\n * second shape. `store.dismiss` is a stable bound arrow property, so the\n * returned function is referentially stable across renders. */\nexport function useDismissExportRun(): (runId: string) => void {\n const runtime = useDataRuntime();\n const store = getExportRunsStore(runtime);\n return store.dismiss;\n}\n\nfunction resourceHandle(resource: string): ErasedResourceHandle {\n return { kind: 'resource', ref: normalizeEntityRef(resource) } as ErasedResourceHandle;\n}\n\n/**\n * Drops own keys whose value is `undefined`.\n *\n * ⚠️ SHALLOW, deliberately narrow — precise about what it closes, not a\n * general portable-value sanitizer:\n * - Strips undefined-valued keys off the TOP-LEVEL `args` object only\n * (`pagination`/`filter`/`sort`/`projection` — `list`/`count`'s own flat\n * parameter shape). This is exactly the failure\n * the since-deleted `apps/playground`'s export browser spec caught live:\n * a `{kind:'filter'}`\n * target with no active filter and no active sort — the default,\n * unfiltered/unsorted list export — handing `{filter: undefined, sort:\n * undefined}` straight to `createQueryDescriptor`, which runs the WHOLE\n * object through `clonePortableValue` (`packages/core`). That function\n * rejects an object whose OWN keys include one whose VALUE is\n * `undefined` — no representation for \"present but meaningless,\" only\n * \"absent\" — hence \"Portable value must contain only JSON-compatible\n * data.\" for every such call.\n * - Does NOT walk into `filter`/`sort` themselves. An `Exporter` (a PUBLIC\n * seam any adopter can implement) that builds a filter expression whose\n * OWN leaf carries an undefined value — e.g. `{ field: 'x', op: 'eq',\n * value: undefined }` — still trips `clonePortableValue` when that\n * nested object reaches it; this function only protects the outer args\n * shape, not arbitrary caller-constructed filter/sort ASTs.\n *\n * `createPaginatedExporter` (`@burojs/export`) now takes the matching care\n * at its own three call sites for exactly the values it itself builds\n * (`target.filter`/`target.sort`/`request.columns`), so this boundary and\n * that exporter agree on the common case; a hypothetical future exporter\n * that constructs a filter/sort value with an undefined LEAF would need its\n * own discipline (or a deeper walk added here) — that residual case is\n * open, not silently closed by this change.\n */\nfunction dropUndefinedValues<T extends Record<string, unknown>>(value: T): Partial<T> {\n const out: Partial<T> = {};\n for (const key of Object.keys(value) as (keyof T)[]) {\n if (value[key] !== undefined) out[key] = value[key];\n }\n return out;\n}\n\n/**\n * Resource-scoped `ExporterDataAccess`, narrowed to `list`/`count` and bound\n * to one resource. Mirrors the REAL query-descriptor construction path —\n * `use-standard-query-descriptor.ts:65-78` (`useList`/`useCount`/`useOne`/\n * `useMany`/`useInfiniteList`), not `action-data-access.ts`'s `resourceBase`\n * — same readiness wait, same registry projection lookup, same binding\n * resolution, same descriptor identity fields (`providerId`, `ref`,\n * `resource`, `sessionKey`, `scopeKey`, `bindingRevision`, `providerOptions`,\n * `dependencies`) — so an exporter's `list`/`count` calls land in the exact\n * cache/generation partition (`queryKeyFor` clones the whole descriptor into\n * the cache key with no field allowlist) that `useList`/`useCount` do for\n * the same resource. Never a second hand-rolled path.\n *\n * Deliberately does NOT include `idField`: it is declared only on the\n * mutation descriptor shapes (`CreateOneDescriptorShape` etc.,\n * `packages/core/src/data/descriptors.ts`), not on `list`/`count`/`one`/\n * `many` — `resourceBase` in `action-data-access.ts` carries it into every\n * descriptor kind uniformly (a pre-existing, out-of-scope quirk there), but\n * copying that here would make an export read canonicalize to a different\n * cache key than the equivalent `useList`/`useCount` call, which is exactly\n * the identity mismatch this mirror exists to prevent. (`ExporterContext\n * .idField`, used by `createPaginatedExporter` to build the bulk `in`\n * predicate on the right column, is unrelated and unaffected — see `start()`\n * below.)\n */\nfunction createExporterDataAccess(\n runtime: DataRuntimeContextValue,\n handle: ErasedResourceHandle,\n /**\n * The active locale, captured by the calling HOOK (this factory is not one).\n * Threaded rather than omitted so the parity claimed above survives the\n * locale axis: for a resource declaring `data.localeVarying`, an export read\n * must land in the same per-locale cache partition — and fetch the same\n * language — as the `useList`/`useCount` it mirrors.\n */\n locale: string,\n): ExporterDataAccess {\n async function identity() {\n const session = await runtime.waitUntilReady();\n const projection = runtime.app.registry.get(handle);\n if (projection === undefined) {\n throw {\n kind: 'configuration',\n code: 'export-resource-unavailable',\n message: `Resource '${handle.ref.namespace}:${handle.ref.id}' is unavailable.`,\n } satisfies DataError;\n }\n const binding = runtime.app.resolveDataBinding(handle);\n return {\n providerId: binding.providerId,\n ref: binding.ref,\n resource: binding.resource,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n ...resolveDescriptorLocale(projection.data, locale),\n bindingRevision: runtime.app.runtime.getSnapshot().manifest.snapshotId,\n ...(projection.data?.providerOptions === undefined\n ? {}\n : { providerOptions: projection.data.providerOptions }),\n ...(projection.data?.dependencies === undefined\n ? {}\n : { dependencies: projection.data.dependencies }),\n };\n }\n\n return Object.freeze({\n async list(args: Parameters<ExporterDataAccess['list']>[0]) {\n const descriptor = createQueryDescriptor({\n ...(await identity()),\n kind: 'list',\n ...dropUndefinedValues(args),\n } as never);\n return executeQuery({ descriptor, runtime, signal: new AbortController().signal }) as Promise<\n ListResult<Record<string, unknown>>\n >;\n },\n async count(args: Parameters<ExporterDataAccess['count']>[0]) {\n const descriptor = createQueryDescriptor({\n ...(await identity()),\n kind: 'count',\n ...dropUndefinedValues(args),\n } as never);\n return executeQuery({\n descriptor,\n runtime,\n signal: new AbortController().signal,\n }) as Promise<CountResult>;\n },\n });\n}\n\n/** Transient provider-registry lifecycle codes (`packages/react/src/data/provider-registry.ts`):\n * the registry hasn't started yet, is mid-transition, or has been disposed.\n * All three self-resolve — the tree re-renders on the next `dataSession`\n * publish and this gets recomputed — so they stay silent. Everything else\n * (an unregistered provider id, a binding that names a provider the app\n * never wired up, a bug inside a provider's own `.exporter` getter) is a\n * real misconfiguration or defect and gets a `console.warn` instead of\n * vanishing into a silent fallback. */\nconst TRANSIENT_PROVIDER_CODES = new Set([\n 'not-started',\n 'provider-transitioning',\n 'registry-disposed',\n]);\n\n/** Dedup key for the provider-exporter-lookup `console.warn` below: one\n * report per (resource, code), not one per render. The hook re-renders on\n * every `dataSession` publish (see `useResourceExport`), so a persistently\n * broken binding would otherwise warn on every render of every component\n * using it. */\nconst reportedProviderExporterFailures = new Set<string>();\n\n/** The provider-bundled exporter for a resource, for both ownership modes.\n * `ResolvedDataBinding.provider` is present only for a BORROWED registration\n * (`packages/core/src/data-binding.ts`) — the uniform accessor for both owned\n * and borrowed providers is the started instance from the react provider\n * registry. */\nfunction resolveProviderExporter(\n runtime: DataRuntimeContextValue,\n handle: ErasedResourceHandle,\n resource: string,\n): Exporter | undefined {\n try {\n const binding = runtime.app.resolveDataBinding(handle);\n return runtime.providers.resolve(binding.providerId).provider.exporter;\n } catch (thrown) {\n const code = (thrown as { readonly code?: string } | undefined)?.code;\n if (code === undefined || !TRANSIENT_PROVIDER_CODES.has(code)) {\n const key = `${resource}::${code ?? ''}`;\n if (!reportedProviderExporterFailures.has(key)) {\n reportedProviderExporterFailures.add(key);\n console.warn('[buro] useResourceExport: provider-bundled exporter lookup failed', thrown);\n }\n }\n return undefined;\n }\n}\n\n/** Dedup key for the resolution-failure `console.error` below: one report\n * per (resource, attempted exporter id), not one per render. */\nconst reportedExportResolutionErrors = new Set<string>();\n\n/**\n * The exporter id the app-config half of the resolution chain would look up —\n * the resource's own `export.exporter` override, else `export.default`.\n *\n * Used for two things: the resolution-failure report below, and the cache key\n * of a deferred (`ExporterLoader`) registration. Both are only ever consulted\n * when the chain actually went through `AppExportConfig.exporters`: a\n * provider-bundled exporter is a ready instance reached without an id (it\n * needs no loading and can never fail to resolve), and `export: false`\n * short-circuits before any lookup.\n */\nfunction attemptedExporterId(\n appExport: AppExportConfig | undefined,\n resourceExportSetting: ResourceExportSetting | undefined,\n): string | undefined {\n return resourceExportSetting !== false && resourceExportSetting?.exporter !== undefined\n ? resourceExportSetting.exporter\n : appExport?.default;\n}\n\n/**\n * `resolveExporter` (`packages/core/src/export/resolve.ts`) does not merely\n * return `undefined` for \"nothing configured\" — it THROWS a `configuration`\n * `DataError` when a named id (a resource's `export.exporter` override, or\n * the app's `export.default`) is not registered. Left unguarded, a typo in\n * either setting crashes the render of every component using this hook.\n * `use-standard-query-descriptor.ts:47-64` sets the precedent: catch,\n * normalize, surface as data rather than an exception.\n */\nfunction resolveExporterSafe(\n appExport: AppExportConfig | undefined,\n resourceExportSetting: ResourceExportSetting | undefined,\n providerExporter: Exporter | undefined,\n resource: string,\n): {\n readonly resolved: Exporter | ExporterLoader | undefined;\n readonly error: DataError | undefined;\n} {\n try {\n return {\n resolved: resolveExporter(appExport, resourceExportSetting, providerExporter),\n error: undefined,\n };\n } catch (thrown) {\n const error = normalizeDataError(thrown);\n const attemptedId = attemptedExporterId(appExport, resourceExportSetting);\n const key = `${resource}::${attemptedId ?? ''}`;\n if (!reportedExportResolutionErrors.has(key)) {\n reportedExportResolutionErrors.add(key);\n console.error(\n `[buro] useResourceExport('${resource}'): exporter '${attemptedId ?? ''}' failed to resolve — ${error.message}`,\n error,\n );\n }\n return { resolved: undefined, error };\n }\n}\n\n/**\n * One in-flight-or-settled load per (app, exporter id).\n *\n * Same keying idiom (and the same reasoning) as `runsStores` above: the\n * `DataRuntimeContextValue` identity IS the app instance, so two dialogs for\n * the same resource — the toolbar's filter-scope one and the bulk bar's\n * ids-scope one — share one entry and therefore ONE `import()`. The stored\n * value is the PROMISE, not merely the settled instance: without that, a\n * second dialog mounting while the first load is still in flight would find\n * nothing cached and start a second one.\n */\nconst exporterLoads = new WeakMap<DataRuntimeContextValue, Map<string, ExporterLoadEntry>>();\n\ninterface ExporterLoadEntry {\n readonly promise: Promise<Exporter>;\n /** Set once the promise fulfils — the synchronous read path for renders\n * that happen after the load finished (including a brand-new component\n * mounting into an app that already loaded this exporter). */\n instance?: Exporter;\n}\n\nfunction exporterLoadsFor(runtime: DataRuntimeContextValue): Map<string, ExporterLoadEntry> {\n let cache = exporterLoads.get(runtime);\n if (cache === undefined) {\n cache = new Map();\n exporterLoads.set(runtime, cache);\n }\n return cache;\n}\n\n/** Dedup key for the load-failure `console.error`: one report per EXPORTER ID,\n * with no resource in it — unlike the two report sets above, which are\n * per-(resource, …) because a misconfigured resource is what they describe. A\n * loader failing is a module-fetch failure of one registration: it is identical\n * for every resource pointing at that id, and `startExporterLoad` is called\n * with no resource in scope precisely because none is relevant. A retry that\n * fails again stays quiet in the console — the failure is surfaced as `error`\n * on the hook result either way. */\nconst reportedExporterLoadFailures = new Set<string>();\n\nfunction exporterLoadFailure(exporterId: string, thrown: unknown): DataError {\n return {\n kind: 'transport',\n code: EXPORT_ERROR_CODES.exporterLoadFailed,\n message: `Exporter '${exporterId}' failed to load: ${normalizeDataError(thrown).message}`,\n retryable: true,\n cause: thrown,\n };\n}\n\n/**\n * Starts (or joins) the load of a deferred exporter registration.\n *\n * A REJECTED load is deliberately not kept: the entry is removed from the\n * cache the moment it fails, so the next attempt runs the loader again — and\n * because the dialog asks to load per OPEN (`{ load: open }`), reopening it is\n * such an attempt. A failed `import()` is usually a network or deploy artefact\n * (a stale chunk hash, an offline tab), i.e. exactly the class of failure a\n * retry fixes — caching it would turn one bad fetch into a dead export for the\n * rest of the session. The rejection is still delivered to everyone already\n * awaiting THIS attempt (they hold the promise), so no caller is left hanging.\n */\nfunction startExporterLoad(\n runtime: DataRuntimeContextValue,\n exporterId: string,\n loader: ExporterLoader,\n): ExporterLoadEntry {\n const cache = exporterLoadsFor(runtime);\n const existing = cache.get(exporterId);\n if (existing !== undefined) return existing;\n\n const entry: { promise: Promise<Exporter>; instance?: Exporter } = {\n // Replaced below, before anything can observe it; a placeholder is needed\n // because the promise's own handlers close over `entry`.\n promise: undefined as unknown as Promise<Exporter>,\n };\n entry.promise = (async () => loader())().then(\n (exporter) => {\n entry.instance = exporter;\n return exporter;\n },\n (thrown: unknown) => {\n if (cache.get(exporterId) === entry) cache.delete(exporterId);\n const error = exporterLoadFailure(exporterId, thrown);\n if (!reportedExporterLoadFailures.has(exporterId)) {\n reportedExporterLoadFailures.add(exporterId);\n console.error(`[buro] useResourceExport: ${error.message}`, thrown);\n }\n throw error;\n },\n );\n cache.set(exporterId, entry);\n return entry;\n}\n\n/** The already-loaded instance for a deferred registration, or `undefined` —\n * a synchronous cache peek that NEVER invokes the loader. */\nfunction peekLoadedExporter(\n runtime: DataRuntimeContextValue,\n exporterId: string | undefined,\n): Exporter | undefined {\n if (exporterId === undefined) return undefined;\n return exporterLoads.get(runtime)?.get(exporterId)?.instance;\n}\n\n/** Per-hook load outcome — SETTLED states only; \"loading\" is derived during\n * render (see the hook), so there is no in-flight state to keep in sync. Keyed\n * by exporter id so a resource whose override changes mid-life never shows the\n * previous exporter's outcome. */\ntype ExporterLoadOutcome =\n | { readonly status: 'loaded'; readonly exporterId: string; readonly exporter: Exporter }\n | { readonly status: 'failed'; readonly exporterId: string; readonly error: DataError };\n\nexport interface UseResourceExportOptions {\n /**\n * Invoke a deferred (`ExporterLoader`) registration — i.e. actually fetch\n * the exporter's chunk. Default `false`: `available`, which is all the\n * toolbar/bulk-bar triggers read, is answerable from the registration\n * alone, and gating those renders on a chunk fetch would defeat the whole\n * point of registering a loader. Only a surface that is about to run an\n * export (the export dialog) passes `true`.\n */\n readonly load?: boolean;\n}\n\nexport interface UseResourceExportResult {\n /**\n * An exporter is registered for this resource — `true` for a ready\n * `Exporter` AND for a not-yet-loaded `ExporterLoader`, since both mean\n * \"this resource can be exported\". Answered without invoking a loader.\n *\n * Flips back to `false` if a load that WAS attempted (`load: true`) failed,\n * with `error` explaining why: at that point this surface genuinely has no\n * exporter to offer. Not permanent — the failed attempt is not cached, so the\n * next attempt retries (for the framework's dialog, that is simply reopening\n * it: it asks to load per open). A consumer that never asked to load is\n * unaffected throughout.\n */\n readonly available: boolean;\n /** A deferred registration for this resource is loading right now — true\n * from the FIRST render that asks to load, not one commit later, so a surface\n * gated on it never paints an empty form first. Only ever `true` for a caller\n * that passed `load: true`. While it is, `formats` is empty and `exporter` is\n * absent. */\n readonly loading: boolean;\n readonly exporter?: Exporter;\n /** Present only when `resolveExporter` itself threw (an unregistered\n * exporter id in a resource override or the app default) or when a\n * deferred registration failed to load — the reason `available` is\n * `false`, for Task 8 to show instead of a bare \"no export\". */\n readonly error?: DataError;\n readonly formats: readonly ExportFormat[];\n /**\n * Starts an export run. SYNCHRONOUS by contract (both entry points and the\n * dialog build on that), so it cannot wait for a deferred registration: if\n * the exporter has not loaded yet it throws an `export/exporter-not-loaded`\n * `DataError` naming the resource. Callers gate their start affordance on\n * `loading` (the dialog disables Start) rather than relying on this guard.\n */\n start(request: Omit<ExportRequest, 'resource'>): ExportRunEntry;\n /**\n * Fire-and-forget: begins loading a deferred registration without this\n * caller having to switch to `load: true` (it will not re-render on\n * completion). Meant for hover/focus prefetch on an export trigger, so the\n * chunk is usually already there when the dialog mounts. A no-op when the\n * exporter is already loaded, was registered as a ready instance, or\n * nothing resolves.\n */\n prefetch(): void;\n}\n\n/**\n * Resolves the exporter for one resource through the core resolution chain\n * (`resolveExporter`, guarded — see `resolveExporterSafe`) and exposes a\n * `start()` that builds the `ExporterContext` (data access + `idField`),\n * runs the exporter, and registers the resulting run in the app's shared\n * `ExportRunsStore`.\n *\n * `available` is `false` whenever nothing resolves — including a resource\n * `export: false` setting (which `resolveExporter` itself treats as \"no\n * exporter\", no throw), a resolution failure, and a deferred registration\n * whose load was attempted and failed (`error` is set in all but the first\n * case). It can flip from `false` to `true` after mount: before the data\n * session is ready, a provider-bundled exporter is unreachable (see\n * `resolveProviderExporter`), and the hook re-renders once the session\n * becomes ready.\n *\n * The returned object, `formats`, and `start` are memoized so Tasks 7-8 can\n * use them as `useEffect`/`useMemo` dependencies without a re-render loop.\n *\n * ## Deferred registrations\n *\n * `AppExportConfig.exporters` may register an `ExporterLoader` (`() =>\n * Promise<Exporter>`) instead of a ready `Exporter`, so an app's exporter\n * factories stay out of its initial JS. This hook is the only place that ever\n * invokes one, and only when the caller passes `{ load: true }` — `available`\n * is deliberately answerable from the registration alone. See\n * {@link UseResourceExportOptions.load}.\n */\nexport function useResourceExport(\n resource: string,\n opts: UseResourceExportOptions = {},\n): UseResourceExportResult {\n const shouldLoad = opts.load === true;\n const runtime = useDataRuntime();\n const store = getExportRunsStore(runtime);\n // Captured here because `start` (and the data access it builds) is not a\n // hook. See `createExporterDataAccess`.\n const locale = useLocale();\n // Re-render on session transitions so a provider-bundled exporter that was\n // unreachable before the session was ready gets picked up once it is.\n useSyncExternalStore(\n runtime.dataSession.subscribe,\n runtime.dataSession.getState,\n runtime.dataSession.getState,\n );\n\n const handle = useMemo(() => resourceHandle(resource), [resource]);\n const projection = runtime.app.registry.get(handle);\n const resourceExportSetting = projection?.export;\n const providerExporter = resolveProviderExporter(runtime, handle, resource);\n const { resolved, error: resolutionError } = resolveExporterSafe(\n runtime.app.exportConfig,\n resourceExportSetting,\n providerExporter,\n resource,\n );\n\n // `typeof === 'function'` IS the whole discrimination between the two\n // registration forms (`AppExportConfig.exporters`): an `Exporter` is an\n // object carrying methods, an `ExporterLoader` is a function. Split into two\n // separately-typed locals rather than casting later.\n const loader: ExporterLoader | undefined = typeof resolved === 'function' ? resolved : undefined;\n const instanceExporter: Exporter | undefined =\n typeof resolved === 'function' ? undefined : resolved;\n const loaderId =\n loader === undefined\n ? undefined\n : attemptedExporterId(runtime.app.exportConfig, resourceExportSetting);\n\n const [outcome, setOutcome] = useState<ExporterLoadOutcome | undefined>(undefined);\n /** The load outcome for the exporter id resolving RIGHT NOW — a stale one\n * from a previous id (a resource override that changed) is ignored. */\n const ownOutcome = outcome?.exporterId === loaderId ? outcome : undefined;\n\n // `shouldLoad` is a REAL dep, not a constant: the export dialog passes\n // `{ load: open }`, so this effect re-runs on every open. That is what makes a\n // failed load recoverable — reopening the dialog runs the loader again and the\n // fresh attempt's outcome replaces the stale `'failed'` one. It was not always\n // so: with `{ load: true }` (plus a dialog kept mounted after close) all four\n // deps were constant for the app's lifetime, the effect ran exactly once per\n // mount, and one rejected load left that surface permanently unavailable until\n // a route change unmounted it — while the changeset and the adopter guide both\n // promised that reopening retries. Do not turn `shouldLoad` back into a\n // literal.\n useEffect(() => {\n if (!shouldLoad || loader === undefined || loaderId === undefined) return;\n const cached = peekLoadedExporter(runtime, loaderId);\n if (cached !== undefined) {\n setOutcome({ status: 'loaded', exporterId: loaderId, exporter: cached });\n return;\n }\n let live = true;\n // Clear any outcome from a previous attempt at this same id before starting\n // a new one, so a reopen after a failure does not show the dead attempt's\n // error while the retry is in flight.\n setOutcome(undefined);\n // `startExporterLoad` dedupes by (app, exporter id), so a second dialog\n // for the same resource — or a StrictMode remount — joins this same\n // promise instead of fetching the chunk twice.\n startExporterLoad(runtime, loaderId, loader).promise.then(\n (loaded) => {\n if (live) setOutcome({ status: 'loaded', exporterId: loaderId, exporter: loaded });\n },\n (thrown: unknown) => {\n if (live)\n setOutcome({ status: 'failed', exporterId: loaderId, error: normalizeDataError(thrown) });\n },\n );\n return () => {\n live = false;\n };\n }, [shouldLoad, loader, loaderId, runtime]);\n\n // The cache peek comes FIRST so a component that mounts into an app which\n // already loaded this exporter (a second dialog, or this one reopened) is\n // never shown a loading state for work that is already done — including the\n // `load: false` triggers, which get the loaded instance for free but never\n // cause a load.\n //\n // ⚠️ This is an impure read of module-level state during render, with no\n // subscription. The VALUE is monotonic (absent → present, never back), so it\n // can never regress and no render sees a torn exporter. What it does NOT give\n // is agreement WITHIN one commit: if the load settles between two components\n // rendering in the same pass, the earlier one can see `undefined` while the\n // later sees the instance. Harmless here — the earlier one is a\n // trigger/dialog that shows \"loading\" and re-renders on the state update the\n // very same promise handler queues (or, for a `load: false` caller, on its\n // next render for any reason) — but it is a real tearing window, not an\n // absence of one, and anything moved onto this peek must be able to tolerate\n // it.\n const loadedExporter =\n loader === undefined\n ? undefined\n : (peekLoadedExporter(runtime, loaderId) ??\n (ownOutcome?.status === 'loaded' ? ownOutcome.exporter : undefined));\n const exporter = instanceExporter ?? loadedExporter;\n // A load error is reported ONLY while there is no exporter to use. Otherwise\n // a `prefetch()` that succeeded after an earlier attempt failed would leave\n // this result carrying `exporter` AND `error` at once — a shape that says two\n // contradictory things about the same resource. Made impossible rather than\n // merely unobservable: `resolutionError` cannot coexist with an exporter\n // either (a resolution throw means nothing resolved, so there is no loader and\n // no instance), so `error` and `exporter` are mutually exclusive by\n // construction.\n const loadError =\n exporter === undefined && ownOutcome?.status === 'failed' ? ownOutcome.error : undefined;\n const error = resolutionError ?? loadError;\n // Derived during RENDER, not from an effect-set 'loading' state: a caller that\n // asked to load and has neither an exporter nor a failure IS loading, whether\n // or not the effect has fired yet. Computing it from state instead cost an\n // extra frame — the first render of a freshly opened dialog reported\n // `loading: false` with `formats: []`, so it painted an empty form before the\n // \"preparing\" affordance appeared one commit later.\n const loading =\n shouldLoad && loader !== undefined && exporter === undefined && error === undefined;\n // A registered-but-unloaded loader still means \"this resource can be\n // exported\" — that is the whole point of the deferred form. A load that was\n // attempted and FAILED does not (see `UseResourceExportResult.available`).\n const available = exporter !== undefined || (loader !== undefined && loadError === undefined);\n\n const formats = useMemo(() => exporter?.formats({ resource }) ?? [], [exporter, resource]);\n\n const prefetch = useCallback(() => {\n if (loader === undefined || loaderId === undefined) return;\n if (peekLoadedExporter(runtime, loaderId) !== undefined) return;\n // Fire-and-forget, so the rejection must be absorbed HERE or it becomes an\n // unhandled promise rejection: this caller does not observe the outcome.\n // Nothing is lost — the failed entry is dropped from the cache, the\n // load-failure `console.error` already fired, and the dialog's own\n // `load: true` attempt reports it as `error`.\n void startExporterLoad(runtime, loaderId, loader).promise.catch(() => undefined);\n }, [loader, loaderId, runtime]);\n\n const start = useCallback(\n (request: Omit<ExportRequest, 'resource'>): ExportRunEntry => {\n if (exporter === undefined) {\n if (error !== undefined) throw error;\n // A deferred registration that has not finished loading. `start` is\n // synchronous by contract, so it cannot wait — it names the cause\n // instead of failing as a bare \"no exporter\", which would be actively\n // misleading (one IS registered).\n if (loader !== undefined) {\n throw {\n kind: 'configuration',\n code: EXPORT_ERROR_CODES.exporterNotLoaded,\n message: `The exporter for resource '${resource}' has not finished loading — start() is synchronous and cannot wait for it. Gate the start affordance on \\`useResourceExport(resource, { load: true }).loading\\`.`,\n } satisfies DataError;\n }\n throw {\n kind: 'configuration',\n code: EXPORT_ERROR_CODES.noExporter,\n message: `No exporter is available for resource '${resource}'.`,\n } satisfies DataError;\n }\n // Generate (and validate) the run id BEFORE the exporter starts doing\n // real work: `crypto.randomUUID` can throw in a non-secure-context\n // browser, and if that happened AFTER `exporter.start(...)` the run\n // would already be live — consuming backend work for a job exporter —\n // yet never make it into the store, so it would be unobservable and\n // uncancelable. This probe result is discarded; `store.start` below\n // generates the id it actually commits. Both calls run synchronously\n // back-to-back with no state change between them, so if the probe\n // succeeds the real one cannot then fail.\n createExportRunId();\n const idField = projection?.data?.idField ?? 'id';\n const data = createExporterDataAccess(runtime, handle, locale);\n const ctx: ExporterContext = { resource, data, idField };\n const fullRequest: ExportRequest = { ...request, resource };\n const exportHandle = exporter.start(fullRequest, ctx);\n return store.start({\n resource,\n exporterId: exporter.id,\n formatId: fullRequest.format.id,\n handle: exportHandle,\n });\n },\n [exporter, error, loader, resource, projection, handle, runtime, store, locale],\n );\n\n return useMemo(\n () => ({\n available,\n loading,\n ...(exporter === undefined ? {} : { exporter }),\n ...(error === undefined ? {} : { error }),\n formats,\n start,\n prefetch,\n }),\n [available, loading, exporter, error, formats, start, prefetch],\n );\n}\n","// Constants\nexport const PACKAGE_NAME = '@burojs/react' as const;\nexport const PACKAGE_VERSION = '0.0.0' as const;\n\n// Core data-session contract\nexport { createDataSession } from '@burojs/core';\nexport type {\n DataSessionController,\n DataSessionState,\n DataSessionTransitionParticipant,\n} from '@burojs/core';\n\n// Native React data runtime\nexport {\n createDataRuntime,\n createDataRuntimeTransitionParticipant,\n type CreateDataRuntimeOptions,\n type CreateDataRuntimeTransitionParticipantOptions,\n type DataRuntimeContextValue,\n type DataRuntimeLease,\n type DataRuntimeTransitionParticipant,\n} from './data/runtime.js';\nexport { useDataRuntime, useOptionalDataRuntime } from './data/context.js';\nexport {\n dehydrateBuroData,\n disposeBuroRequest,\n hydrateBuroData,\n serializeBuroHydration,\n validateBuroHydration,\n type BuroDehydratedData,\n} from './data/ssr.js';\nexport {\n createAuthController,\n type AuthController,\n type CreateAuthControllerOptions,\n} from './auth/controller.js';\nexport { useIdentity, useIsAuthenticated, useLogin, useLogout } from './hooks/auth/use-auth.js';\nexport { useList, type UseListOptions } from './hooks/data/use-list.js';\nexport { useOne, type UseOneOptions } from './hooks/data/use-one.js';\nexport { useMany, type UseManyOptions } from './hooks/data/use-many.js';\nexport { useCount, type UseCountOptions } from './hooks/data/use-count.js';\nexport {\n useInfiniteList,\n type InfiniteListData,\n type NativeInfiniteListResult,\n type UseInfiniteListOptions,\n} from './hooks/data/use-infinite-list.js';\nexport { resolveCountExecution, type CountExecution } from './data/count-policy.js';\nexport { useCustomQuery, type UseCustomQueryOptions } from './hooks/data/use-custom-query.js';\nexport type { NativeQueryOptions, NativeQueryResult } from './hooks/data/use-query-descriptor.js';\nexport {\n buroMutationOptions,\n type NativeMutationOptions,\n} from './data/mutation-options.js';\nexport {\n useCreateOne,\n useCreateMany,\n type UseCreateOneOptions,\n type UseCreateManyOptions,\n} from './hooks/data/use-create.js';\nexport {\n useUpdateOne,\n useUpdateMany,\n type UseUpdateOneOptions,\n type UseUpdateManyOptions,\n} from './hooks/data/use-update.js';\nexport {\n useDeleteOne,\n useDeleteMany,\n type UseDeleteOneOptions,\n type UseDeleteManyOptions,\n} from './hooks/data/use-delete.js';\nexport {\n useCustomMutation,\n type UseCustomMutationOptions,\n} from './hooks/data/use-custom-mutation.js';\n\n// Provider + contexts\nexport { BuroProvider, type BuroProviderProps } from './provider.js';\nexport { useAudit } from './audit/context.js';\nexport { buildFormDiff, type BuildFormDiffArgs } from './audit/form-diff.js';\nexport {\n useFormSubmitAudit,\n type FormSubmitAudit,\n type FormSubmitAuditArgs,\n} from './audit/use-form-submit-audit.js';\nexport {\n UiSettingsProvider,\n useUiSettings,\n type UiSettingsProviderProps,\n type UseUiSettingsCollectionResult,\n type UseUiSettingsResult,\n type UseUiSettingsSingletonResult,\n} from './ui-settings/index.js';\nexport {\n hydrateManifest,\n createManifestHydrationScope,\n type InitialManifest,\n type ManifestHydration,\n type ManifestHydrationScope,\n} from './runtime/manifest-hydration.js';\nexport {\n BuroRuntimeProvider,\n useApplicationSnapshot,\n useLayerRuntime,\n useLayerStatus,\n useProjection,\n type BuroRuntimeProviderProps,\n} from './runtime.js';\nexport { ComponentsContext, I18nContext, ResourceContext, TestIdContext } from './context.js';\nexport { createRuntimeActionDataAccess } from './data/action-data-access.js';\n\n// Hooks\nexport { useApp } from './hooks/use-app.js';\nexport { useResource } from './hooks/use-resource.js';\nexport {\n RecordCodecError,\n createResourceRecordCodec,\n normalizeServerRecordIssues,\n type RecordCodecOutcome,\n type ResourceRecordCodec,\n} from '@burojs/core';\nexport {\n FieldImplementationProvider,\n useFieldImplementationCatalog,\n EMPTY_FIELD_IMPLEMENTATIONS,\n composeFieldImplementations,\n resolveFieldImplementation,\n useFieldImplementation,\n defineFieldWithImplementation,\n} from './fields/index.js';\nexport type {\n CollectionDisplayProps,\n CollectionInputProps,\n FieldAccessibilityIds,\n FieldImplementation,\n FieldImplementationLayout,\n FieldI18n,\n FieldImplementationComponent,\n FieldImplementationDiagnostic,\n FieldImplementationCatalog,\n FieldImplementationMap,\n FieldImplementationSource,\n FieldPresentation,\n FieldRenderContext,\n FieldRenderSurface,\n FieldTestIds,\n FieldUiHints,\n ResolvedFieldImplementation,\n ScalarDisplayProps,\n ScalarInputProps,\n UseFieldImplementationArgs,\n DefinedField,\n} from './fields/index.js';\nexport { useDoc } from './hooks/use-doc.js';\nexport {\n DocsProvider,\n useDocPanel,\n useDocTopic,\n useDocTopics,\n useDocsConfig,\n useDocScopes,\n useDocTrailScopes,\n useHasDocTopics,\n usePublishDocVariant,\n useTrailHasDocs,\n useDocumentedScopes,\n type DocumentedScope,\n} from './hooks/use-doc-panel.js';\nexport type {\n DocPanelApi,\n DocPanelTarget,\n DocScopeView,\n DocTopicView,\n} from './hooks/use-doc-panel.js';\nexport { useCurrentResource } from './hooks/use-current-resource.js';\nexport { useCtx } from './hooks/use-ctx.js';\nexport {\n usePermissions,\n useScopeCtx,\n useVisibilityCtx,\n useOptionalVisibilityCtx,\n} from './hooks/use-permissions.js';\nexport { useVisibleTemplates } from './hooks/use-visible-templates.js';\nexport { useCapability, useCapabilityResolver } from './hooks/use-capability.js';\nexport type { CapabilityResolver, UseCapabilityArgs } from './hooks/use-capability.js';\nexport {\n useAvailability,\n useAvailabilityGate,\n useAvailabilityResolver,\n} from './hooks/use-availability.js';\nexport { useAppActions } from './hooks/use-app-actions.js';\nexport type { AppActionEntry } from './hooks/use-app-actions.js';\nexport { useSetSlice } from './hooks/use-set-slice.js';\nexport {\n useT,\n useOptionalT,\n useLocale,\n useOptionalLocale,\n useChangeLocale,\n useTranslate,\n useI18nCaps,\n useResourceI18n,\n} from './hooks/use-t.js';\nexport { useComponent, useDefaultComponent } from './hooks/use-component.js';\nexport { useTestIds, type TestIdBuilder } from './hooks/use-test-ids.js';\nexport { useRecordTitle } from './hooks/use-record-title.js';\nexport { useAction, type UseActionResult, type UseActionArgs } from './hooks/use-action.js';\nexport {\n useTaskRun,\n type TaskRunController,\n type TaskRunReporter,\n type UseTaskRunOptions,\n} from './hooks/use-task-run.js';\nexport { useChecks, type UseChecksOptions, type UseChecksResult } from './checks/use-checks.js';\nexport {\n useCheckGate,\n type CheckGateRequest,\n type CheckGateState,\n type UseCheckGateResult,\n} from './checks/use-check-gate.js';\nexport {\n useBulkAction,\n type UseBulkActionResult,\n type UseBulkActionArgs,\n} from './hooks/use-bulk-action.js';\nexport { useLocalStorage } from './hooks/use-local-storage.js';\nexport {\n RouterAdapterProvider,\n useRouterAdapter,\n type RouterAdapter,\n type RouterAdapterProviderProps,\n} from './hooks/router/router-adapter.js';\nexport { useDebouncedValue } from './hooks/use-debounced-value.js';\nexport {\n useFileField,\n formatBytes,\n matchesAccept,\n type FileItem,\n type FileItemStatus,\n type UseFileFieldArgs,\n type UseFileFieldResult,\n} from './hooks/file/use-file-field.js';\nexport { useFileStorage, useOptionalFileStorage } from './hooks/file/use-file-storage.js';\nexport {\n useFileUrls,\n type UseFileUrlsOpts,\n type UseFileUrlsResult,\n} from './hooks/file/use-file-urls.js';\nexport {\n createUrlCache,\n sharedUrlCache,\n RESOLVE_COOLDOWN_MS,\n type UrlCache,\n} from './hooks/file/url-cache.js';\nexport { useEnumValues, type UseEnumValuesResult } from './hooks/use-enum-values.js';\nexport {\n RelationAggregatorProvider,\n useRelatedRecord,\n type RelationAggregatorProviderProps,\n type UseRelatedRecordResult,\n type RelatedRecord,\n} from './hooks/relation-aggregator.js';\nexport {\n useResourceUrlState,\n DEFAULT_HISTORY_MODE,\n serializeResourceState,\n deserializeResourceState,\n RESOURCE_URL_STATE_LIMITS,\n getResourceParams,\n type HistoryMode,\n type SetterOptions,\n type ResourceUrlState,\n type CodecOptions,\n type FieldType,\n} from './hooks/url-state/index.js';\nexport {\n useSavedViews,\n type SavedViewEntry,\n type UseSavedViewsResult,\n} from './hooks/saved-views/use-saved-views.js';\n// The framework-owned local-user scope id (Task 9): the ONE `UiSettingScope`\n// id the default local-storage adapter ever produces. UI recognizes this\n// EXACT id to swap its data-layer placeholder label for a reactive i18n\n// one — see `local-storage-adapter.ts`'s doc on `LOCAL_USER_SCOPE_ID`.\nexport {\n createLocalStorageUiSettingsAdapter,\n LOCAL_USER_SCOPE_ID,\n type LocalStorageUiSettingsAdapterOptions,\n} from './ui-settings/local-storage-adapter.js';\nexport {\n applyViewToUrlState,\n type ApplyViewToUrlStateOptions,\n type ApplyViewUrlStateSetters,\n} from './hooks/saved-views/apply-view-to-url-state.js';\nexport {\n useCommandPalette,\n type UseCommandPaletteResult,\n type UseCommandPaletteOptions,\n useTrackRecentRecord,\n getRecentRecords,\n clearRecentRecords,\n type RecentRecord,\n type RecentEnvelope,\n type UseTrackRecentRecordOptions,\n} from './hooks/command-palette/index.js';\nexport {\n useItemActions,\n modeForSurface,\n buildDI,\n RENDER_TIME_DATA,\n type ResolvedItemAction,\n} from './hooks/use-item-actions.js';\nexport {\n useResourceList,\n type UseResourceListOptions,\n useFilterFields,\n type UseFilterFieldsOptions,\n type FilterFieldsResult,\n ResourceListProvider,\n useResourceListContext,\n type ResourceListProviderProps,\n type ResourceListController,\n type FilterFieldSpec,\n type FilterKind,\n type RowRecord,\n} from './hooks/use-resource-list/index.js';\n\n// UI presentation (imperative)\nexport {\n UIActivationSurfaceProvider,\n UIInstanceProvider,\n UIPresentationRuntimeProvider,\n useCurrentUIActivation,\n useOptionalUIActivationSurface,\n useOptionalUIInstance,\n useOptionalUIPresentation,\n useUIInstance,\n useUIPresent,\n useUIPresentationRuntime,\n UIPresentations,\n BuroPresentationOutlet,\n type UIInstance,\n type UIPresent,\n type UIPresentInput,\n type UIPresentationHost,\n type UIPresentationHostProps,\n type UIPresentationHosts,\n type UIPresentationLifecycle,\n type UIPresentationOptionsSchema,\n type UIPresentationsProps,\n type PresentationsMode,\n} from './ui/index.js';\n\n// Helpers\nexport { mergeComponents } from './merge-components.js';\n\n// Routes\nexport {\n BuroRoutes,\n generateRouteDescriptors,\n isCustomPageRoute,\n type RouteDescriptor,\n type ResourceRouteDescriptor,\n type CustomPageRouteDescriptor,\n} from './components/buro-routes.js';\n\n// Locales\nexport { en } from './locales/en.js';\nexport { ru } from './locales/ru.js';\n\n// Declarative forms\nexport { useDeclarativeForm } from './forms/use-declarative-form.js';\nexport type {\n UseDeclarativeFormOptions,\n DeclarativeFormApi,\n FieldBinding,\n FormValues,\n ResolvedIssue,\n RelationFilterOpt,\n} from './forms/types.js';\n// Shared conditional-visibility resolution (Task 4) — the same `resolveFieldFlags`\n// the controller runs internally, re-exported so a resource-independent\n// renderer with NO controller instance (`<DeclarativeDisplay>`,\n// `@burojs/ui-shadcn`) can resolve `hidden` off a raw values snapshot without\n// inventing a second visibility mechanism.\nexport { resolveFieldFlags } from './forms/conditional.js';\nexport type { ResolvedFieldFlags } from './forms/conditional.js';\n\n// Export runs store + hooks\nexport {\n ExportRunsStore,\n type ExportRunEntry,\n useDismissExportRun,\n useExportRuns,\n useResourceExport,\n type UseResourceExportOptions,\n type UseResourceExportResult,\n} from './export/index.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["cancelledError","structuralKey","configurationError","sameSession","configurationError","sessionSnapshot","#runtime","#descriptor","#listeners","#state","#active","#set","#tailPromise","#tailController","sessionSnapshot","EMPTY","EMPTY","AppContext","isImplementation","#entries","#listeners","#handleUnsubscribes","#attachHandle","#invalidate","#notify","#snapshot","#detachAll","#detachHandle"],"sources":["../src/data/batch-coordinator.ts","../src/data/live/coordinator.ts","../src/data/provider-registry.ts","../src/data/runtime.ts","../src/data/ssr.ts","../src/auth/controller.ts","../src/auth/context.tsx","../src/hooks/auth/use-auth.ts","../src/hooks/data/use-count.ts","../src/data/infinite-list-observer.ts","../src/hooks/data/use-infinite-list.ts","../src/hooks/data/use-custom-query.ts","../src/hooks/data/use-delete.ts","../src/hooks/data/use-custom-mutation.ts","../src/audit/use-nav-audit.ts","../src/hooks/use-doc-panel.tsx","../src/blocks/context.ts","../src/frames/context.ts","../src/runtime/manifest-hydration.tsx","../src/ui-settings/local-storage-adapter.ts","../src/ui-settings/context.ts","../src/ui-settings/provider.tsx","../src/quick/quick-overlays.tsx","../src/provider.tsx","../src/ui-settings/use-ui-settings.ts","../src/hooks/use-resource.ts","../src/blocks/implementation.ts","../src/frames/implementation.ts","../src/frames/check-context.ts","../src/frames/use-frame-t.ts","../src/forms/controller/use-page-screen.ts","../src/record/record-frame-context.tsx","../src/blocks/use-placement.ts","../src/blocks/use-route-list-implementation.ts","../src/fields/field-implementation.ts","../src/fields/define-field-with-implementation.ts","../src/fields/use-field-meta.ts","../src/fields/use-candidates-access.ts","../src/hooks/use-doc.ts","../src/hooks/use-current-resource.ts","../src/hooks/use-capability.ts","../src/hooks/use-availability.ts","../src/hooks/use-app-actions.ts","../src/hooks/use-set-slice.ts","../src/hooks/use-test-ids.ts","../src/hooks/use-task-run.ts","../src/hooks/use-refresh.ts","../src/hooks/use-local-storage.ts","../src/hooks/use-debounced-value.ts","../src/hooks/file/use-file-storage.ts","../src/hooks/file/use-file-field.ts","../src/hooks/file/url-cache.ts","../src/hooks/file/use-file-urls.ts","../src/hooks/use-enum-values.ts","../src/hooks/saved-views/saved-view-setting.ts","../src/hooks/saved-views/use-saved-views.ts","../src/hooks/saved-views/apply-view-to-url-state.ts","../src/hooks/command-palette/use-command-palette.ts","../src/hooks/use-item-actions.ts","../src/hooks/use-resource-list/helpers.ts","../src/hooks/use-resource-list/use-filter-fields.ts","../src/hooks/use-resource-list/row-href.ts","../src/hooks/use-resource-list/use-resource-list.ts","../src/hooks/use-resource-list/context.tsx","../src/ui/present-block.ts","../src/flows/open-implementation.ts","../src/flows/resource-flows.ts","../src/merge-components.ts","../src/components/buro-routes.tsx","../src/locales/en.ts","../src/locales/ru.ts","../src/forms/validation-message.ts","../src/hooks/url-state/use-search-params-writer.ts","../src/export/runs-store.ts","../src/export/use-export.ts","../src/index.ts"],"sourcesContent":["import {\n normalizeDataError,\n queryKeyFor,\n validateBatchResult,\n type BatchedQueryOperation,\n type DataError,\n type DataProviderSessionSnapshot,\n type ErasedQueryDescriptor,\n type QueryContext,\n type RequestContext,\n} from '@burojs/core';\n\nfunction cancelledError(code: 'aborted' | 'stale-generation' = 'aborted'): DataError {\n return {\n kind: 'cancelled',\n code,\n message:\n code === 'aborted'\n ? 'Data query was aborted.'\n : 'Data query completed after its session generation changed.',\n };\n}\n\nexport interface BatchExecutionContext {\n /** Opaque resolved provider-instance identity; provider IDs are insufficient. */\n readonly serviceIdentity: object;\n readonly providerServiceKey: string;\n readonly requestContext: Readonly<RequestContext>;\n readonly session: DataProviderSessionSnapshot;\n readonly signal: AbortSignal;\n readonly batch: (\n operations: readonly BatchedQueryOperation[],\n context: QueryContext,\n ) => Promise<unknown>;\n}\n\nexport interface BatchCoordinator {\n execute<T>(operation: BatchedQueryOperation, context: BatchExecutionContext): Promise<T>;\n cancelGeneration(generation: number): void;\n dispose(): void;\n}\n\ninterface Waiter<T = unknown> {\n readonly resolve: (value: T) => void;\n readonly reject: (reason: DataError) => void;\n readonly signal: AbortSignal;\n removeAbortListener(): void;\n}\n\ninterface Entry {\n readonly operation: BatchedQueryOperation;\n readonly descriptorKey: string;\n readonly group: Group;\n readonly waiters: Set<Waiter>;\n}\n\ninterface Group {\n readonly key: string;\n readonly context: BatchExecutionContext;\n readonly entries: Map<string, Entry>;\n readonly controller: AbortController;\n dispatched: boolean;\n}\n\nfunction structuralKey(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction operationKey(descriptor: ErasedQueryDescriptor): string {\n return structuralKey(queryKeyFor(descriptor));\n}\n\n/**\n * Groups optional provider batch requests without widening their authority:\n * a group is bound to the resolved provider object, active execution session,\n * scope, and binding revision of each descriptor.\n */\nexport function createBatchCoordinator(): BatchCoordinator {\n let disposed = false;\n let nextObjectToken = 0;\n let nextOperationToken = 0;\n const objectTokens = new WeakMap<object, number>();\n /** Includes dispatched groups which a newer same-key microtask superseded. */\n const activeGroups = new Set<Group>();\n const groups = new Map<string, Group>();\n\n function objectToken(value: object): number {\n const existing = objectTokens.get(value);\n if (existing !== undefined) return existing;\n nextObjectToken += 1;\n objectTokens.set(value, nextObjectToken);\n return nextObjectToken;\n }\n\n function groupKey(operation: BatchedQueryOperation, context: BatchExecutionContext): string {\n return structuralKey([\n objectToken(context.serviceIdentity),\n context.session.sessionKey,\n context.session.generation,\n context.session.scopeKey,\n operation.descriptor.sessionKey,\n operation.descriptor.scopeKey,\n operation.descriptor.bindingRevision,\n ]);\n }\n\n function rejectWaiter(waiter: Waiter, error: DataError): void {\n waiter.removeAbortListener();\n waiter.reject(error);\n }\n\n function settleEntry(\n entry: Entry,\n result:\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: DataError },\n ): void {\n for (const waiter of [...entry.waiters]) {\n entry.waiters.delete(waiter);\n waiter.removeAbortListener();\n if (result.ok) waiter.resolve(result.value);\n else waiter.reject(result.error);\n }\n }\n\n function discardEntry(entry: Entry): void {\n entry.group.entries.delete(entry.descriptorKey);\n }\n\n function abortSubmittedGroupWhenEmpty(group: Group): void {\n if (!group.dispatched) return;\n if ([...group.entries.values()].every((entry) => entry.waiters.size === 0)) {\n group.controller.abort();\n }\n }\n\n function cancelWaiter(entry: Entry, waiter: Waiter, code: 'aborted' | 'stale-generation'): void {\n if (!entry.waiters.delete(waiter)) return;\n rejectWaiter(waiter, cancelledError(code));\n if (!entry.group.dispatched && entry.waiters.size === 0) discardEntry(entry);\n abortSubmittedGroupWhenEmpty(entry.group);\n }\n\n function finishGroup(group: Group): void {\n activeGroups.delete(group);\n if (groups.get(group.key) === group) groups.delete(group.key);\n }\n\n async function dispatch(group: Group): Promise<void> {\n if (disposed || group.entries.size === 0) {\n finishGroup(group);\n return;\n }\n group.dispatched = true;\n const entries = [...group.entries.values()];\n const operations = entries.map((entry) => entry.operation);\n const context: QueryContext = Object.freeze({\n signal: group.controller.signal,\n requestContext: group.context.requestContext,\n session: group.context.session,\n providerServiceKey: group.context.providerServiceKey,\n });\n\n try {\n const response = validateBatchResult(\n operations,\n await group.context.batch(operations, context),\n );\n const results = new Map(response.results.map((result) => [result.id, result]));\n for (const entry of entries) {\n const result = results.get(entry.operation.id);\n if (result === undefined) continue; // Core validation already rejects this protocol violation.\n if (entry.waiters.size === 0) continue;\n if (result.status === 'success') settleEntry(entry, { ok: true, value: result.value });\n else settleEntry(entry, { ok: false, error: result.error });\n }\n } catch (error) {\n const normalized = normalizeDataError(error);\n for (const entry of entries) {\n if (entry.waiters.size > 0) settleEntry(entry, { ok: false, error: normalized });\n }\n } finally {\n finishGroup(group);\n }\n }\n\n function schedule(group: Group): void {\n queueMicrotask(() => {\n void dispatch(group);\n });\n }\n\n return Object.freeze({\n execute<T>(operation: BatchedQueryOperation, context: BatchExecutionContext): Promise<T> {\n if (disposed) {\n return Promise.reject({\n kind: 'configuration',\n code: 'batch-coordinator-disposed',\n message: 'Batch coordinator has been disposed.',\n } satisfies DataError);\n }\n if (context.signal.aborted) return Promise.reject(cancelledError());\n\n const descriptorKey = operationKey(operation.descriptor);\n const key = groupKey(operation, context);\n let group = groups.get(key);\n if (group === undefined || group.dispatched) {\n group = {\n key,\n context,\n entries: new Map(),\n controller: new AbortController(),\n dispatched: false,\n };\n groups.set(key, group);\n activeGroups.add(group);\n schedule(group);\n }\n let entry = group.entries.get(descriptorKey);\n if (entry === undefined) {\n nextOperationToken += 1;\n entry = {\n operation: Object.freeze({\n id: `buro-batch-${nextOperationToken.toString(36)}`,\n descriptor: operation.descriptor,\n }),\n descriptorKey,\n group,\n waiters: new Set(),\n };\n group.entries.set(descriptorKey, entry);\n }\n\n return new Promise<T>((resolve, reject) => {\n let waiter: Waiter;\n const abort = () => cancelWaiter(entry!, waiter, 'aborted');\n waiter = {\n resolve: resolve as (value: unknown) => void,\n reject,\n signal: context.signal,\n removeAbortListener() {\n context.signal.removeEventListener('abort', abort);\n },\n };\n entry.waiters.add(waiter);\n context.signal.addEventListener('abort', abort, { once: true });\n if (context.signal.aborted) abort();\n });\n },\n cancelGeneration(generation: number) {\n for (const group of [...activeGroups]) {\n if (group.context.session.generation !== generation) continue;\n for (const entry of [...group.entries.values()]) {\n for (const waiter of [...entry.waiters]) cancelWaiter(entry, waiter, 'stale-generation');\n }\n }\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n for (const group of [...activeGroups]) {\n for (const entry of [...group.entries.values()]) {\n for (const waiter of [...entry.waiters]) cancelWaiter(entry, waiter, 'aborted');\n }\n group.controller.abort();\n }\n groups.clear();\n activeGroups.clear();\n },\n });\n}\n","import {\n isDataError,\n normalizeDataError,\n queryKeyFor,\n resolveDataCapability,\n type DataError,\n type DataSessionController,\n type ErasedQueryDescriptor,\n type LiveConnectionStatus,\n type LiveObserver,\n type LivePlan,\n type Unsubscribe,\n} from '@burojs/core';\n\nimport type { AppRuntime } from '@burojs/core';\n\nimport type { DataProviderRegistry } from '../provider-registry.js';\nimport type { LiveCoordinator, LiveEvent, LiveLease, LiveState } from './types.js';\n\nexport interface LiveCoordinatorRuntime {\n readonly app: AppRuntime;\n readonly dataSession: DataSessionController;\n readonly providers: DataProviderRegistry;\n readonly liveSetupTimeoutMs: number;\n}\n\ninterface Lease<T = unknown> {\n readonly entry: Entry;\n readonly generation: number;\n readonly listeners: Set<() => void>;\n released: boolean;\n state: LiveState<T>;\n}\n\ninterface Entry {\n readonly key: string;\n readonly descriptor: ErasedQueryDescriptor;\n readonly controller: AbortController;\n readonly leases: Set<Lease>;\n executionGeneration: number;\n active: boolean;\n terminal: boolean;\n state: LiveState;\n unsubscribe?: Unsubscribe;\n cleanup?: Promise<void>;\n}\n\nconst OFF_STATE: LiveState = Object.freeze({ status: 'off' });\n\nfunction structuralKey(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction setupTimeoutError(phase: 'open' | 'subscribe'): DataError {\n return {\n kind: 'transport',\n code: 'live-setup-timeout',\n message: `Live ${phase} setup exceeded the runtime timeout.`,\n retryable: true,\n };\n}\n\nfunction invalidPlanError(): DataError {\n return {\n kind: 'protocol',\n code: 'invalid-live-plan',\n message: 'Data provider returned an invalid live plan.',\n };\n}\n\nfunction isValidPlan(value: unknown): value is LivePlan {\n if (value === null || typeof value !== 'object') return false;\n const candidate = value as Partial<LivePlan>;\n if (typeof candidate.subscribe !== 'function') return false;\n return (\n (candidate.kind === 'invalidate' && candidate.initial === 'query') ||\n (candidate.kind === 'snapshot' &&\n (candidate.initial === 'query' || candidate.initial === 'stream'))\n );\n}\n\nfunction readinessTimeout(plan: LivePlan, remaining: number): number | undefined {\n if (plan.initial === 'stream') return undefined;\n const declared = plan.readinessTimeoutMs;\n if (declared === undefined) return remaining;\n if (!Number.isFinite(declared) || declared <= 0) return 0;\n return Math.min(declared, remaining);\n}\n\nfunction planView<T>(plan: LivePlan<T>): LivePlan<T> {\n return plan;\n}\n\n/**\n * Owns one logical provider subscription per canonical descriptor. It is\n * deliberately cache-free: Task 11 interprets its invalidation/snapshot events.\n */\nexport function createLiveCoordinator(runtime: LiveCoordinatorRuntime): LiveCoordinator {\n let disposed = false;\n let nextExecutionGeneration = 0;\n const entries = new Map<string, Entry>();\n\n function notify(lease: Lease): void {\n for (const listener of lease.listeners) listener();\n }\n\n function updateLease<T>(lease: Lease<T>, state: LiveState<T>): void {\n if (lease.released) return;\n lease.state = state;\n notify(lease);\n }\n\n function publish(entry: Entry, state: LiveState): void {\n if (!entry.active) return;\n entry.state = state;\n for (const lease of entry.leases) updateLease(lease, state);\n }\n\n function publishEvent(entry: Entry, event: LiveEvent): void {\n if (!entry.active) return;\n publish(entry, { ...entry.state, event });\n }\n\n async function callUnsubscribe(unsubscribe: Unsubscribe | undefined): Promise<void> {\n if (unsubscribe === undefined) return;\n try {\n await unsubscribe();\n } catch {\n // Provider close is best effort. Setup errors remain the observable state.\n }\n }\n\n function close(entry: Entry): Promise<void> {\n if (!entry.active) return entry.cleanup ?? Promise.resolve();\n entry.active = false;\n entry.executionGeneration += 1;\n entry.controller.abort();\n if (entries.get(entry.key) === entry) entries.delete(entry.key);\n entry.cleanup = callUnsubscribe(entry.unsubscribe);\n return entry.cleanup;\n }\n\n function release(lease: Lease): void {\n if (lease.released) return;\n lease.released = true;\n lease.listeners.clear();\n lease.entry.leases.delete(lease);\n if (lease.entry.leases.size === 0) void close(lease.entry);\n }\n\n function statusForProvider(status: LiveConnectionStatus): LiveState['status'] {\n return status;\n }\n\n function createObserver(entry: Entry, plan: LivePlan, generation: number): LiveObserver {\n return {\n next(value: unknown) {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n const event: LiveEvent =\n plan.kind === 'invalidate'\n ? { type: 'invalidate' }\n : { type: 'snapshot', value, initial: plan.initial };\n publishEvent(entry, event);\n },\n status(status) {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n publish(entry, { ...entry.state, status: statusForProvider(status) });\n },\n error(error) {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n entry.terminal = true;\n publish(entry, {\n ...entry.state,\n status: 'degraded',\n error: isDataError(error) ? error : normalizeDataError(error),\n });\n },\n complete() {\n if (!entry.active || entry.terminal || entry.executionGeneration !== generation) return;\n entry.terminal = true;\n publish(entry, { ...entry.state, status: 'degraded' });\n },\n };\n }\n\n async function awaitWithTimeout<T>(\n entry: Entry,\n value: Promise<T>,\n timeoutMs: number | undefined,\n phase: 'open' | 'subscribe',\n ): Promise<T> {\n if (timeoutMs === undefined) return value;\n if (timeoutMs <= 0) {\n entry.controller.abort();\n throw setupTimeoutError(phase);\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n value,\n new Promise<T>((_resolve, reject) => {\n timer = setTimeout(() => {\n entry.controller.abort();\n reject(setupTimeoutError(phase));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }\n\n async function begin(entry: Entry): Promise<void> {\n const generation = entry.executionGeneration;\n const startedAt = Date.now();\n try {\n const service = runtime.providers.resolve(entry.descriptor.providerId);\n const capability = resolveDataCapability(service.provider, {\n lifecycle: 'live',\n kind: entry.descriptor.kind,\n });\n if (isDataError(capability)) throw capability;\n const plan = await awaitWithTimeout(\n entry,\n Promise.resolve(\n capability(entry.descriptor, {\n signal: entry.controller.signal,\n requestContext: runtime.app.requestContext,\n session: service.session,\n providerServiceKey: service.id,\n }),\n ),\n runtime.liveSetupTimeoutMs,\n 'open',\n );\n if (!entry.active || entry.executionGeneration !== generation) return;\n if (plan === null) {\n throw {\n kind: 'capability',\n code: 'live-unavailable',\n message: 'Data provider declined live execution for this descriptor.',\n } satisfies DataError;\n }\n if (!isValidPlan(plan)) throw invalidPlanError();\n\n publish(entry, { status: 'connecting', plan: planView(plan) });\n const remaining = Math.max(0, runtime.liveSetupTimeoutMs - (Date.now() - startedAt));\n const subscribe = Promise.resolve(\n plan.subscribe(createObserver(entry, plan, generation), {\n signal: entry.controller.signal,\n }),\n );\n // A timeout wins the race below, but the provider may still finish its\n // asynchronous registration. That handle belongs to the cancelled\n // lifecycle and must never be adopted by a later descriptor entry.\n void subscribe.then(\n (lateHandle) => {\n if (\n !entry.active ||\n entry.executionGeneration !== generation ||\n entry.controller.signal.aborted\n ) {\n void callUnsubscribe(lateHandle);\n }\n },\n () => undefined,\n );\n const handle = await awaitWithTimeout(\n entry,\n subscribe,\n readinessTimeout(plan, remaining),\n 'subscribe',\n );\n if (\n !entry.active ||\n entry.executionGeneration !== generation ||\n entry.controller.signal.aborted\n ) {\n // The continuation registered on `subscribe` above owns late-handle\n // disposal, including this cancellation window.\n return;\n }\n entry.unsubscribe = handle;\n if (entry.terminal) return;\n publish(entry, { ...entry.state, status: 'connected' });\n } catch (error) {\n if (!entry.active || entry.executionGeneration !== generation) return;\n entry.terminal = true;\n publish(entry, { ...entry.state, status: 'degraded', error: normalizeDataError(error) });\n }\n }\n\n function acquire<T>(descriptor: ErasedQueryDescriptor, consumerGeneration: number): LiveLease<T> {\n if (disposed) {\n throw new Error('Live coordinator has been disposed.');\n }\n const key = structuralKey(queryKeyFor(descriptor));\n let entry = entries.get(key);\n if (entry === undefined) {\n entry = {\n key,\n descriptor,\n controller: new AbortController(),\n leases: new Set(),\n executionGeneration: ++nextExecutionGeneration,\n active: true,\n terminal: false,\n state: { status: 'connecting' },\n };\n entries.set(key, entry);\n void begin(entry);\n }\n\n const lease: Lease<T> = {\n entry,\n generation: consumerGeneration,\n listeners: new Set(),\n released: false,\n state: entry.state as LiveState<T>,\n };\n entry.leases.add(lease);\n return Object.freeze({\n getState: () => lease.state,\n subscribe(listener: () => void): () => void {\n if (lease.released) return () => undefined;\n lease.listeners.add(listener);\n return () => lease.listeners.delete(listener);\n },\n release: () => release(lease),\n });\n }\n\n function cancelGeneration(generation: number): void {\n for (const entry of [...entries.values()]) {\n for (const lease of [...entry.leases]) {\n if (lease.generation === generation) release(lease);\n }\n }\n }\n\n async function dispose(): Promise<void> {\n if (disposed) return;\n disposed = true;\n await Promise.all([...entries.values()].map((entry) => close(entry)));\n }\n\n return Object.freeze({ acquire, cancelGeneration, dispose });\n}\n","import {\n type AppRuntime,\n type DataError,\n type DataProvider,\n type DataProviderFactoryContext,\n type DataProviderRegistration,\n type DataSessionSnapshot,\n type PushInvalidationBinding,\n PUSH_INVALIDATION_NOT_ROUTABLE_CODE,\n collectPushInvalidationMismatches,\n formatPushInvalidationRefusal,\n normalizeDataError,\n resourceKey,\n} from '@burojs/core';\n\nexport interface ProviderServiceRef {\n readonly id: string;\n /** Opaque per-provider-instance identity for cache and execution partitioning. */\n readonly identity: object;\n readonly provider: DataProvider;\n readonly session: DataSessionSnapshot;\n}\n\nexport interface DataProviderRegistry {\n start(session: DataSessionSnapshot): Promise<void>;\n resolve(id?: string): ProviderServiceRef;\n replaceScope(next: DataSessionSnapshot, previous: DataSessionSnapshot): Promise<void>;\n rotateSession(next: DataSessionSnapshot, previous: DataSessionSnapshot): Promise<void>;\n dispose(): Promise<void>;\n}\n\nexport interface CreateDataProviderRegistryOptions {\n /** Request-local SSR cannot safely reuse caller-owned provider instances. */\n readonly requestDependentSsr?: boolean;\n}\n\ninterface OwnedProviderService {\n readonly ownership: 'owned';\n readonly controller: AbortController;\n readonly ref: ProviderServiceRef;\n disposed: boolean;\n}\n\ninterface BorrowedProviderService {\n readonly ownership: 'borrowed';\n readonly ref: ProviderServiceRef;\n}\n\ntype ProviderService = OwnedProviderService | BorrowedProviderService;\n\nfunction configurationError(code: string, message: string): DataError {\n return Object.assign(new Error(message), {\n kind: 'configuration' as const,\n code,\n });\n}\n\nfunction assertProvider(value: unknown, id: string): asserts value is DataProvider {\n if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {\n throw configurationError(\n 'invalid-provider',\n `Data provider '${id}' factory returned a non-object value.`,\n );\n }\n}\n\nfunction serviceRef(\n id: string,\n provider: DataProvider,\n session: DataSessionSnapshot,\n): ProviderServiceRef {\n return Object.freeze({\n id,\n identity: Object.freeze({}),\n provider,\n session,\n });\n}\n\nfunction sameSession(left: DataSessionSnapshot, right: DataSessionSnapshot): boolean {\n return (\n left === right || (left.sessionKey === right.sessionKey && left.generation === right.generation)\n );\n}\n\n/**\n * Every registered resource's binding, as the app runtime resolves it.\n *\n * A resource whose binding cannot be resolved at all (no effective provider,\n * or a provider id that is not registered) is skipped: that is a different,\n * pre-existing failure with its own error, and swallowing it here would\n * replace a precise message with a vaguer one.\n */\nfunction resolvedBindings(app: AppRuntime): readonly PushInvalidationBinding[] {\n const bindings: PushInvalidationBinding[] = [];\n for (const resource of app.registry.list()) {\n try {\n const binding = app.resolveDataBinding(resource.ref ?? resource.name);\n bindings.push({\n ref: resourceKey(binding.ref),\n resource: binding.resource,\n providerId: binding.providerId,\n });\n } catch {\n // See the doc comment above: not this check's failure to report.\n }\n }\n return bindings;\n}\n\n/**\n * REFUSES A PUSH-INVALIDATION OPT-IN THAT CAN NEVER FIRE, at registration.\n *\n * The opt-in is provider-side (`@burojs/hasura`'s `ResourceMapping.live`) and\n * the runtime resolves a descriptor's live channel from\n * `descriptor.providerId`, so a provider is only ever asked to `open` for\n * resources it already serves. An opt-in written against a resource ANOTHER\n * provider serves is therefore unreachable — and it used to be silent in\n * every observable way: the declaring provider's `open` was never called, the\n * serving provider declined (or, like `@burojs/pocketbase`, had no live slot\n * at all), the live coordinator published `degraded` onto a lease\n * `ResourceListController` deliberately does not re-expose, and no console\n * channel was touched.\n *\n * ⚠️ REGISTRATION, NOT SUBSCRIBE TIME — deliberately. Registration knows every\n * provider instance and every resource binding at once, which is exactly what\n * this mismatch is about, and it fails before a single query runs rather than\n * only when someone opens the affected screen. The cost is the other half:\n * registration cannot see a resource that is registered LAZILY afterwards, so\n * an opt-in naming a not-yet-registered resource is skipped rather than\n * refused (see `collectPushInvalidationMismatches`).\n *\n * Two further limits, recorded rather than assumed away:\n *\n * - It runs on `start` only. `replaceScope` and `rotateSession` recreate owned\n * providers from the SAME registrations, so a capability set cannot change\n * in practice; a factory returning a differently CONFIGURED provider per\n * session would slip through.\n * - It compares an opt-in against the provider that SERVES the resource. A\n * resource served by a provider with a push channel that simply did not opt\n * in stays silent exactly as before — there is no resource-side statement of\n * intent to compare against, and inventing one would create two declarations\n * that must agree.\n */\nfunction assertPushInvalidationIsRoutable(\n app: AppRuntime,\n services: ReadonlyMap<string, ProviderService>,\n): void {\n const declarations: [string, readonly string[]][] = [];\n for (const [id, service] of services) {\n const declared = service.ref.provider.live?.declaredPushInvalidation?.();\n if (declared !== undefined && declared.length > 0) declarations.push([id, declared]);\n }\n if (declarations.length === 0) return;\n\n const mismatches = collectPushInvalidationMismatches(declarations, resolvedBindings(app));\n if (mismatches.length === 0) return;\n throw configurationError(\n PUSH_INVALIDATION_NOT_ROUTABLE_CODE,\n formatPushInvalidationRefusal(mismatches),\n );\n}\n\n/**\n * Resolves app-registered provider services for exactly one active data\n * session. Owned instances are created from their factory and are always\n * aborted before disposal; borrowed instances are never disposed by React.\n */\nexport function createDataProviderRegistry(\n app: AppRuntime,\n options: CreateDataProviderRegistryOptions = {},\n): DataProviderRegistry {\n let activeSession: DataSessionSnapshot | undefined;\n let disposed = false;\n let disposePromise: Promise<void> | undefined;\n let pendingLifecycleOperations = 0;\n let lifecycleTail: Promise<void> = Promise.resolve();\n const services = new Map<string, ProviderService>();\n\n function assertActive(allowPendingLifecycle = false): DataSessionSnapshot {\n if (disposed)\n throw configurationError('registry-disposed', 'Data provider registry has been disposed.');\n if (!allowPendingLifecycle && pendingLifecycleOperations > 0) {\n throw configurationError(\n 'provider-transitioning',\n 'Data provider registry is transitioning to a new data session.',\n );\n }\n if (activeSession === undefined) {\n throw configurationError('not-started', 'Data provider registry has not been started.');\n }\n return activeSession;\n }\n\n function assertPrevious(previous: DataSessionSnapshot): void {\n const active = assertActive(true);\n if (!sameSession(active, previous)) {\n throw configurationError(\n 'session-mismatch',\n 'Data provider registry transition does not match its active data session.',\n );\n }\n }\n\n function serialize<T>(operation: () => Promise<T>): Promise<T> {\n pendingLifecycleOperations += 1;\n const run = lifecycleTail.then(operation, operation);\n lifecycleTail = run.then(\n () => undefined,\n () => undefined,\n );\n return run.finally(() => {\n pendingLifecycleOperations -= 1;\n });\n }\n\n async function createOwned(\n id: string,\n registration: Extract<DataProviderRegistration, { readonly ownership: 'owned' }>,\n session: DataSessionSnapshot,\n ): Promise<OwnedProviderService> {\n const controller = new AbortController();\n const context: DataProviderFactoryContext = Object.freeze({\n requestContext: app.requestContext,\n session,\n signal: controller.signal,\n });\n\n try {\n const provider = await registration.factory(context);\n assertProvider(provider, id);\n return {\n ownership: 'owned',\n controller,\n ref: serviceRef(id, provider, session),\n disposed: false,\n };\n } catch (error) {\n controller.abort();\n throw normalizeDataError(error);\n }\n }\n\n function createBorrowed(\n id: string,\n registration: Extract<DataProviderRegistration, { readonly ownership: 'borrowed' }>,\n session: DataSessionSnapshot,\n ): BorrowedProviderService {\n if (options.requestDependentSsr) {\n throw configurationError(\n 'borrowed-provider-request-dependent-ssr',\n `Borrowed data provider '${id}' is not allowed for request-dependent SSR.`,\n );\n }\n return {\n ownership: 'borrowed',\n ref: serviceRef(id, registration.provider, session),\n };\n }\n\n async function createService(\n id: string,\n registration: DataProviderRegistration,\n session: DataSessionSnapshot,\n ): Promise<ProviderService> {\n return registration.ownership === 'owned'\n ? createOwned(id, registration, session)\n : createBorrowed(id, registration, session);\n }\n\n async function disposeOwned(service: OwnedProviderService): Promise<void> {\n if (service.disposed) return;\n service.disposed = true;\n service.controller.abort();\n await service.ref.provider.dispose?.();\n }\n\n async function disposeServices(values: Iterable<ProviderService>): Promise<unknown | undefined> {\n let failure: unknown;\n for (const service of values) {\n if (service.ownership !== 'owned') continue;\n try {\n await disposeOwned(service);\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n }\n return failure;\n }\n\n function updateBorrowedSession(\n service: BorrowedProviderService,\n session: DataSessionSnapshot,\n ): BorrowedProviderService {\n return { ownership: 'borrowed', ref: Object.freeze({ ...service.ref, session }) };\n }\n\n function updateOwnedSession(\n service: OwnedProviderService,\n session: DataSessionSnapshot,\n ): OwnedProviderService {\n return { ...service, ref: Object.freeze({ ...service.ref, session }) };\n }\n\n async function startNow(session: DataSessionSnapshot): Promise<void> {\n if (disposed)\n throw configurationError('registry-disposed', 'Data provider registry has been disposed.');\n if (activeSession !== undefined) {\n throw configurationError(\n 'already-started',\n 'Data provider registry has already been started.',\n );\n }\n\n const created = new Map<string, ProviderService>();\n try {\n for (const [id, registration] of app.dataProviderFactories) {\n created.set(id, await createService(id, registration, session));\n }\n assertPushInvalidationIsRoutable(app, created);\n } catch (error) {\n await disposeServices(created.values());\n throw normalizeDataError(error);\n }\n\n activeSession = session;\n for (const [id, service] of created) services.set(id, service);\n }\n\n async function replaceScopeNow(\n next: DataSessionSnapshot,\n previous: DataSessionSnapshot,\n ): Promise<void> {\n assertPrevious(previous);\n activeSession = next;\n\n for (const [id, registration] of app.dataProviderFactories) {\n const current = services.get(id);\n if (registration.ownership === 'borrowed') {\n const borrowed =\n current?.ownership === 'borrowed' ? current : createBorrowed(id, registration, previous);\n try {\n await borrowed.ref.provider.onSessionChange?.(next, previous);\n services.set(id, updateBorrowedSession(borrowed, next));\n } catch (error) {\n throw normalizeDataError(error);\n }\n continue;\n }\n\n if (current?.ownership === 'owned' && current.ref.provider.onSessionChange !== undefined) {\n try {\n await current.ref.provider.onSessionChange(next, previous);\n services.set(id, updateOwnedSession(current, next));\n continue;\n } catch (error) {\n services.delete(id);\n try {\n await disposeOwned(current);\n } catch {\n // The transition error is the observable failure; cleanup remains best effort.\n }\n throw normalizeDataError(error);\n }\n }\n\n if (current?.ownership === 'owned') {\n services.delete(id);\n await disposeOwned(current);\n }\n services.set(id, await createOwned(id, registration, next));\n }\n }\n\n async function rotateSessionNow(\n next: DataSessionSnapshot,\n previous: DataSessionSnapshot,\n ): Promise<void> {\n assertPrevious(previous);\n activeSession = next;\n\n for (const [id, registration] of app.dataProviderFactories) {\n const current = services.get(id);\n if (registration.ownership === 'borrowed') {\n const borrowed =\n current?.ownership === 'borrowed' ? current : createBorrowed(id, registration, previous);\n try {\n await borrowed.ref.provider.onSessionChange?.(next, previous);\n services.set(id, updateBorrowedSession(borrowed, next));\n } catch (error) {\n throw normalizeDataError(error);\n }\n continue;\n }\n\n if (current?.ownership === 'owned') {\n services.delete(id);\n await disposeOwned(current);\n }\n services.set(id, await createOwned(id, registration, next));\n }\n }\n\n function dispose(): Promise<void> {\n if (disposePromise !== undefined) return disposePromise;\n disposed = true;\n disposePromise = serialize(async () => {\n const failure = await disposeServices(services.values());\n services.clear();\n activeSession = undefined;\n if (failure !== undefined) throw failure;\n });\n return disposePromise;\n }\n\n return Object.freeze({\n start(session: DataSessionSnapshot) {\n return serialize(() => startNow(session));\n },\n resolve(id?: string) {\n assertActive();\n const providerId = id ?? app.defaultProviderId;\n if (providerId === undefined) {\n throw configurationError(\n 'missing-default-provider',\n 'No default data provider is configured.',\n );\n }\n const service = services.get(providerId);\n if (service === undefined) {\n throw configurationError(\n 'unknown-provider',\n `Data provider '${providerId}' is not registered.`,\n );\n }\n return service.ref;\n },\n replaceScope(next: DataSessionSnapshot, previous: DataSessionSnapshot) {\n return serialize(() => replaceScopeNow(next, previous));\n },\n rotateSession(next: DataSessionSnapshot, previous: DataSessionSnapshot) {\n return serialize(() => rotateSessionNow(next, previous));\n },\n dispose,\n });\n}\n","import type {\n AppRuntime,\n DataSessionController,\n DataSessionSnapshot,\n DataSessionTransitionParticipant,\n} from '@burojs/core';\nimport { normalizeDataError } from '@burojs/core';\nimport type { QueryClient } from '@tanstack/react-query';\n\nimport type { AuthController } from '../auth/controller.js';\n\nimport { createBatchCoordinator, type BatchCoordinator } from './batch-coordinator.js';\nimport { createLiveCoordinator } from './live/coordinator.js';\nimport { createLiveQueryRegistry, type LiveQueryRegistry } from './live/live-queries.js';\nimport type { LiveCoordinator } from './live/types.js';\nimport { createDataProviderRegistry, type DataProviderRegistry } from './provider-registry.js';\n\nconst DEFAULT_LIVE_SETUP_TIMEOUT_MS = 5_000;\n\ninterface ParticipantStartupControl {\n begin(): void;\n activate(): void;\n fail(error: unknown): void;\n}\n\nconst participantStartupControls = new WeakMap<\n DataRuntimeTransitionParticipant,\n ParticipantStartupControl\n>();\n\nfunction configurationError(\n code: string,\n message: string,\n): Error & {\n readonly kind: 'configuration';\n readonly code: string;\n} {\n return Object.assign(new Error(message), { kind: 'configuration' as const, code });\n}\n\nfunction cancelledError(): Error & {\n readonly kind: 'cancelled';\n readonly code: 'aborted';\n} {\n return Object.assign(new Error('Data runtime operation was aborted.'), {\n kind: 'cancelled' as const,\n code: 'aborted' as const,\n });\n}\n\nfunction sameSession(left: DataSessionSnapshot, right: DataSessionSnapshot): boolean {\n return left.sessionKey === right.sessionKey;\n}\n\nexport interface DataRuntimeContextValue {\n readonly app: AppRuntime;\n readonly queryClient: QueryClient;\n readonly dataSession: DataSessionController;\n readonly providers: DataProviderRegistry;\n readonly batchCoordinator: BatchCoordinator;\n readonly liveCoordinator: LiveCoordinator;\n /**\n * One shared live query observer per descriptor and session generation,\n * retained by the query hooks.\n *\n * @internal\n */\n readonly liveQueries: LiveQueryRegistry;\n readonly liveSetupTimeoutMs: number;\n /** Present only in React trees configured with a native AuthProvider. */\n readonly authController?: AuthController;\n waitUntilReady(signal?: AbortSignal): Promise<DataSessionSnapshot>;\n}\n\n/**\n * The lease owns Buro's provider/cache coordination only. The app,\n * QueryClient, and DataSession remain caller-owned and are never disposed by\n * React mounting or unmounting.\n */\nexport interface DataRuntimeLease extends DataRuntimeContextValue {\n readonly ownership: 'external';\n dispose(): Promise<void>;\n}\n\nexport interface DataRuntimeTransitionParticipant extends DataSessionTransitionParticipant {\n bind(lease: DataRuntimeLease): void;\n}\n\nexport interface CreateDataRuntimeTransitionParticipantOptions {\n readonly app: AppRuntime;\n readonly queryClient: QueryClient;\n}\n\nexport interface CreateDataRuntimeOptions {\n readonly app: AppRuntime;\n readonly queryClient: QueryClient;\n readonly dataSession: DataSessionController;\n readonly transitionParticipant: DataRuntimeTransitionParticipant;\n readonly liveSetupTimeoutMs?: number;\n readonly requestDependentSsr?: boolean;\n}\n\n/**\n * Creates the participant which core DataSession invokes at each committed\n * lifecycle boundary. Register it on the DataSession before creating its\n * lease; that keeps transition serialization in core.\n */\nexport function createDataRuntimeTransitionParticipant(\n options: CreateDataRuntimeTransitionParticipantOptions,\n): DataRuntimeTransitionParticipant {\n let lease: DataRuntimeLease | undefined;\n let bound = false;\n let creationStarted = false;\n let pendingCancellation: Promise<void> = Promise.resolve();\n let settleStartup!: (value: void | PromiseLike<void>) => void;\n let rejectStartup!: (reason?: unknown) => void;\n const startup = new Promise<void>((resolve, reject) => {\n settleStartup = resolve;\n rejectStartup = reject;\n });\n void startup.catch(() => undefined);\n\n function requireLease(): DataRuntimeLease {\n if (lease === undefined) {\n throw configurationError(\n 'data-runtime-transition-unbound',\n 'Data runtime transition participant must be bound before a session transition.',\n );\n }\n return lease;\n }\n\n const participant: DataRuntimeTransitionParticipant = Object.freeze({\n bind(nextLease: DataRuntimeLease) {\n if (bound) {\n throw configurationError(\n 'data-runtime-transition-already-bound',\n 'Data runtime transition participant is already bound to a lease.',\n );\n }\n if (nextLease.app !== options.app || nextLease.queryClient !== options.queryClient) {\n throw configurationError(\n 'data-runtime-transition-mismatch',\n 'Data runtime transition participant must bind to its original app and QueryClient.',\n );\n }\n lease = nextLease;\n bound = true;\n },\n abort(previous: DataSessionSnapshot) {\n // Startup can reject after this participant is registered but before a\n // lease exists. Core disposal must still leave that caller-owned session\n // safely disposable; transition() below remains the configuration gate.\n const active = lease;\n if (active === undefined) return;\n // Native descriptor keys are added by subsequent tasks. Until then, the\n // lease has one active cache partition, which is cleared atomically at\n // the core session boundary.\n active.batchCoordinator.cancelGeneration(previous.generation);\n active.liveCoordinator.cancelGeneration(previous.generation);\n pendingCancellation = active.queryClient.cancelQueries().then(() => {\n active.queryClient.clear();\n });\n },\n async transition(next: DataSessionSnapshot, previous: DataSessionSnapshot) {\n if (!creationStarted) requireLease();\n const active = requireLease();\n await startup;\n await pendingCancellation;\n if (sameSession(next, previous)) {\n await active.providers.replaceScope(next, previous);\n } else {\n await active.providers.rotateSession(next, previous);\n }\n },\n dispose() {\n // The creator disposes the lease first, then its caller-owned\n // DataSession. This participant deliberately has no second disposal\n // path that could race the lease or take ownership of caller objects.\n },\n });\n\n participantStartupControls.set(participant, {\n begin() {\n creationStarted = true;\n },\n activate() {\n settleStartup();\n },\n fail(error) {\n rejectStartup(error);\n },\n });\n return participant;\n}\n\nfunction waitForReady(\n dataSession: DataSessionController,\n signal: AbortSignal | undefined,\n): Promise<DataSessionSnapshot> {\n if (signal === undefined) return dataSession.waitUntilReady();\n if (signal.aborted) return Promise.reject(cancelledError());\n\n return new Promise<DataSessionSnapshot>((resolve, reject) => {\n const abort = () => reject(cancelledError());\n signal.addEventListener('abort', abort, { once: true });\n dataSession\n .waitUntilReady()\n .then(resolve, reject)\n .finally(() => {\n signal.removeEventListener('abort', abort);\n });\n });\n}\n\n/**\n * Starts the React-owned provider registry for an externally owned app/cache/\n * session triple. It is intentionally separate from BuroProvider so SSR\n * and browser callers choose the full teardown order themselves.\n */\nexport async function createDataRuntime(\n options: CreateDataRuntimeOptions,\n): Promise<DataRuntimeLease> {\n const liveSetupTimeoutMs = options.liveSetupTimeoutMs ?? DEFAULT_LIVE_SETUP_TIMEOUT_MS;\n if (!Number.isFinite(liveSetupTimeoutMs) || liveSetupTimeoutMs < 0) {\n throw configurationError(\n 'invalid-live-setup-timeout',\n 'liveSetupTimeoutMs must be a non-negative finite number.',\n );\n }\n\n const providers = createDataProviderRegistry(options.app, {\n requestDependentSsr: options.requestDependentSsr,\n });\n const batchCoordinator = createBatchCoordinator();\n const liveCoordinator = createLiveCoordinator({\n app: options.app,\n dataSession: options.dataSession,\n providers,\n liveSetupTimeoutMs,\n });\n const initialState = options.dataSession.getState();\n if (initialState.status !== 'ready') {\n throw configurationError(\n 'data-runtime-session-not-ready',\n 'Data runtime can only be created while its DataSession is ready.',\n );\n }\n const initial = initialState.snapshot;\n const startupControl = participantStartupControls.get(options.transitionParticipant);\n startupControl?.begin();\n\n let disposed = false;\n let disposePromise: Promise<void> | undefined;\n const lease: DataRuntimeLease = Object.freeze({\n app: options.app,\n ownership: 'external' as const,\n queryClient: options.queryClient,\n dataSession: options.dataSession,\n providers,\n batchCoordinator,\n liveCoordinator,\n liveQueries: createLiveQueryRegistry(() => lease),\n liveSetupTimeoutMs,\n waitUntilReady(signal?: AbortSignal) {\n if (disposed) {\n return Promise.reject(\n configurationError('data-runtime-disposed', 'Data runtime lease has been disposed.'),\n );\n }\n return waitForReady(options.dataSession, signal);\n },\n dispose() {\n if (disposePromise !== undefined) return disposePromise;\n disposed = true;\n disposePromise = (async () => {\n let failure: unknown;\n try {\n batchCoordinator.dispose();\n } catch (error) {\n failure = normalizeDataError(error);\n }\n try {\n await liveCoordinator.dispose();\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n try {\n await options.queryClient.cancelQueries();\n } catch (error) {\n failure = normalizeDataError(error);\n }\n try {\n options.queryClient.clear();\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n try {\n await providers.dispose();\n } catch (error) {\n failure ??= normalizeDataError(error);\n }\n if (failure !== undefined) throw failure;\n })();\n return disposePromise;\n },\n });\n\n try {\n options.transitionParticipant.bind(lease);\n await providers.start(initial);\n startupControl?.activate();\n } catch (error) {\n disposed = true;\n startupControl?.fail(error);\n batchCoordinator.dispose();\n await liveCoordinator.dispose();\n try {\n await providers.dispose();\n } catch {\n // Startup failure remains the observable error; registry cleanup is best effort.\n }\n throw normalizeDataError(error);\n }\n\n return lease;\n}\n","import {\n clonePortableValue,\n createQueryDescriptor,\n DEFAULT_DATA_DESCRIPTOR_LIMITS,\n queryKeyFor,\n type ApplicationSnapshot,\n type AppRuntime,\n type DataSessionController,\n type ErasedQueryDescriptor,\n type PortableValue,\n type SnapshotHydrationCodec,\n} from '@burojs/core';\nimport { hashKey, hydrate, type Query, type QueryClient } from '@tanstack/react-query';\n\nimport type { DataRuntimeLease } from './runtime.js';\n\nconst QUERY_KEY_PREFIX = 'buro-data';\nconst QUERY_KEY_VERSION = 1;\nconst HYDRATION_VERSION = 1;\n\ntype HydrationReason = 'version' | 'definition' | 'catalog' | 'binding';\ntype QueryKind = ErasedQueryDescriptor['kind'];\n\ninterface PortableHydrationQuery {\n readonly queryHash: string;\n readonly queryKey: PortableValue;\n readonly state: PortableValue;\n readonly dehydratedAt: number;\n}\n\ninterface PortableHydrationState {\n readonly mutations: readonly [];\n readonly queries: readonly PortableHydrationQuery[];\n}\n\ninterface ValidatedQuery {\n readonly queryHash: string;\n readonly queryKey: PortableValue;\n readonly dehydratedAt: number;\n readonly dataUpdateCount: number;\n readonly dataUpdatedAt: number;\n readonly codec: SnapshotHydrationCodec;\n readonly payload: PortableValue;\n}\n\n/** Serialized server query state that is safe to put into an HTML document. */\nexport interface BuroDehydratedData {\n readonly version: 1;\n readonly definitionFingerprint: string;\n readonly implementationCatalogFingerprint: string;\n /** Revision per dehydrated declaration; never includes undeclared bindings. */\n readonly bindingRevisions: Readonly<Record<string, string>>;\n /** Non-secret query partition; it prevents accidental mixed-session payloads. */\n readonly partition: Readonly<{ readonly sessionKey: string; readonly scopeKey: PortableValue }>;\n readonly queryState: PortableValue;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction ownKeysOnly(\n value: Readonly<Record<string, unknown>>,\n allowed: readonly string[],\n): boolean {\n return Object.keys(value).every((key) => allowed.includes(key));\n}\n\nfunction portable(value: unknown): PortableValue | undefined {\n try {\n return clonePortableValue(value, DEFAULT_DATA_DESCRIPTOR_LIMITS) as PortableValue;\n } catch {\n return undefined;\n }\n}\n\nfunction samePortable(left: unknown, right: unknown): boolean {\n return JSON.stringify(left) === JSON.stringify(right);\n}\n\nfunction normalizedRef(\n value: unknown,\n): { readonly namespace: string; readonly id: string } | undefined {\n if (!isRecord(value) || typeof value.namespace !== 'string' || typeof value.id !== 'string')\n return undefined;\n return { namespace: value.namespace, id: value.id };\n}\n\nfunction sameRef(left: unknown, right: unknown): boolean {\n const a = normalizedRef(left);\n const b = normalizedRef(right);\n return a !== undefined && b !== undefined && a.namespace === b.namespace && a.id === b.id;\n}\n\nfunction descriptorKeys(kind: QueryKind): readonly string[] {\n const identity = [\n 'kind',\n 'providerId',\n 'ref',\n 'resource',\n 'sessionKey',\n 'scopeKey',\n 'bindingRevision',\n 'projection',\n 'providerOptions',\n 'dependencies',\n ];\n switch (kind) {\n case 'list':\n return [...identity, 'pagination', 'filter', 'sort'];\n case 'one':\n return [...identity, 'id'];\n case 'many':\n return [...identity, 'ids'];\n case 'count':\n return [...identity, 'filter'];\n case 'custom':\n return [...identity, 'operation', 'input'];\n }\n}\n\n/** Reads only an exact native descriptor whose canonical key can be reconstructed. */\nfunction descriptorFromKey(key: unknown): ErasedQueryDescriptor | undefined {\n if (\n !Array.isArray(key) ||\n key.length !== 3 ||\n key[0] !== QUERY_KEY_PREFIX ||\n key[1] !== QUERY_KEY_VERSION\n )\n return undefined;\n const raw = key[2];\n if (!isRecord(raw) || typeof raw.kind !== 'string') return undefined;\n const kind = raw.kind as QueryKind;\n if (\n !['list', 'one', 'many', 'count', 'custom'].includes(kind) ||\n !ownKeysOnly(raw, descriptorKeys(kind))\n )\n return undefined;\n try {\n const descriptor = createQueryDescriptor(raw as never) as ErasedQueryDescriptor;\n return samePortable(descriptor, raw) && samePortable(queryKeyFor(descriptor), key)\n ? descriptor\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction projectionFor(\n snapshot: ApplicationSnapshot,\n target: {\n readonly kind: 'resource' | 'custom-query';\n readonly ref: { readonly namespace: string; readonly id: string };\n },\n) {\n const projection = snapshot.getProjection(target);\n return projection !== undefined &&\n projection.kind === target.kind &&\n sameRef(projection.ref, target.ref)\n ? projection\n : undefined;\n}\n\nfunction fieldsContainProjection(\n value: PortableValue,\n projection: readonly unknown[] | undefined,\n): boolean {\n if (projection === undefined) return true;\n if (!isRecord(value)) return false;\n const fields = value.fields;\n if (!Array.isArray(fields)) return false;\n const names = new Set(\n fields.flatMap((field) =>\n isRecord(field) && typeof field.name === 'string' ? [field.name] : [],\n ),\n );\n return projection.every((field) => typeof field === 'string' && names.has(field));\n}\n\n/** Ensures a key corresponds to a real currently compiled binding and codec. */\nfunction resolveDescriptorCodec(\n snapshot: ApplicationSnapshot,\n descriptor: ErasedQueryDescriptor,\n): SnapshotHydrationCodec | undefined {\n const ref = normalizedRef(descriptor.ref);\n if (ref === undefined || descriptor.bindingRevision !== snapshot.manifest.snapshotId)\n return undefined;\n\n if (descriptor.kind === 'custom') {\n const target = { kind: 'custom-query' as const, ref };\n const projection = projectionFor(snapshot, target);\n const value =\n projection === undefined || !isRecord(projection.value) ? undefined : projection.value;\n const binding = value === undefined || !isRecord(value.binding) ? undefined : value.binding;\n if (\n binding === undefined ||\n binding.provider !== descriptor.providerId ||\n (binding.resource ?? ref.id) !== descriptor.resource ||\n binding.operation !== descriptor.operation\n )\n return undefined;\n return snapshot.resolveHydrationCodec(target);\n }\n\n const target = { kind: 'resource' as const, ref };\n const projection = projectionFor(snapshot, target);\n const value =\n projection === undefined || !isRecord(projection.value) ? undefined : projection.value;\n const binding = value === undefined || !isRecord(value.data) ? undefined : value.data;\n if (\n binding === undefined ||\n binding.provider !== descriptor.providerId ||\n (binding.resource ?? ref.id) !== descriptor.resource ||\n !fieldsContainProjection(projection!.value, descriptor.projection)\n )\n return undefined;\n return snapshot.resolveHydrationCodec(target);\n}\n\nfunction queryState(data: unknown): PortableHydrationState | undefined {\n const cloned = portable(data);\n if (\n !isRecord(cloned) ||\n !Array.isArray(cloned.mutations) ||\n !Array.isArray(cloned.queries) ||\n cloned.mutations.length !== 0\n )\n return undefined;\n const queries: PortableHydrationQuery[] = [];\n for (const entry of cloned.queries) {\n if (!isRecord(entry) || !ownKeysOnly(entry, ['queryHash', 'queryKey', 'state', 'dehydratedAt']))\n return undefined;\n if (\n typeof entry.queryHash !== 'string' ||\n typeof entry.dehydratedAt !== 'number' ||\n !Number.isFinite(entry.dehydratedAt)\n )\n return undefined;\n if (!Array.isArray(entry.queryKey) || entry.queryHash !== hashKey(entry.queryKey))\n return undefined;\n if (descriptorFromKey(entry.queryKey) === undefined || !isRecord(entry.state)) return undefined;\n queries.push({\n queryHash: entry.queryHash,\n queryKey: entry.queryKey as PortableValue,\n state: entry.state as PortableValue,\n dehydratedAt: entry.dehydratedAt,\n });\n }\n return { mutations: [], queries };\n}\n\nfunction dataMatchesSnapshot(\n data: BuroDehydratedData,\n snapshot: ApplicationSnapshot,\n): HydrationReason | undefined {\n if (\n !isRecord(data) ||\n data.version !== HYDRATION_VERSION ||\n typeof data.definitionFingerprint !== 'string' ||\n typeof data.implementationCatalogFingerprint !== 'string' ||\n !isRecord(data.bindingRevisions) ||\n !isRecord(data.partition) ||\n typeof data.partition.sessionKey !== 'string' ||\n !('scopeKey' in data.partition) ||\n portable(data.partition.scopeKey) === undefined ||\n !('queryState' in data)\n )\n return 'version';\n if (data.definitionFingerprint !== snapshot.manifest.definitionFingerprint) return 'definition';\n if (data.implementationCatalogFingerprint !== snapshot.manifest.implementationCatalogFingerprint)\n return 'catalog';\n if (\n Object.values(data.bindingRevisions).some(\n (revision) => revision !== snapshot.manifest.snapshotId,\n )\n )\n return 'binding';\n return undefined;\n}\n\nfunction portableSuccessState(query: Query, payload: PortableValue): PortableValue | undefined {\n const updatedAt = query.state.dataUpdatedAt;\n const updateCount = query.state.dataUpdateCount;\n if (!Number.isFinite(updatedAt) || !Number.isSafeInteger(updateCount) || updateCount < 0)\n return undefined;\n return portable({\n status: 'success',\n error: null,\n data: { payload },\n dataUpdatedAt: updatedAt,\n dataUpdateCount: updateCount,\n });\n}\n\n/**\n * Dehydrates only successful native query results through the declaration-owned\n * compiled codec. Raw provider values, query metadata, credentials, provider\n * instances, errors, live state, and hydration tokens never cross this boundary.\n */\nexport function dehydrateBuroData(\n runtime: DataRuntimeLease,\n options: { readonly shouldDehydrateQuery?: (query: Query) => boolean } = {},\n): BuroDehydratedData {\n const snapshot = runtime.app.runtime.getSnapshot();\n const bindings: Record<string, string> = Object.create(null);\n const queries: PortableHydrationQuery[] = [];\n let partition: { readonly sessionKey: string; readonly scopeKey: PortableValue } | undefined;\n\n for (const query of runtime.queryClient.getQueryCache().getAll()) {\n if (\n query.state.status !== 'success' ||\n query.state.error !== null ||\n query.state.data === undefined ||\n !(options.shouldDehydrateQuery?.(query) ?? true)\n )\n continue;\n const descriptor = descriptorFromKey(query.queryKey);\n const codec =\n descriptor === undefined ? undefined : resolveDescriptorCodec(snapshot, descriptor);\n if (descriptor === undefined || codec === undefined) continue;\n const scopeKey = portable(descriptor.scopeKey);\n if (scopeKey === undefined) continue;\n const nextPartition = { sessionKey: descriptor.sessionKey, scopeKey };\n if (partition !== undefined && !samePortable(partition, nextPartition)) continue;\n const queryKey = portable(query.queryKey);\n if (queryKey === undefined) continue;\n try {\n const payload = portable(codec.encode(query.state.data));\n const state = payload === undefined ? undefined : portableSuccessState(query, payload);\n if (state === undefined) continue;\n const queryHash = hashKey(queryKey as readonly unknown[]);\n bindings[queryHash] = descriptor.bindingRevision;\n partition = nextPartition;\n queries.push({ queryHash, queryKey, state, dehydratedAt: query.state.dataUpdatedAt });\n } catch {\n // A bad or non-portable codec result makes this query ineligible, never raw.\n }\n }\n\n return Object.freeze({\n version: HYDRATION_VERSION,\n definitionFingerprint: snapshot.manifest.definitionFingerprint,\n implementationCatalogFingerprint: snapshot.manifest.implementationCatalogFingerprint,\n bindingRevisions: Object.freeze({ ...bindings }),\n partition: partition ?? Object.freeze({ sessionKey: '', scopeKey: null }),\n queryState: portable({ mutations: [], queries }) ?? { mutations: [], queries: [] },\n });\n}\n\n/** Checks whether the outer payload belongs to this immutable application snapshot. */\nexport function validateBuroHydration(\n data: BuroDehydratedData,\n snapshot: ApplicationSnapshot,\n): { readonly ok: true } | { readonly ok: false; readonly reason: HydrationReason } {\n const reason = dataMatchesSnapshot(data, snapshot);\n return reason === undefined ? { ok: true } : { ok: false, reason };\n}\n\nfunction validateQuery(\n entry: PortableHydrationQuery,\n data: BuroDehydratedData,\n snapshot: ApplicationSnapshot,\n): ValidatedQuery | undefined {\n const descriptor = descriptorFromKey(entry.queryKey);\n if (\n descriptor === undefined ||\n data.bindingRevisions[entry.queryHash] !== descriptor.bindingRevision\n )\n return undefined;\n if (\n !samePortable(\n { sessionKey: descriptor.sessionKey, scopeKey: descriptor.scopeKey },\n data.partition,\n )\n )\n return undefined;\n const codec = resolveDescriptorCodec(snapshot, descriptor);\n if (\n codec === undefined ||\n !isRecord(entry.state) ||\n !ownKeysOnly(entry.state, ['status', 'error', 'data', 'dataUpdatedAt', 'dataUpdateCount'])\n )\n return undefined;\n if (\n entry.state.status !== 'success' ||\n entry.state.error !== null ||\n !isRecord(entry.state.data) ||\n !ownKeysOnly(entry.state.data, ['payload'])\n )\n return undefined;\n if (typeof entry.state.dataUpdatedAt !== 'number' || !Number.isFinite(entry.state.dataUpdatedAt))\n return undefined;\n const dataUpdateCount = entry.state.dataUpdateCount;\n if (\n typeof dataUpdateCount !== 'number' ||\n !Number.isSafeInteger(dataUpdateCount) ||\n dataUpdateCount < 0\n )\n return undefined;\n const payload = portable(entry.state.data.payload);\n return payload === undefined\n ? undefined\n : {\n queryHash: entry.queryHash,\n queryKey: entry.queryKey,\n dehydratedAt: entry.dehydratedAt,\n dataUpdateCount,\n dataUpdatedAt: entry.state.dataUpdatedAt,\n codec,\n payload,\n };\n}\n\n/**\n * Validates every query and its declaration-owned codec before a single\n * TanStack cache write. The helper deliberately has no runtime/session\n * argument; host code adopts the core branded session token separately.\n */\nexport function hydrateBuroData(\n queryClient: QueryClient,\n snapshot: ApplicationSnapshot,\n data: BuroDehydratedData,\n): boolean {\n if (!validateBuroHydration(data, snapshot).ok) return false;\n const state = queryState(data.queryState);\n if (state === undefined || Object.keys(data.bindingRevisions).length !== state.queries.length)\n return false;\n const validated = state.queries.map((entry) => validateQuery(entry, data, snapshot));\n if (validated.some((entry) => entry === undefined)) return false;\n const restored: Array<Record<string, unknown>> = [];\n try {\n for (const entry of validated as ValidatedQuery[]) {\n restored.push({\n queryHash: entry.queryHash,\n queryKey: entry.queryKey,\n dehydratedAt: entry.dehydratedAt,\n state: {\n status: 'success',\n error: null,\n data: entry.codec.decode(entry.payload),\n dataUpdatedAt: entry.dataUpdatedAt,\n dataUpdateCount: entry.dataUpdateCount,\n errorUpdateCount: 0,\n errorUpdatedAt: 0,\n fetchFailureCount: 0,\n fetchFailureReason: null,\n fetchMeta: null,\n fetchStatus: 'idle',\n isInvalidated: false,\n },\n });\n }\n } catch {\n return false;\n }\n hydrate(queryClient, { mutations: [], queries: restored });\n return true;\n}\n\n/** Encodes a hydration payload for inline HTML without permitting script termination. */\nexport function serializeBuroHydration(data: BuroDehydratedData): string {\n return JSON.stringify(data)\n .replace(/</gu, '\\\\u003c')\n .replace(/>/gu, '\\\\u003e')\n .replace(/&/gu, '\\\\u0026')\n .replace(/\\u2028/gu, '\\\\u2028')\n .replace(/\\u2029/gu, '\\\\u2029');\n}\n\ntype RequestResources = {\n readonly dataRuntime: DataRuntimeLease;\n readonly queryClient: QueryClient;\n readonly dataSession: DataSessionController;\n readonly app: AppRuntime;\n};\n\nconst requestDisposals = new WeakMap<object, Promise<void>>();\n\n/** Disposes a host-owned SSR request in the only safe teardown order. */\nexport function disposeBuroRequest(resources: RequestResources): Promise<void> {\n const existing = requestDisposals.get(resources);\n if (existing !== undefined) return existing;\n const disposal = disposeRequest(resources);\n requestDisposals.set(resources, disposal);\n return disposal;\n}\n\nasync function disposeRequest(resources: RequestResources): Promise<void> {\n const failures: unknown[] = [];\n const attempt = async (operation: () => void | Promise<void>): Promise<void> => {\n try {\n await operation();\n } catch (error) {\n failures.push(error);\n }\n };\n await attempt(() => resources.dataRuntime.dispose());\n await attempt(() => resources.queryClient.cancelQueries());\n await attempt(() => resources.queryClient.clear());\n await attempt(() => resources.dataSession.dispose());\n await attempt(() => resources.app.runtime.dispose());\n if (failures.length > 0) throw new AggregateError(failures, 'Buro SSR request disposal failed.');\n}\n","import {\n type AuthCheckResult,\n type AuthContext,\n type AuthErrorResult,\n type AuthProvider,\n type AuthResult,\n type DataError,\n type DataSessionSnapshot,\n normalizeDataError,\n} from '@burojs/core';\n\nimport type { DataRuntimeContextValue } from '../data/runtime.js';\n\nexport interface AuthController<TIdentity = unknown> {\n getIdentity(): Promise<TIdentity | null>;\n check(): Promise<AuthCheckResult>;\n login(params: unknown): Promise<AuthResult>;\n logout(params: unknown): Promise<AuthResult>;\n recover(error: DataError, snapshot: DataSessionSnapshot): Promise<DataError | 'replay'>;\n}\n\nexport interface CreateAuthControllerOptions<TIdentity = unknown> {\n readonly runtime: DataRuntimeContextValue;\n readonly provider: AuthProvider<TIdentity>;\n}\n\nfunction configurationError(code: string, message: string): DataError {\n return { kind: 'configuration', code, message };\n}\n\nfunction sameSnapshot(left: DataSessionSnapshot, right: DataSessionSnapshot): boolean {\n return left.sessionKey === right.sessionKey && left.generation === right.generation;\n}\n\n/**\n * Owns auth-provider invocation at the active DataSession boundary. Refreshes\n * are deliberately shared only while in flight for one captured epoch.\n */\nexport function createAuthController<TIdentity = unknown>(\n options: CreateAuthControllerOptions<TIdentity>,\n): AuthController<TIdentity> {\n const recoveries = new Map<string, Promise<DataError | 'replay'>>();\n let lifecycleTail: Promise<void> = Promise.resolve();\n\n function context(snapshot: DataSessionSnapshot): AuthContext {\n return Object.freeze({\n requestContext: options.runtime.app.requestContext,\n sessionKey: snapshot.sessionKey,\n scopeKey: snapshot.scopeKey,\n generation: snapshot.generation,\n });\n }\n\n async function activeSnapshot(): Promise<DataSessionSnapshot> {\n return options.runtime.waitUntilReady();\n }\n\n function serializeLifecycle<T>(operation: () => Promise<T>): Promise<T> {\n const queued = lifecycleTail.then(operation, operation);\n lifecycleTail = queued.then(\n () => undefined,\n () => undefined,\n );\n return queued;\n }\n\n async function currentSnapshot(): Promise<DataSessionSnapshot> {\n const snapshot = await activeSnapshot();\n const state = options.runtime.dataSession.getState();\n if (state.status !== 'ready' || !sameSnapshot(state.snapshot, snapshot))\n return currentSnapshot();\n return snapshot;\n }\n\n async function resolveRecovery(\n error: DataError,\n snapshot: DataSessionSnapshot,\n ): Promise<DataError | 'replay'> {\n let result: AuthErrorResult;\n try {\n result =\n options.provider.onError === undefined\n ? { action: 'propagate' }\n : await options.provider.onError(error, context(snapshot));\n } catch (failure) {\n return normalizeDataError(failure);\n }\n if (result.action === 'refreshed') return 'replay';\n if (result.action === 'logout') {\n try {\n await serializeLifecycle(async () => {\n const state = options.runtime.dataSession.getState();\n if (state.status !== 'ready' || !sameSnapshot(state.snapshot, snapshot)) return false;\n // A recovery that logs out is a forced sign-out (session expiry): flow attempts\n // survive it for the same user (spec 4.10, plan ruling 4).\n await options.runtime.dataSession.rotateSession('forced-sign-out');\n return true;\n });\n } catch (failure) {\n return normalizeDataError(failure);\n }\n return error;\n }\n return result.error ?? error;\n }\n\n const controller: AuthController<TIdentity> = {\n async getIdentity() {\n const snapshot = await activeSnapshot();\n try {\n return await options.provider.getIdentity(context(snapshot));\n } catch (error) {\n throw normalizeDataError(error);\n }\n },\n async check() {\n const snapshot = await activeSnapshot();\n try {\n return await options.provider.check(context(snapshot));\n } catch (error) {\n throw normalizeDataError(error);\n }\n },\n async login(params: unknown) {\n return serializeLifecycle(async () => {\n try {\n await options.runtime.dataSession.rotateSession('sign-in');\n const snapshot = await currentSnapshot();\n if (options.provider.login === undefined) {\n return {\n success: false,\n error: configurationError(\n 'login-unsupported',\n 'Authentication provider does not support login.',\n ),\n };\n }\n const result = await options.provider.login(params, context(snapshot));\n // A second rotation on SUCCESS ONLY (SP3 stage B Task 5 finding):\n // the FIRST rotation above starts `useIdentity()`/`useIsAuthenticated()`\n // fetching for the NEW session generation, but `provider.login()`\n // itself (the network call + wherever it persists the session,\n // e.g. `localStorage`) has not written anything yet at the moment\n // those queries read — they settle \"no session\" a beat too early,\n // and with no further generation bump nothing ever asks again\n // unless some OTHER, unrelated component happens to mount fresh\n // for the exact same query key afterward (what made this go\n // unnoticed: every app in this repo navigates immediately after a\n // successful login, and the destination route usually mounts a\n // component that also calls `useIdentity()`/`useIsAuthenticated()`,\n // incidentally re-triggering a correctly-timed fetch — an app\n // whose post-login route does not, or whose auth-state UI lives\n // outside the routed tree entirely, e.g. a header identity badge,\n // sees a stale \"signed out\" display until something else happens\n // to remount). Rotating again, strictly after `provider.login()`\n // has returned, guarantees the query that finally answers\n // \"who is signed in\" only ever starts once the provider has\n // actually finished writing that answer.\n if (result.success) await options.runtime.dataSession.rotateSession('sign-in');\n return result;\n } catch (error) {\n return { success: false, error: normalizeDataError(error) };\n }\n });\n },\n async logout(params: unknown) {\n return serializeLifecycle(async () => {\n try {\n await options.runtime.dataSession.rotateSession('sign-out');\n const snapshot = await currentSnapshot();\n if (options.provider.logout === undefined) {\n return {\n success: false,\n error: configurationError(\n 'logout-unsupported',\n 'Authentication provider does not support logout.',\n ),\n };\n }\n const result = await options.provider.logout(params, context(snapshot));\n // Same reasoning as `login` above, for the symmetric case: without\n // this, an identity/check query built right after the FIRST\n // rotation can settle using whatever the provider's `logout()`\n // had not yet cleared.\n if (result.success) await options.runtime.dataSession.rotateSession('sign-out');\n return result;\n } catch (error) {\n return { success: false, error: normalizeDataError(error) };\n }\n });\n },\n async recover(error: DataError, captured: DataSessionSnapshot) {\n const state = options.runtime.dataSession.getState();\n if (state.status !== 'ready' || !sameSnapshot(state.snapshot, captured)) return error;\n const key = `${captured.sessionKey}:${captured.generation}`;\n const existing = recoveries.get(key);\n const pending = existing ?? resolveRecovery(error, captured);\n if (existing === undefined) recoveries.set(key, pending);\n let result: DataError | 'replay';\n try {\n result = await pending;\n } finally {\n if (recoveries.get(key) === pending) recoveries.delete(key);\n }\n if (result !== 'replay') return result;\n const current = options.runtime.dataSession.getState();\n return current.status === 'ready' && sameSnapshot(current.snapshot, captured)\n ? 'replay'\n : error;\n },\n };\n return Object.freeze(controller);\n}\n","import type { AuthProvider } from '@burojs/core';\nimport { createContext, useContext, useMemo, type ReactElement, type ReactNode } from 'react';\n\nimport { DataRuntimeProvider } from '../data/context.js';\nimport type { DataRuntimeContextValue } from '../data/runtime.js';\nimport { createAuthController, type AuthController } from './controller.js';\n\nexport const AuthControllerContext = createContext<AuthController | null>(null);\n\nexport interface AuthRuntimeProviderProps {\n readonly runtime: DataRuntimeContextValue;\n readonly provider: AuthProvider;\n readonly children: ReactNode;\n}\n\n/** Installs a native auth provider beside the caller-owned data runtime lease. */\nexport function AuthRuntimeProvider({\n runtime,\n provider,\n children,\n}: AuthRuntimeProviderProps): ReactElement {\n const controller = useMemo(\n () => createAuthController({ runtime, provider }),\n [provider, runtime],\n );\n const value = useMemo<DataRuntimeContextValue>(\n () => Object.freeze({ ...runtime, authController: controller }),\n [controller, runtime],\n );\n return (\n <AuthControllerContext.Provider value={controller}>\n <DataRuntimeProvider value={value}>{children}</DataRuntimeProvider>\n </AuthControllerContext.Provider>\n );\n}\n\nexport function useAuthController(): AuthController {\n const controller = useContext(AuthControllerContext);\n if (controller === null)\n throw new Error('Native auth hooks must be used within BuroProvider with authProvider.');\n return controller;\n}\n\n/** The auth controller, or `null` when `BuroProvider` has no `authProvider`. Never throws. */\nexport function useOptionalAuthController(): AuthController | null {\n return useContext(AuthControllerContext);\n}\n","import type { AuthCheckResult, AuthResult, DataError, DataSessionState } from '@burojs/core';\nimport {\n type UseMutationResult,\n type UseQueryResult,\n useMutation,\n useQuery,\n} from '@tanstack/react-query';\nimport { useSyncExternalStore } from 'react';\n\nimport { useAuthController } from '../../auth/context.js';\nimport { useDataRuntime } from '../../data/context.js';\n\nfunction sessionState(runtime: ReturnType<typeof useDataRuntime>): DataSessionState {\n return runtime.dataSession.getState();\n}\n\nfunction sessionSnapshot(state: DataSessionState) {\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\n/**\n * Gates the query on the DataSession being genuinely 'ready' for the exact\n * snapshot the query key already reflects — not merely \"has a session\".\n *\n * What this is MEASURED to do (`packages/react/tests/auth-query-session-gate.test.tsx`,\n * which reddens per line if either `enabled` below is removed): no auth query\n * is ever ISSUED while a transition is open. Without the gate, a query built\n * from a 'transitioning' snapshot starts fetching immediately, and\n * `AuthController.check()`/`.getIdentity()` themselves `await` that SAME\n * transition finishing (`createAuthController`'s `activeSnapshot()` →\n * `runtime.waitUntilReady()`) before they can answer, so the fetch parks\n * there and is then thrown away by the `queryClient.cancelQueries()`/\n * `.clear()` that `createDataRuntimeTransitionParticipant`'s `abort()` runs\n * at the next boundary. Counted: one `rotateSession()` costs 2\n * `getIdentity()` calls with the gate and 3 without; two back-to-back\n * rotations 2 vs 4; a `replaceScope()` then a rotation 3 vs 5. Wasted\n * provider work on every session rotation and every scope replacement,\n * removed.\n *\n * What this is NOT measured to do, despite an earlier claim in this repo\n * that it was: prevent the query getting permanently STUCK after a\n * same-route transition. That failure mode is arguable from the mechanism\n * above, but nobody has reproduced it. `abort()` runs synchronously right\n * after the 'transitioning' state is published and before React can render\n * the new query key, so the cancel lands before the new query exists; and\n * every later transition changes the key again, which mounts a fresh query.\n * Four scenarios built to provoke it (a transition held open across a React\n * render, two back-to-back rotations, a rotation landing mid-flight, a\n * `replaceScope`) settled on the fresh value with the gate and without it.\n * See `examples/marketplace-ops/docs/coverage-matrix.md` for the full\n * measurement in both states, including the app-stack tests that were once\n * recorded as proving this and do not.\n *\n * Consequence to keep in mind when consuming these hooks: during a\n * transition the query is DISABLED, so it reports `status: 'pending'` with\n * `fetchStatus: 'idle'` and therefore `isLoading === false`. Guards must\n * branch on `status`, not on `isLoading`.\n */\nfunction isReady(state: DataSessionState): boolean {\n return state.status === 'ready';\n}\n\n/** Returns the current auth-provider identity without making any UI decision. */\nexport function useIdentity<TIdentity = unknown>(): UseQueryResult<TIdentity | null, DataError> {\n const runtime = useDataRuntime();\n const controller = useAuthController();\n const state = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionState(runtime),\n () => sessionState(runtime),\n );\n const session = sessionSnapshot(state);\n return useQuery({\n queryKey: ['buro-auth', 'identity', session.sessionKey, session.generation, session.scopeKey],\n queryFn: () => controller.getIdentity() as Promise<TIdentity | null>,\n enabled: isReady(state),\n retry: false,\n });\n}\n\n/** Returns the auth-provider check result without redirecting or notifying. */\nexport function useIsAuthenticated(): UseQueryResult<AuthCheckResult, DataError> {\n const runtime = useDataRuntime();\n const controller = useAuthController();\n const state = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionState(runtime),\n () => sessionState(runtime),\n );\n const session = sessionSnapshot(state);\n return useQuery({\n queryKey: ['buro-auth', 'check', session.sessionKey, session.generation, session.scopeKey],\n queryFn: () => controller.check(),\n enabled: isReady(state),\n retry: false,\n });\n}\n\nexport function useLogin(): UseMutationResult<AuthResult, DataError, unknown> {\n const controller = useAuthController();\n return useMutation({ mutationFn: (params: unknown) => controller.login(params), retry: false });\n}\n\nexport function useLogout(): UseMutationResult<AuthResult, DataError, unknown> {\n const controller = useAuthController();\n return useMutation({ mutationFn: (params: unknown) => controller.logout(params), retry: false });\n}\n","import type {\n CountDescriptor,\n ErasedQueryDescriptor,\n ErasedResourceHandle,\n FieldDefBase,\n PortableObject,\n QueryResultFor,\n ResourceHandle,\n} from '@burojs/core';\n\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\nimport { type ResourceInput, useStandardQueryDescriptor } from './use-standard-query-descriptor.js';\n\ntype AnyResource = ResourceHandle<unknown, Record<string, FieldDefBase>, string, string>;\nexport type UseCountOptions<\n R extends AnyResource,\n TSelected = QueryResultFor<CountDescriptor<R>>,\n> = {\n readonly filter?: CountDescriptor<R> extends { readonly filter?: infer T } ? T : never;\n readonly providerOptionsOverride?: PortableObject;\n readonly projection?: readonly string[];\n} & NativeQueryOptions<QueryResultFor<CountDescriptor<R>>, TSelected>;\n\nexport function useCount<R extends AnyResource, TSelected = QueryResultFor<CountDescriptor<R>>>(\n resource: R,\n options?: UseCountOptions<R, TSelected>,\n): NativeQueryResult<QueryResultFor<CountDescriptor<R>>, TSelected>;\nexport function useCount<TSelected = QueryResultFor<CountDescriptor<ErasedResourceHandle>>>(\n resource: string,\n options?: UseCountOptions<ErasedResourceHandle, TSelected>,\n): NativeQueryResult<QueryResultFor<CountDescriptor<ErasedResourceHandle>>, TSelected>;\nexport function useCount(resource: AnyResource | string, options: any = {}): any {\n const { providerOptionsOverride, projection, filter, ...queryOptions } = options;\n const descriptor = useStandardQueryDescriptor<AnyResource, CountDescriptor<AnyResource>>(\n resource,\n {\n kind: 'count',\n ...(filter === undefined ? {} : { filter }),\n ...(projection === undefined ? {} : { projection }),\n },\n providerOptionsOverride,\n );\n return useQueryDescriptor(descriptor as unknown as ErasedQueryDescriptor, queryOptions);\n}\n","import {\n createQueryDescriptor,\n type DataError,\n type ErasedQueryDescriptor,\n type Pagination,\n} from '@burojs/core';\n\nimport { executeQuery } from './query-execution.js';\nimport type { DataRuntimeContextValue } from './runtime.js';\n\ntype ErasedListDescriptor = Extract<ErasedQueryDescriptor, { readonly kind: 'list' }>;\n\nexport interface InfiniteListPage {\n readonly data: readonly unknown[];\n readonly pageInfo?: {\n readonly nextCursor?: string;\n readonly hasNextPage?: boolean;\n };\n}\n\nexport interface InfiniteListObserverState {\n readonly pages: readonly InfiniteListPage[];\n readonly error: DataError | null;\n readonly isFetchingNextPage: boolean;\n}\n\nconst EMPTY_STATE: InfiniteListObserverState = Object.freeze({\n pages: Object.freeze([]),\n error: null,\n isFetchingNextPage: false,\n});\n\nfunction nextPagination(\n current: Pagination | undefined,\n page: InfiniteListPage,\n): Pagination | undefined {\n if (current?.kind === 'cursor') {\n const after = page.pageInfo?.nextCursor;\n return after === undefined ? undefined : { kind: 'cursor', limit: current.limit, after };\n }\n if (current?.kind === 'offset' && page.pageInfo?.hasNextPage === true) {\n return { kind: 'offset', page: current.page + 1, pageSize: current.pageSize };\n }\n return undefined;\n}\n\n/**\n * Owns one infinite-list page sequence for one canonical descriptor identity.\n * React only subscribes to it; no controller or component keeps page arrays,\n * cancellation handles, or generation checks. The first page comes from the\n * identity's `QueryLiveObserver`; following pages share this sequence's\n * lifetime and execute only through the native descriptor executor.\n */\nexport class InfiniteListObserver {\n readonly #runtime: DataRuntimeContextValue;\n readonly #descriptor: ErasedListDescriptor | undefined;\n readonly #listeners = new Set<() => void>();\n #state = EMPTY_STATE;\n #active = true;\n #tailController: AbortController | undefined;\n #tailPromise: Promise<void> | undefined;\n\n constructor(args: {\n readonly descriptor: ErasedListDescriptor | undefined;\n readonly runtime: DataRuntimeContextValue;\n }) {\n this.#descriptor = args.descriptor;\n this.#runtime = args.runtime;\n }\n\n getState = (): InfiniteListObserverState => this.#state;\n\n subscribe = (listener: () => void): (() => void) => {\n if (!this.#active) return () => undefined;\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n };\n\n acceptInitial(page: InfiniteListPage | undefined, isCurrent: boolean): void {\n if (!this.#active || !isCurrent || page === undefined) return;\n const pages = this.#state.pages.length === 0 ? [page] : [page, ...this.#state.pages.slice(1)];\n this.#set({ ...this.#state, pages });\n }\n\n get hasNextPage(): boolean {\n if (this.#descriptor === undefined) return false;\n const page = this.#state.pages[this.#state.pages.length - 1];\n return page !== undefined && nextPagination(this.#descriptor.pagination, page) !== undefined;\n }\n\n fetchNextPage = async (): Promise<void> => {\n if (this.#tailPromise !== undefined) return this.#tailPromise;\n if (!this.#active || this.#descriptor === undefined) return;\n const page = this.#state.pages[this.#state.pages.length - 1];\n if (page === undefined) return;\n const pagination = nextPagination(this.#descriptor.pagination, page);\n if (pagination === undefined) return;\n const controller = new AbortController();\n this.#tailController = controller;\n this.#set({ ...this.#state, error: null, isFetchingNextPage: true });\n const request = (async () => {\n try {\n const descriptor = createQueryDescriptor({\n ...this.#descriptor,\n pagination,\n } as never) as ErasedListDescriptor;\n const result = await executeQuery({\n descriptor,\n runtime: this.#runtime,\n signal: controller.signal,\n });\n if (!this.#active || controller.signal.aborted) return;\n this.#set({ ...this.#state, pages: [...this.#state.pages, result as InfiniteListPage] });\n } catch (error) {\n if (this.#active && !controller.signal.aborted) {\n this.#set({ ...this.#state, error: error as DataError });\n }\n throw error;\n } finally {\n if (this.#tailController === controller) this.#tailController = undefined;\n if (this.#active) this.#set({ ...this.#state, isFetchingNextPage: false });\n this.#tailPromise = undefined;\n }\n })();\n this.#tailPromise = request;\n return request;\n };\n\n dispose(): void {\n if (!this.#active) return;\n this.#active = false;\n this.#tailController?.abort();\n this.#tailController = undefined;\n this.#listeners.clear();\n }\n\n #set(next: InfiniteListObserverState): void {\n this.#state = next;\n for (const listener of this.#listeners) listener();\n }\n}\n","import {\n isDataError,\n queryKeyFor,\n type DataError,\n type ErasedQueryDescriptor,\n type ErasedResourceHandle,\n type FieldDefBase,\n type ListDescriptor,\n type PortableObject,\n type QueryResultFor,\n type ResourceHandle,\n} from '@burojs/core';\nimport { useEffect, useMemo, useSyncExternalStore } from 'react';\n\nimport { InfiniteListObserver, type InfiniteListPage } from '../../data/infinite-list-observer.js';\nimport { useDataRuntime } from '../../data/context.js';\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\nimport { type ResourceInput, useStandardQueryDescriptor } from './use-standard-query-descriptor.js';\n\ntype AnyResource = ResourceHandle<unknown, Record<string, FieldDefBase>, string, string>;\ntype ErasedListDescriptor = Extract<ErasedQueryDescriptor, { readonly kind: 'list' }>;\n\nexport interface InfiniteListData<TPage = InfiniteListPage> {\n readonly pages: readonly TPage[];\n}\n\nexport type UseInfiniteListOptions<R extends AnyResource> = {\n readonly pagination: ListDescriptor<R> extends { readonly pagination?: infer T } ? T : never;\n readonly filter?: ListDescriptor<R> extends { readonly filter?: infer T } ? T : never;\n readonly sort?: ListDescriptor<R> extends { readonly sort?: infer T } ? T : never;\n readonly projection?: readonly string[];\n readonly providerOptionsOverride?: PortableObject;\n} & NativeQueryOptions<QueryResultFor<ListDescriptor<R>>>;\n\nexport interface NativeInfiniteListResult<TPage = InfiniteListPage>\n extends Omit<NativeQueryResult<TPage>, 'data' | 'isFetching' | 'error'> {\n readonly data: InfiniteListData<TPage> | undefined;\n readonly error: DataError | null;\n readonly isFetching: boolean;\n readonly hasNextPage: boolean;\n readonly isFetchingNextPage: boolean;\n fetchNextPage(): Promise<void>;\n}\n\nfunction identityFor(descriptor: ErasedListDescriptor | DataError): string {\n if (isDataError(descriptor))\n return `error:${descriptor.kind}:${descriptor.code}:${descriptor.message}`;\n return JSON.stringify(queryKeyFor(descriptor));\n}\n\n/**\n * Native infinite-list bridge. The reusable `InfiniteListObserver` owns page\n * sequence, cancellation, and tail execution; React supplies the first page\n * from the identity-bound live query observer and subscribes to its state.\n */\nexport function useInfiniteList<R extends AnyResource>(\n resource: R,\n options: UseInfiniteListOptions<R>,\n): NativeInfiniteListResult<QueryResultFor<ListDescriptor<R>>>;\nexport function useInfiniteList(\n resource: string,\n options: UseInfiniteListOptions<ErasedResourceHandle>,\n): NativeInfiniteListResult<QueryResultFor<ListDescriptor<ErasedResourceHandle>>>;\nexport function useInfiniteList(resource: ResourceInput<AnyResource>, options: any): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, pagination, filter, sort, projection, ...queryOptions } =\n options;\n const descriptor = useStandardQueryDescriptor<AnyResource, ListDescriptor<AnyResource>>(\n resource,\n {\n kind: 'list',\n ...(pagination === undefined ? {} : { pagination }),\n ...(filter === undefined ? {} : { filter }),\n ...(sort === undefined ? {} : { sort }),\n ...(projection === undefined ? {} : { projection }),\n },\n providerOptionsOverride,\n );\n const initial = useQueryDescriptor<QueryResultFor<ListDescriptor<AnyResource>>>(\n descriptor as ErasedQueryDescriptor | DataError,\n queryOptions,\n );\n const identity = identityFor(descriptor as ErasedListDescriptor | DataError);\n const observer = useMemo(\n () =>\n new InfiniteListObserver({\n descriptor: isDataError(descriptor) ? undefined : (descriptor as ErasedListDescriptor),\n runtime,\n }),\n [identity, runtime],\n );\n useEffect(() => () => observer.dispose(), [observer]);\n useEffect(() => {\n observer.acceptInitial(initial.data as InfiniteListPage | undefined, initial.isCurrentData);\n }, [observer, initial.data, initial.isCurrentData]);\n const state = useSyncExternalStore(observer.subscribe, observer.getState, observer.getState);\n return {\n ...initial,\n data: state.pages.length === 0 ? undefined : { pages: state.pages },\n error: state.error ?? initial.error,\n isFetching: initial.isFetching || state.isFetchingNextPage,\n hasNextPage: observer.hasNextPage,\n isFetchingNextPage: state.isFetchingNextPage,\n fetchNextPage: observer.fetchNextPage,\n } as NativeInfiniteListResult<QueryResultFor<ListDescriptor<AnyResource>>>;\n}\n","import {\n type CustomQueryHandle,\n type DataSessionSnapshot,\n type ErasedQueryDescriptor,\n type InferCustomInput,\n type InferCustomOutput,\n type PortableObject,\n type PortableValue,\n createCustomQueryDescriptor,\n} from '@burojs/core';\nimport { useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../../data/context.js';\nimport { useApplicationSnapshot } from '../../runtime.js';\nimport { useLocale } from '../use-t.js';\nimport {\n type NativeQueryOptions,\n type NativeQueryResult,\n useQueryDescriptor,\n} from './use-query-descriptor.js';\n\nexport type UseCustomQueryOptions<TOutput, TSelected = TOutput> = NativeQueryOptions<\n TOutput,\n TSelected\n> & {\n readonly providerOptionsOverride?: PortableObject;\n readonly projection?: readonly string[];\n};\n\nfunction sessionSnapshot(runtime: ReturnType<typeof useDataRuntime>): DataSessionSnapshot {\n const state = runtime.dataSession.getState();\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\n/** Resolves a trusted custom operation from the current compiled projection. */\nexport function useCustomQuery<\n THandle extends CustomQueryHandle<unknown, unknown>,\n TSelected = InferCustomOutput<THandle>,\n>(\n handle: THandle,\n input: InferCustomInput<THandle>,\n options: UseCustomQueryOptions<InferCustomOutput<THandle>, TSelected> = {},\n): NativeQueryResult<InferCustomOutput<THandle>, TSelected> {\n const runtime = useDataRuntime();\n const snapshot = useApplicationSnapshot();\n const session = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionSnapshot(runtime),\n () => sessionSnapshot(runtime),\n );\n // See `use-standard-query-descriptor.ts` — subscribed unconditionally, but\n // only a binding declaring `localeVarying` puts the locale in the key.\n const locale = useLocale();\n const { providerOptionsOverride, projection: selectedProjection, ...queryOptions } = options;\n const descriptor = createCustomQueryDescriptor({\n snapshot,\n session,\n locale,\n ref: handle.ref,\n input: input as PortableValue,\n ...(selectedProjection === undefined ? {} : { projection: selectedProjection }),\n ...(providerOptionsOverride === undefined ? {} : { providerOptionsOverride }),\n });\n return useQueryDescriptor<InferCustomOutput<THandle>, TSelected>(\n descriptor as unknown as ErasedQueryDescriptor,\n queryOptions,\n );\n}\n","import type {\n BulkTarget,\n DataError,\n DeleteManyDescriptor,\n DeleteOneDescriptor,\n ErasedResourceHandle,\n FieldDefBase,\n MutationResultFor,\n PortableObject,\n ResourceHandle,\n} from '@burojs/core';\nimport { useMutation, type UseMutationResult } from '@tanstack/react-query';\n\nimport { buroMutationOptions, type NativeMutationOptions } from '../../data/mutation-options.js';\nimport { useDataRuntime } from '../../data/context.js';\nimport { useStandardMutationDescriptor } from './use-standard-mutation-descriptor.js';\n\ntype AnyResource = ResourceHandle<any, Record<string, FieldDefBase>, string, string>;\ntype DeleteOneVariables<R extends AnyResource> = { readonly id: DeleteOneDescriptor<R>['id'] };\ntype DeleteManyVariables<R extends AnyResource> = { readonly target: BulkTarget<R> };\nexport type UseDeleteOneOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<DeleteOneDescriptor<R>>,\n DeleteOneVariables<R>\n> & { readonly providerOptionsOverride?: PortableObject };\nexport type UseDeleteManyOptions<R extends AnyResource> = NativeMutationOptions<\n MutationResultFor<DeleteManyDescriptor<R>>,\n DeleteManyVariables<R>\n> & { readonly providerOptionsOverride?: PortableObject };\n\nexport function useDeleteOne<R extends AnyResource>(\n resource: R,\n options?: UseDeleteOneOptions<R>,\n): UseMutationResult<MutationResultFor<DeleteOneDescriptor<R>>, DataError, DeleteOneVariables<R>>;\nexport function useDeleteOne(\n resource: string,\n options?: UseDeleteOneOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<DeleteOneDescriptor<ErasedResourceHandle>>,\n DataError,\n DeleteOneVariables<ErasedResourceHandle>\n>;\nexport function useDeleteOne(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly id: unknown }) =>\n descriptorFor({ kind: 'deleteOne', id: variables.id }),\n runtime,\n ),\n });\n}\n\nexport function useDeleteMany<R extends AnyResource>(\n resource: R,\n options?: UseDeleteManyOptions<R>,\n): UseMutationResult<MutationResultFor<DeleteManyDescriptor<R>>, DataError, DeleteManyVariables<R>>;\nexport function useDeleteMany(\n resource: string,\n options?: UseDeleteManyOptions<ErasedResourceHandle>,\n): UseMutationResult<\n MutationResultFor<DeleteManyDescriptor<ErasedResourceHandle>>,\n DataError,\n DeleteManyVariables<ErasedResourceHandle>\n>;\nexport function useDeleteMany(resource: AnyResource | string, options: any = {}): any {\n const runtime = useDataRuntime();\n const { providerOptionsOverride, ...mutationOptions } = options;\n const descriptorFor = useStandardMutationDescriptor(resource, providerOptionsOverride);\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(\n (variables: { readonly target: unknown }) =>\n descriptorFor({ kind: 'deleteMany', target: variables.target }),\n runtime,\n ),\n });\n}\n","import {\n createMutationDescriptor,\n normalizeDataError,\n type CustomMutationDescriptor,\n type CustomMutationHandle,\n type DataError,\n type InferCustomInput,\n type InferCustomOutput,\n type PortableObject,\n} from '@burojs/core';\nimport { useMutation, type UseMutationResult } from '@tanstack/react-query';\nimport { useCallback, useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../../data/context.js';\nimport { buroMutationOptions, type NativeMutationOptions } from '../../data/mutation-options.js';\nimport { useApplicationSnapshot } from '../../runtime.js';\n\nexport type UseCustomMutationOptions<TInput, TOutput> = NativeMutationOptions<TOutput, TInput> & {\n readonly providerOptionsOverride?: PortableObject;\n};\n\nfunction sessionSnapshot(runtime: ReturnType<typeof useDataRuntime>) {\n const state = runtime.dataSession.getState();\n return state.status === 'ready' ? state.snapshot : state.target;\n}\n\n/** Resolves a trusted custom mutation and its declaration-owned effects. */\nexport function useCustomMutation<THandle extends CustomMutationHandle<unknown, unknown>>(\n handle: THandle,\n options: UseCustomMutationOptions<InferCustomInput<THandle>, InferCustomOutput<THandle>> = {},\n): UseMutationResult<InferCustomOutput<THandle>, DataError, InferCustomInput<THandle>> {\n const runtime = useDataRuntime();\n const snapshot = useApplicationSnapshot();\n const session = useSyncExternalStore(\n runtime.dataSession.subscribe,\n () => sessionSnapshot(runtime),\n () => sessionSnapshot(runtime),\n );\n const { providerOptionsOverride, ...mutationOptions } = options;\n const projection = snapshot.getProjection(handle);\n const descriptorFor = useCallback(\n (input: InferCustomInput<THandle>) => {\n if (projection === undefined || projection.kind !== 'custom-mutation') {\n throw normalizeDataError(\n Object.assign(\n new Error(`Custom mutation '${handle.ref.namespace}:${handle.ref.id}' is unavailable.`),\n {\n kind: 'configuration' as const,\n code: 'custom-mutation-unavailable',\n },\n ),\n );\n }\n const value = projection.value as Readonly<Record<string, unknown>>;\n const binding = value.binding as Readonly<Record<string, unknown>> | undefined;\n if (\n binding === undefined ||\n typeof binding.provider !== 'string' ||\n typeof binding.operation !== 'string' ||\n (binding.resource !== undefined && typeof binding.resource !== 'string')\n ) {\n throw normalizeDataError(\n Object.assign(\n new Error(\n `Custom mutation '${handle.ref.namespace}:${handle.ref.id}' has an invalid binding.`,\n ),\n {\n kind: 'configuration' as const,\n code: 'custom-mutation-binding-invalid',\n },\n ),\n );\n }\n return createMutationDescriptor({\n providerId: binding.provider,\n kind: 'custom',\n ref: handle.ref,\n resource: binding.resource ?? handle.ref.id,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n bindingRevision: snapshot.manifest.snapshotId,\n operation: binding.operation,\n input,\n ...(binding.providerOptions === undefined\n ? {}\n : { providerOptions: binding.providerOptions as PortableObject }),\n ...(providerOptionsOverride === undefined ? {} : { providerOptionsOverride }),\n ...(value.replay === undefined\n ? {}\n : (() => {\n const replay = value.replay as Readonly<Record<string, unknown>>;\n const policy =\n replay.capability === 'mutation-replay-policy' && typeof replay.id === 'string'\n ? runtime.app.getPluginCapability('mutation-replay-policy', replay.id)\n : undefined;\n return policy === undefined ? {} : { replay: policy };\n })()),\n } as never) as CustomMutationDescriptor<\n InferCustomInput<THandle>,\n InferCustomOutput<THandle>\n >;\n },\n [handle.ref, projection, providerOptionsOverride, session, snapshot.manifest.snapshotId],\n );\n return useMutation({\n ...mutationOptions,\n ...buroMutationOptions(descriptorFor, runtime),\n });\n}\n","'use client';\nimport { matchPath, type AppRuntime, type Audit, type AuditRoute } from '@burojs/core';\nimport { useEffect } from 'react';\nimport { useOptionalRouterAdapter } from '../hooks/router/router-adapter.js';\n\n/**\n * Emit `nav.enter` from pathname transitions.\n *\n * Mounted once by `ReadyBuroProvider`. `app` and `audit` are arguments rather\n * than context reads because the component that mounts this hook is the one\n * that PROVIDES `AppContext` and `AuditContext` — it cannot read its own.\n *\n * Everything happens in an effect, never during render: computing this in a\n * component body yields duplicate events under StrictMode and a side effect in\n * render.\n *\n * **There is deliberately no `nav.leave`.** How long a screen was open is the\n * difference between adjacent `nav.enter` timestamps, so a paired leave event\n * would double the navigation volume to carry information the sink can already\n * derive. That leaves exactly one case a leave would add — the last screen of a\n * session — and that is the case a browser cannot report reliably: closing a tab\n * runs no React cleanup (the page simply dies), and `pagehide` is not delivered\n * at all when a mobile tab is killed while backgrounded. An adopter who needs\n * the session tail owns it at the transport layer, where `visibilitychange` and\n * `sendBeacon` live — that is application policy, not framework behaviour.\n */\nexport function useNavAudit(app: AppRuntime, audit: Audit | null): void {\n const router = useOptionalRouterAdapter();\n const pathname = router?.pathname;\n\n useEffect(() => {\n if (!audit || pathname === undefined) return;\n\n let parsed: AuditRoute = { path: pathname };\n try {\n const match = matchPath(app.registry, pathname);\n if (match) {\n parsed = {\n path: pathname,\n resource: match.name,\n view: match.action,\n recordId: match.id,\n };\n }\n } catch {\n // A registry that cannot resolve this path is not a reason to lose the\n // event — the raw path is still worth recording.\n }\n\n audit.emit({ type: 'nav.enter', route: parsed }, { initiates: true });\n }, [audit, pathname, app]);\n}\n","'use client';\n\nimport {\n type DocKeyRef,\n type DocsConfig,\n type I18nCaps,\n type ResolvedDocTopic,\n docAddressToKey,\n listDocTopics,\n resolveContentSlot,\n resolveDoc,\n resolveDocLoader,\n resolveConceptLabel,\n resolveEnumLabel,\n resolveResourceLabel,\n type ResourceLabels,\n} from '@burojs/core';\nimport {\n type ReactNode,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport { useApp } from './use-app.js';\nimport { useI18nCaps, useLocale } from './use-t.js';\n\n/**\n * What the panel is currently showing.\n *\n * `scopes` is a LIST because the natural entry point is the breadcrumb trail,\n * and a trail names several documented things at once — «Документы › wo:2921 ›\n * Коды» offers help for two resources. A single «i» beside one field passes a\n * one-element list.\n */\nexport interface DocPanelTarget {\n /** Scopes offered, in trail order. Always at least one. */\n scopes: string[];\n /** The article currently open, if any. */\n topicId?: string;\n /** Which of `scopes` owns `topicId`. Defaults to the first. */\n scope?: string;\n}\n\ninterface DocPanelState {\n open: boolean;\n target: DocPanelTarget | null;\n /**\n * Id of the element that opened the panel, so Escape can hand focus back.\n * Stored as an ID rather than as a node: a form re-render unmounts the node,\n * and a stale reference would send focus to nothing.\n */\n returnFocusTo: string | null;\n}\n\n/** Panel API. `open` records where focus should go when the panel closes. */\nexport interface DocPanelApi extends DocPanelState {\n openPanel: (target: DocPanelTarget, returnFocusTo?: string) => void;\n /** Navigate WITHIN the panel; the return-focus target is preserved. */\n goTo: (target: DocPanelTarget) => void;\n close: () => void;\n}\n\n/**\n * A tiny external store rather than React state.\n *\n * The panel is opened from `<DocInfo>` buttons scattered all over the tree and\n * rendered once in the layout — there is no common ancestor to hold state that\n * is not the provider itself, and putting it in the provider would re-render\n * the entire application on every open.\n */\nfunction createStore() {\n let state: DocPanelState = { open: false, target: null, returnFocusTo: null };\n const listeners = new Set<() => void>();\n const emit = () => {\n for (const l of listeners) l();\n };\n return {\n subscribe(l: () => void): () => void {\n listeners.add(l);\n // Explicitly `void`: `Set.delete` returns a boolean, and React's\n // EffectCallback rejects a cleanup that returns anything.\n return () => {\n listeners.delete(l);\n };\n },\n get: () => state,\n set(next: DocPanelState) {\n state = next;\n emit();\n },\n };\n}\n\ntype Store = ReturnType<typeof createStore>;\n\ninterface DocsContextValue {\n config: DocsConfig | null;\n store: Store;\n /** Separate store for the on-screen record's documentation variant. */\n variants: Store;\n}\n\nconst DocsContext = createContext<DocsContextValue | null>(null);\n\n/*\n NO URL MIRROR.\n\n The panel used to write `?help=<scope>:<topic>` so an article could be pasted\n into a ticket. Removed on the owner's call, and the reasoning is worth\n keeping: the panel is STICKY ACROSS NAVIGATION by design — it stays put while\n the reader works — so the query param it left behind rode along on every\n subsequent link, describing an article the reader had long since stopped\n looking at. A pointer that goes stale the moment you use the page is worse\n than no pointer.\n\n Sharing a specific article still works, and better: the handbook at `/help`\n carries `?area=` / `?topic=` plus a per-heading anchor, which is a real page\n the recipient lands on rather than a panel that has to be re-opened.\n*/\n\nexport function DocsProvider({\n config,\n children,\n}: {\n config: DocsConfig | undefined;\n children: ReactNode;\n}): ReactNode {\n // One store for the lifetime of the provider; `useRef` rather than `useMemo`\n // because a store must never be recreated by a render.\n const storeRef = useRef<Store | null>(null);\n storeRef.current ??= createStore();\n const store = storeRef.current as Store;\n const variantRef = useRef<Store | null>(null);\n variantRef.current ??= createStore();\n const variants = variantRef.current as Store;\n const value = useMemo<DocsContextValue>(\n () => ({ config: config ?? null, store, variants }),\n [config, store, variants],\n );\n return <DocsContext.Provider value={value}>{children}</DocsContext.Provider>;\n}\n\n/** The article-body configuration, or `null` when the app supplied none. */\nexport function useDocsConfig(): DocsConfig | null {\n return useContext(DocsContext)?.config ?? null;\n}\n\nconst EMPTY: DocPanelState = { open: false, target: null, returnFocusTo: null };\n\n/**\n * Control and observe the documentation panel.\n *\n * State lives in a store, NOT in the URL. Every navigation link in the app is a\n * bare path with no query, so URL-as-source-of-truth would close the panel on\n * each navigation — destroying the one behaviour it exists for, which is being\n * readable WHILE the reader works. The URL is written for sharing and read back\n * on load; it never drives the panel during a session.\n */\nexport function useDocPanel(): DocPanelApi {\n const ctx = useContext(DocsContext);\n const store = ctx?.store;\n const subscribe = useCallback((cb: () => void) => store?.subscribe(cb) ?? (() => {}), [store]);\n const getSnapshot = useCallback(() => store?.get() ?? EMPTY, [store]);\n const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const openPanel = useCallback(\n (target: DocPanelTarget, returnFocusTo?: string) => {\n store?.set({ open: true, target, returnFocusTo: returnFocusTo ?? null });\n },\n [store],\n );\n const goTo = useCallback(\n (target: DocPanelTarget) => {\n const prev = store?.get();\n store?.set({ open: true, target, returnFocusTo: prev?.returnFocusTo ?? null });\n },\n [store],\n );\n const close = useCallback(() => {\n store?.set({ open: false, target: null, returnFocusTo: null });\n }, [store]);\n\n return { ...state, openPanel, goTo, close };\n}\n\n/** A topic plus the title the bundle gives it in the active locale. */\nexport interface DocTopicView extends ResolvedDocTopic {\n title: string;\n /** Scope this topic belongs to — needed once several are listed together. */\n scope: string;\n}\n\n/**\n * Human name for a scope. A resource scope reads its collection title\n * (`resolveResourceLabel` over the declared labels, then the humanized name);\n * an `enum/<ns>/<value>` scope reads the enum VALUE's label, which is what makes\n * a variant group read «Заказ кодов» rather than a raw token.\n */\nfunction resolveScopeLabel(\n caps: I18nCaps,\n scope: string,\n ref: DocKeyRef | undefined,\n def: ResourceLabels | undefined,\n): string {\n const parts = scope.split('/');\n if (parts[0] === 'enum' && parts[1] !== undefined && parts[2] !== undefined) {\n return resolveEnumLabel(caps, parts[1], parts[2]);\n }\n // A glossary term names itself. Without this the panel header for a field\n // that defers to one reads the raw address, «concept/gtin».\n if (parts[0] === 'concept' && parts[1] !== undefined) {\n return resolveConceptLabel(caps, parts[1]);\n }\n if (ref?.resource !== undefined) {\n return resolveResourceLabel(caps, ref.resource, 'plural', def);\n }\n return scope;\n}\n\n/** One scope's topics, with the scope's own label and summary. */\nexport interface DocScopeView {\n scope: string;\n label: string;\n summary?: string;\n topics: DocTopicView[];\n}\n\n/**\n * Topics of one scope, ordered, each with its resolved title.\n *\n * Order comes from the map (kind, then explicit `order`, then id) and NOT from\n * the title — sorting by title would reshuffle the panel whenever the reader\n * switches language.\n *\n * `fields.<f>` / `actions.<a>` / `tabs.<t>` topics take their title from the\n * entity's own label instead of `doc.topics.<id>`, so a name never has to be\n * written twice.\n */\nexport function useDocTopics(scope: string | undefined): DocTopicView[] {\n const scopes = useMemo(() => (scope ? [scope] : []), [scope]);\n const groups = useDocScopes(scopes);\n return useMemo(() => groups.flatMap((g) => g.topics), [groups]);\n}\n\n/**\n * Topics for SEVERAL scopes at once, each with its label, summary and ordered\n * topic list. Scopes with nothing at all are dropped.\n *\n * One `useI18nCaps()` for the whole walk, with `resource` passed per lookup —\n * `useI18nCaps(scope)` in a loop would be a hook in a loop. Scopes keep the\n * caller's order (the breadcrumb trail), not alphabetical: the trail reads\n * outermost-first and the list should match what the reader just looked at.\n */\nexport function useDocScopes(scopes: readonly string[]): DocScopeView[] {\n const app = useApp();\n const config = useDocsConfig();\n const locale = useLocale();\n const caps = useI18nCaps();\n\n return useMemo(() => {\n const out: DocScopeView[] = [];\n for (const scope of scopes) {\n /*\n No `config` is NOT the same as \"nothing to show\". An app can document\n entirely through bundle summaries and never ship a single article — that\n is the whole of part one of this feature — and such a scope still\n belongs in the trail's help. Articles are the part that needs a config;\n summaries never were.\n */\n const ref = docAddressToKey(scope);\n const opts = ref?.resource !== undefined ? { resource: ref.resource } : {};\n const topics = (config ? listDocTopics(config, scope, locale) : []).map((topic) => {\n /*\n The title key hangs off the ADDRESS, which makes one formula serve\n both kinds of scope: a resource resolves `doc.topics.<id>`, an\n enum-value variant resolves `enums.<ns>.<value>.doc.topics.<id>`.\n\n `fields.*` / `actions.*` / `tabs.*` additionally fall back to the\n entity's own label, so a name is never written twice.\n */\n const entityKey = /^(fields|actions|tabs)\\./.test(topic.id)\n ? [`${topic.id}.label`, topic.id]\n : [];\n const title =\n resolveContentSlot(\n caps,\n [`${ref?.key ?? 'doc'}.topics.${topic.id}`, ...entityKey],\n opts,\n ) ?? topic.id;\n return { ...topic, title, scope };\n });\n /*\n A scope is an ADDRESS, not necessarily a resource name. `document_document`\n is one; `enum/document_type/work_order` is another, and that is how a\n resource's help splits by kind. Routing both through the same address\n grammar means the panel never has to care which it is looking at.\n */\n const summary = ref ? resolveContentSlot(caps, [`${ref.key}.summary`], opts) : undefined;\n const def = ref?.resource === undefined ? undefined : app.registry.get(ref.resource);\n const label = resolveScopeLabel(caps, scope, ref, def);\n if (topics.length === 0 && summary === undefined) continue;\n out.push({\n scope,\n label,\n ...(summary !== undefined ? { summary } : {}),\n topics,\n });\n }\n return out;\n }, [app, config, scopes, locale, caps]);\n}\n\n/** One topic of a scope, with its title, or `undefined` when it has no body. */\nexport function useDocTopic(\n scope: string | undefined,\n topicId: string | undefined,\n): DocTopicView | undefined {\n const topics = useDocTopics(scope);\n return topicId === undefined ? undefined : topics.find((t) => t.id === topicId);\n}\n\n/** True when the scope has at least one article — the condition for «Подробнее». */\nexport function useHasDocTopics(scope: string | undefined): boolean {\n return useDocTopics(scope).length > 0;\n}\n\n/**\n * The scope a documentation VARIANT currently resolves to, e.g.\n * `enum/document_type/work_order`, or `null` on a page with no variant.\n *\n * A store rather than React context because of where the two ends live: the\n * breadcrumb sits in the app HEADER and the record is loaded by the PAGE, which\n * is a sibling, not an ancestor. Same reason the panel state is a store.\n */\nfunction useVariantStore(): Store | undefined {\n return useContext(DocsContext)?.variants;\n}\n\n/**\n * Publish the variant of the record on screen. Called by whatever renders a\n * record; clears on unmount so the trail never keeps offering help for a\n * document the reader has navigated away from.\n */\nexport function usePublishDocVariant(\n resource: string | undefined,\n record: Record<string, unknown> | undefined,\n): void {\n const app = useApp();\n const store = useVariantStore();\n const def = resource ? app.registry.get(resource) : undefined;\n const variant = def?.docVariant;\n const value = variant && record ? record[variant.field] : undefined;\n const scope =\n variant && (typeof value === 'string' || typeof value === 'number')\n ? `enum/${variant.enum}/${value}`\n : null;\n\n useEffect(() => {\n if (!store) return;\n store.set({ open: false, target: scope ? { scopes: [scope] } : null, returnFocusTo: null });\n return () => {\n store.set({ open: false, target: null, returnFocusTo: null });\n };\n }, [store, scope]);\n}\n\n/**\n * Scopes the trail should offer for one resource: the resource itself, plus its\n * documentation variant when there is one.\n *\n * The variant is read from the published record first, and from the URL query\n * second — a create screen carries `?type=…` and has no record at all, which is\n * exactly when a reader most wants to know what the thing they are creating is.\n */\nexport function useDocTrailScopes(resource: string | undefined): string[] {\n const app = useApp();\n const store = useVariantStore();\n const subscribe = useCallback((cb: () => void) => store?.subscribe(cb) ?? (() => {}), [store]);\n const getSnapshot = useCallback(() => store?.get().target?.scopes[0] ?? null, [store]);\n const published = useSyncExternalStore(subscribe, getSnapshot, () => null);\n\n return useMemo(() => {\n if (!resource) return [];\n const def = app.registry.get(resource);\n /*\n An explicit mapping wins outright. A resource that is a VIEW onto another\n one — the playground's `doc_order_code` is `document_document` filtered to\n one type — cannot be related to its source by anything in the registry:\n they share a table, not a declaration. Left to infer, both its own list\n AND the shared detail page reached from it showed no help at all, because\n the breadcrumb roots at the per-type resource and asked IT.\n */\n if (def?.docScopes && def.docScopes.length > 0) return def.docScopes;\n const variant = def?.docVariant;\n /*\n MOST SPECIFIC FIRST. A reader on a code order is asking about a code\n order; «что такое документ вообще» is the fallback they widen to, not the\n thing they came for. Note this is the opposite of the HANDBOOK, where the\n type is nested UNDER the resource — the handbook shows structure, the\n panel shows relevance, and those are different orderings on purpose.\n */\n if (!variant) return [resource];\n if (published) return [published, resource];\n if (typeof window !== 'undefined') {\n const fromUrl = new URLSearchParams(window.location.search).get(variant.field);\n if (fromUrl) return [`enum/${variant.enum}/${fromUrl}`, resource];\n }\n return [resource];\n }, [app, resource, published]);\n}\n\n/** True when anything in the trail is documented — the condition for the «?». */\nexport function useTrailHasDocs(scopes: readonly string[]): boolean {\n return useDocScopes(scopes).length > 0;\n}\n\n/** Re-exported so consumers need not reach into core for the lookup. */\nexport { resolveDocLoader };\n\n/** One documented area, in the order a handbook should list them. */\nexport interface DocumentedScope {\n /** Doc address, and the key into `DocsConfig.sources`. */\n scope: string;\n /** A glossary term, a resource, or one kind of a resource. */\n kind: 'concept' | 'resource' | 'variant';\n /** For a variant: the resource it belongs under. */\n owner?: string;\n}\n\n/**\n * Every area the reader may browse, ordered: glossary terms first, then each\n * resource with its own kinds nested under it.\n *\n * EXPORTED, and that is the point. This enumeration existed twice — once in the\n * handbook and once in the command palette — and the palette's copy accepted\n * only scopes matching a registered resource. So `concept/gtin` and\n * `enum/document_type/order_code` were dropped from it: ⌘K → «GTIN» returned a\n * packing-config record and not the glossary article, and the whole glossary\n * plus every per-type article were unreachable from the one control people\n * actually use to look things up. Fixing the handbook's copy alone left that\n * standing. One function, two callers, one behaviour.\n *\n * Only scopes the registry knows are listed: a palette that surfaced topics for\n * entities the reader's role cannot see would leak the shape of the app.\n */\nexport function useDocumentedScopes(): DocumentedScope[] {\n const app = useApp();\n const config = useDocsConfig();\n const caps = useI18nCaps();\n\n return useMemo(() => {\n if (!config) return [];\n const resources = app.registry.list();\n const hasArticles = (scope: string) => config.sources[scope] !== undefined;\n const out: DocumentedScope[] = [];\n\n for (const name of config.concepts ?? []) {\n out.push({ scope: `concept/${name}`, kind: 'concept' });\n }\n\n for (const r of resources) {\n /*\n Variants come from the ENUM REGISTRY, not from the article map: a type\n documented with a summary and no `.md` is still a documented type.\n Loader-backed enums expose nothing synchronously, so those contribute\n only the variants that do have articles.\n */\n const variants = new Set<string>();\n const ns = r.docVariant?.enum;\n if (ns !== undefined) {\n for (const v of app.registry.enums.get(ns)?.values ?? []) {\n const scope = `enum/${ns}/${v.value}`;\n if (hasArticles(scope) || resolveDoc(caps, scope)) variants.add(scope);\n }\n for (const scope of Object.keys(config.sources)) {\n if (scope.startsWith(`enum/${ns}/`)) variants.add(scope);\n }\n }\n\n const summary = resolveDoc(caps, r.name)?.summary;\n if (!hasArticles(r.name) && summary === undefined && variants.size === 0) continue;\n out.push({ scope: r.name, kind: 'resource' });\n for (const scope of [...variants].sort()) {\n out.push({ scope, kind: 'variant', owner: r.name });\n }\n }\n return out;\n }, [app, config, caps]);\n}\n","import { createContext, useContext } from 'react';\nimport type { BlockImplementationCatalog } from './implementation.js';\n\nconst EMPTY: BlockImplementationCatalog = {};\n\n/** The app's block views (`<BuroProvider blockImplementations>`); the built-ins are the renderer's. */\nexport const BlockImplementationsContext = createContext<BlockImplementationCatalog>(EMPTY);\n\n/** The app's block catalogue; `{}` outside a provider. @internal */\nexport function useBlockImplementations(): BlockImplementationCatalog {\n return useContext(BlockImplementationsContext);\n}\n","import { createContext, useContext } from 'react';\nimport type { FrameImplementationCatalog } from './implementation.js';\n\nconst EMPTY: FrameImplementationCatalog = Object.freeze({});\n\n/** The app's frame views (`<BuroProvider frameImplementations>`); the built-ins are the kit's. */\nexport const FrameImplementationsContext = createContext<FrameImplementationCatalog>(EMPTY);\n\n/** The app's frame catalogue; `{}` outside a provider. @internal */\nexport function useFrameImplementations(): FrameImplementationCatalog {\n return useContext(FrameImplementationsContext);\n}\n","import {\n resolveManifest,\n serializePortableManifest,\n type AppDefinition,\n type ApplicationSnapshot,\n type LayerRuntime,\n type ManifestFingerprint,\n type ManifestResolution,\n type PortableSnapshotManifest,\n} from '@burojs/core';\n\n/**\n * The portable server snapshot and the static definition which can safely\n * rebuild its framework-owned lookup identities. Request context, services,\n * and other runtime attachments deliberately do not belong here.\n */\nexport interface InitialManifest {\n readonly definition: AppDefinition;\n readonly manifest: PortableSnapshotManifest;\n}\n\nconst SCOPE_SNAPSHOTS: unique symbol = Symbol('buro.manifestHydrationSnapshots');\n\n/** A host/request-owned cache for one server/client manifest handoff. */\nexport interface ManifestHydrationScope {\n readonly [SCOPE_SNAPSHOTS]: Map<\n string,\n {\n readonly serializedManifest: string;\n readonly snapshot: ApplicationSnapshot;\n }\n >;\n}\n\nexport function createManifestHydrationScope(): ManifestHydrationScope {\n return Object.freeze({ [SCOPE_SNAPSHOTS]: new Map() });\n}\n\nexport type ManifestHydration =\n | {\n readonly status: 'hydrated';\n readonly runtime: LayerRuntime;\n readonly snapshot: ApplicationSnapshot;\n activate(): void;\n dispose(): void;\n }\n | {\n readonly status: 'fallback';\n readonly runtime: LayerRuntime;\n readonly snapshot: ApplicationSnapshot;\n readonly verification: Extract<ManifestResolution, { readonly status: 'mismatch' }>;\n activate(): void;\n dispose(): void;\n };\n\nfunction fingerprintOf(snapshot: ApplicationSnapshot): ManifestFingerprint {\n const { compilerVersion, definitionFingerprint, implementationCatalogFingerprint } =\n snapshot.manifest;\n return { compilerVersion, definitionFingerprint, implementationCatalogFingerprint };\n}\n\nconst MAX_RECONSTRUCTED_SNAPSHOTS = 64;\n\nfunction fingerprintKey(fingerprint: ManifestFingerprint): string {\n return `${fingerprint.compilerVersion}\\u0000${fingerprint.definitionFingerprint}\\u0000${fingerprint.implementationCatalogFingerprint}`;\n}\n\nfunction cachedSnapshot(\n manifest: PortableSnapshotManifest,\n fingerprint: ManifestFingerprint,\n snapshot: ApplicationSnapshot,\n scope: ManifestHydrationScope,\n): ApplicationSnapshot {\n // `snapshotId` is the transport identity, but the canonical payload must\n // agree too: a hostile or stale payload must never borrow an unrelated\n // in-process snapshot merely by repeating that ID.\n const serializedManifest = serializePortableManifest(manifest);\n const key = `${fingerprintKey(fingerprint)}\\u0000${manifest.snapshotId}`;\n const snapshots = scope[SCOPE_SNAPSHOTS];\n const existing = snapshots.get(key);\n if (existing?.serializedManifest === serializedManifest) {\n snapshots.delete(key);\n snapshots.set(key, existing);\n return existing.snapshot;\n }\n snapshots.set(key, { serializedManifest, snapshot });\n if (snapshots.size > MAX_RECONSTRUCTED_SNAPSHOTS) {\n const oldest = snapshots.keys().next().value as string | undefined;\n if (oldest !== undefined) snapshots.delete(oldest);\n }\n return snapshot;\n}\n\nfunction runtimeWithInitialSnapshot(\n runtime: LayerRuntime,\n initialSnapshot: ApplicationSnapshot,\n): LayerRuntime {\n let hasPublished = false;\n let observedRuntimeSnapshot = runtime.getSnapshot();\n let stopObserving: (() => void) | undefined;\n const listeners = new Set<() => void>();\n const activate = (): void => {\n if (stopObserving !== undefined) return;\n const currentSnapshot = runtime.getSnapshot();\n if (!Object.is(currentSnapshot, observedRuntimeSnapshot)) {\n hasPublished = true;\n }\n observedRuntimeSnapshot = currentSnapshot;\n // Snapshot IDs may repeat after a publication, so snapshot object identity\n // detects a publication that occurred while this adapter was inactive.\n stopObserving = runtime.subscribe(() => {\n hasPublished = true;\n observedRuntimeSnapshot = runtime.getSnapshot();\n for (const listener of [...listeners]) listener();\n });\n };\n const dispose = (): void => {\n stopObserving?.();\n stopObserving = undefined;\n listeners.clear();\n };\n const getSnapshot = (): ApplicationSnapshot => {\n return hasPublished ? runtime.getSnapshot() : initialSnapshot;\n };\n return Object.freeze(\n Object.defineProperties(Object.create(runtime), {\n getSnapshot: { value: getSnapshot, enumerable: true },\n getServerSnapshot: { value: getSnapshot, enumerable: true },\n subscribe: {\n value: (listener: () => void) => {\n listeners.add(listener);\n activate();\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) dispose();\n };\n },\n enumerable: true,\n },\n activateManifestHydration: { value: activate, enumerable: false },\n disposeManifestHydration: { value: dispose, enumerable: false },\n }),\n ) as LayerRuntime;\n}\n\n/**\n * Verifies and reconstructs a server-provided portable manifest for one\n * already-created runtime. A fingerprint mismatch is deliberately non-fatal:\n * the host keeps its local request-scoped runtime and can render a controlled\n * fallback instead of binding stale server declarations to local code.\n */\nexport function hydrateManifest(\n runtime: LayerRuntime,\n initialManifest: InitialManifest,\n scope: ManifestHydrationScope = createManifestHydrationScope(),\n): ManifestHydration {\n const fallback = runtime.getSnapshot();\n const fingerprint = fingerprintOf(fallback);\n const resolution = resolveManifest(\n initialManifest.manifest,\n initialManifest.definition,\n fingerprint,\n );\n if (resolution.status === 'mismatch') {\n return Object.freeze({\n status: 'fallback' as const,\n runtime,\n snapshot: fallback,\n verification: resolution,\n activate: () => undefined,\n dispose: () => undefined,\n });\n }\n const snapshot = cachedSnapshot(\n initialManifest.manifest,\n fingerprint,\n resolution.snapshot,\n scope,\n );\n const hydratedRuntime = runtimeWithInitialSnapshot(runtime, snapshot) as LayerRuntime & {\n activateManifestHydration(): void;\n disposeManifestHydration(): void;\n };\n return Object.freeze({\n status: 'hydrated' as const,\n runtime: hydratedRuntime,\n snapshot,\n activate: () => hydratedRuntime.activateManifestHydration(),\n dispose: () => hydratedRuntime.disposeManifestHydration(),\n });\n}\n","/**\n * The default browser `localStorage`-backed `UiSettingsAdapter`.\n *\n * One framework-owned scope (`buro:local-user`) covers every entry this\n * adapter ever produces — there is exactly one browser, one local user. Each\n * `open()` call stores at most one versioned JSON envelope under a single\n * `localStorage` key derived from the canonical `typeId`/`params` pair\n * (`buro:ui-settings:v1:<encoded-key>`); a singleton collection's\n * envelope holds at most one entry, a collection's holds any number.\n *\n * This module is the ERASED adapter boundary (see `@burojs/core`'s\n * `./adapter.ts`): it receives portable `typeId`/`params`/`valueVersion`,\n * never a typed `UiSettingTypeDefinition`, and every value it reads back out\n * of storage is opaque `unknown` — core validates and clones it on the way\n * back in through `createUiSettingsStore`.\n *\n * SSR safety: every `window`/`localStorage` access is guarded by\n * `typeof window === 'undefined'`. Opening a collection during server\n * render (or with `localStorage` unavailable — private browsing, a locked\n * down iframe) yields an empty, ready snapshot and never throws; the real\n * client-side content is picked up the moment `open()` next runs in a\n * browser (see `provider.tsx`'s no-adapter fallback, which constructs a\n * fresh adapter/store per mounted tree rather than reusing one across a\n * server/client boundary).\n */\n\nimport type {\n UiSettingCardinality,\n UiSettingEntry,\n UiSettingEntryPermissions,\n UiSettingMutationResult,\n UiSettingScope,\n UiSettingsAdapter,\n UiSettingsAdapterCollection,\n UiSettingsAdapterOpenInput,\n UiSettingsAdapterSnapshot,\n UiSettingsIssue,\n} from '@burojs/core';\n\n/**\n * The one framework-owned scope every entry this adapter creates belongs\n * to. Task 9 recognizes entries by this EXACT `id` and swaps `label`\n * reactively through i18n — every other part of the framework must keep\n * treating it as an ordinary opaque `UiSettingScope`, never special-casing\n * its id itself.\n */\nexport const LOCAL_USER_SCOPE_ID = 'buro:local-user';\n\nconst LOCAL_USER_SCOPE: UiSettingScope = Object.freeze({\n id: LOCAL_USER_SCOPE_ID,\n label: 'My settings',\n});\n\n/** The user owns their own local settings outright — every permission is granted. */\nconst FULL_PERMISSIONS: UiSettingEntryPermissions = Object.freeze({\n update: true,\n remove: true,\n fork: true,\n export: true,\n});\n\nconst STORAGE_KEY_PREFIX = 'buro:ui-settings:v1:';\nconst ENVELOPE_FORMAT_VERSION = 1 as const;\n\nexport interface LocalStorageUiSettingsAdapterOptions {\n /**\n * Overrides the `Storage` instance the adapter reads/writes. Defaults to\n * `window.localStorage`, resolved lazily (never at construction time) so\n * constructing the adapter itself is always SSR-safe. Tests use this to\n * inject an isolated in-memory `Storage`, share one fake store across two\n * adapter instances (simulating two tabs), or simulate quota failures.\n */\n readonly storage?: Storage;\n}\n\n/** One entry as persisted on disk — the scope/permissions are NOT stored, since both are constant. */\ninterface StoredEntryRecord {\n readonly id: string;\n readonly label?: string;\n readonly value: unknown;\n readonly revision: string;\n readonly createdAt: string;\n readonly updatedAt: string;\n}\n\ninterface StoredEnvelope {\n readonly formatVersion: typeof ENVELOPE_FORMAT_VERSION;\n readonly cardinality: UiSettingCardinality;\n readonly valueVersion: number;\n readonly entries: readonly StoredEntryRecord[];\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isStoredEntryRecord(value: unknown): value is StoredEntryRecord {\n if (!isPlainObject(value)) return false;\n if (typeof value.id !== 'string' || value.id.length === 0) return false;\n if (typeof value.revision !== 'string' || value.revision.length === 0) return false;\n if (typeof value.createdAt !== 'string' || typeof value.updatedAt !== 'string') return false;\n if (value.label !== undefined && typeof value.label !== 'string') return false;\n return true;\n}\n\nfunction computeStorageKey(typeId: string, params: unknown): string {\n const canonical = JSON.stringify([typeId, params]);\n return `${STORAGE_KEY_PREFIX}${encodeURIComponent(canonical)}`;\n}\n\nlet localIdCounter = 0;\n\n/** Collision-resistant entry/revision id. Prefers `crypto.randomUUID`; falls back when unavailable. */\nfunction newLocalId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n localIdCounter += 1;\n return `local-${Date.now().toString(36)}-${localIdCounter.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction toPublicEntry(record: StoredEntryRecord): UiSettingEntry<unknown> {\n return Object.freeze({\n id: record.id,\n ...(record.label === undefined ? {} : { label: record.label }),\n value: record.value,\n scope: LOCAL_USER_SCOPE,\n permissions: FULL_PERMISSIONS,\n revision: record.revision,\n createdAt: record.createdAt,\n updatedAt: record.updatedAt,\n });\n}\n\nfunction buildSnapshot(\n entries: readonly StoredEntryRecord[],\n issues: readonly UiSettingsIssue[],\n): UiSettingsAdapterSnapshot {\n return {\n entries: entries.map(toPublicEntry),\n writeScopes: [LOCAL_USER_SCOPE],\n pending: false,\n issues,\n };\n}\n\nfunction rejected(issues: readonly UiSettingsIssue[]): UiSettingMutationResult<unknown> {\n return { status: 'rejected', issues };\n}\n\nfunction corruptedEnvelopeIssue(storageKey: string, error: unknown): UiSettingsIssue {\n return {\n code: 'local-storage-envelope-corrupted',\n message:\n `Stored UI settings at \"${storageKey}\" could not be read and were ignored: ` +\n `${error instanceof Error ? error.message : String(error)}`,\n severity: 'warning',\n };\n}\n\nfunction unreadableStorageIssue(storageKey: string, error: unknown): UiSettingsIssue {\n return {\n code: 'local-storage-unreadable',\n message:\n `Stored UI settings at \"${storageKey}\" could not be read from localStorage: ` +\n `${error instanceof Error ? error.message : String(error)}`,\n severity: 'warning',\n };\n}\n\nfunction unavailableIssue(): UiSettingsIssue {\n return {\n code: 'local-storage-unavailable',\n message:\n 'localStorage is not available in this environment (server render or a blocked browser context).',\n severity: 'error',\n };\n}\n\nfunction writeFailedIssue(error: unknown): UiSettingsIssue {\n const quota =\n (typeof DOMException !== 'undefined' &&\n error instanceof DOMException &&\n (error.name === 'QuotaExceededError' || error.code === 22 || error.code === 1014)) ||\n (error instanceof Error && /quota/i.test(error.message));\n return {\n code: quota ? 'local-storage-quota-exceeded' : 'local-storage-write-failed',\n message: error instanceof Error ? error.message : 'Writing UI settings to localStorage failed.',\n severity: 'error',\n };\n}\n\nfunction invalidScopeIssue(scopeId: string): UiSettingsIssue {\n return {\n code: 'local-storage-invalid-scope',\n message: `Scope \"${scopeId}\" is not writable; only \"${LOCAL_USER_SCOPE_ID}\" is.`,\n severity: 'error',\n scopeId,\n };\n}\n\nfunction entryNotFoundIssue(entryId: string): UiSettingsIssue {\n return {\n code: 'local-storage-entry-not-found',\n message: `UI setting entry \"${entryId}\" does not exist.`,\n severity: 'error',\n entryId,\n };\n}\n\n/** Reads and parses the envelope for `storageKey`. Never throws — corruption degrades to empty + an issue. */\nfunction readEnvelope(\n storage: Storage,\n storageKey: string,\n): { entries: StoredEntryRecord[]; issues: UiSettingsIssue[] } {\n let raw: string | null;\n try {\n raw = storage.getItem(storageKey);\n } catch (error) {\n return { entries: [], issues: [unreadableStorageIssue(storageKey, error)] };\n }\n if (raw === null) return { entries: [], issues: [] };\n try {\n const parsed: unknown = JSON.parse(raw);\n if (!isPlainObject(parsed) || !Array.isArray(parsed.entries)) {\n throw new Error('stored value is not a UI settings envelope');\n }\n const entries = parsed.entries.filter(isStoredEntryRecord);\n return { entries, issues: [] };\n } catch (error) {\n return { entries: [], issues: [corruptedEnvelopeIssue(storageKey, error)] };\n }\n}\n\nfunction persistEnvelope(\n storage: Storage,\n storageKey: string,\n cardinality: UiSettingCardinality,\n valueVersion: number,\n entries: readonly StoredEntryRecord[],\n): { ok: true } | { ok: false; issue: UiSettingsIssue } {\n const envelope: StoredEnvelope = {\n formatVersion: ENVELOPE_FORMAT_VERSION,\n cardinality,\n valueVersion,\n entries,\n };\n try {\n storage.setItem(storageKey, JSON.stringify(envelope));\n return { ok: true };\n } catch (error) {\n return { ok: false, issue: writeFailedIssue(error) };\n }\n}\n\nfunction resolveStorage(options: LocalStorageUiSettingsAdapterOptions): Storage | undefined {\n if (options.storage !== undefined) return options.storage;\n if (typeof window === 'undefined') return undefined;\n try {\n return window.localStorage;\n } catch {\n return undefined;\n }\n}\n\nfunction sameEntries(a: readonly StoredEntryRecord[], b: readonly StoredEntryRecord[]): boolean {\n return a.length === b.length && JSON.stringify(a) === JSON.stringify(b);\n}\n\nfunction openCollection(\n input: UiSettingsAdapterOpenInput,\n options: LocalStorageUiSettingsAdapterOptions,\n): UiSettingsAdapterCollection {\n const storageKey = computeStorageKey(input.typeId, input.params);\n const listeners = new Set<() => void>();\n let disposed = false;\n let entries: StoredEntryRecord[] = [];\n let issues: readonly UiSettingsIssue[] = [];\n let currentSnapshot: UiSettingsAdapterSnapshot;\n\n function commit(nextEntries: StoredEntryRecord[], nextIssues: readonly UiSettingsIssue[]): void {\n entries = nextEntries;\n issues = nextIssues;\n currentSnapshot = buildSnapshot(entries, issues);\n }\n\n function notify(): void {\n for (const listener of Array.from(listeners)) listener();\n }\n\n /** Re-reads storage and, only on an actual content change, updates the snapshot and notifies. */\n function resync(): void {\n const storage = resolveStorage(options);\n if (storage === undefined) return;\n const loaded = readEnvelope(storage, storageKey);\n if (\n sameEntries(loaded.entries, entries) &&\n JSON.stringify(loaded.issues) === JSON.stringify(issues)\n )\n return;\n commit(loaded.entries, loaded.issues);\n notify();\n }\n\n // SSR-safe initial snapshot: always empty and ready, SYNCHRONOUSLY — this\n // is exactly what a server render produces (no `window`). `useUiSettings`\n // (Task 6, `use-ui-settings.ts:211`) passes THIS SAME `getSnapshot` as\n // both the live snapshot getter AND the `getServerSnapshot` argument to\n // `useSyncExternalStore`. If real `localStorage` content were read\n // synchronously right here, the client's hydration-matching render could\n // return something DIFFERENT from what the server rendered — React reports\n // that as a hydration content mismatch. So the real first read is\n // deferred by one microtask tick (below) — after hydration-matching has\n // already happened — and arrives as an ordinary async update (commit +\n // notify), exactly like a live cross-tab storage-event resync. Mutations\n // are NOT affected: `create`/`update`/`set`/`remove` still commit\n // synchronously, since those only ever run after mount, never during a\n // render pass.\n commit([], []);\n // `queueMicrotask` exists in Node too, so this also runs on the server —\n // harmlessly: `resync`'s own `resolveStorage` guard is a no-op there,\n // since there is no `window` (and no injected `options.storage`, in the\n // real no-adapter-fallback path) to read from.\n queueMicrotask(() => {\n if (disposed) return;\n resync();\n });\n\n function onStorageEvent(event: StorageEvent): void {\n if (event.key !== null && event.key !== storageKey) return;\n resync();\n }\n\n const hasDom = typeof window !== 'undefined';\n if (hasDom) {\n window.addEventListener('storage', onStorageEvent);\n }\n\n /**\n * Shared write tail for every mutator below: persist `nextEntries`, and\n * only on a successful write commit the new snapshot + notify subscribers\n * (a failed write leaves the last good snapshot's object identity intact —\n * see the quota-exceeded tests).\n */\n function persistAndCommit(\n storage: Storage,\n nextEntries: StoredEntryRecord[],\n ): { ok: true } | { ok: false; issue: UiSettingsIssue } {\n const persisted = persistEnvelope(\n storage,\n storageKey,\n input.cardinality,\n input.valueVersion,\n nextEntries,\n );\n if (!persisted.ok) return persisted;\n commit(nextEntries, []);\n notify();\n return persisted;\n }\n\n async function create(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as { scopeId: string; label?: string; value: unknown };\n if (parsed.scopeId !== LOCAL_USER_SCOPE_ID)\n return rejected([invalidScopeIssue(parsed.scopeId)]);\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const now = nowIso();\n const record: StoredEntryRecord = {\n id: newLocalId(),\n ...(parsed.label === undefined ? {} : { label: parsed.label }),\n value: parsed.value,\n revision: newLocalId(),\n createdAt: now,\n updatedAt: now,\n };\n const nextEntries = [...entries, record];\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: 'created', entry: toPublicEntry(record) };\n }\n\n async function update(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as {\n id: string;\n label?: string;\n value: unknown;\n expectedRevision?: string;\n };\n const existing = entries.find((candidate) => candidate.id === parsed.id);\n if (existing === undefined) return rejected([entryNotFoundIssue(parsed.id)]);\n if (parsed.expectedRevision !== undefined && parsed.expectedRevision !== existing.revision) {\n return { status: 'conflict', current: toPublicEntry(existing) };\n }\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const updated: StoredEntryRecord = {\n ...existing,\n ...(parsed.label === undefined ? {} : { label: parsed.label }),\n value: parsed.value,\n revision: newLocalId(),\n updatedAt: nowIso(),\n };\n const nextEntries = entries.map((candidate) =>\n candidate.id === parsed.id ? updated : candidate,\n );\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: 'updated', entry: toPublicEntry(updated) };\n }\n\n async function set(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as { scopeId: string; value: unknown; expectedRevision?: string };\n if (parsed.scopeId !== LOCAL_USER_SCOPE_ID)\n return rejected([invalidScopeIssue(parsed.scopeId)]);\n // Singleton invariant: at most one entry ever exists for this collection.\n const existing = entries[0];\n if (\n existing !== undefined &&\n parsed.expectedRevision !== undefined &&\n parsed.expectedRevision !== existing.revision\n ) {\n return { status: 'conflict', current: toPublicEntry(existing) };\n }\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const now = nowIso();\n const record: StoredEntryRecord =\n existing === undefined\n ? {\n id: newLocalId(),\n value: parsed.value,\n revision: newLocalId(),\n createdAt: now,\n updatedAt: now,\n }\n : { ...existing, value: parsed.value, revision: newLocalId(), updatedAt: now };\n const nextEntries = [record];\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: existing === undefined ? 'created' : 'updated', entry: toPublicEntry(record) };\n }\n\n async function remove(rawInput: unknown): Promise<UiSettingMutationResult<unknown>> {\n const parsed = rawInput as { id: string; expectedRevision?: string };\n const existing = entries.find((candidate) => candidate.id === parsed.id);\n // Removing an already-absent entry is idempotent success — nothing left to reject.\n if (existing === undefined) return { status: 'removed' };\n if (parsed.expectedRevision !== undefined && parsed.expectedRevision !== existing.revision) {\n return { status: 'conflict', current: toPublicEntry(existing) };\n }\n const storage = resolveStorage(options);\n if (storage === undefined) return rejected([unavailableIssue()]);\n\n const nextEntries = entries.filter((candidate) => candidate.id !== parsed.id);\n const persisted = persistAndCommit(storage, nextEntries);\n if (!persisted.ok) return rejected([persisted.issue]);\n return { status: 'removed' };\n }\n\n const shared = {\n getSnapshot(): UiSettingsAdapterSnapshot {\n return currentSnapshot;\n },\n subscribe(listener: () => void): () => void {\n if (disposed) return () => {};\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n refresh(): void {\n if (disposed) return;\n resync();\n },\n dispose(): void {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n if (hasDom) window.removeEventListener('storage', onStorageEvent);\n },\n remove,\n };\n\n return input.cardinality === 'collection' ? { ...shared, create, update } : { ...shared, set };\n}\n\n/**\n * Creates the default browser `localStorage`-backed `UiSettingsAdapter`.\n * One collection is opened per canonical `typeId`/`params` pair (Task 3's\n * `createUiSettingsStore` already deduplicates opens sharing a key, so this\n * factory never sees two live collections for the same key at once); each\n * one owns its own `localStorage` key and its own cross-tab `storage`\n * listener, independent of every other open collection.\n */\nexport function createLocalStorageUiSettingsAdapter(\n options: LocalStorageUiSettingsAdapterOptions = {},\n): UiSettingsAdapter {\n return {\n open(input: UiSettingsAdapterOpenInput): UiSettingsAdapterCollection {\n return openCollection(input, options);\n },\n };\n}\n","import type { UiSettingsStore } from '@burojs/core';\nimport { createContext } from 'react';\n\n/**\n * Holds exactly one caller-owned `UiSettingsStore` (see `@burojs/core`).\n * `null` means no `UiSettingsProvider` is mounted above — `useUiSettings`\n * turns that into a thrown, actionable error rather than a silent no-op.\n *\n * The provider never disposes the store it receives (same convention as\n * `DataRuntimeContext`/`DataRuntimeLease`): construction and disposal stay\n * the caller's responsibility. The default local-storage-backed store lands\n * in Task 7 — this context only ever carries what a caller explicitly\n * supplies.\n */\nexport const UiSettingsStoreContext = createContext<UiSettingsStore | null>(null);\n","import type { UiSettingsStore } from '@burojs/core';\nimport type { ReactElement, ReactNode } from 'react';\nimport { UiSettingsStoreContext } from './context.js';\n\nexport interface UiSettingsProviderProps {\n /**\n * Externally owned live UI settings store (`createUiSettingsStore` from\n * `@burojs/core`). This provider only attaches it to the React tree —\n * it never disposes it, matching `DataRuntimeProvider`'s treatment of a\n * caller-owned `DataRuntimeLease`.\n */\n readonly store: UiSettingsStore;\n readonly children: ReactNode;\n}\n\n/**\n * Attaches a caller-owned `UiSettingsStore` to the React tree so\n * `useUiSettings` can resolve it. Mount one of these per app/runtime\n * boundary — two providers with two different stores never share entries,\n * subscriptions, or mutations, since each `UiSettingsStore` instance owns\n * its own adapter collections.\n */\nexport function UiSettingsProvider({ store, children }: UiSettingsProviderProps): ReactElement {\n return (\n <UiSettingsStoreContext.Provider value={store}>{children}</UiSettingsStoreContext.Provider>\n );\n}\n","'use client';\nimport { useCallback, useContext, useEffect, useRef, useSyncExternalStore } from 'react';\nimport { useOptionalDataRuntime } from '../data/context.js';\nimport { useOptionalRouterAdapter } from '../hooks/router/router-adapter.js';\nimport { DismissRegistryContext } from '../navigation/dismiss-scope.js';\nimport { useUIPresentationRuntime } from '../ui/context.js';\nimport { PEEK_COMPONENT, QUICK_COMPONENT } from '../ui/ui-presentations.js';\nimport { QuickStack } from './quick-stack.js';\n\nconst NO_SESSION = '';\nconst noSubscription = () => () => undefined;\n\n/** The data session's identity, or `''` without a data runtime: what quick reads belong to. */\nfunction useSessionIdentity(): string {\n const runtime = useOptionalDataRuntime();\n const session = runtime?.dataSession;\n const subscribe = session?.subscribe ?? noSubscription;\n const read = useCallback(() => {\n if (session === undefined) return NO_SESSION;\n const state = session.getState();\n const snapshot = state.status === 'ready' ? state.snapshot : state.target;\n return JSON.stringify([snapshot.sessionKey, snapshot.scopeKey]);\n }, [session]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\n/**\n * @internal Mounted by `<BuroProvider>`: the lifetime of quick overlays and peeks.\n *\n * - A quick overlay is state of the page it opened over (spec 4.2): when the router's pathname\n * changes, every `buro:quick` and `buro:peek` presentation closes without asking (the\n * navigation already passed the guard). A search-only change closes nothing, and an\n * overlay whose form is submitting stays open (its pending lock).\n * - Their reads and their stack belong to the user and scope they opened under (plan ruling\n * 18): a change of the data session's `sessionKey` or `scopeKey` closes them the same way.\n * - A quick overlay that closes without a created row settles its stack with `null`, so\n * `useQuick().create` resolves.\n */\nexport function QuickOverlays(): null {\n const runtime = useUIPresentationRuntime();\n const pathname = useOptionalRouterAdapter()?.pathname ?? null;\n const session = useSessionIdentity();\n\n const registry = useContext(DismissRegistryContext);\n const lastPathname = useRef(pathname);\n const lastSession = useRef(session);\n useEffect(() => {\n const sessionChanged = lastSession.current !== session;\n if (lastPathname.current === pathname && !sessionChanged) return;\n lastPathname.current = pathname;\n lastSession.current = session;\n for (const descriptor of runtime.getSnapshot()) {\n if (descriptor.component !== QUICK_COMPONENT && descriptor.component !== PEEK_COMPONENT) {\n continue;\n }\n // A form submitting inside keeps its overlay through a route change (P3-34): its blocker\n // is inactive while it submits, so the navigation was not held, and closing now would\n // lose the values and the error a failed write leaves. A session change closes it anyway:\n // nothing of the previous user's may stay on screen.\n if (!sessionChanged && registry?.isLocked(descriptor.id) === true) continue;\n runtime.dismiss(descriptor.id);\n }\n }, [runtime, registry, pathname, session]);\n\n // Settle every quick stack whose presentation has gone, whoever closed it.\n useEffect(() => {\n let open = new Map<string, QuickStack>();\n const sync = () => {\n const next = new Map<string, QuickStack>();\n for (const descriptor of runtime.getSnapshot()) {\n const stack = descriptor.props.stack;\n if (descriptor.component === QUICK_COMPONENT && stack instanceof QuickStack) {\n next.set(descriptor.id, stack);\n }\n }\n for (const [id, stack] of open) if (!next.has(id)) stack.settle(null);\n open = next;\n };\n sync();\n return runtime.subscribe(sync);\n }, [runtime]);\n\n return null;\n}\n","import type { Resolver, SliceDefinition } from '@burojs/context';\nimport {\n createUiSettingsStore,\n createUIPresentationRuntime,\n type AppRuntime,\n type Audit,\n type AuthProvider,\n type DispatcherEffects,\n type DocsConfig,\n type UiSettingsStore,\n} from '@burojs/core';\nimport type { I18nFacade } from '@burojs/i18n-core';\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport {\n Suspense,\n use,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { AuditContext } from './audit/context.js';\nimport { useNavAudit } from './audit/use-nav-audit.js';\nimport { DataRuntimeProvider, useOptionalDataRuntime } from './data/context.js';\nimport { RelationAggregatorMount } from './hooks/relation-aggregator.js';\nimport { RootDispatcherProvider } from './dispatch/dispatcher-context.js';\nimport { NavigationGuardProvider } from './navigation/navigation-guard.js';\nimport { RouteNavigationScope } from './navigation/navigation-guard.js';\nimport { NotificationSinkProvider } from './notifications/notification-sink.js';\nimport type { DataRuntimeLease } from './data/runtime.js';\nimport { AuthRuntimeProvider } from './auth/context.js';\nimport { DocsProvider } from './hooks/use-doc-panel.js';\nimport { FieldImplementationProvider } from './fields/provider.js';\nimport { BlockImplementationsContext } from './blocks/context.js';\nimport { FrameImplementationsContext } from './frames/context.js';\nimport type { FrameImplementationCatalog } from './frames/implementation.js';\nimport type { BlockImplementationCatalog } from './blocks/implementation.js';\n\nconst NO_BLOCK_IMPLEMENTATIONS: BlockImplementationCatalog = {};\nconst NO_FRAME_IMPLEMENTATIONS: FrameImplementationCatalog = Object.freeze({});\n/** A removed record override's components key (P6-56). */\nconst RECORD_OVERRIDE_KEY = /^record\\.(show|edit|create)\\..+$/u;\nimport type { FieldImplementationCatalog } from './fields/definitions.js';\nimport {\n createManifestHydrationScope,\n hydrateManifest,\n type InitialManifest,\n type ManifestHydration,\n type ManifestHydrationScope,\n} from './runtime/manifest-hydration.js';\nimport { BuroRuntimeProvider } from './runtime.js';\nimport { createLocalStorageUiSettingsAdapter } from './ui-settings/local-storage-adapter.js';\nimport { UiSettingsProvider } from './ui-settings/provider.js';\nimport { DraftSessionBinding } from './forms/controller/draft-session-binding.js';\nimport { FlowAttemptsProvider } from './flows/attempts-binding.js';\nimport { QuickOverlays } from './quick/quick-overlays.js';\nimport {\n UIPresentationRuntimeProvider,\n UIPresentations,\n createPresentationOutletRegistry,\n PresentationMountProvider,\n RESERVED_COMPONENT_PREFIX,\n type PresentationsMode,\n type UIPresentationHosts,\n} from './ui/index.js';\nimport {\n AppContext,\n ComponentsContext,\n DEFAULT_LANGUAGE_STORAGE_KEY,\n I18nContext,\n LanguageStorageKeyContext,\n ResolverContext,\n} from './context.js';\n\nconst NO_PRESENTATION_HOSTS: UIPresentationHosts = Object.freeze({});\n\nexport interface BuroProviderProps<\n TSlices extends Record<string, SliceDefinition> = Record<string, SliceDefinition>,\n> {\n app: AppRuntime;\n /**\n * Externally owned native data-runtime lease installed into this React tree.\n * Optional: omitting it never creates a fallback lease or data context,\n * so consumers that don't use the data-runtime-backed hooks\n * (`useResourceList`, relation aggregation, etc.) don't need to wire one.\n */\n dataRuntime?: DataRuntimeLease;\n /** Optional native auth provider; auth remains UI- and router-independent. */\n authProvider?: AuthProvider;\n /**\n * Externally owned live UI settings store (`createUiSettingsStore` from\n * `@burojs/core`). Omitting it does NOT leave `useUiSettings`\n * unresolvable: exactly one default browser `localStorage`-backed store\n * (`createLocalStorageUiSettingsAdapter`) is created per mounted provider\n * tree and provided instead, so `useUiSettings` always resolves. Passing\n * an explicit store suppresses that default entirely — no local store is\n * created, and nothing is ever mirrored to `localStorage`. The provider\n * never disposes a store it is given (explicit or default).\n */\n uiSettings?: UiSettingsStore;\n /**\n * The resolver built by `createResolver(defineContextSlices(...))`, with\n * whatever slice map the adopter declared.\n *\n * ⚠️ This used to be typed `Resolver<never>`, which is unsatisfiable: a\n * concrete `Resolver<{ env: … }>` is not assignable to it (`setSlice`'s key\n * parameter is contravariant, and `never` has no keys), so EVERY adopter had\n * to write `resolver as never` at their provider — the framework's own test\n * helpers each shipped a `providerResolver()` laundering function for it.\n * The provider is generic now and infers the slice map from this prop.\n *\n * The widening still has to happen — the context is shared by consumers that\n * cannot know the adopter's slice map — but it happens once, here, instead of\n * at every call site.\n */\n resolver: Resolver<TSlices>;\n i18n: I18nFacade;\n /**\n * The `localStorage` key a language control (`useLanguageSwitch`,\n * `<LanguageSwitch>`) saves the chosen locale under. Read it back at boot the\n * same way (`loadLocale(key)`) so the choice survives a reload. Default\n * `'buro:language'`.\n */\n languageStorageKey?: string;\n components: Record<string, unknown>;\n /**\n * Immutable, host-provided React field implementations. They are scoped to\n * this provider tree and are intentionally outside AppRuntime/manifests.\n */\n fieldImplementations?: FieldImplementationCatalog;\n /**\n * The app's block views (`composeBlockImplementations(...)`), keyed by block id. The renderer\n * composes its built-in views first and these over them: an app entry with a built-in id\n * replaces that view (with a development notice).\n */\n blockImplementations?: BlockImplementationCatalog;\n /**\n * The app's frame views (`composeFrameImplementations(...)`), keyed by frame id. The kit draws\n * the built-in (`buro:`) frames itself; an app entry for one is ignored (P6-9).\n */\n frameImplementations?: FrameImplementationCatalog;\n /**\n * Article bodies for the documentation panel — the map of lazy loaders plus\n * an optional fallback locale.\n *\n * Lives here rather than on `defineApp` because it is React-layer data, the\n * same class of thing as `components`. Plugins can contribute named trusted\n * UI components, while this prop remains the direct application override. Omit it and the\n * contextual tier still works; only the panel and the browser disappear.\n */\n docs?: DocsConfig;\n /**\n * A portable server manifest plus the static definition used to reconstruct\n * it. Runtime services and request context stay exclusively on `app`.\n */\n initialManifest?: InitialManifest;\n /** Optional host/request scope shared by a matching server/client handoff. */\n manifestHydrationScope?: ManifestHydrationScope;\n /**\n * Concrete dialog/sheet host components for the framework-mounted\n * `<UIPresentations/>` overlay stack, keyed by `UIPresentationDescriptor['host']`.\n * `packages/react` stays DOM-free — these are always host-supplied (e.g.\n * ui-shadcn's dialog/sheet wrappers), never imported here. Omitting this\n * prop does not disable `useUIPresent()`/the presentation runtime: `present()`\n * calls still register and are reflected in `getSnapshot()`, they simply\n * have nothing to render into, matching a genuinely un-wired app.\n */\n presentationHosts?: UIPresentationHosts;\n /**\n * Who renders the overlay stack. `'framework'` (default) keeps today's\n * behavior: `BuroProvider` mounts `<UIPresentations/>` beside `{children}`.\n * `'app'` hands the mount to the app, which must render\n * `<BuroPresentationOutlet/>` inside its own provider stack — the only way a\n * presented component can reach app-level providers (the link component) as\n * the SAME instances the app tree uses. The dispatcher, the navigation guard\n * and the relation aggregator are the framework's own and reach presented\n * components in both modes.\n */\n presentations?: PresentationsMode;\n /**\n * The application's audit emitter, from `createAudit({ onEvent })`.\n *\n * The application constructs it — not this provider — because\n * `currentCorrelationId()` has to be readable from the application's own\n * data-provider wrapper, which is composed outside the React tree and cannot\n * read a context.\n *\n * Omitted → no events are emitted and no emission site does any work.\n */\n audit?: Audit;\n /**\n * Overrides for the dispatcher's effects, merged per key over the defaults\n * `BuroProvider` supplies: `refetch` invalidates the `buro-data` queries,\n * `notify` reaches the notification sink a UI kit's toaster registers (a\n * no-op without one), `redirect` navigates through the `RouterAdapter` and is\n * skipped when it resolves to the current pathname with no query of its own\n * (the built-in delete fired from a filtered list), `setClipboard` and\n * `download` use the browser, `modal` presents through the presentation\n * runtime. `clearSelection` has no default — the caller owns the selection.\n * Read through a ref, so an inline object neither rebuilds the dispatcher nor\n * goes stale.\n */\n effects?: Partial<DispatcherEffects>;\n /**\n * The relation aggregator `<BuroProvider>` mounts around the app and its overlays (when a\n * `dataRuntime` is given). `maxPage` is the largest page the application's provider serves:\n * an id batch is read in chunks of this many ids, and a `by` read asks for at most this many\n * rows. Default 100.\n */\n relationBatch?: { readonly maxPage?: number };\n children: ReactNode;\n}\n\nexport function BuroProvider<TSlices extends Record<string, SliceDefinition>>({\n app,\n dataRuntime,\n authProvider,\n uiSettings,\n resolver,\n i18n,\n languageStorageKey,\n components,\n fieldImplementations,\n blockImplementations,\n frameImplementations,\n docs,\n initialManifest,\n manifestHydrationScope,\n presentationHosts,\n presentations,\n audit,\n effects,\n relationBatch,\n children,\n}: BuroProviderProps<TSlices>): ReactElement {\n if (authProvider !== undefined && dataRuntime === undefined) {\n throw Object.assign(new Error('BuroProvider authProvider requires dataRuntime.'), {\n kind: 'configuration' as const,\n code: 'auth-provider-data-runtime-required',\n });\n }\n if (dataRuntime !== undefined && dataRuntime.app !== app) {\n throw Object.assign(new Error('BuroProvider app must match dataRuntime.app.'), {\n kind: 'configuration' as const,\n code: 'data-runtime-app-mismatch',\n });\n }\n return (\n <LanguageStorageKeyContext.Provider value={languageStorageKey ?? DEFAULT_LANGUAGE_STORAGE_KEY}>\n <Suspense fallback={null}>\n {dataRuntime === undefined ? (\n <ReadyBuroProvider\n app={app}\n uiSettings={uiSettings}\n resolver={resolver}\n i18n={i18n}\n components={components}\n fieldImplementations={fieldImplementations}\n blockImplementations={blockImplementations}\n frameImplementations={frameImplementations}\n docs={docs}\n initialManifest={initialManifest}\n manifestHydrationScope={manifestHydrationScope}\n presentationHosts={presentationHosts}\n presentations={presentations}\n audit={audit}\n effects={effects}\n relationBatch={relationBatch}\n >\n {children}\n </ReadyBuroProvider>\n ) : (\n <ReadyDataBuroProvider\n app={app}\n dataRuntime={dataRuntime}\n authProvider={authProvider}\n uiSettings={uiSettings}\n resolver={resolver}\n i18n={i18n}\n components={components}\n fieldImplementations={fieldImplementations}\n blockImplementations={blockImplementations}\n frameImplementations={frameImplementations}\n docs={docs}\n initialManifest={initialManifest}\n manifestHydrationScope={manifestHydrationScope}\n presentationHosts={presentationHosts}\n presentations={presentations}\n audit={audit}\n effects={effects}\n relationBatch={relationBatch}\n >\n {children}\n </ReadyDataBuroProvider>\n )}\n </Suspense>\n </LanguageStorageKeyContext.Provider>\n );\n}\n\ntype ReadyBuroProviderProps<TSlices extends Record<string, SliceDefinition>> = Omit<\n BuroProviderProps<TSlices>,\n 'dataRuntime' | 'authProvider'\n>;\n\nfunction ReadyBuroProvider<TSlices extends Record<string, SliceDefinition>>({\n app,\n uiSettings,\n resolver,\n i18n,\n components,\n fieldImplementations,\n blockImplementations,\n frameImplementations,\n docs,\n initialManifest,\n manifestHydrationScope,\n presentationHosts,\n presentations,\n audit,\n effects,\n relationBatch,\n children,\n}: ReadyBuroProviderProps<TSlices>): ReactElement {\n // Every non-ready state observes the barrier. In particular, a settled\n // failed/disposed runtime rethrows its startup error instead of mounting an\n // invalid provider tree.\n if (app.readiness.status === 'disposed') {\n throw app.readiness.error ?? new Error(`Buro app '${app.name}' is disposed.`);\n }\n if (app.readiness.status === 'failed') throw app.readiness.error;\n if (app.readiness.status === 'pending') use(app.ready);\n useNavAudit(app, audit ?? null);\n const manifestRuntime = useRef<\n | {\n readonly appRuntime: AppRuntime;\n readonly definition: InitialManifest['definition'];\n readonly manifest: InitialManifest['manifest'];\n readonly runtime: AppRuntime['runtime'];\n readonly hydration: ManifestHydration;\n }\n | undefined\n >(undefined);\n const defaultScope = useRef<ManifestHydrationScope | undefined>(undefined);\n const scope = manifestHydrationScope ?? (defaultScope.current ??= createManifestHydrationScope());\n let runtime = app.runtime;\n let hydration: ManifestHydration | undefined;\n if (initialManifest !== undefined) {\n const prior = manifestRuntime.current;\n if (\n prior?.appRuntime === app &&\n prior.definition === initialManifest.definition &&\n prior.manifest === initialManifest.manifest\n ) {\n runtime = prior.runtime;\n hydration = prior.hydration;\n } else {\n hydration = hydrateManifest(app.runtime, initialManifest, scope);\n runtime = hydration.runtime;\n manifestRuntime.current = {\n appRuntime: app,\n definition: initialManifest.definition,\n manifest: initialManifest.manifest,\n runtime,\n hydration,\n };\n }\n }\n useEffect(() => {\n hydration?.activate();\n return () => hydration?.dispose();\n }, [hydration]);\n // No-adapter fallback (Task 7): exactly one default local store per\n // mounted provider tree, built once via `useState`'s lazy initializer —\n // it runs a single time at mount, so a later render passing/removing\n // `uiSettings` never creates a second local store, and no store at all is\n // constructed when the caller supplies one from the start. Reading\n // `localStorage` only happens once something actually opens a collection\n // through it (`UiSettingsAdapter.open`, not `createUiSettingsStore`\n // itself), so this stays SSR-safe on its own even though `useState`'s\n // initializer runs during server render too.\n const [defaultUiSettings] = useState<UiSettingsStore | undefined>(() =>\n uiSettings === undefined\n ? createUiSettingsStore(createLocalStorageUiSettingsAdapter())\n : undefined,\n );\n const effectiveUiSettings = uiSettings ?? defaultUiSettings;\n // Framework-owned imperative overlay runtime: exactly one per mounted\n // provider tree, built once via `useState`'s lazy initializer — the same\n // exactly-once construction as the default UI settings store above, and\n // for the same reason (a later render must not silently swap the instance\n // every `useUIPresent()` call site or `<UIPresentations/>` is holding a\n // reference to). Never disposed here, mirroring the settings store: this\n // component's own unmount is the runtime's end of life.\n const [presentationRuntime] = useState(() => createUIPresentationRuntime());\n // One registry per mounted provider tree, built exactly once — same\n // reasoning as the runtime above: `useUIPresent()` closes over it.\n const [outletRegistry] = useState(() => createPresentationOutletRegistry());\n const presentationMode: PresentationsMode = presentations ?? 'framework';\n const presentationMount = useMemo(\n () => ({\n mode: presentationMode,\n hosts: presentationHosts ?? NO_PRESENTATION_HOSTS,\n registry: outletRegistry,\n }),\n [presentationMode, presentationHosts, outletRegistry],\n );\n // `buro:` keys are the framework's overlay screens, supplied with the presentation hosts\n // (P3-6): an app component registered under one would never render. Say so once per key\n // per provider, in development.\n const reportedReserved = useRef<Set<string>>(new Set());\n useEffect(() => {\n if (process.env.NODE_ENV === 'production') return;\n for (const key of Object.keys(components)) {\n if (!key.startsWith(RESERVED_COMPONENT_PREFIX) || reportedReserved.current.has(key)) continue;\n reportedReserved.current.add(key);\n console.error(\n `[burojs] The component key \"${key}\" is reserved: buro: keys resolve from presentationHosts.screens, never from components.`,\n );\n }\n // Record overrides were removed in P6 (P6-56): a `record.<mode>.<resource>` component is\n // never rendered.\n for (const key of Object.keys(components)) {\n if (!RECORD_OVERRIDE_KEY.test(key) || reportedReserved.current.has(key)) continue;\n reportedReserved.current.add(key);\n console.error(\n `[burojs] screen.override-removed: ${key} is never rendered — record overrides were removed in P6; use a frame (views.<mode>.frame) or <RecordScreen frame>.`,\n );\n }\n }, [components]);\n const resolvedComponents = useMemo(\n () =>\n new Proxy(components, {\n get(target, key, receiver) {\n if (typeof key !== 'string' || Object.prototype.hasOwnProperty.call(target, key)) {\n return Reflect.get(target, key, receiver);\n }\n return app.getPluginCapability('ui-component', key);\n },\n has(target, key) {\n return (\n Reflect.has(target, key) ||\n (typeof key === 'string' && app.getPluginCapability('ui-component', key) !== undefined)\n );\n },\n }),\n [app, components],\n );\n // Framework-owned overlay mount. `presentationHosts` is the only injection\n // point: packages/react never imports a concrete dialog/sheet\n // implementation (ui-shadcn supplies them at the app), so omitting the\n // prop leaves the runtime fully functional (`useUIPresent()` still\n // records presentations) with nothing rendered for them — the correct\n // default-off behavior for an app that hasn't wired hosts yet.\n //\n // It is mounted as the LAST CHILD inside the deepest framework provider,\n // adjacent to `{children}`, not as a sibling above the provider chain:\n // presented components (modals/sheets) must render in the SAME framework\n // context as the rest of the app so they can use `FieldImplementationProvider`\n // field inputs, `useUiSettings`, `useDocPanel`, `useT`/i18n, etc. A mount\n // above `BuroRuntimeProvider`/`FieldImplementationProvider` would put\n // presented components outside all of that. `UIPresentationRuntimeProvider`\n // still wraps both `{children}` and this mount, since both need the runtime.\n //\n // App-level providers (the link component) live inside `{children}` and are\n // out of reach in this mode by construction. An app that needs them switches\n // to `presentations=\"app\"` and renders `<BuroPresentationOutlet/>` inside its\n // own stack. The relation aggregator is the framework's own (below), around\n // both, so an overlay's relation cells batch with the page's.\n const dataRuntimeContext = useOptionalDataRuntime();\n const frameworkPresentations =\n presentationMode === 'framework' ? (\n <UIPresentations hosts={presentationHosts ?? NO_PRESENTATION_HOSTS} />\n ) : null;\n // The interaction layer the framework owns (P0): one notification sink, one\n // navigation guard and one dispatcher per provider tree, around `{children}`\n // AND the framework-mounted presentation stack, so a presented component\n // dispatches through the same instance as the page behind it. Under\n // `presentations=\"app\"` the app's outlet already sits inside `{children}`.\n const interactive = (\n <RouteNavigationScope>\n <NotificationSinkProvider>\n <NavigationGuardProvider>\n <RootDispatcherProvider effects={effects}>\n <DraftSessionBinding />\n <FlowAttemptsProvider>\n <QuickOverlays />\n {dataRuntimeContext === null ? (\n <>\n {children}\n {frameworkPresentations}\n </>\n ) : (\n // One aggregator per provider tree (P3-29): a second mount would split batches.\n <RelationAggregatorMount maxPage={relationBatch?.maxPage}>\n {children}\n {frameworkPresentations}\n </RelationAggregatorMount>\n )}\n </FlowAttemptsProvider>\n </RootDispatcherProvider>\n </NavigationGuardProvider>\n </NotificationSinkProvider>\n </RouteNavigationScope>\n );\n return (\n <AppContext.Provider value={app}>\n <AuditContext.Provider value={audit ?? null}>\n <ResolverContext.Provider value={resolver as unknown as Resolver<never>}>\n <I18nContext.Provider value={i18n}>\n <ComponentsContext.Provider value={resolvedComponents}>\n <UIPresentationRuntimeProvider runtime={presentationRuntime}>\n <PresentationMountProvider mount={presentationMount}>\n <BuroRuntimeProvider runtime={runtime}>\n <FieldImplementationProvider fieldImplementations={fieldImplementations}>\n <BlockImplementationsContext.Provider\n value={blockImplementations ?? NO_BLOCK_IMPLEMENTATIONS}\n >\n <FrameImplementationsContext.Provider\n value={frameImplementations ?? NO_FRAME_IMPLEMENTATIONS}\n >\n {effectiveUiSettings === undefined ? (\n <DocsProvider config={docs}>{interactive}</DocsProvider>\n ) : (\n <UiSettingsProvider store={effectiveUiSettings}>\n <DocsProvider config={docs}>{interactive}</DocsProvider>\n </UiSettingsProvider>\n )}\n </FrameImplementationsContext.Provider>\n </BlockImplementationsContext.Provider>\n </FieldImplementationProvider>\n </BuroRuntimeProvider>\n </PresentationMountProvider>\n </UIPresentationRuntimeProvider>\n </ComponentsContext.Provider>\n </I18nContext.Provider>\n </ResolverContext.Provider>\n </AuditContext.Provider>\n </AppContext.Provider>\n );\n}\n\nfunction ReadyDataBuroProvider<TSlices extends Record<string, SliceDefinition>>({\n dataRuntime,\n authProvider,\n ...contentProps\n}: BuroProviderProps<TSlices> & { readonly dataRuntime: DataRuntimeLease }): ReactElement {\n useSyncExternalStore(\n dataRuntime.dataSession.subscribe,\n dataRuntime.dataSession.getState,\n dataRuntime.dataSession.getState,\n );\n return (\n <QueryClientProvider client={dataRuntime.queryClient}>\n {authProvider === undefined ? (\n <DataRuntimeProvider value={dataRuntime}>\n <ReadyBuroProvider {...contentProps} />\n </DataRuntimeProvider>\n ) : (\n <AuthRuntimeProvider runtime={dataRuntime} provider={authProvider}>\n <ReadyBuroProvider {...contentProps} />\n </AuthRuntimeProvider>\n )}\n </QueryClientProvider>\n );\n}\n","import {\n DEFAULT_COMPILER_LIMITS,\n type UiSettingCardinality,\n type UiSettingCollection,\n type UiSettingHandle,\n type UiSettingSingleton,\n type UiSettingTypeDefinition,\n type UiSettingsSnapshot,\n type UiSettingsStore,\n clonePortableValue,\n} from '@burojs/core';\nimport { useContext, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';\nimport { UiSettingsStoreContext } from './context.js';\n\n/**\n * What `useUiSettings` returns for a `collection` definition: the typed\n * mutation/refresh operations plus the live snapshot. `getSnapshot`,\n * `subscribe`, and `dispose` are deliberately NOT re-exposed — the hook\n * already routes them through `useSyncExternalStore` and owns disposal of\n * its own lease (see the effect below), so handing them to the caller would\n * let a component dispose a lease the hook still depends on.\n */\nexport type UseUiSettingsCollectionResult<TValue> = Pick<\n UiSettingCollection<TValue>,\n 'create' | 'update' | 'remove' | 'refresh'\n> & {\n readonly snapshot: UiSettingsSnapshot<TValue>;\n};\n\n/** The `singleton` counterpart of {@link UseUiSettingsCollectionResult}. */\nexport type UseUiSettingsSingletonResult<TValue> = Pick<\n UiSettingSingleton<TValue>,\n 'set' | 'remove' | 'refresh'\n> & {\n readonly snapshot: UiSettingsSnapshot<TValue>;\n};\n\n/** Picks the cardinality-specific result shape, mirroring `UiSettingHandle`. */\nexport type UseUiSettingsResult<\n TValue,\n TCardinality extends UiSettingCardinality,\n> = TCardinality extends 'collection'\n ? UseUiSettingsCollectionResult<TValue>\n : UseUiSettingsSingletonResult<TValue>;\n\n/** This hook instance's currently-open lease and the identity it was opened for. */\ninterface AcquiredLease<TParams, TValue, TCardinality extends UiSettingCardinality> {\n readonly store: UiSettingsStore;\n readonly definition: UiSettingTypeDefinition<TParams, TValue, TCardinality>;\n readonly key: string;\n readonly handle: UiSettingHandle<TValue, TCardinality>;\n}\n\nfunction sortedClone(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortedClone);\n if (value !== null && typeof value === 'object') {\n const sortedEntries = Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([entryKey, entryValue]) => [entryKey, sortedClone(entryValue)] as const);\n return Object.fromEntries(sortedEntries);\n }\n return value;\n}\n\n/**\n * A stable, key-order-independent string for `params`. This is a purely\n * LOCAL memoization aid for one hook instance across its own re-renders —\n * it decides whether the params passed THIS render still match the ones the\n * currently-open lease was opened for, so a re-render with a fresh-but-equal\n * params object does not close and reopen a lease.\n *\n * Tries `clonePortableValue` first — the SAME canonicalization\n * `createUiSettingsStore` uses internally (deeply frozen, codepoint-sorted\n * object keys; both exported from `@burojs/core`'s root) — so this hook's\n * local memoization key agrees with the store's own canonical key on every\n * portable-value `params` shape, rather than merely approximating it via a\n * separate `sortedClone`. Falls back to that local best-effort\n * canonicalization only if `clonePortableValue` throws (raw, not-yet-\n * `parseParams`-validated `params` containing something non-portable, e.g. a\n * function) — a throw here must never propagate out of render, since this\n * key is computed on every render, not just at mutation time.\n */\nfunction stableParamsKey(params: unknown): string {\n try {\n return JSON.stringify(clonePortableValue(params, DEFAULT_COMPILER_LIMITS));\n } catch {\n return JSON.stringify(sortedClone(params));\n }\n}\n\nfunction buildResult<TValue>(\n cardinality: UiSettingCardinality,\n handle: UiSettingCollection<TValue> | UiSettingSingleton<TValue>,\n snapshot: UiSettingsSnapshot<TValue>,\n): UseUiSettingsCollectionResult<TValue> | UseUiSettingsSingletonResult<TValue> {\n if (cardinality === 'collection') {\n const collection = handle as UiSettingCollection<TValue>;\n return {\n create: collection.create,\n update: collection.update,\n remove: collection.remove,\n refresh: collection.refresh,\n snapshot,\n };\n }\n const singleton = handle as UiSettingSingleton<TValue>;\n return {\n set: singleton.set,\n remove: singleton.remove,\n refresh: singleton.refresh,\n snapshot,\n };\n}\n\n/**\n * One handle's disposal bookkeeping for the StrictMode guard below:\n * `scheduled` is true from the moment a cleanup defers this handle's real\n * `dispose()` call until either the deferred check runs it for real, or a\n * later setup for the SAME handle cancels it.\n */\ninterface PendingDisposal<TValue, TCardinality extends UiSettingCardinality> {\n readonly handle: UiSettingHandle<TValue, TCardinality>;\n scheduled: boolean;\n}\n\n/**\n * Opens (and keeps open) a live lease on `definition` at `params` against\n * the `UiSettingsStore` provided by the nearest `UiSettingsProvider`, and\n * subscribes this component to it.\n *\n * - Two components calling this with the same definition and structurally\n * equal params each get their OWN lease, but `store.open` dedups them onto\n * one underlying adapter collection (see `@burojs/core`'s\n * `createUiSettingsStore`) — so there is exactly one live subscription to\n * the adapter, and both components re-render off the same snapshot.\n * - A re-render with a new-but-equal `params` object reuses the already-open\n * lease; only a genuine change (new canonical params, or a new\n * `definition`) releases the old lease and opens a new one.\n * - Unmounting (or a query change) disposes ONLY this hook's own lease. The\n * underlying adapter collection is disposed by the store once every lease\n * sharing it has been released — this hook never disposes the store\n * itself.\n *\n * **StrictMode safety.** React's development `<StrictMode>` mounts effects\n * as setup → cleanup → setup, with NO render in between (see\n * `examples/marketplace-ops/src/main.tsx` and `examples/vite/src/main.tsx`,\n * both of which wrap the whole app in it and both of which mount the default\n * store, so this is a live path, not a hypothetical one — the application\n * this note originally cited, `apps/playground`, left with SP9). A\n * `UiSettingLease` from core is single-shot: once\n * `dispose()` runs, it never becomes usable again (`store.ts`'s\n * `disposed` flag is permanent), so disposing on every cleanup would let the\n * phantom cleanup permanently kill a lease that was never actually meant to\n * go away, and the very next `getSnapshot()` call would throw. The effect\n * below defers the real `handle.dispose()` call by one microtask tick; a\n * StrictMode phantom re-setup for the SAME handle (nothing else changed —\n * still no render happened) cancels it before it ever fires, so the\n * original lease and its subscription survive the whole phantom cycle\n * untouched — no reopen, no resubscription, no swapped handle for callers\n * to worry about. A genuine unmount, or a genuine params/definition change\n * (a DIFFERENT handle), has nothing left to cancel it, so the deferred\n * dispose runs for real.\n */\nexport function useUiSettings<TParams, TValue, TCardinality extends UiSettingCardinality>(\n definition: UiSettingTypeDefinition<TParams, TValue, TCardinality>,\n params: TParams,\n): UseUiSettingsResult<TValue, TCardinality> {\n const store = useContext(UiSettingsStoreContext);\n if (store === null) {\n throw new Error('[useUiSettings] must be used within a UiSettingsProvider.');\n }\n\n const key = `${definition.id} ${stableParamsKey(params)}`;\n const acquiredRef = useRef<AcquiredLease<TParams, TValue, TCardinality> | undefined>(undefined);\n const acquired = acquiredRef.current;\n if (\n acquired === undefined ||\n acquired.store !== store ||\n acquired.definition !== definition ||\n acquired.key !== key\n ) {\n acquiredRef.current = { store, definition, key, handle: store.open(definition, params) };\n }\n // Non-null: the block above always assigns before this line runs.\n const handle = (acquiredRef.current as AcquiredLease<TParams, TValue, TCardinality>).handle;\n\n const pendingDisposalRef = useRef<PendingDisposal<TValue, TCardinality> | null>(null);\n useEffect(() => {\n // Reuse the existing bookkeeping record when this setup's `handle` is\n // the SAME object a moment-ago cleanup just scheduled for disposal —\n // that can only be a StrictMode phantom re-setup (a genuine params/\n // definition change always produces a NEW handle, from the render-phase\n // block above, before this effect ever sees it). Cancel the pending\n // dispose either way: a brand-new handle has nothing scheduled yet\n // (no-op), and a StrictMode-survived handle must not be torn down.\n const reused =\n pendingDisposalRef.current !== null && pendingDisposalRef.current.handle === handle\n ? pendingDisposalRef.current\n : null;\n const record = reused ?? { handle, scheduled: false };\n pendingDisposalRef.current = record;\n record.scheduled = false;\n\n return () => {\n record.scheduled = true;\n queueMicrotask(() => {\n if (!record.scheduled) return; // Cancelled by an immediate resetup for this same handle.\n handle.dispose();\n });\n };\n }, [handle]);\n\n const snapshot = useSyncExternalStore(handle.subscribe, handle.getSnapshot, handle.getSnapshot);\n\n return useMemo(\n () => buildResult(definition.cardinality, handle, snapshot),\n [definition.cardinality, handle, snapshot],\n ) as UseUiSettingsResult<TValue, TCardinality>;\n}\n","import type { RegistryResource, ResourceRefInput } from '@burojs/core';\nimport { useApp } from './use-app.js';\n\nexport function useResource(ref: ResourceRefInput): RegistryResource | undefined {\n const app = useApp();\n return app.registry.get(ref);\n}\n","import {\n type EntityRef,\n type InferBlockData,\n type InferBlockProps,\n formatEntityRef,\n normalizeEntityRef,\n} from '@burojs/core';\nimport type { ComponentType, ReactElement } from 'react';\n\n/** Whether a prop of `B` is a `block()` prop, by its schema's output. */\ntype IsBlockProp<O> = O extends { readonly block: EntityRef } ? true : false;\n\n/**\n * The props a block view receives: each prop's schema output, a `block()` prop as the rendered\n * nested placement (`ReactElement`, `ReactElement[]` for a list).\n */\nexport type BlockViewPropValues<B> = {\n [K in keyof InferBlockProps<B>]: InferBlockProps<B>[K] extends readonly (infer E)[]\n ? IsBlockProp<E> extends true\n ? readonly ReactElement[]\n : InferBlockProps<B>[K]\n : IsBlockProp<InferBlockProps<B>[K]> extends true\n ? ReactElement\n : InferBlockProps<B>[K];\n};\n\n/** The names of a block's `data` entries. */\nexport type BlockDataEntryName<B> = keyof InferBlockData<B> & string;\n\n/** What a block view is rendered with (spec 8.2). */\nexport interface BlockViewProps<B> {\n /** Each prop's schema output; a `block()` prop is the nested placement, rendered. */\n readonly props: BlockViewPropValues<B>;\n /** Ready values only: the framework chrome draws pending, failed and absent. */\n readonly data: Readonly<Record<BlockDataEntryName<B>, unknown>>;\n /** Reads `blocks.<id>.<key>`. */\n readonly t: (\n key: string,\n options?: { readonly params?: Record<string, unknown>; readonly count?: number },\n ) => string;\n}\n\n/** A block's view, registered in `<BuroProvider blockImplementations>` (spec 8.2). */\nexport interface BlockImplementation<B = unknown> {\n /** `<namespace>:<name>`. */\n readonly id: string;\n readonly block: EntityRef;\n /** The block handle `implementBlock` was given (`renderBlock` validates props through it). */\n readonly definition: B;\n readonly load?: () => Promise<{ readonly default: ComponentType<BlockViewProps<B>> }>;\n readonly component?: ComponentType<BlockViewProps<B>>;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: a catalogue holds the views of many blocks\nexport type BlockImplementationCatalog = Readonly<Record<string, BlockImplementation<any>>>;\n\n/**\n * The view of a block: `load` (a module whose default export is the view, requested only when a\n * placement mounts) or `component`. Register the result through `composeBlockImplementations`\n * on `<BuroProvider blockImplementations>`.\n *\n * @throws TypeError when `block` is not a block handle, or when both or neither of `load` and\n * `component` are given.\n */\nexport function implementBlock<B>(\n block: B,\n impl:\n | { readonly load: NonNullable<BlockImplementation<B>['load']>; readonly component?: never }\n | { readonly component: ComponentType<BlockViewProps<B>>; readonly load?: never },\n): BlockImplementation<B> {\n const handle = block as { readonly kind?: unknown; readonly ref?: unknown } | null;\n if (handle === null || typeof handle !== 'object' || handle.kind !== 'block')\n throw new TypeError('implementBlock: the first argument must be a block handle.');\n const ref = normalizeEntityRef(handle.ref as EntityRef);\n const options = impl as { readonly load?: unknown; readonly component?: unknown };\n const hasLoad = options.load !== undefined;\n const hasComponent = options.component !== undefined;\n if (hasLoad === hasComponent)\n throw new TypeError(\n `implementBlock(${formatEntityRef(ref)}): give exactly one of load and component.`,\n );\n if (hasLoad && typeof options.load !== 'function')\n throw new TypeError(`implementBlock(${formatEntityRef(ref)}): load must be a function.`);\n return Object.freeze({\n id: formatEntityRef(ref),\n block: ref,\n definition: block,\n ...(hasLoad\n ? { load: options.load as NonNullable<BlockImplementation<B>['load']> }\n : { component: options.component as ComponentType<BlockViewProps<B>> }),\n });\n}\n\nfunction isImplementation(value: unknown): value is BlockImplementation<unknown> {\n if (value === null || typeof value !== 'object') return false;\n const entry = value as Partial<BlockImplementation<unknown>>;\n return (\n typeof entry.id === 'string' &&\n entry.block !== undefined &&\n (entry.load !== undefined || entry.component !== undefined)\n );\n}\n\n/**\n * The app's block views as one catalogue, keyed by block id: takes `implementBlock` results (not\n * records). A duplicate id is a development error and the later entry wins.\n *\n * @throws TypeError for an argument that is not an `implementBlock` result.\n */\nexport function composeBlockImplementations(\n // biome-ignore lint/suspicious/noExplicitAny: entries of many blocks\n ...entries: readonly BlockImplementation<any>[]\n): BlockImplementationCatalog {\n // biome-ignore lint/suspicious/noExplicitAny: entries of many blocks\n const out: Record<string, BlockImplementation<any>> = Object.create(null);\n for (const entry of entries) {\n if (!isImplementation(entry))\n throw new TypeError(\n 'composeBlockImplementations takes implementBlock(...) results; pass each entry as an argument, not a record of them.',\n );\n if (Object.hasOwn(out, entry.id) && process.env.NODE_ENV !== 'production')\n console.error(\n `[burojs] composeBlockImplementations: ${entry.id} is implemented twice; the later entry wins.`,\n );\n out[entry.id] = entry;\n }\n return Object.freeze(out);\n}\n","import {\n type AnyFrameHandle,\n type EntityRef,\n type FrameKind,\n formatEntityRef,\n isFrameHandle,\n normalizeEntityRef,\n} from '@burojs/core';\nimport type { ComponentType } from 'react';\nimport type { FrameViewProps } from './view-props.js';\n\n/**\n * A frame's view, registered in `<BuroProvider frameImplementations>` (spec 3.2). Without a type\n * argument, the view of any frame.\n */\n// biome-ignore lint/suspicious/noExplicitAny: the default is the view of any frame\nexport interface FrameImplementation<F extends AnyFrameHandle = any> {\n /** `<namespace>:<name>`. */\n readonly id: string;\n readonly frame: EntityRef;\n readonly for: FrameKind;\n /** The frame handle `implementFrame` was given. */\n readonly definition: F;\n readonly component?: ComponentType<FrameViewProps<F>>;\n readonly load?: () => Promise<{ readonly default: ComponentType<FrameViewProps<F>> }>;\n}\n\n/** The app's frame views, keyed by frame id. */\n// biome-ignore lint/suspicious/noExplicitAny: a catalogue holds the views of many frames\nexport type FrameImplementationCatalog = Readonly<Record<string, FrameImplementation<any>>>;\n\n/**\n * The view of a frame: `component`, or `load` (a module whose default export is the view,\n * requested when a screen first renders it). Register the result through\n * `composeFrameImplementations` on `<BuroProvider frameImplementations>`.\n *\n * @throws TypeError when `frame` is not a frame handle, or when both or neither of `load` and\n * `component` are given.\n */\nexport function implementFrame<F extends AnyFrameHandle>(\n frame: F,\n impl:\n | { readonly component: ComponentType<FrameViewProps<F>>; readonly load?: never }\n | { readonly load: NonNullable<FrameImplementation<F>['load']>; readonly component?: never },\n): FrameImplementation<F> {\n if (!isFrameHandle(frame))\n throw new TypeError('implementFrame: the first argument must be a frame handle.');\n const ref = normalizeEntityRef(frame.ref);\n const id = formatEntityRef(ref);\n const options = (impl ?? {}) as { readonly load?: unknown; readonly component?: unknown };\n const hasLoad = options.load !== undefined;\n const hasComponent = options.component !== undefined;\n if (hasLoad === hasComponent)\n throw new TypeError(`implementFrame(${id}): give exactly one of load and component.`);\n if (hasLoad && typeof options.load !== 'function')\n throw new TypeError(`implementFrame(${id}): load must be a function.`);\n return Object.freeze({\n id,\n frame: ref,\n for: frame.for,\n definition: frame,\n ...(hasLoad\n ? { load: options.load as NonNullable<FrameImplementation<F>['load']> }\n : { component: options.component as ComponentType<FrameViewProps<F>> }),\n });\n}\n\nfunction isImplementation(value: unknown): value is FrameImplementation {\n if (value === null || typeof value !== 'object') return false;\n const entry = value as Partial<FrameImplementation>;\n return (\n typeof entry.id === 'string' &&\n entry.frame !== undefined &&\n isFrameHandle(entry.definition) &&\n (entry.load !== undefined || entry.component !== undefined)\n );\n}\n\n/**\n * The app's frame views as one catalogue, keyed by frame id: takes `implementFrame` results.\n * A duplicate id is a development error and the later entry wins; an entry for a built-in\n * (`buro:`) frame is a development error and is dropped — the app's default frame is chosen in\n * `defineAppDefinition({ frames })`, never by replacing a built-in view (P6-9).\n *\n * @throws TypeError for an argument that is not an `implementFrame` result.\n */\nexport function composeFrameImplementations(\n // biome-ignore lint/suspicious/noExplicitAny: entries of many frames\n ...entries: readonly FrameImplementation<any>[]\n): FrameImplementationCatalog {\n // biome-ignore lint/suspicious/noExplicitAny: entries of many frames\n const out: Record<string, FrameImplementation<any>> = Object.create(null);\n const development = process.env.NODE_ENV !== 'production';\n for (const entry of entries) {\n if (!isImplementation(entry))\n throw new TypeError(\n 'composeFrameImplementations takes implementFrame(...) results; pass each entry as an argument, not a record of them.',\n );\n if (entry.frame.namespace === 'buro') {\n if (development)\n console.error(\n `[burojs] composeFrameImplementations: ${entry.id} is a built-in frame; choose the app's default in defineAppDefinition({ frames }) instead. The entry is ignored.`,\n );\n continue;\n }\n if (Object.hasOwn(out, entry.id) && development)\n console.error(\n `[burojs] composeFrameImplementations: ${entry.id} is implemented twice; the later entry wins.`,\n );\n out[entry.id] = entry;\n }\n return Object.freeze(out);\n}\n","import { createContext, useContext, useEffect } from 'react';\n\n/** The kit's frame pieces a frame view places. */\nexport type FramePiece =\n | 'RecordTitle'\n | 'RecordActions'\n | 'CopyId'\n | 'FormActions'\n // The route list's pieces (P7-33).\n | 'ListControls'\n | 'ListFilters'\n | 'ListFlows'\n | 'ListLive'\n | 'ListSavedViews'\n | 'ListColumns'\n | 'ListExport'\n | 'ListCreate'\n | 'ListBody'\n | 'ListBulkBar';\n\n/**\n * What a frame's pieces report to (`@internal`): the record frame host counts their mounts to\n * check a custom frame's obligations at runtime (P6-15), and `checkFrame` renders a view\n * alone with `stub` set, so each piece draws a marker instead of reading the record chrome.\n */\nexport interface FrameCheckValue {\n /** Draw `<span data-check-piece>` instead of the piece (`checkFrame`). */\n readonly stub: boolean;\n /** Records a mount; the returned function records the unmount. */\n mount(piece: FramePiece): () => void;\n}\n\n/** @internal */\nexport const FrameCheckContext = createContext<FrameCheckValue | null>(null);\n\n/** @internal Records the calling piece's mount while it is mounted; returns the context. */\nexport function useFramePiece(piece: FramePiece): FrameCheckValue | null {\n const check = useContext(FrameCheckContext);\n useEffect(() => check?.mount(piece), [check, piece]);\n return check;\n}\n","import { useContext, useMemo } from 'react';\nimport { I18nContext } from '../context.js';\nimport { useLocale } from '../hooks/use-t.js';\nimport type { FrameTranslate } from './view-props.js';\n\n/** A frame view's `t`: reads `frames.<id>.<key>` (the block convention, foundation 12). @internal */\nexport function useFrameT(id: string): FrameTranslate {\n const i18n = useContext(I18nContext);\n const locale = useLocale();\n // biome-ignore lint/correctness/useExhaustiveDependencies: `locale` re-translates on a language switch\n return useMemo(\n () =>\n (\n key: string,\n options?: { readonly params?: Record<string, unknown>; readonly count?: number },\n ) =>\n i18n === null\n ? key\n : i18n.t(`frames.${id}.${key}`, {\n ...(options?.params === undefined ? {} : { params: options.params }),\n ...(options?.count === undefined ? {} : { count: options.count }),\n }),\n [i18n, id, locale],\n );\n}\n","import {\n type CompiledScreen,\n type PlanAccess,\n planScreen,\n ruleContextFor,\n type ScreenPlan,\n} from '@burojs/core';\nimport {\n createContext,\n createElement,\n type ReactElement,\n type ReactNode,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { PlacementRuntime } from './placements.js';\nimport { EMPTY_ROUTE, useRouteSource } from './route-source.js';\nimport { useScreenState } from './screen-state.js';\nimport type { FormController } from './types.js';\nimport { planOpenOf } from './use-form-controller.js';\nimport {\n NO_DEMAND,\n readPermissions,\n type ResolverDemand,\n sameDemand,\n useContextSnapshot,\n useSourceResolver,\n} from './use-source-resolver.js';\n\n/** What a placement on a page reads of its screen: the plan, its own runtime and Retry. */\nexport type PagePlacementOwner = Pick<FormController, 'plan' | 'placement' | 'retry'>;\n\n/** The page screen above a placement, for `usePlacement(key)` outside a record frame. Internal. */\nexport const PagePlacementContext = createContext<PagePlacementOwner | null>(null);\n\nexport interface PageScreen {\n /** The page's one plan; empty for a failure marker. */\n readonly plan: ScreenPlan;\n /** Refetches only the failed requests under these source names (`block:<key>` for a placement). */\n retry(sources: readonly string[]): void;\n /** A placement's runtime at mount, by key. */\n placement(key: string): PlacementRuntime | undefined;\n /** Provides the page to `usePlacement(key)` below it, as a record frame does on a record. */\n readonly PlacementScope: (props: { readonly children: ReactNode }) => ReactElement;\n}\n\nconst EMPTY_PLAN: ScreenPlan = Object.freeze({\n mode: 'show' as const,\n slots: Object.freeze(Object.assign(Object.create(null), { body: Object.freeze([]) })),\n frame: Object.freeze({ namespace: 'buro', id: 'record' }),\n fields: Object.freeze({}),\n view: Object.freeze({}),\n submitBlocked: false,\n blockingFields: Object.freeze([]),\n demand: Object.freeze({ active: Object.freeze([]), shown: Object.freeze([]) }),\n texts: Object.freeze([]),\n byKey: Object.freeze(Object.create(null) as Record<string, never>),\n blockDemand: Object.freeze([]),\n});\n\n/**\n * @internal The resolver and planner half of a custom page's body (P1b+P1c decision 52), for the\n * page host: the screen's sources resolved with no record and no form values, the access of the\n * signed-in user (no resource rules: a page has none), and the page's one `planScreen` call, with\n * what is open from the surrounding `ScreenStateProvider` and the placements' block data. As on a\n * record, the plan's `blockDemand` is fed back to the resolver, so a placement under a panel whose\n * access is pending or denied never has its `data` requested. A `null` screen (a failure marker)\n * resolves and plans nothing.\n */\nexport function usePageScreen(compiled: CompiledScreen | null): PageScreen {\n const [demand, setDemand] = useState<ResolverDemand>(NO_DEMAND);\n // The page's declared params, parsed by the page host (spec 4.5).\n const routeSource = useRouteSource();\n const { sources, retry, blockData, placements, blockAccess } = useSourceResolver({\n compiled,\n resource: compiled?.resource ?? 'page',\n values: EMPTY_VALUES,\n page: true,\n route: routeSource ?? EMPTY_ROUTE,\n demand,\n });\n const context = useContextSnapshot();\n const permissions = readPermissions(context);\n const access: PlanAccess = useMemo(\n () => ({\n rules: [],\n context: ruleContextFor({\n user: context.user as never,\n scope: context.scope,\n ...(permissions === undefined ? {} : { permissions }),\n mode: 'show',\n }),\n permissions,\n }),\n [context.user, context.scope, permissions],\n );\n const hostOpen = useScreenState()?.open;\n const open = useMemo(() => planOpenOf(hostOpen, compiled, {}), [hostOpen, compiled]);\n const plan = useMemo(\n () =>\n compiled === null\n ? EMPTY_PLAN\n : planScreen(compiled, {\n sources,\n access,\n ...(open === undefined ? {} : { open }),\n blockData,\n blockAccess,\n }),\n [compiled, sources, access, open, blockData, blockAccess],\n );\n // What the plan demands is what the resolver loads next (the controller's rule, spec 10.1).\n if (compiled !== null) {\n const next: ResolverDemand = {\n sources: [...plan.demand.active, ...plan.demand.shown],\n blocks: plan.blockDemand,\n };\n if (!sameDemand(next, demand)) setDemand(next);\n }\n const latest = useRef(placements);\n latest.current = placements;\n const placement = useCallback(\n (key: string) => (Object.hasOwn(latest.current, key) ? latest.current[key] : undefined),\n [],\n );\n const owner = useMemo<PagePlacementOwner>(\n () => ({ plan, retry, placement }),\n [plan, retry, placement],\n );\n const ownerRef = useRef(owner);\n ownerRef.current = owner;\n // One component for the hook's life, reading the latest owner: a new component per render\n // would remount the page body.\n const [PlacementScope] = useState(\n () =>\n function PlacementScope({ children }: { readonly children: ReactNode }): ReactElement {\n return createElement(PagePlacementContext.Provider, { value: ownerRef.current }, children);\n },\n );\n return useMemo(\n () => ({ plan, retry, placement, PlacementScope }),\n [plan, retry, placement, PlacementScope],\n );\n}\n\nconst EMPTY_VALUES: Record<string, unknown> = Object.freeze({}) as Record<string, unknown>;\n","import type { ScreenMode } from '@burojs/core';\nimport { createContext, useContext } from 'react';\nimport type { FormController } from '../forms/controller/types.js';\n\n/** What a record frame gives the pieces rendered inside `<RecordScreen>`. */\nexport interface RecordFrameValue {\n /** The resource's canonical name. */\n readonly resource: string;\n readonly recordId: string | undefined;\n readonly mode: ScreenMode;\n /** The record being shown or edited, once it is read; `undefined` in create. */\n readonly record: Readonly<Record<string, unknown>> | undefined;\n /** The form controller planning the frame's screen. */\n readonly controller: FormController;\n}\n\n/** The record frame `<RecordScreen>` provides; `null` outside one. */\nexport const RecordFrameContext = createContext<RecordFrameValue | null>(null);\n\n/**\n * The record frame around the caller. A frame piece rendered outside\n * `<RecordScreen>` is a development error (P1b+P1c decision 6), so this throws there.\n */\nexport function useRecordFrame(): RecordFrameValue {\n const frame = useContext(RecordFrameContext);\n if (frame === null)\n throw new Error('[burojs] useRecordFrame() must be called inside <RecordScreen>');\n return frame;\n}\n\n/** The record frame around the caller, or `null` outside `<RecordScreen>`. */\nexport function useOptionalRecordFrame(): RecordFrameValue | null {\n return useContext(RecordFrameContext);\n}\n","import { type EntityRef, formatEntityRef } from '@burojs/core';\nimport { useContext, useEffect, useMemo, useRef } from 'react';\nimport { I18nContext } from '../context.js';\nimport type { FormController } from '../forms/controller/types.js';\nimport { PagePlacementContext } from '../forms/controller/use-page-screen.js';\nimport { useLocale } from '../hooks/use-t.js';\nimport { useOptionalRecordFrame } from '../record/record-frame-context.js';\nimport { useBlockImplementations } from './context.js';\nimport type { BlockImplementation, BlockViewProps } from './implementation.js';\n\n/** A placement as its host draws it (spec 8.1, 8.2). */\nexport interface PlacementView {\n readonly state: 'absent' | 'pending' | 'ready' | 'failed';\n /**\n * Refetches what failed. Absent for a refused prop and for a block without a view: Retry\n * cannot help them.\n */\n readonly retry?: () => void;\n readonly error?: unknown;\n readonly block: EntityRef;\n /** The app's view of the block (`<BuroProvider blockImplementations>`), if it has one. */\n // biome-ignore lint/suspicious/noExplicitAny: a view of any block\n readonly appImplementation?: BlockImplementation<any>;\n /** What the view is rendered with, once the placement is ready. */\n readonly viewProps?: BlockViewProps<unknown>;\n}\n\nconst UNKNOWN: EntityRef = Object.freeze({ namespace: '', id: '' });\n\n/**\n * A placement of the screen being rendered, by its key (a nested placement by its derived key,\n * `<host>.<prop>`): its state over the plan (access, `when`, its sources) and its own mount (props\n * validated, `data` entries), the app's view of its block and the props the view receives.\n * `controller` defaults to the record frame's, else to the custom page's body around it.\n */\nexport function usePlacement(\n key: string,\n controller?: Pick<FormController, 'plan' | 'placement' | 'retry'>,\n): PlacementView {\n const frame = useOptionalRecordFrame();\n const page = useContext(PagePlacementContext);\n const owner = controller ?? frame?.controller ?? page ?? undefined;\n if (owner === undefined)\n throw new Error(\n `[burojs] usePlacement('${key}') must be called inside <RecordScreen> or a page body, or be given the form controller.`,\n );\n const catalog = useBlockImplementations();\n const i18n = useContext(I18nContext);\n const locale = useLocale();\n const runtime = owner.placement(key);\n const node = owner.plan?.byKey[key];\n const block = runtime?.block ?? UNKNOWN;\n const id = formatEntityRef(block);\n const reported = useRef<string | undefined>(undefined);\n const problem = runtime?.problem;\n useEffect(() => {\n if (problem === undefined || process.env.NODE_ENV === 'production') return;\n const text = `[burojs] ${problem.message} (placement ${key})`;\n if (reported.current === text) return;\n reported.current = text;\n console.error(text);\n }, [problem, key]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: `locale` re-translates on a language switch\n const t = useMemo(\n () =>\n (\n name: string,\n options?: { readonly params?: Record<string, unknown>; readonly count?: number },\n ): string =>\n i18n === null\n ? name\n : i18n.t(`blocks.${id}.${name}`, {\n ...(options?.params === undefined ? {} : { params: options.params }),\n ...(options?.count === undefined ? {} : { count: options.count }),\n }),\n [i18n, id, locale],\n );\n const appImplementation = runtime === undefined ? undefined : catalog[id];\n const base = {\n block,\n ...(appImplementation === undefined ? {} : { appImplementation }),\n };\n if (node === undefined || node.state === 'absent' || runtime === undefined)\n return { state: 'absent', ...base };\n if (node.state === 'pending') return { state: 'pending', ...base };\n if (node.state === 'failed') {\n // Its own data failing for a reason no refetch changes (a refused entry) offers no Retry.\n const own = `block:${key}`;\n const failedOn = node.failedOn.filter((name) => name !== own || runtime.retryable);\n return {\n state: 'failed',\n ...base,\n ...(runtime.error === undefined ? {} : { error: runtime.error }),\n ...(failedOn.length === 0 ? {} : { retry: () => owner.retry(failedOn) }),\n };\n }\n if (runtime.state === 'failed')\n return {\n state: 'failed',\n ...base,\n error: runtime.error,\n ...(runtime.retryable ? { retry: () => owner.retry([`block:${key}`]) } : {}),\n };\n if (runtime.state !== 'ready') return { state: runtime.state, ...base };\n return {\n state: 'ready',\n ...base,\n viewProps: {\n props: (runtime.props ?? {}) as BlockViewProps<unknown>['props'],\n data: runtime.data as BlockViewProps<unknown>['data'],\n t,\n },\n };\n}\n","import { useBlockImplementations } from './context.js';\nimport type { BlockImplementation } from './implementation.js';\n\n/**\n * The app's view of the built-in `buro:related-list` block (`<BuroProvider blockImplementations>`),\n * or `undefined`: an app entry replaces the list view everywhere, the route list included, so\n * `ResourceListPage` renders it instead of the built-in view.\n */\n// biome-ignore lint/suspicious/noExplicitAny: the related-list block's view\nexport function useRouteListImplementation(): BlockImplementation<any> | undefined {\n const catalog = useBlockImplementations();\n return Object.hasOwn(catalog, 'buro:related-list') ? catalog['buro:related-list'] : undefined;\n}\n","import type { InferSchemaOutput, StandardSchemaV1 } from '@burojs/core';\nimport type { ComponentType } from 'react';\nimport type {\n CollectionDisplayProps,\n CollectionInputProps,\n FieldImplementation,\n FieldImplementationLayout,\n ScalarDisplayProps,\n ScalarInputProps,\n} from './types.js';\n\ntype MetaOf<S extends StandardSchemaV1> =\n InferSchemaOutput<S> extends Readonly<Record<string, unknown>> ? InferSchemaOutput<S> : never;\n\n/**\n * A field implementation whose `meta` is typed by a schema (P7 3.3): the schema's output is the\n * type of `props.meta` in every surface, and the framework applies the schema to the resolved\n * `meta` at render — a refusal renders the field misconfigured, never the implementation.\n *\n * ```tsx\n * const hsCode = fieldImplementation({\n * meta: z.object({ origin: z.string().nullable() }),\n * Input: ({ meta: { origin } }) => <CodePicker origin={origin} />,\n * });\n * ```\n */\nexport function fieldImplementation<const S extends StandardSchemaV1, T = unknown>(implementation: {\n readonly meta: S;\n readonly Input?: ComponentType<ScalarInputProps<T, MetaOf<S>>>;\n readonly Display?: ComponentType<ScalarDisplayProps<T, MetaOf<S>>>;\n readonly CollectionInput?: ComponentType<CollectionInputProps<T, MetaOf<S>>>;\n readonly CollectionDisplay?: ComponentType<CollectionDisplayProps<T, MetaOf<S>>>;\n readonly layout?: FieldImplementationLayout;\n}): FieldImplementation<T, MetaOf<S>> {\n return implementation as unknown as FieldImplementation<T, MetaOf<S>>;\n}\n","import { defineFieldDeclaration, type FieldDeclaration } from '@burojs/core';\nimport { composeFieldImplementations, type FieldImplementationCatalog } from './definitions.js';\nimport type { FieldImplementation } from './types.js';\n\ntype FieldDeclarationOverrides<TMeta extends Readonly<Record<string, unknown>>> = Omit<\n FieldDeclaration,\n 'type' | 'format' | 'meta'\n> & { readonly meta?: TMeta };\n\nexport interface DefinedField<\n TMeta extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>,\n> {\n (overrides?: FieldDeclarationOverrides<TMeta>): FieldDeclaration & { readonly meta?: TMeta };\n readonly declaration: FieldDeclaration;\n readonly catalog: FieldImplementationCatalog;\n}\n\n/**\n * Application-local authoring sugar. It makes a portable field declaration\n * helper and a separate, immutable catalog contribution once at module setup;\n * each helper call returns data only and never registers implementation code.\n */\nexport function defineFieldWithImplementation<\n TMeta extends Readonly<Record<string, unknown>> = Readonly<Record<string, unknown>>,\n>(\n declaration: FieldDeclaration,\n implementation: FieldImplementation<any, TMeta>,\n): DefinedField<TMeta> {\n const base = defineFieldDeclaration(declaration as FieldDeclaration);\n const id = base.format ?? base.type;\n const catalog = composeFieldImplementations({ [id]: implementation });\n const field = ((overrides: FieldDeclarationOverrides<TMeta> = {}) =>\n defineFieldDeclaration({\n ...base,\n ...overrides,\n type: base.type,\n ...(base.format === undefined ? {} : { format: base.format }),\n } as FieldDeclaration) as FieldDeclaration & { readonly meta?: TMeta }) as DefinedField<TMeta>;\n return Object.freeze(\n Object.assign(field, {\n declaration: base,\n catalog,\n }),\n );\n}\n","import { type FieldDeclaration, type ScreenSources, type SourceState } from '@burojs/core';\nimport { useMemo, useReducer, useRef } from 'react';\nimport {\n scopeSourceState,\n useContextSnapshot,\n userSourceState,\n} from '../forms/controller/use-source-resolver.js';\nimport { useLocale } from '../hooks/use-t.js';\nimport { fieldMetaStateFor, useRerenderOnSettle } from './meta-validation.js';\nimport type { FieldImplementation } from './types.js';\n\n/**\n * What a field's input receives as `meta` (P7 3.2, 3.3): its refs read from the owner's sources,\n * then the implementation's schema over the result. `pending` while a source or an asynchronous\n * schema is; `failed` once a source failed or the schema refused it, with the reason a\n * development message names.\n */\nexport type FieldMetaState =\n | { readonly status: 'ready'; readonly meta: Readonly<Record<string, unknown>> }\n | { readonly status: 'pending' }\n | { readonly status: 'failed'; readonly reason: string };\n\nconst READY_NULL: SourceState = Object.freeze({\n status: 'ready',\n value: null,\n refreshing: false,\n});\n\nconst ready = (value: unknown): SourceState =>\n Object.freeze({ status: 'ready', value, refreshing: false });\n\n/**\n * The sources a field's `meta` reads when its owner supplies none of its own: `record` (the\n * record the field renders from, `null` in create), `values` (the live form values), `scope` and\n * `user`. An owner's own states (`extra`: a form controller's projected `record` and `values`, a\n * flow's `with` and `args`) replace these by name, so a field decided pending by P5 stays pending.\n *\n * @internal\n */\nexport function useFieldMetaSources(input: {\n readonly record: Readonly<Record<string, unknown>> | undefined;\n readonly values: Readonly<Record<string, unknown>> | undefined;\n readonly extra?: ScreenSources | undefined;\n}): ScreenSources {\n const snapshot = useContextSnapshot();\n const locale = useLocale();\n const hasScope = Object.hasOwn(snapshot, 'scope');\n const hasUser = Object.hasOwn(snapshot, 'user');\n const scopeSlot = snapshot.scope;\n const userSlot = snapshot.user;\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed by the scope slot\n const scope = useMemo(() => scopeSourceState(snapshot), [hasScope, scopeSlot]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed by the user slot and the locale\n const user = useMemo(() => userSourceState(snapshot, locale), [hasUser, userSlot, locale]);\n const { record, values, extra } = input;\n return useMemo(\n () =>\n Object.freeze({\n record: record === undefined ? READY_NULL : ready(record),\n values: values === undefined ? ready({}) : ready(values),\n scope,\n user,\n ...(extra ?? {}),\n }),\n [record, values, scope, user, extra],\n );\n}\n\n/**\n * A field's `meta` as its implementation receives it (P7 3.2, 3.3). `implementation` is the\n * catalogue entry the field resolved to: its `meta` schema, when it declares one, is applied to\n * the resolved meta, and an asynchronous schema keeps the state `pending` until it settles.\n * The same state object is returned while the values the refs read are the same.\n *\n * @internal\n */\nexport function useFieldMeta(\n field: Pick<FieldDeclaration, 'meta'>,\n implementation: FieldImplementation<unknown> | undefined,\n sources: ScreenSources,\n): FieldMetaState {\n const [tick, rerender] = useReducer((count: number) => count + 1, 0);\n const waiting = useRef<Promise<void> | undefined>(undefined);\n const schema = implementation?.meta;\n const meta = field.meta;\n // The verdict is cached per schema and resolved meta, so reading it again costs nothing.\n // biome-ignore lint/correctness/useExhaustiveDependencies: `tick` re-reads a settled async schema\n const state = useMemo(() => {\n const answer = fieldMetaStateFor(meta, schema, sources);\n waiting.current = answer.state.status === 'pending' ? answer.settled : undefined;\n return answer.state;\n }, [meta, schema, sources, tick]);\n useRerenderOnSettle(\n state.status === 'pending' && waiting.current ? [waiting.current] : [],\n rerender,\n [state],\n );\n return state;\n}\n","import type { RelationCandidate } from '@burojs/core';\nimport { useMemo } from 'react';\nimport { useListAccess } from '../hooks/use-field-access.js';\n\n/**\n * Whether a relation's select may read its target under its candidates (P7 3.4): every field a\n * candidate names must be one its user may view in the target. A predicate on a hidden field is\n * never sent — it would filter on data the user cannot see, and the rows offered would tell.\n */\nexport type CandidatesAccess =\n | { readonly status: 'pending' }\n | { readonly status: 'allowed' }\n | { readonly status: 'forbidden'; readonly field: string };\n\nconst PENDING: CandidatesAccess = Object.freeze({ status: 'pending' });\nconst ALLOWED: CandidatesAccess = Object.freeze({ status: 'allowed' });\n\n/**\n * `pending` while the permission map loads and a field decision depends on it; `forbidden`, with\n * the first such field, when a candidate names a field the user may not view; else `allowed`.\n * No candidates is `allowed` whatever the map says. A target the application lacks is closed\n * (every field hidden), so a candidate on it is `forbidden`.\n *\n * @internal\n */\nexport function useCandidatesAccess(\n target: string,\n candidates: readonly RelationCandidate[] | undefined,\n): CandidatesAccess {\n const access = useListAccess(target);\n return useMemo(() => {\n if (candidates === undefined || candidates.length === 0) return ALLOWED;\n if (access.status === 'pending') return PENDING;\n const hidden = candidates.find((candidate) => !access.fieldVisible(candidate.field));\n return hidden === undefined\n ? ALLOWED\n : Object.freeze({ status: 'forbidden', field: hidden.field });\n }, [access, candidates]);\n}\n","import { type DocContent, resolveDoc } from '@burojs/core';\nimport { useMemo } from 'react';\nimport { useI18nCaps } from './use-t.js';\n\n/**\n * Contextual documentation for one address, resolved at render time.\n *\n * `useI18nCaps()` re-derives on a locale change, so this memo recomputes when\n * the language flips — the popover's text follows the live language switch\n * without a reload, like every other content slot in the app.\n *\n * Returns `undefined` when there is nothing to show, which is exactly the\n * condition for rendering no affordance at all: density is authored in the\n * bundle, not imposed by the framework.\n */\nexport function useDoc(address: string | undefined): DocContent | undefined {\n const caps = useI18nCaps();\n return useMemo(() => (address ? resolveDoc(caps, address) : undefined), [caps, address]);\n}\n","import type { RegistryResource } from '@burojs/core';\nimport { useContext } from 'react';\nimport { ResourceContext } from '../context.js';\nimport { useApp } from './use-app.js';\n\nexport function useCurrentResource(): RegistryResource | null {\n const ctx = useContext(ResourceContext);\n const app = useApp();\n if (!ctx.resource) return null;\n return app.registry.get(ctx.resource) ?? null;\n}\n","import type { AppContext, Capability, CapabilityDecision, RuleContext } from '@burojs/core';\nimport { resolveCapability, ruleContextFor } from '@burojs/core';\nimport { useCallback } from 'react';\nimport { useApp } from './use-app.js';\nimport { useCtx } from './use-ctx.js';\n\nexport interface UseCapabilityArgs {\n /** Resource whose rules apply. */\n resource: string;\n target: { kind: string; name?: string };\n /** The record under consideration. Omit while creating. */\n record?: unknown;\n mode?: RuleContext['mode'];\n /**\n * Fallback when no rule matches. `edit`/`view` default OPEN (a field is\n * editable unless a rule says otherwise); gate capabilities like `run`\n * should pass `false`.\n */\n defaultAllowed?: boolean;\n}\n\nexport type CapabilityResolver = (\n capability: Capability,\n target: { kind: string; name?: string },\n defaultAllowed?: boolean,\n) => CapabilityDecision;\n\n/**\n * A single resolver bound to one (resource, record, mode) — the right primitive\n * when many targets are checked in one render (a form iterating its fields).\n * Calling the per-target `useCapability` in that loop would violate the Rules\n * of Hooks; this hoists the hook calls to one fixed set and returns a plain\n * function.\n *\n * The context is assembled from the built-in AppContext slots (`scope`, `user`,\n * `permissions`) plus `record`/`mode`, so a predicate can combine any of them.\n * Rules come through `app.ruleSource` — the MERGED source (application rules\n * from `defineApp({ rules })` + the resource's own), not a direct `def.rules`\n * read — so an app-wide policy governs form fields exactly as it governs\n * buttons, and a backend source can be composed in later without touching call\n * sites.\n *\n * ⚠️ `mode` defaults to `'edit'` here while `useAvailabilityResolver` defaults\n * to `'list'`. Deliberate: this resolver's caller is a form deciding field\n * editability, that one's is a list deciding what to draw per row. A rule that\n * branches on `ctx.mode` therefore sees different defaults from the two hooks —\n * pass `mode` explicitly whenever the two must agree (see `ActionButton`, which\n * derives its mode from its surface for exactly this reason).\n */\nexport function useCapabilityResolver(\n resource: string,\n record?: unknown,\n mode: RuleContext['mode'] = 'edit',\n): CapabilityResolver {\n const app = useApp();\n const scope = useCtx((c: AppContext) => c.scope);\n const user = useCtx((c: AppContext) => c.user);\n const permissions = useCtx((c: AppContext) => c.permissions);\n\n return useCallback(\n (capability, target, defaultAllowed = true) => {\n // The merged source, so an application-level rule is not invisible here.\n // The empty shortcut stays — the merged source returns `[]` only when\n // NEITHER half has a rule, which is the case it was there to make cheap.\n const rules = app.ruleSource.rules(resource);\n if (rules.length === 0) return { allowed: defaultAllowed };\n // The one builder the form planner uses too (P1b+P1c decision 3): a scope that is not a\n // plain object reaches a rule as `{}`, and a user whose id is '' is signed out.\n const ctx = ruleContextFor({ user, scope, permissions, record, mode, resource });\n return resolveCapability(rules, capability, target, ctx, defaultAllowed);\n },\n [app.ruleSource, resource, record, mode, scope, user, permissions],\n );\n}\n\n/**\n * Decide a single capability at one call site (a button, a tab). Built on\n * {@link useCapabilityResolver}.\n */\nexport function useCapability(capability: Capability, args: UseCapabilityArgs): CapabilityDecision {\n const resolve = useCapabilityResolver(args.resource, args.record, args.mode);\n return resolve(capability, args.target, args.defaultAllowed ?? true);\n}\n","'use client';\nimport type { AppContext, Availability, RuleContext } from '@burojs/core';\nimport { resolveAvailability, ruleContextFor } from '@burojs/core';\nimport { useCallback } from 'react';\nimport { useApp } from './use-app.js';\nimport { useCtx } from './use-ctx.js';\n\n/**\n * One resolver bound to a resource, for callers that ask about MANY operations\n * or many records in one render — a list building a link per row, a menu\n * filtering its items. Calling `useAvailability` in such a loop would violate\n * the Rules of Hooks; this hoists the hook calls to a fixed set.\n *\n * ⚠️ `mode` defaults to `'list'` while `useCapabilityResolver` defaults to\n * `'edit'`. Deliberate — this hook's typical caller is a list drawing a row,\n * that one's is a form deciding field editability — but it means a rule\n * branching on `ctx.mode` gets different answers from the two hooks unless the\n * caller passes `mode`. A container and its children must therefore agree\n * explicitly: `ActionOverflow` and `ActionButton` both derive theirs from the\n * surface via `modeForSurface`, because when they did not, a menu rendered and\n * its only item then vanished.\n */\nexport function useAvailabilityResolver(\n resource: string,\n mode: RuleContext['mode'] = 'list',\n): (operation: string, record?: unknown) => Availability {\n const gate = useAvailabilityGate(mode);\n return useCallback((operation, record) => gate(resource, operation, record), [gate, resource]);\n}\n\n/**\n * The same gate with the resource as a PARAMETER rather than a binding — for\n * the few surfaces that ask about many different resources in one render.\n *\n * The command palette's Create group asks every registered resource whether it\n * can be created; a relation picker asks about its target, not about the\n * resource whose form it sits on. Neither can call `useAvailabilityResolver`\n * per resource without breaking the Rules of Hooks, and building the\n * `RuleContext` by hand at each such call site is how the synthesized\n * `{ id: '', roles: [], authenticated: false }` for a signed-out visitor ends\n * up written three slightly different ways.\n */\nexport function useAvailabilityGate(\n mode: RuleContext['mode'] = 'list',\n): (resource: string, operation: string, record?: unknown) => Availability {\n const app = useApp();\n const scope = useCtx((c: AppContext) => c.scope);\n const user = useCtx((c: AppContext) => c.user);\n const permissions = useCtx((c: AppContext) => c.permissions);\n\n return useCallback(\n (resource, operation, record) => {\n const ctx = ruleContextFor({ user, scope, permissions, record, mode, resource });\n return resolveAvailability(app.ruleSource, app.registry, resource, operation, ctx);\n },\n [app.ruleSource, app.registry, mode, scope, user, permissions],\n );\n}\n\n/** Decide one operation at one call site. */\nexport function useAvailability(\n resource: string,\n operation: string,\n record?: unknown,\n): Availability {\n const resolve = useAvailabilityResolver(resource);\n return resolve(operation, record);\n}\n","'use client';\nimport {\n APP_ACTION_RESOURCE,\n type EntityRef,\n canonicalEntityNodeKey,\n compileFlow,\n resolveFlowGate,\n ruleContextFor,\n} from '@burojs/core';\nimport { useMemo } from 'react';\nimport { readPermissions, useContextSnapshot } from '../forms/controller/use-source-resolver.js';\nimport { hostPageFor } from '../flows/page-host.js';\nimport { useApp } from './use-app.js';\nimport { useAvailabilityGate } from './use-availability.js';\n\nexport interface AppActionEntry {\n readonly name: string;\n /** The declared default; a renderer resolves `appActions.<name>` in the bundle over it. */\n readonly label: string;\n /** `'flow'`: an app flow (P4); run it with `useAction({ appAction: name })`. */\n readonly kind: 'modal' | 'link' | 'flow';\n /** `kind: 'modal'`: the block the action presents (P7 3.16), with its portable props. */\n readonly block?: EntityRef;\n readonly props?: Readonly<Record<string, unknown>>;\n readonly host?: 'dialog' | 'sheet';\n readonly to?: string;\n readonly icon?: string;\n /** Present when a rule allows it but disables it; the rule's own reason. */\n readonly disabledReason?: string;\n /**\n * A flow hosted on a custom page (`host: { page }`, P7 3.15): the page's own path. Its control\n * is a guarded link, not a runner; the entry exists only for a user who may open the page.\n */\n readonly hostHref?: string;\n}\n\n/**\n * Every app-level action (`defineAppAction`, `registerAppAction`) the\n * registry knows about, filtered and annotated by the same deny-wins rule\n * engine that gates resource actions.\n *\n * An app action belongs to no resource — there is no `resource.rules` for it\n * to live in — so it is asked about at the reserved address\n * `APP_ACTION_RESOURCE` (`'buro:app-actions'`, from `@burojs/core`). This is\n * not a typo and not a real resource: it is a fixed rule address\n * (`{ resource: APP_ACTION_RESOURCE, operation: <action name> }`) that gives\n * rule authors a stable, predictable place to target app actions\n * (`{ target: { kind: 'action', name: 'incident.collect' } }` in an\n * app-level rule, which — like all app-level rules — applies regardless of\n * the resource argument) without inventing a second gating engine next to\n * `useAvailabilityGate`.\n *\n * An app flow (`kind: 'flow'`, P4) is gated by the flow's own gate (`resolveFlowGate`: its\n * `requires`, its mutation's `requires`, and the same `action/run` rules at the same address),\n * the one gate its button and `useAction` run; while permissions load it is left out.\n *\n * Rule-hidden (or absent) actions are dropped from the list entirely; a rule\n * that allows-but-disables an action keeps it in the list with its\n * `disabledReason` set so a caller can render it inert instead of missing.\n */\nexport function useAppActions(): readonly AppActionEntry[] {\n const app = useApp();\n const gate = useAvailabilityGate();\n const context = useContextSnapshot();\n const list = app.registry.appActions.list();\n\n const permissions = readPermissions(context);\n /** An app flow's gate (4.17): `null` when it is not offered, else its disabled reason if any. */\n const flowGate = (name: string, def: unknown): { readonly reason?: string } | null => {\n let compiled: ReturnType<typeof compileFlow>;\n try {\n compiled = compileFlow(def as never, name);\n } catch {\n return null;\n }\n const answer = resolveFlowGate({\n app,\n resource: null,\n flow: compiled,\n ctx: ruleContextFor({\n mode: 'list',\n user: context.user as never,\n scope: context.scope as never,\n ...(permissions === undefined ? {} : { permissions }),\n }),\n permissionsStatus: permissions?.status as 'loading' | 'ready' | 'error' | undefined,\n });\n if (answer.state === 'available') return {};\n if (answer.state === 'disabled')\n return answer.reason === undefined ? { reason: '' } : { reason: answer.reason };\n return null;\n };\n\n return useMemo(() => {\n const entries: AppActionEntry[] = [];\n for (const action of list) {\n // `action.name` is the raw, possibly-namespace-dropping id the\n // projection stores (`projectAppAction` keeps `ref.id`, same as pages/\n // groups/sections) — a plugin-registered `'incidents:collect'` lands\n // there as the lossy `'collect'`. `canonicalEntityNodeKey` is the same\n // helper `canonicalNavKey` uses for nav nodes: default-namespace\n // actions keep their short id, a namespaced one gets its qualified\n // `ns:id` form back, which is exactly the string the registry's\n // `appActionByRef` map (and a rule author's `{ name: 'incidents:collect' }`)\n // was keyed on. Gating on the lossy `action.name` here means the gate\n // can never resolve a namespaced action.\n const name = canonicalEntityNodeKey(action);\n if (action.kind === 'flow') {\n const flow = flowGate(name, action);\n if (flow === null) continue;\n // A flow hosted on a custom page is offered to a user who may open the page, and only\n // once that is decided: undecided and denied leave it out.\n const hostPage = hostPageFor(\n app.registry,\n (action as { host?: unknown }).host,\n permissions,\n {\n ...(permissions === undefined ? {} : { permissions }),\n scope: context.scope as never,\n user: context.user as never,\n },\n );\n if (hostPage !== undefined && hostPage.access !== 'allowed') continue;\n entries.push({\n name,\n label: action.label,\n kind: 'flow',\n ...(hostPage === undefined ? {} : { hostHref: hostPage.href }),\n ...(action.icon === undefined ? {} : { icon: action.icon }),\n ...(flow.reason === undefined ? {} : { disabledReason: flow.reason }),\n });\n continue;\n }\n const availability = gate(APP_ACTION_RESOURCE, name);\n if (availability.state === 'absent' || availability.state === 'hidden') continue;\n entries.push({\n name,\n label: action.label,\n kind: action.kind,\n block: action.block as EntityRef | undefined,\n props: action.props,\n host: action.host as 'dialog' | 'sheet' | undefined,\n to: action.to,\n icon: action.icon,\n disabledReason: availability.state === 'disabled' ? availability.reason : undefined,\n });\n }\n return entries;\n // biome-ignore lint/correctness/useExhaustiveDependencies: flowGate reads app, context and permissions\n }, [list, gate, app, context, permissions]);\n}\n","import { useCallback, useContext } from 'react';\nimport { ResolverContext } from '../context.js';\n\nexport function useSetSlice<TName extends string = string>(name: TName): (value: unknown) => void {\n const resolver = useContext(ResolverContext);\n if (!resolver) throw new Error('[useSetSlice] must be used within a BuroProvider');\n\n return useCallback(\n (value) => {\n resolver.setSlice(name as never, value);\n },\n [resolver, name],\n );\n}\n","import { useMemo } from 'react';\n\nexport interface TestIdBuilder {\n navMenuItem: (resource: string) => string;\n navGroup: (name: string) => string;\n navBreadcrumb: (resource: string, id?: string) => string;\n /**\n * A sidebar entry for an adopter-declared custom page (`<NavMain>`), keyed\n * by the page key rather than a resource name — the one nav entry that has\n * no resource behind it.\n */\n sidebarCustomPage: (pageKey: string) => string;\n contextPicker: (sliceName: string) => string;\n contextPickerOption: (sliceName: string, value: string) => string;\n\n /**\n * The header language switcher and one locale inside it\n * (`<LanguageSwitch>`). The trigger additionally carries\n * `data-language-state=\"<code>\"`, which is how a test reads the ACTIVE\n * locale without opening the menu.\n */\n languageSwitch: () => string;\n languageSwitchOption: (localeCode: string) => string;\n\n /**\n * `<LoginForm>`'s three controls. Argument-less because the login form is a\n * singleton screen with no resource, record or view to key on — they are\n * factories anyway so that a test never spells the string, which is the\n * whole point of this builder.\n */\n loginEmail: () => string;\n loginPassword: () => string;\n loginSubmit: () => string;\n\n pageList: (resource: string) => string;\n listToolbar: (resource: string) => string;\n listAction: (resource: string, actionName: string) => string;\n listSearch: (resource: string) => string;\n /** The filter bar's \"Some saved filters were not applied\" notice (P5 spec 3.7). */\n listPredicatesDropped: (resource: string) => string;\n /** A list frame's slot, around its planned tree (P7-34). */\n listSlot: (resource: string, slot: string) => string;\n /** A resource-level flow on the route list's toolbar (P7-31). */\n listFlow: (resource: string, flowName: string) => string;\n /** The toolbar's overflow menu of resource-level flows. */\n listFlowsMenu: (resource: string) => string;\n listFilter: (resource: string, fieldName: string) => string;\n listTable: (resource: string) => string;\n /** A `related-list` card (`view: 'cards'`): the placement key and the row id. */\n relatedCard: (key: string, recordId: string) => string;\n /** A `related-list` timeline entry (`view: 'timeline'`): the placement key and the row id. */\n timelineEntry: (key: string, recordId: string) => string;\n listRow: (resource: string, recordId: string) => string;\n listCell: (resource: string, recordId: string, fieldName: string) => string;\n listRowAction: (resource: string, recordId: string, actionName: string) => string;\n /** The list-row overflow (`…`) menu trigger — present when a row has ≥2 actions. */\n listRowActionsMenu: (resource: string, recordId: string) => string;\n listRowCheckbox: (resource: string, recordId: string) => string;\n listPaginationPrev: (resource: string) => string;\n listPaginationNext: (resource: string) => string;\n listPaginationPage: (resource: string, n: number) => string;\n listEmpty: (resource: string) => string;\n listBulkBar: (resource: string) => string;\n bulkAction: (resource: string, actionName: string) => string;\n resourceAction: (resource: string, actionName: string) => string;\n /**\n * `<ExportDialog>`'s root testid (`@burojs/ui-shadcn`). The dialog's own\n * internal controls (format selector, columns toggle, start/download/\n * cancel buttons, the close-while-running confirm) compose off this same\n * id with a `:` suffix rather than each getting their own factory entry —\n * they have no meaning outside one mounted dialog, unlike e.g. `bulkAction`.\n */\n exportDialog: (resource: string) => string;\n /** The list-toolbar Export button (Task 8) — opens `<ExportDialog>` with the current filter/sort scope. */\n exportButton: (resource: string) => string;\n /**\n * The bulk-bar Export item (Task 8) — opens `<ExportDialog>` with the\n * selected ids. A DISTINCT factory from {@link bulkAction} on purpose: a\n * resource may declare its own custom bulk action literally named\n * `'export'` (see `bulk-action-toolbar.test.tsx`), and this built-in entry\n * point must never collide with that testid.\n */\n exportBulkAction: (resource: string) => string;\n\n pageShow: (resource: string, recordId: string) => string;\n pageEdit: (resource: string, recordId: string) => string;\n pageCreate: (resource: string) => string;\n\n /**\n * The notice a record screen renders for a record whose discriminator value\n * no declared type holds (P1b+P1c decision 64). Keyed by RESOURCE and not by the offending value: the value\n * is by definition one the application does not know, so a testid built from\n * it could not be written down in advance by the test that looks for it.\n */\n unsupportedDocumentType: (resource: string) => string;\n\n /**\n * A quick overlay (sheet or dialog; P3-21) by its top entry: `quick-sheet:<resource>:<id>`, or\n * `quick-sheet:<resource>` for a create.\n */\n quickSheet: (resource: string, recordId?: string) => string;\n /** The quick sheet's Back (when its history is deeper than one entry). */\n quickBack: () => string;\n /** The quick overlay's close button. */\n quickClose: () => string;\n /** The quick overlay's \"Open as page\" link. */\n quickOpenPage: () => string;\n /** A peek (the hover preview of a relation display's record, P3-22): `peek:<resource>:<key>`. */\n peek: (resource: string, key: string) => string;\n\n /**\n * A flow's host (P4 spec 4.15) and its controls, by the flow's identity\n * (`'<ns>:<resource>/actions/<name>'`, `'app/<name>'`): `flow-host:<flowId>`, and\n * `flow-<control>:<flowId>` for each control.\n */\n flowHost: (flowId: string) => string;\n /** The page-hosted flow's route body (P6): `page-flow:<flowId>`. */\n pageFlow: (flowId: string) => string;\n /** An inline flow's placement (P6): `inline-flow:<flowId>:<placement key>`. */\n inlineFlow: (flowId: string, key: string) => string;\n flowSubmit: (flowId: string) => string;\n flowBack: (flowId: string) => string;\n /** The footer's Cancel: closes through the dismiss guard. */\n flowCancel: (flowId: string) => string;\n /** The header's ✕, and an outcome screen's Close. */\n flowClose: (flowId: string) => string;\n /** The outcome message (rejected, failed, unknown, busy). */\n flowOutcome: (flowId: string) => string;\n flowCheckAgain: (flowId: string) => string;\n flowSendAsNew: (flowId: string) => string;\n flowStartOver: (flowId: string) => string;\n flowResend: (flowId: string) => string;\n /** The draft-found banner of a flow's form, and its two buttons (`:restore`, `:discard`). */\n flowDraft: (flowId: string) => string;\n /** A bulk flow's per-outcome summary. */\n bulkSummary: (resource: string, actionName: string) => string;\n\n form: (resource: string, view: string, recordId?: string) => string;\n formField: (resource: string, view: string, fieldName: string) => string;\n formFieldInput: (resource: string, view: string, fieldName: string) => string;\n formFieldError: (resource: string, view: string, fieldName: string) => string;\n formFieldLocked: (resource: string, view: string, fieldName: string) => string;\n /** A field leaf its user may not read the value of: the label and the restriction, no value. */\n formFieldRestricted: (resource: string, view: string, fieldName: string) => string;\n /**\n * A field's help text — the hint under the input, resolved from the i18n\n * `fields.<name>.description` slot or from the field's description.\n *\n * ⚠️ This one was the other way round: the id was spelled identically on\n * both sides and simply never rendered. the old record form drew the hint\n * paragraph with an `id` (for `aria-describedby`) and no `data-testid`, so\n * `form.field(x).help()` had matched nothing since it was written. The\n * producer was added at SP9 task 5, which is what lets a browser test assert\n * that `aria-describedby` points at THIS element and that it yields to an\n * error.\n */\n formFieldHelp: (resource: string, view: string, fieldName: string) => string;\n /**\n * Per-field async-validation pending indicator (B2). Rendered next to\n * the field label while a per-field async validator is in flight.\n */\n formFieldValidating: (resource: string, view: string, fieldName: string) => string;\n formSubmit: (resource: string, view: string) => string;\n formCancel: (resource: string, view: string) => string;\n formAction: (resource: string, view: string, actionName: string) => string;\n /** The show/edit toolbar overflow (`…`) menu trigger — present when there are unpinned actions. */\n formActionsMenu: (resource: string, view: string) => string;\n /**\n * Form-level async-validation pending indicator (B2). Rendered near\n * the submit button while the resource-level cross-field validate is\n * in flight.\n */\n formValidating: (resource: string, view: string) => string;\n /**\n * Auto-save / draft-found banner (B7.1). Rendered above the form's\n * field stack on mount when a non-stale localStorage draft exists.\n */\n /** One option of the built-in type offer of a typed create (P1b+P1c decision 24). */\n typeOffer: (resource: string, type: string) => string;\n formDraftBanner: (resource: string, view: string) => string;\n /** Restore button inside the draft banner (B7.1). */\n formDraftRestore: (resource: string, view: string) => string;\n /** Discard button inside the draft banner (B7.1). */\n formDraftDiscard: (resource: string, view: string) => string;\n\n /**\n * THE RELATION PICKER — and why every one of these is spelled\n * `relation-picker:…` rather than `picker-…` (SP9 task 5).\n *\n * ⚠️ **This family used to name a vocabulary nothing emitted.** Seven\n * factories spelled `picker-trigger:` / `picker-dialog:` / `picker-popover:`\n * / `picker-search:` / `picker-option:` / `picker-clear:` /\n * `picker-quickcreate:`, and `@burojs/test-helpers`' `createPickerObject`\n * spelled the same seven — while `@burojs/ui-shadcn`'s\n * `fields/relation-picker.tsx` and `fields/relation-picker-dialog.tsx` have\n * always emitted `relation-picker:<target>:…` and\n * `relation-picker-dialog:<target>:…`. Measured: **zero producers** for any\n * of the seven, anywhere in the repository.\n *\n * The reason it survived is worth more than the fix. `examples/marketplace-\n * ops/tests/page-object-vocabulary.test.tsx` exists precisely to stop these\n * two hand-written copies drifting, and it was green — because it compared\n * the page object with THIS file and nothing compared either with the\n * component. Two copies of a wrong convention agree perfectly. The producer\n * side is now pinned by `packages/ui-shadcn/tests/relation-picker-\n * testids.test.tsx`, which renders the real picker and reads the ids off the\n * DOM, so the agreement has a third party that can disagree.\n *\n * `quickCreate` is gone rather than re-spelled: the picker's quick-create is\n * deferred to v2 and no element exists to address. `popover` is gone because\n * the popover CONTENT carries no id of its own — {@link pickerList} is the\n * element inside it that does.\n *\n * The trigger takes the TARGET resource, not (resource, view, field): the\n * component composes it from `to`. Inside a record form the trigger's\n * id is overridden with `formFieldInput(resource, view, field)` — the form\n * passes its own `testid` prop so a field's input is addressable the same\n * way whatever its kind — while every child of the popover keeps the\n * per-target prefix below. Both facts are asserted in that same test.\n */\n pickerTrigger: (targetResource: string) => string;\n /**\n * The select's \"view\" button (P6-28): the target resource and the form field that holds the key,\n * `relation-view:<target>:<field>`.\n */\n relationView: (targetResource: string, field: string) => string;\n /** The select's \"+ create\" button (P6-29): `relation-create:<target>:<field>`. */\n relationCreate: (targetResource: string, field: string) => string;\n /**\n * What the select says in place of its options while it must not read (P7 3.4): which field to\n * choose first, or that its candidates name a field the user may not see.\n * `relation-candidates-hint:<resource>:<field>`.\n */\n relationCandidatesHint: (resource: string, field: string) => string;\n /** A chip of a to-many select (P7 3.5): `relation-many-chip:<resource>:<field>:<id>`. */\n relationManyChip: (resource: string, field: string, id: string) => string;\n /** The popover's search box. */\n pickerSearch: (targetResource: string) => string;\n /** The popover's result list (the popover content itself carries no id). */\n pickerList: (targetResource: string) => string;\n /** One result row, keyed by the target record's id. */\n pickerOption: (targetResource: string, value: string) => string;\n /** The \"No results.\" row. */\n pickerEmpty: (targetResource: string) => string;\n /** The Clear link — rendered only when `clearable` and a value is set. */\n pickerClear: (targetResource: string) => string;\n /** The \"Advanced search\" link, which escalates to the modal below. */\n pickerAdvanced: (targetResource: string) => string;\n /** The \"Open list\" link to the target resource's own list page. */\n pickerViewAll: (targetResource: string) => string;\n /** The escalation modal (`<RelationPickerDialog>`). */\n pickerDialog: (targetResource: string) => string;\n /** The escalation modal's own search box. */\n pickerDialogSearch: (targetResource: string) => string;\n /** The disabled trigger rendered when the target resource is unregistered. */\n pickerUnregistered: (targetResource: string) => string;\n\n childrenTable: (resource: string, view: string, fieldName: string) => string;\n childrenRow: (resource: string, view: string, fieldName: string, index: number) => string;\n childrenAdd: (resource: string, view: string, fieldName: string) => string;\n childrenRemove: (resource: string, view: string, fieldName: string, index: number) => string;\n\n /**\n * `<TaskRunPanel>` (`@burojs/ui-shadcn`) — the surface that reports progress\n * and partial failure for work long enough to watch. Keyed by the RUN's own\n * name (the app names the run: `'stock'`, `'import'`, …), not by a resource:\n * a task run has no resource in the general case — a bulk run spans a\n * selection and a long server-side operation has no record at all.\n *\n * The root carries `data-state=\"idle|running|succeeded|failed|cancelled\"`, so\n * a test reads the outcome without matching translated text — the same device\n * `<LanguageSwitch>`'s `data-language-state` uses.\n */\n taskRun: (name: string) => string;\n /** The bar itself (`role=\"progressbar\"`), whose `aria-valuenow` is the count. */\n taskRunProgress: (name: string) => string;\n /**\n * One named unit that did not succeed — a refused row, or the step a run\n * stopped at. Keyed by SUBJECT because that is the half a reader needs:\n * three entries all reading \"failed\" name nothing.\n */\n taskRunFailure: (name: string, subject: string) => string;\n\n notification: (type: 'success' | 'error' | 'progress' | 'info') => string;\n notificationClose: (type: string) => string;\n}\n\nfunction withId(parts: Array<string | number | undefined>): string {\n return parts.filter((p) => p !== undefined && p !== '').join(':');\n}\n\nexport function useTestIds(): TestIdBuilder {\n return useMemo<TestIdBuilder>(\n () => ({\n navMenuItem: (resource) => `nav-menu-item:${resource}`,\n navGroup: (name) => `nav-group:${name}`,\n navBreadcrumb: (resource, id) => withId(['nav-breadcrumb', resource, id]),\n sidebarCustomPage: (pageKey) => `sidebar-custompage:${pageKey}`,\n contextPicker: (slice) => `context-picker:${slice}`,\n contextPickerOption: (slice, value) => `context-picker-option:${slice}:${value}`,\n\n languageSwitch: () => 'language-switch',\n languageSwitchOption: (localeCode) => `language-switch:${localeCode}`,\n\n loginEmail: () => 'login-email',\n loginPassword: () => 'login-password',\n loginSubmit: () => 'login-submit',\n\n pageList: (r) => `page-list:${r}`,\n listToolbar: (r) => `list-toolbar:${r}`,\n listAction: (r, a) => `list-action:${r}:${a}`,\n listSearch: (r) => `list-search:${r}`,\n listPredicatesDropped: (r) => `list-predicates-dropped:${r}`,\n listSlot: (r, s) => `list-slot:${r}:${s}`,\n listFlow: (r, a) => `list-flow:${r}:${a}`,\n listFlowsMenu: (r) => `list-flows-menu:${r}`,\n listFilter: (r, f) => `list-filter:${r}:${f}`,\n listTable: (r) => `list-table:${r}`,\n relatedCard: (key, id) => `related-card:${key}:${id}`,\n timelineEntry: (key, id) => `timeline-entry:${key}:${id}`,\n listRow: (r, id) => `list-row:${r}:${id}`,\n listCell: (r, id, f) => `list-cell:${r}:${id}:${f}`,\n listRowAction: (r, id, a) => `list-row-action:${r}:${id}:${a}`,\n listRowActionsMenu: (r, id) => `list-row-actions-menu:${r}:${id}`,\n listRowCheckbox: (r, id) => `list-row-checkbox:${r}:${id}`,\n listPaginationPrev: (r) => `list-pagination-prev:${r}`,\n listPaginationNext: (r) => `list-pagination-next:${r}`,\n listPaginationPage: (r, n) => `list-pagination-page:${r}:${n}`,\n listEmpty: (r) => `list-empty:${r}`,\n listBulkBar: (r) => `list-bulk-bar:${r}`,\n bulkAction: (r, a) => `bulk-action:${r}:${a}`,\n resourceAction: (r, a) => `list-action:${r}:${a}`,\n exportDialog: (r) => `export-dialog:${r}`,\n exportButton: (r) => `export-button:${r}`,\n exportBulkAction: (r) => `export-bulk-action:${r}`,\n\n pageShow: (r, id) => `page-show:${r}:${id}`,\n pageEdit: (r, id) => `page-edit:${r}:${id}`,\n pageCreate: (r) => `page-create:${r}`,\n unsupportedDocumentType: (r) => `unsupported-document-type:${r}`,\n\n quickSheet: (r, id) => withId(['quick-sheet', r, id]),\n quickBack: () => 'quick-back',\n quickClose: () => 'quick-close',\n quickOpenPage: () => 'quick-open-page',\n peek: (r, key) => `peek:${r}:${key}`,\n\n flowHost: (id) => `flow-host:${id}`,\n pageFlow: (id) => `page-flow:${id}`,\n inlineFlow: (id, key) => `inline-flow:${id}:${key}`,\n flowSubmit: (id) => `flow-submit:${id}`,\n flowBack: (id) => `flow-back:${id}`,\n flowCancel: (id) => `flow-cancel:${id}`,\n flowClose: (id) => `flow-close:${id}`,\n flowOutcome: (id) => `flow-outcome:${id}`,\n flowCheckAgain: (id) => `flow-check-again:${id}`,\n flowSendAsNew: (id) => `flow-send-as-new:${id}`,\n flowStartOver: (id) => `flow-start-over:${id}`,\n flowResend: (id) => `flow-resend:${id}`,\n flowDraft: (id) => `flow-draft:${id}`,\n bulkSummary: (r, a) => `bulk-summary:${r}:${a}`,\n\n form: (r, v, id) => withId(['form', r, v, id]),\n formField: (r, v, f) => `form-field:${r}:${v}:${f}`,\n formFieldInput: (r, v, f) => `form-field-input:${r}:${v}:${f}`,\n formFieldError: (r, v, f) => `form-field-error:${r}:${v}:${f}`,\n formFieldLocked: (r, v, f) => `form-field-locked:${r}:${v}:${f}`,\n formFieldRestricted: (r, v, f) => `form-field-restricted:${r}:${v}:${f}`,\n formFieldHelp: (r, v, f) => `form-field-help:${r}:${v}:${f}`,\n formFieldValidating: (r, v, f) => `form-field-validating:${r}:${v}:${f}`,\n formSubmit: (r, v) => `form-submit:${r}:${v}`,\n formCancel: (r, v) => `form-cancel:${r}:${v}`,\n formAction: (r, v, a) => `form-action:${r}:${v}:${a}`,\n formActionsMenu: (r, v) => `form-actions-menu:${r}:${v}`,\n formValidating: (r, v) => `form-validating:${r}:${v}`,\n typeOffer: (r, t) => `type-offer:${r}:${t}`,\n formDraftBanner: (r, v) => `form-draft-banner:${r}:${v}`,\n formDraftRestore: (r, v) => `form-draft-restore:${r}:${v}`,\n formDraftDiscard: (r, v) => `form-draft-discard:${r}:${v}`,\n\n pickerTrigger: (t) => `relation-picker:${t}`,\n relationView: (t, field) => `relation-view:${t}:${field}`,\n relationCreate: (t, field) => `relation-create:${t}:${field}`,\n relationCandidatesHint: (r, field) => `relation-candidates-hint:${r}:${field}`,\n relationManyChip: (r, field, id) => `relation-many-chip:${r}:${field}:${id}`,\n pickerSearch: (t) => `relation-picker:${t}:search`,\n pickerList: (t) => `relation-picker:${t}:list`,\n pickerOption: (t, v) => `relation-picker:${t}:option:${v}`,\n pickerEmpty: (t) => `relation-picker:${t}:empty`,\n pickerClear: (t) => `relation-picker:${t}:clear`,\n pickerAdvanced: (t) => `relation-picker:${t}:advanced`,\n pickerViewAll: (t) => `relation-picker:${t}:view-all`,\n pickerDialog: (t) => `relation-picker-dialog:${t}`,\n pickerDialogSearch: (t) => `relation-picker-dialog:${t}:search`,\n pickerUnregistered: (t) => `relation-picker:${t}:unregistered`,\n\n childrenTable: (r, v, f) => `children-table:${r}:${v}:${f}`,\n childrenRow: (r, v, f, i) => `children-row:${r}:${v}:${f}:${i}`,\n childrenAdd: (r, v, f) => `children-add:${r}:${v}:${f}`,\n childrenRemove: (r, v, f, i) => `children-remove:${r}:${v}:${f}:${i}`,\n\n taskRun: (name) => `task-run:${name}`,\n taskRunProgress: (name) => `task-run-progress:${name}`,\n taskRunFailure: (name, subject) => `task-run-failure:${name}:${subject}`,\n\n notification: (type) => `notification:${type}`,\n notificationClose: (type) => `notification-close:${type}`,\n }),\n [],\n );\n}\n","import {\n type TaskRunEvent,\n type TaskRunFailure,\n type TaskRunReport,\n IDLE_TASK_RUN,\n applyTaskRunEvent,\n} from '@burojs/core';\nimport { useCallback, useEffect, useReducer, useRef } from 'react';\n\n/**\n * DRIVES ONE PIECE OF WORK AND KEEPS A {@link TaskRunReport} A VIEW CAN RENDER.\n *\n * The hook knows nothing about what the work IS. It hands the task a\n * {@link TaskRunReporter} and an `AbortSignal` and gets out of the way — the\n * task can poll an RPC endpoint for a step count, loop over a selection, walk\n * pages of a file upload, or anything else, and this hook's job is only to keep\n * what it says in a report and stop listening once the run is over.\n *\n * That is deliberate and it is what makes this not an operations affordance.\n * The two callers this framework already has for it are a polled server-side\n * run and a client-side `for` loop over selected rows (a bulk flow has its own\n * per-outcome summary since P4) — nothing about a poll or a loop appears\n * anywhere below.\n */\n\n/** What a running task tells the report. Handed to the task; never held afterwards. */\nexport interface TaskRunReporter {\n /**\n * How far the work has got, ABSOLUTE — `{ completed: 2, total: 3 }`, not\n * \"+1\". A snapshot from a poll and an index from a loop are both absolute;\n * a delta would need the task to keep its own copy of the count.\n */\n advance(update: {\n readonly completed: number;\n readonly total?: number;\n readonly unit?: string;\n }): void;\n /**\n * One unit that will not be done, while the rest carries on. The bulk case:\n * three of eleven rows are not shippable and the other eight still ship.\n * A task that cannot continue at all THROWS instead — that ends the run.\n */\n refuse(failure: TaskRunFailure): void;\n}\n\nexport interface UseTaskRunOptions {\n /** Known up front, when it is. Reported as the run's `total` before the first `advance`. */\n readonly total?: number;\n /**\n * Turns whatever the task threw into the failure that ended the run.\n *\n * **The default deliberately drops the message.** A thrown `Error`'s text is\n * written for a developer and can carry a URL, a token or a row of somebody's\n * data, and a failure list is precisely the thing that gets screenshotted.\n * Only the caller knows which of its own errors are safe to show, so the\n * default reports a stable code and nothing else, and an app that wants its\n * own domain messages on screen maps them here explicitly.\n */\n readonly mapError?: (error: unknown) => TaskRunFailure;\n}\n\nexport interface TaskRunController {\n readonly report: TaskRunReport;\n readonly isRunning: boolean;\n /**\n * Runs `task`. Resolves when the run is over, whichever way it ended — this\n * hook reports failures rather than rethrowing them, because the report IS\n * the error channel and a caller that also had to catch would have two.\n *\n * A second call while a run is in flight is refused (and reported as such by\n * the resolved promise's `false`): two runs sharing one report would\n * interleave counts into nonsense.\n */\n start(\n task: (reporter: TaskRunReporter, signal: AbortSignal) => Promise<unknown>,\n ): Promise<boolean>;\n /** Asks the in-flight task to stop, through its `AbortSignal`. */\n cancel(): void;\n /** Back to `idle`. Refused while a run is in flight. */\n reset(): void;\n}\n\n/** No message, on purpose — see {@link UseTaskRunOptions.mapError}. */\nfunction defaultMapError(): TaskRunFailure {\n return { subject: 'run', code: 'task-run/failed' };\n}\n\n/**\n * `reset` is this hook's own event, not the model's. `applyTaskRunEvent`\n * describes ONE run and refuses to move a terminal report — correctly, since a\n * late poll must not resurrect a finished run. Emptying the slot the report\n * sits in is a different act, and it belongs to whoever holds the slot.\n */\ntype TaskRunSlotEvent = TaskRunEvent | { readonly kind: 'reset' };\n\nfunction reduce(report: TaskRunReport, event: TaskRunSlotEvent): TaskRunReport {\n return event.kind === 'reset' ? IDLE_TASK_RUN : applyTaskRunEvent(report, event);\n}\n\nexport function useTaskRun(options: UseTaskRunOptions = {}): TaskRunController {\n const [report, dispatch] = useReducer(reduce, IDLE_TASK_RUN);\n const controllerRef = useRef<AbortController | null>(null);\n const mountedRef = useRef(true);\n // Read through a ref so a caller re-creating `mapError` inline on every\n // render does not change `start`'s identity — an effect or a memo depending\n // on it would then re-run on every keystroke elsewhere on the page.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n // A run outlives its screen otherwise: the task keeps polling into a\n // report nobody renders, and every report is a state update on an\n // unmounted tree.\n controllerRef.current?.abort();\n controllerRef.current = null;\n };\n }, []);\n\n const start = useCallback<TaskRunController['start']>(async (task) => {\n if (controllerRef.current !== null) return false;\n\n const controller = new AbortController();\n controllerRef.current = controller;\n const live = (): boolean => mountedRef.current && controllerRef.current === controller;\n\n dispatch({ kind: 'start', total: optionsRef.current.total });\n\n const reporter: TaskRunReporter = {\n advance: (update) => {\n if (!live()) return;\n dispatch({ kind: 'advance', ...update });\n },\n refuse: (failure) => {\n if (!live()) return;\n dispatch({ kind: 'refuse', failure });\n },\n };\n\n try {\n const result = await task(reporter, controller.signal);\n if (live()) dispatch({ kind: 'finish', result });\n } catch (error) {\n // A cancelled run is not a failed one, and the two must not render the\n // same. `controller.signal.aborted` is the check and not the shape of\n // the thrown value: a task may abandon its work with any error at all\n // once its signal fires, including one this hook has never seen.\n if (!live()) {\n // Unmounted, or superseded — nothing left to report to.\n } else if (controller.signal.aborted) {\n dispatch({ kind: 'cancel' });\n } else {\n dispatch({ kind: 'fail', error: (optionsRef.current.mapError ?? defaultMapError)(error) });\n }\n } finally {\n if (controllerRef.current === controller) controllerRef.current = null;\n }\n return true;\n }, []);\n\n const cancel = useCallback(() => {\n const controller = controllerRef.current;\n if (controller === null) return;\n controller.abort();\n // Reported here rather than only in `start`'s catch: a task that ignores\n // its signal and resolves normally would otherwise report `succeeded` for\n // a run the operator stopped. The reducer's terminal rule makes the later\n // `finish` a no-op.\n dispatch({ kind: 'cancel' });\n }, []);\n\n const reset = useCallback(() => {\n if (controllerRef.current !== null) return;\n dispatch({ kind: 'reset' });\n }, []);\n\n return { report, isRunning: report.state === 'running', start, cancel, reset };\n}\n","import { useCallback, useRef, useState } from 'react';\n\nimport { useOptionalDataRuntime } from '../data/context.js';\nimport { isBuroDataQueryKey } from '../data/invalidation.js';\n\nexport interface UseRefreshResult {\n /** Invalidates every native data query and resolves once the active ones have refetched. */\n readonly refresh: () => Promise<void>;\n readonly isRefreshing: boolean;\n /**\n * False without a native data runtime: there is nothing to refresh and `refresh` is a no-op.\n * A bare `QueryClientProvider` does not count — only the data runtime's own query client holds\n * the queries this hook invalidates.\n */\n readonly available: boolean;\n}\n\nconst noop = (): Promise<void> => Promise.resolve();\n\n/** Refetches all data the app is showing: a header \"Refresh\" control, or any custom trigger. */\nexport function useRefresh(): UseRefreshResult {\n const queryClient = useOptionalDataRuntime()?.queryClient;\n const [isRefreshing, setIsRefreshing] = useState(false);\n // Overlapping calls: `isRefreshing` holds until the last one settles.\n const inFlight = useRef(0);\n const refresh = useCallback(async () => {\n if (queryClient === undefined) return;\n inFlight.current += 1;\n setIsRefreshing(true);\n try {\n await queryClient.invalidateQueries({\n predicate: (query) => isBuroDataQueryKey(query.queryKey),\n });\n } finally {\n inFlight.current -= 1;\n if (inFlight.current === 0) setIsRefreshing(false);\n }\n }, [queryClient]);\n return queryClient === undefined\n ? { refresh: noop, isRefreshing: false, available: false }\n : { refresh, isRefreshing, available: true };\n}\n","import { useCallback, useEffect, useState } from 'react';\n\n/**\n * SSR-safe localStorage hook.\n *\n * Returns `[value, setValue]`. Hydrates from `localStorage` on mount —\n * `value` is `undefined` during SSR and the initial render to avoid\n * hydration mismatches; on mount it switches to the stored value (or the\n * provided `initial` if no stored value exists).\n *\n * Setter accepts `undefined` to clear the key. Storage write errors\n * (quota / private mode) are swallowed — UI continues to reflect the\n * in-memory state.\n *\n * @example\n * const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('theme', 'light');\n * const [companyId, setCompanyId] = useLocalStorage<number>('selected-company');\n */\nexport function useLocalStorage<T>(\n key: string,\n initial?: T,\n): [T | undefined, (value: T | undefined) => void] {\n const [value, setStateValue] = useState<T | undefined>(undefined);\n\n // Hydrate from storage on mount\n useEffect(() => {\n if (typeof window === 'undefined') return;\n try {\n const raw = window.localStorage.getItem(key);\n if (raw == null) {\n setStateValue(initial);\n return;\n }\n // Try JSON.parse first; if it fails, fall back to the raw string\n // (handles legacy plain-string values like '1' or 'dark').\n try {\n setStateValue(JSON.parse(raw) as T);\n } catch {\n setStateValue(raw as unknown as T);\n }\n } catch {\n setStateValue(initial);\n }\n // intentionally only on mount — caller treats `key` as stable\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const setValue = useCallback(\n (next: T | undefined) => {\n setStateValue(next);\n if (typeof window === 'undefined') return;\n try {\n if (next === undefined) {\n window.localStorage.removeItem(key);\n } else {\n window.localStorage.setItem(key, typeof next === 'string' ? next : JSON.stringify(next));\n }\n } catch {\n // ignore storage write errors\n }\n },\n [key],\n );\n\n return [value, setValue];\n}\n","'use client';\nimport { useEffect, useState } from 'react';\n\n/**\n * Returns a debounced reflection of `value`. The returned value lags\n * behind the input by `ms` milliseconds: each change resets a pending\n * timer; only the latest value paints once the timer settles.\n *\n * Typical use: gate a network request on a user input that may change\n * rapidly (cmdk search box, free-form filter input). Pair this with the\n * source state and feed only the debounced value into the request hook\n * so rapid keystrokes don't fire one request per character.\n *\n * Edge cases:\n * - On mount: the debounced value initialises to the current `value`\n * so the first render does NOT fire an extra \"change\" through the\n * debounce — adopters can use the result on first paint without a\n * conditional `if (debouncedValue === undefined)` guard.\n * - On unmount: the pending timer is cleared in the effect cleanup\n * (no setState-after-unmount warning).\n * - On `ms === 0`: the timer fires synchronously next tick (setTimeout\n * semantics) — adopters who want truly synchronous behaviour should\n * pass the source value directly without the hook.\n *\n * SSR: `useState` + `useEffect` are SSR-safe. The initial render uses\n * the source value so server-rendered HTML matches the first client\n * paint exactly.\n */\nexport function useDebouncedValue<T>(value: T, ms: number): T {\n const [debounced, setDebounced] = useState<T>(value);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setDebounced(value);\n }, ms);\n return () => clearTimeout(timer);\n }, [value, ms]);\n\n return debounced;\n}\n","import {\n FILE_STORAGE_SERVICE,\n type FileStorageAdapter,\n type FileStorageRegistry,\n} from '@burojs/file-storage';\nimport { useApp } from '../use-app.js';\n\n/** Resolve a registered storage by name. Throws with the registered names. */\nexport function useFileStorage(name?: string): FileStorageAdapter {\n const app = useApp();\n const registry = app.getService<FileStorageRegistry>(FILE_STORAGE_SERVICE);\n if (!registry) {\n throw new Error(\n 'No file storage registered — add fileStoragePlugin({ default: … }) to defineApp',\n );\n }\n return registry.get(name);\n}\n\n/**\n * Same resolution, but reports failure instead of throwing.\n *\n * `useFileStorage` throwing is right where a throw stays local — a form field\n * that cannot be configured should fail loudly at the developer. It is wrong\n * in a READ path: a list renders one file cell per row, all of them inside the\n * DataGrid's single render, so one misspelled `ui.fileStorage` doesn't blank a\n * cell, it takes down the entire table (and anything else in that subtree)\n * with no error boundary between them. A record's data is fine; only the\n * config naming its storage is wrong.\n *\n * Returns the reason rather than a bare `undefined` so the caller can show\n * WHICH name failed and what was registered, instead of an anonymous blank.\n */\nexport function useOptionalFileStorage(\n name?: string,\n): { adapter: FileStorageAdapter; error?: undefined } | { adapter?: undefined; error: string } {\n const app = useApp();\n const registry = app.getService<FileStorageRegistry>(FILE_STORAGE_SERVICE);\n if (!registry) {\n return {\n error: 'No file storage registered — add fileStoragePlugin({ default: … }) to defineApp',\n };\n }\n // `has` before `get`, because `get` is the thing that throws.\n if (name != null && !registry.has(name)) {\n return { error: `Unknown file storage '${name}'. Registered: ${registry.names().join(', ')}.` };\n }\n return { adapter: registry.get(name) };\n}\n","'use client';\nimport type { FileRef } from '@burojs/file-storage';\nimport * as React from 'react';\nimport { useFileStorage } from './use-file-storage.js';\n\nexport type FileItemStatus =\n | 'deferred'\n | 'queued'\n | 'uploading'\n | 'uploaded'\n | 'failed'\n | 'rejected';\n\nexport interface FileItem {\n ref: FileRef;\n status: FileItemStatus;\n /** 0..1 while uploading; 1 once done. */\n progress?: number;\n error?: string;\n}\n\nexport interface UseFileFieldArgs {\n resource: string;\n field: string;\n multiple?: boolean;\n value: unknown;\n onChange: (columnValue: unknown) => void;\n record?: Record<string, unknown>;\n storage?: string;\n defer?: boolean;\n orphans?: 'best-effort' | 'keep';\n accept?: string[];\n maxSize?: number;\n /** Uploads in flight at once. Default 3. */\n concurrency?: number;\n}\n\nexport interface UseFileFieldResult {\n items: FileItem[];\n add: (files: File[]) => void;\n remove: (localId: string) => void;\n retry: (localId: string) => void;\n abort: (localId: string) => void;\n reorder: (from: number, to: number) => void;\n busy: boolean;\n}\n\n/** Match a file against HTML `accept` tokens. Empty list matches everything. */\nexport function matchesAccept(file: File, accept: string[]): boolean {\n if (accept.length === 0) return true;\n const mime = (file.type || '').toLowerCase();\n const name = file.name.toLowerCase();\n return accept.some((raw) => {\n const token = raw.trim().toLowerCase();\n if (!token) return false;\n if (token.startsWith('.')) return name.endsWith(token);\n if (token.endsWith('/*')) return mime.startsWith(token.slice(0, -1));\n return mime === token;\n });\n}\n\nexport function formatBytes(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes < 0) return `${bytes}B`;\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n if (bytes < 1024 ** 3) return `${(bytes / 1024 / 1024).toFixed(1)}MB`;\n return `${(bytes / 1024 ** 3).toFixed(2)}GB`;\n}\n\n/** Sentinel: we have not emitted anything yet, so nothing can match. */\nconst NOTHING_EMITTED = Symbol('buro.fileField.nothingEmitted');\n\n/**\n * A cheap structural fingerprint of a column value, used only to decide\n * whether an EXTERNAL change arrived. A controlled form hands back a fresh\n * literal every render, so reference identity alone would reseed forever.\n *\n * ⚠️ File-aware on purpose. `JSON.stringify` renders a File as `{}`, so two\n * genuinely different Files fingerprint identically — and in the fused\n * pipeline a column value really can carry raw Files. Without this branch a\n * newly picked file silently fails to appear.\n */\nfunction valueKey(value: unknown): string {\n const seen = new WeakSet<object>();\n try {\n return (\n JSON.stringify(value, (_k, v) => {\n if (typeof File !== 'undefined' && v instanceof File) {\n return `File:${v.name}:${v.size}:${v.lastModified}`;\n }\n if (v && typeof v === 'object') {\n if (seen.has(v)) return '[circular]';\n seen.add(v);\n }\n return v;\n }) ?? 'undefined'\n );\n } catch {\n // Never let fingerprinting break a render.\n return String(value);\n }\n}\n\nexport function useFileField(args: UseFileFieldArgs): UseFileFieldResult {\n const adapter = useFileStorage(args.storage);\n // `defer: true` is only meaningful for a fused-pipeline storage: there the\n // raw File rides inside the record mutation itself (`withFileStorage`\n // encodes it at submit time), so \"hold the bytes until submit\" is simply\n // what the pipeline already does — the flag changes nothing.\n //\n // For an immediate/handshake/resumable pipeline there is no equivalent.\n // Nothing on this branch flushes a deferred ref through `adapter.upload`\n // before the form's mutation runs — `runUpload` only fires for\n // `status === 'queued'`, and every mapper's `write` (scalarHandle included)\n // omits a handle-less ref rather than writing a placeholder. Silently\n // honouring `defer: true` here would upload nothing, emit no error, and\n // hand the mutation a column value with the file quietly missing. Fail\n // loudly at declaration time instead of shipping that.\n if (args.defer === true && adapter.pipeline !== 'fused') {\n throw new Error(\n `f.file({ defer: true }): not implemented for storage \"${args.storage ?? 'default'}\" (pipeline: \"${adapter.pipeline}\"). Deferred upload only works for a fused-pipeline storage (e.g. inline, PocketBase), where the file rides inside the record mutation itself. There is no form-submit integration on this branch that flushes a deferred ref through adapter.upload before the mutation runs, so honouring this flag would silently drop the file. Remove \\`defer: true\\` from this field — immediate/handshake/resumable pipelines already upload on pick.`,\n );\n }\n const deferred = adapter.pipeline === 'fused';\n const orphanPolicy = args.orphans ?? adapter.orphans ?? 'best-effort';\n const concurrency = args.concurrency ?? 3;\n\n // The normalized domain FileRef[] is the source of truth for what is SAVED;\n // provider mapping and canonical codecs have already run outside React.\n // `items` tracks the\n // in-flight world on top of it. Reading the column on every render would\n // discard upload state, so it seeds state once per distinct incoming value.\n //\n // \"Distinct\" is judged structurally, not referentially: a controlled form\n // typically hands back a brand-new array/object each render even when the\n // logical value hasn't changed (`value: []` in the caller re-creates that\n // array every time). Comparing by `Object.is` alone would treat every\n // render as a new value and reseed forever — an infinite render loop the\n // moment nothing is in flight — so the guard also checks a structural\n // fingerprint (`valueKey`). But a fingerprint match is not enough either:\n // whatever we last handed to `onChange` need not be treated as an external\n // change (`lastEmitted`).\n const [items, setItems] = React.useState<FileItem[]>(() =>\n readDomainRefs(args.value).map((ref) => ({ ref, status: 'uploaded' as const })),\n );\n const lastSeenValue = React.useRef(args.value);\n // Whatever we last handed to onChange. A controlled form hands it straight\n // back as `value`; avoid reseeding from our own output.\n const lastEmitted = React.useRef<unknown>(NOTHING_EMITTED);\n\n if (\n !Object.is(lastSeenValue.current, args.value) &&\n !Object.is(lastEmitted.current, args.value) &&\n valueKey(lastSeenValue.current) !== valueKey(args.value) &&\n !items.some(isInFlight)\n ) {\n lastSeenValue.current = args.value;\n setItems(readDomainRefs(args.value).map((ref) => ({ ref, status: 'uploaded' as const })));\n }\n\n const controllers = React.useRef(new Map<string, AbortController>());\n const pendingFiles = React.useRef(new Map<string, File>());\n // Handles uploaded during THIS editing session that the record does not own\n // yet. Cleared on submit; deleted on unmount under best-effort.\n const unsaved = React.useRef(new Set<string>());\n\n const itemsRef = React.useRef(items);\n itemsRef.current = items;\n\n // Single synchronous choke point every mutator below goes through, instead\n // of each calling `setItems` with its own ad hoc updater.\n //\n // `itemsRef.current` is updated HERE, synchronously, at the moment of the\n // mutation — not just once per render the way the top-of-body\n // `itemsRef.current = items` mirror is. That is what makes it safe for\n // `add`/`remove`/`reorder`/`runUpload`'s success handler to read\n // `itemsRef.current` as \"the current state\" and compute `next` from it\n // directly: with `concurrency > 1`, several `runUpload` calls can resolve\n // one after another with no render in between (React does not necessarily\n // re-render synchronously between two `setState` calls from two separate\n // promise continuations), so a version of `commit` that only wrote `items`\n // via `setState` and left the ref to catch up on the next render would let\n // the second resolution overwrite the first's change — a lost update\n // (`busy` never clears). Reading and writing `itemsRef.current` in the same\n // synchronous stretch of code (no `await` in between) closes that gap: JS's\n // single-threaded execution means nothing else can run between the read\n // and the write, however many async continuations are pending.\n const commit = React.useCallback((next: FileItem[]) => {\n itemsRef.current = next;\n setItems(next);\n }, []);\n\n const emit = React.useCallback(\n (next: FileItem[]) => {\n const refs = next\n .filter((i) => i.status === 'uploaded' || i.status === 'deferred')\n .map((i) => i.ref);\n // Remember it by reference so the value coming back from the form is\n // recognised as our own and never reseeds the list.\n lastEmitted.current = refs;\n args.onChange(refs);\n },\n [args.onChange],\n );\n\n const patch = React.useCallback(\n (localId: string, next: Partial<FileItem>) => {\n commit(itemsRef.current.map((i) => (i.ref.localId === localId ? { ...i, ...next } : i)));\n },\n [commit],\n );\n\n const runUpload = React.useCallback(\n async (localId: string) => {\n const file = pendingFiles.current.get(localId);\n if (!file) return;\n const controller = new AbortController();\n controllers.current.set(localId, controller);\n patch(localId, { status: 'uploading', progress: 0, error: undefined });\n try {\n const ref = await adapter.upload(file, {\n signal: controller.signal,\n onProgress: (loaded, total) =>\n patch(localId, { progress: total > 0 ? loaded / total : 0 }),\n });\n if (ref.handle) unsaved.current.add(ref.handle);\n pendingFiles.current.delete(localId);\n // Compute `next` from the ref, `commit` it, THEN `emit` — both plain\n // calls in the function body, never from inside a `setItems` updater.\n // `emit` calls `args.onChange`, which touches the PARENT form's\n // state; calling that from inside a state updater is exactly what\n // produced \"Cannot update a component while rendering a different\n // component\" — React may invoke an updater more than once\n // (StrictMode's deliberate double-invoke), which would double-fire\n // `onChange`, and it is simply not a safe place for a side effect\n // touching a different component while this one is still being\n // reconciled.\n const next = itemsRef.current.map((i) =>\n i.ref.localId === localId\n ? { ref: { ...ref, localId }, status: 'uploaded' as const, progress: 1 }\n : i,\n );\n commit(next);\n emit(next);\n } catch (e) {\n const err = e as Error;\n patch(localId, {\n status: err.name === 'AbortError' ? 'rejected' : 'failed',\n error: err.message,\n });\n } finally {\n controllers.current.delete(localId);\n }\n },\n [adapter, commit, emit, patch],\n );\n\n // Pump the queue: start uploads until `concurrency` are in flight.\n React.useEffect(() => {\n const uploading = items.filter((i) => i.status === 'uploading').length;\n const slots = concurrency - uploading;\n if (slots <= 0) return;\n for (const item of items.filter((i) => i.status === 'queued').slice(0, slots)) {\n void runUpload(item.ref.localId);\n }\n }, [items, concurrency, runUpload]);\n\n const add = React.useCallback(\n (files: File[]) => {\n const additions: FileItem[] = files.map((file) => {\n const localId = `local-${Math.random().toString(36).slice(2)}-${file.name}`;\n const shared = { localId, name: file.name, mime: file.type || undefined, size: file.size };\n\n if (args.maxSize != null && file.size > args.maxSize) {\n return {\n ref: shared,\n status: 'rejected',\n error: `File exceeds the maximum size of ${formatBytes(args.maxSize)} (got ${formatBytes(file.size)})`,\n };\n }\n if (args.accept?.length && !matchesAccept(file, args.accept)) {\n return {\n ref: shared,\n status: 'rejected',\n error: `This file type isn't accepted. Accepted: ${args.accept.join(', ')}`,\n };\n }\n if (deferred) {\n return { ref: { ...shared, pending: file }, status: 'deferred' };\n }\n pendingFiles.current.set(localId, file);\n return { ref: shared, status: 'queued' };\n });\n\n const next = args.multiple ? [...itemsRef.current, ...additions] : additions.slice(-1);\n commit(next);\n if (additions.some((a) => a.status === 'deferred')) emit(next);\n },\n [args.accept, args.maxSize, args.multiple, deferred, commit, emit],\n );\n\n const remove = React.useCallback(\n (localId: string) => {\n const target = itemsRef.current.find((i) => i.ref.localId === localId);\n controllers.current.get(localId)?.abort();\n pendingFiles.current.delete(localId);\n // Removing a file the record never owned: drop it from storage too,\n // since nothing else will ever point at it.\n if (target?.ref.handle && unsaved.current.has(target.ref.handle)) {\n unsaved.current.delete(target.ref.handle);\n if (orphanPolicy === 'best-effort') void adapter.remove?.(target.ref).catch(() => {});\n }\n const next = itemsRef.current.filter((i) => i.ref.localId !== localId);\n commit(next);\n emit(next);\n },\n [adapter, commit, emit, orphanPolicy],\n );\n\n const retry = React.useCallback(\n (localId: string) => {\n patch(localId, { status: 'queued', error: undefined });\n },\n [patch],\n );\n\n const abort = React.useCallback((localId: string) => {\n controllers.current.get(localId)?.abort();\n }, []);\n\n const reorder = React.useCallback(\n (from: number, to: number) => {\n const next = [...itemsRef.current];\n const [moved] = next.splice(from, 1);\n if (moved) next.splice(to, 0, moved);\n commit(next);\n emit(next);\n },\n [commit, emit],\n );\n\n // Orphan sweep. Best effort by design and documented as such: a closed tab\n // never runs this.\n React.useEffect(() => {\n return () => {\n for (const controller of controllers.current.values()) controller.abort();\n if (orphanPolicy !== 'best-effort' || !adapter.remove) return;\n for (const item of itemsRef.current) {\n if (item.ref.handle && unsaved.current.has(item.ref.handle)) {\n void adapter.remove(item.ref).catch(() => {});\n }\n }\n };\n }, [adapter, orphanPolicy]);\n\n const busy = items.some(isInFlight);\n return { items, add, remove, retry, abort, reorder, busy };\n}\n\nfunction isInFlight(item: FileItem): boolean {\n return item.status === 'queued' || item.status === 'uploading';\n}\n\nfunction readDomainRefs(value: unknown): FileRef[] {\n return isFileRefs(value) ? value : [];\n}\n\nfunction isFileRefs(value: unknown): value is FileRef[] {\n return (\n Array.isArray(value) &&\n value.every(\n (entry) =>\n entry !== null &&\n typeof entry === 'object' &&\n typeof (entry as { localId?: unknown }).localId === 'string',\n )\n );\n}\n","interface Entry {\n url: string;\n /** Epoch ms. Absent means permanent. */\n expiresAt?: number;\n}\n\nexport interface UrlCache {\n get(key: string): string | undefined;\n set(key: string, url: string, expiresAt?: number): void;\n invalidate(key: string): void;\n /** Drop every entry. Mainly for test isolation of the module-scoped cache. */\n clear(): void;\n /**\n * Epoch ms of the last `set()` for this key, or 0 if it was never resolved\n * (or was explicitly `invalidate`d/`clear`ed since).\n *\n * Kept OUTSIDE the evictable entry itself: a URL that arrives already\n * expired — a few ms of clock skew between signer and client is enough —\n * must still register as \"just resolved\" even though `get()` will evict it\n * on the very next read. Callers use this to cool down before resolving\n * the same key again, rather than resolving it forever in a tight loop.\n */\n lastResolvedAt(key: string): number;\n /**\n * True when this key currently holds a SIGNED entry (has an `expiresAt`),\n * whether or not that expiry has already passed. Does not evict — unlike\n * `get()`, checking this never has the side effect of dropping a stale\n * entry. Lets a caller skip scanning entries that can never expire (a\n * permanent, string-form `ResolvedUrl` has none) without forcing eviction\n * as a side effect of merely asking.\n */\n isSigned(key: string): boolean;\n}\n\n/** Entries less than this old are not eligible to be re-resolved. */\nexport const RESOLVE_COOLDOWN_MS = 1000;\n\n/**\n * Module-scoped so two components showing the same file resolve it once.\n *\n * An expired entry is reported as ABSENT rather than stale: a signed URL past\n * its expiry is not a slightly old URL, it is a broken image.\n */\nexport function createUrlCache(): UrlCache {\n const entries = new Map<string, Entry>();\n const resolvedAt = new Map<string, number>();\n return {\n get(key) {\n const found = entries.get(key);\n if (!found) return undefined;\n if (found.expiresAt != null && found.expiresAt <= Date.now()) {\n entries.delete(key);\n return undefined;\n }\n return found.url;\n },\n set(key, url, expiresAt) {\n entries.set(key, { url, ...(expiresAt != null ? { expiresAt } : {}) });\n resolvedAt.set(key, Date.now());\n },\n invalidate(key) {\n entries.delete(key);\n resolvedAt.delete(key);\n },\n clear() {\n entries.clear();\n resolvedAt.clear();\n },\n lastResolvedAt(key) {\n return resolvedAt.get(key) ?? 0;\n },\n isSigned(key) {\n return entries.get(key)?.expiresAt != null;\n },\n };\n}\n\nexport const sharedUrlCache = createUrlCache();\n","'use client';\nimport type { FileRef, ResolveCtx } from '@burojs/file-storage';\nimport * as React from 'react';\nimport { RESOLVE_COOLDOWN_MS, sharedUrlCache } from './url-cache.js';\nimport { useOptionalFileStorage } from './use-file-storage.js';\n\nexport interface UseFileUrlsOpts extends ResolveCtx {\n storage?: string;\n /** Set false to resolve nothing — e.g. a cell scrolled out of view. */\n enabled?: boolean;\n}\n\nexport interface UseFileUrlsResult {\n /** Keyed by `localId`. `undefined` means unresolved or unresolvable. */\n urls: Record<string, string | undefined>;\n pending: boolean;\n /** Drop the cached URL for one ref and resolve it again. */\n refresh: (localId: string) => void;\n /**\n * Set when `opts.storage` names nothing registered. Resolution is skipped\n * (every entry in `urls` stays `undefined`) rather than throwing — see the\n * note on the hook.\n */\n storageError?: string;\n}\n\nfunction cacheKey(storage: string | undefined, ref: FileRef, opts: UseFileUrlsOpts): string {\n const v = opts.variant ? `${opts.variant.width ?? ''}x${opts.variant.height ?? ''}` : '';\n return [storage ?? 'default', ref.handle, v, opts.disposition ?? '', opts.record?.id ?? ''].join(\n '|',\n );\n}\n\n/**\n * Resolve display URLs for a list of refs in ONE pass.\n *\n * ⚠️ \"One pass\" means PARALLEL, not batched — this is NOT what relation\n * aggregation does for relation cells. Fifty rows issue fifty concurrent\n * `resolveUrl` calls via `Promise.all`, deduplicated against the shared cache\n * (an already-resolved or in-flight handle costs nothing extra). A true\n * single-request batch would need a port-level `resolveUrls(refs[])` entry\n * point — `resolveUrl` is single-ref by signature, and no adapter here\n * implements anything else. Cache-dedup keeps the common case (a list\n * re-rendering with mostly-already-resolved rows) cheap; it does not turn N\n * network calls into one.\n *\n * Signed URLs are re-resolved when the cache reports them expired, and a\n * caller whose <img> failed can force one retry through `refresh`.\n *\n * An unregistered `opts.storage` REPORTS rather than throws. This is a read\n * path: callers render one of these per row, inside a single list render with\n * no error boundary between the rows, so throwing would replace a table with\n * a blank screen over one misspelled name. The caller gets `storageError` and\n * decides how loud to be.\n */\nexport function useFileUrls(refs: FileRef[], opts: UseFileUrlsOpts): UseFileUrlsResult {\n const { adapter, error: storageError } = useOptionalFileStorage(opts.storage);\n const [urls, setUrls] = React.useState<Record<string, string | undefined>>({});\n const [pending, setPending] = React.useState(false);\n const [nonce, setNonce] = React.useState(0);\n\n // Whether ANY currently-resolvable ref's cache entry is signed (carries a\n // TTL). Read by the watchdog below to skip its per-render scan entirely\n // when nothing displayed can ever expire — a list of fifty permanent URLs\n // re-rendering on every mousemove of a column-resize drag has no business\n // building fifty cache keys and doing fifty lookups per frame.\n const hasSignedRef = React.useRef(false);\n\n const resolvable = refs.filter((r) => r.handle != null);\n // A stable signature so the effect fires on real change, not on a new array.\n const signature = resolvable.map((r) => `${r.localId}:${r.handle}`).join(',');\n const optsKey = [\n opts.storage,\n opts.variant?.width,\n opts.variant?.height,\n opts.disposition,\n opts.resource,\n (opts.record as { id?: unknown } | undefined)?.id,\n ].join('|');\n\n // `signature` and `optsKey` are deliberate stand-ins for `refs`/`opts` — see\n // the comment below the dependency array. Listing the raw fields too would\n // fire this effect on every render, since `refs`/`opts` are new references\n // each time.\n // biome-ignore lint/correctness/useExhaustiveDependencies: see comment above\n React.useEffect(() => {\n // No adapter means nothing to resolve WITH — same shape as \"disabled\",\n // not an error to throw. The caller renders `storageError`.\n if (opts.enabled === false || resolvable.length === 0 || !adapter) {\n setPending(false);\n hasSignedRef.current = false;\n return;\n }\n let cancelled = false;\n\n const refreshSignedFlag = () => {\n hasSignedRef.current = resolvable.some((ref) =>\n sharedUrlCache.isSigned(cacheKey(opts.storage, ref, opts)),\n );\n };\n\n // Cache first: anything already known needs no round trip at all.\n const seeded: Record<string, string | undefined> = {};\n const misses: FileRef[] = [];\n for (const ref of resolvable) {\n const hit = sharedUrlCache.get(cacheKey(opts.storage, ref, opts));\n if (hit) seeded[ref.localId] = hit;\n else misses.push(ref);\n }\n if (Object.keys(seeded).length > 0) {\n setUrls((current) => ({ ...current, ...seeded }));\n }\n refreshSignedFlag();\n if (misses.length === 0) {\n setPending(false);\n return;\n }\n\n setPending(true);\n void Promise.all(\n misses.map(async (ref) => {\n try {\n const resolved = await adapter.resolveUrl(ref, {\n variant: opts.variant,\n disposition: opts.disposition,\n resource: opts.resource,\n record: opts.record,\n });\n const url = typeof resolved === 'string' ? resolved : resolved.url;\n const expiresAt = typeof resolved === 'string' ? undefined : resolved.expiresAt;\n sharedUrlCache.set(cacheKey(opts.storage, ref, opts), url, expiresAt);\n return [ref.localId, url] as const;\n } catch {\n // A missing or forbidden file renders a placeholder; it never throws\n // through a list of fifty rows.\n return [ref.localId, undefined] as const;\n }\n }),\n ).then((pairs) => {\n if (cancelled) return;\n setUrls((current) => ({ ...current, ...Object.fromEntries(pairs) }));\n setPending(false);\n // The freshly resolved entries just landed in the cache with their real\n // expiresAt — recompute now that we actually know.\n refreshSignedFlag();\n });\n\n return () => {\n cancelled = true;\n };\n // `signature` and `optsKey` stand in for the array and the options object,\n // both of which are new references on every render.\n }, [signature, optsKey, nonce, adapter, opts.enabled]);\n\n // The resolution effect above only re-enters on a real change to `signature`,\n // `optsKey`, `nonce` or `adapter` — none of which move on their own when a\n // signed URL's clock runs out. This watchdog runs on every render instead,\n // and only acts when a URL this hook is CURRENTLY DISPLAYING has gone stale\n // in the cache (i.e. `UrlCache.get` evicted it as expired). Clearing it and\n // bumping `nonce` hands the actual re-resolution back to the effect above,\n // so there is still exactly one code path that ever calls `resolveUrl`.\n React.useEffect(() => {\n if (opts.enabled === false) return;\n // Nothing displayed can expire — skip the per-ref cacheKey+lookup scan\n // entirely. This is the common case on every render that ISN'T about a\n // freshly (re)resolved batch, e.g. a list re-rendering during a\n // column-resize drag.\n if (!hasSignedRef.current) return;\n const stale = resolvable.filter((ref) => {\n if (urls[ref.localId] == null) return false;\n const key = cacheKey(opts.storage, ref, opts);\n // A URL that arrives already expired — a few ms of clock skew between\n // signer and client is enough — must not be evicted and re-resolved on\n // the very next render: that setUrls call is itself a render, on which\n // this watchdog would find it \"expired\" again, forever. A key inside\n // its cooldown is left alone even if the cache reports it absent; the\n // next render after the cooldown lapses will pick it up.\n if (Date.now() - sharedUrlCache.lastResolvedAt(key) < RESOLVE_COOLDOWN_MS) return false;\n return sharedUrlCache.get(key) === undefined;\n });\n if (stale.length === 0) return;\n setUrls((current) => {\n const next = { ...current };\n for (const ref of stale) next[ref.localId] = undefined;\n return next;\n });\n setNonce((n) => n + 1);\n });\n\n const refresh = React.useCallback(\n (localId: string) => {\n const ref = refs.find((r) => r.localId === localId);\n if (ref) sharedUrlCache.invalidate(cacheKey(opts.storage, ref, opts));\n setUrls((current) => ({ ...current, [localId]: undefined }));\n setNonce((n) => n + 1);\n },\n [refs, opts],\n );\n\n return { urls, pending, refresh, storageError };\n}\n","import type { EnumValue } from '@burojs/core';\nimport { useEffect, useState } from 'react';\nimport { useApp } from './use-app.js';\n\n/**\n * Result returned by `useEnumValues`. Mirrors the standard\n * `{ data | isLoading | error }` shape used by data-provider hooks.\n */\nexport interface UseEnumValuesResult {\n /** Resolved values, or `undefined` while loading or on error. */\n values: readonly EnumValue[] | undefined;\n /** True from first render until the loader resolves (or rejects). */\n isLoading: boolean;\n /** Set when the loader rejects OR when the enum is not registered. */\n error: Error | null;\n}\n\n/**\n * Resolve an enum's values from the app registry. Static enums (declared\n * with `defineEnum({ values: [...] })`) resolve synchronously on first\n * render. Loader-backed enums (declared with `defineEnum({ loader })`)\n * transition through `isLoading: true` before settling.\n *\n * Caching: backed by `app.registry.enums.getValuesAsync(name)` which is\n * single-flight per enum name. Mounting `<EnumBadge>` and `<EnumPicker>`\n * for the same enum simultaneously triggers exactly one loader call.\n *\n * Error policy: an unregistered enum surfaces as\n * `{ values: undefined, isLoading: false, error: Error('not registered') }`.\n * The bundled `<EnumBadge>` etc primitives degrade gracefully on error\n * (render the raw value as plain text) — adopters writing custom\n * primitives can do the same.\n */\nexport function useEnumValues(enumName: string): UseEnumValuesResult {\n const app = useApp();\n // Synchronous fast-path: if the enum is registered with static values\n // we can return them on the very first render with no loading flicker.\n // This matches the v0 (pre-runtime-load) behaviour of `<EnumBadge>` so\n // the regression e2e suites stay green without changes.\n const def = app.registry.enums.get(enumName);\n const initialValues = def?.values;\n\n const [values, setValues] = useState<readonly EnumValue[] | undefined>(initialValues);\n const [isLoading, setIsLoading] = useState<boolean>(initialValues === undefined);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n // If we already have static values from the synchronous path, no\n // async work needed for the static case; effect still runs in case\n // enumName changed and the new enum is loader-backed.\n const currentDef = app.registry.enums.get(enumName);\n if (currentDef?.values !== undefined) {\n setValues(currentDef.values);\n setIsLoading(false);\n setError(null);\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n setError(null);\n setValues(undefined);\n\n app.registry.enums\n .getValuesAsync(enumName)\n .then((next) => {\n if (cancelled) return;\n setValues(next);\n setIsLoading(false);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setValues(undefined);\n setIsLoading(false);\n setError(err instanceof Error ? err : new Error(String(err)));\n });\n\n return () => {\n cancelled = true;\n };\n }, [app, enumName]);\n\n return { values, isLoading, error };\n}\n","import type {\n ErasedResourceHandle,\n FilterExpression,\n FilterGroup,\n SortExpression,\n} from '@burojs/core';\nimport { defineUiSetting, isFilterGroup } from '@burojs/core';\n\n/**\n * The first built-in UI setting type (spec\n * `docs/superpowers/specs/2026-08-02-ui-config-catalog-design.md` §12):\n * `buro/saved-view`, a `collection` keyed by `{ resource }`.\n *\n * `use-saved-views.ts` is the ONLY intended consumer — it projects this\n * setting's live collection into the pre-existing `useSavedViews` compat\n * surface (`adopterViews` / `userViews` / `entries` / the mutators). This\n * module owns just the typed contract: params, value, and validation.\n */\n\n/**\n * Params selecting one saved-view collection: one per resource, matching\n * the legacy `buro:saved-views:<resource>` `localStorage` key's own\n * granularity.\n */\nexport interface SavedViewSettingParams {\n readonly resource: string;\n}\n\n/**\n * Portable value persisted for one saved-view entry: everything needed to\n * REPLACE the list page's URL state on apply, except `page`.\n *\n * A view describes list *configuration*, not a position within one query's\n * results — applying a view always opens page one (spec §12; see\n * `apply-view-to-url-state.ts`). `page` is therefore not a field of this\n * value at all; `parseValue` below tolerates (and drops) a legacy stored\n * value that still carries one rather than rejecting it, so an as-is\n * legacy `SavedViewDef.state` read from `localStorage` can be handed\n * straight to `create()` during migration with no separate stripping\n * step.\n *\n * Filters and sort are the SAME portable, provider-facing \"wire form\"\n * `ResourceUrlState` itself uses — no domain conversion happens at this\n * boundary. Field codecs, once introduced, apply between the wire form and\n * the domain form elsewhere; a saved view is never rewritten just because\n * a codec is added later (spec §12).\n */\nexport interface SavedViewSettingValue {\n readonly filters?: readonly FilterExpression<ErasedResourceHandle>[];\n /**\n * The filter-builder group (Task 7, SP1). Absent on a view saved before\n * the builder shipped — `applyViewToUrlState` substitutes\n * `EMPTY_FILTER_GROUP` for a missing value, so no migration is needed;\n * this setting simply passes through whatever `buildCleanState` gives it.\n */\n readonly filterGroup?: FilterGroup;\n readonly sort?: SortExpression<ErasedResourceHandle>;\n readonly pageSize?: number;\n readonly search?: string;\n readonly visibleColumns?: string[] | null;\n}\n\nfunction parseSavedViewParams(input: unknown): SavedViewSettingParams {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n throw new TypeError('[buro/saved-view] params must be an object with a \"resource\" string.');\n }\n const resource = (input as Record<string, unknown>).resource;\n if (typeof resource !== 'string' || resource.length === 0) {\n throw new TypeError('[buro/saved-view] params.resource must be a non-empty string.');\n }\n return { resource };\n}\n\n/**\n * Validates and normalizes a raw candidate into a `SavedViewSettingValue`.\n *\n * Shallow validation only — same posture the legacy hook's `isSavedViewDef`\n * already used: the outer shape of `filters` / `sort` is checked (must be\n * an array), but the AST entries inside are not deeply validated here (the\n * portable clone boundary run by the store bounds and sanitizes the full\n * value regardless, and a malformed nested filter surfaces via the\n * existing render-time guards, same as before this task).\n *\n * Unknown keys — most notably a legacy `page` carried over from a\n * pre-migration `SavedViewDef.state` — are silently DROPPED, never\n * rejected. Never throws for a well-formed-but-unfamiliar shape; only a\n * non-object input, or a KNOWN key with the wrong runtime type, is\n * rejected (which the store turns into a `rejected` mutation result, never\n * a thrown error reaching a caller — see `store.ts`'s\n * `parseMutationValue`).\n */\nfunction parseSavedViewValue(input: unknown): SavedViewSettingValue {\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n throw new TypeError('[buro/saved-view] value must be an object.');\n }\n const raw = input as Record<string, unknown>;\n const value: {\n filters?: readonly FilterExpression<ErasedResourceHandle>[];\n filterGroup?: FilterGroup;\n sort?: SortExpression<ErasedResourceHandle>;\n pageSize?: number;\n search?: string;\n visibleColumns?: string[] | null;\n } = {};\n\n if (raw.filters !== undefined) {\n if (!Array.isArray(raw.filters)) {\n throw new TypeError('[buro/saved-view] value.filters must be an array.');\n }\n value.filters = raw.filters as readonly FilterExpression<ErasedResourceHandle>[];\n }\n if (raw.filterGroup !== undefined) {\n if (!isFilterGroup(raw.filterGroup)) {\n throw new TypeError('[buro/saved-view] value.filterGroup must be a {join, rows} group.');\n }\n value.filterGroup = raw.filterGroup;\n }\n if (raw.sort !== undefined) {\n if (!Array.isArray(raw.sort)) {\n throw new TypeError('[buro/saved-view] value.sort must be an array.');\n }\n value.sort = raw.sort as SortExpression<ErasedResourceHandle>;\n }\n if (raw.pageSize !== undefined) {\n if (typeof raw.pageSize !== 'number') {\n throw new TypeError('[buro/saved-view] value.pageSize must be a number.');\n }\n value.pageSize = raw.pageSize;\n }\n if (raw.search !== undefined) {\n if (typeof raw.search !== 'string') {\n throw new TypeError('[buro/saved-view] value.search must be a string.');\n }\n value.search = raw.search;\n }\n if (raw.visibleColumns !== undefined) {\n if (raw.visibleColumns !== null && !Array.isArray(raw.visibleColumns)) {\n throw new TypeError('[buro/saved-view] value.visibleColumns must be an array or null.');\n }\n value.visibleColumns = raw.visibleColumns as string[] | null;\n }\n // `page` (legacy) and any other unrecognized key are intentionally NOT\n // copied through — dropped, never rejected. See the module doc above.\n\n return value;\n}\n\nexport const savedViewSetting = defineUiSetting({\n id: 'buro/saved-view',\n cardinality: 'collection' as const,\n currentVersion: 1,\n parseParams: parseSavedViewParams,\n parseValue: parseSavedViewValue,\n});\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n SavedViewDef,\n UiSettingEntryPermissions,\n UiSettingMutationResult,\n UiSettingScope,\n UiSettingsIssue,\n} from '@burojs/core';\nimport { useApp } from '../use-app.js';\nimport type { ResourceUrlState } from '../url-state/codec.js';\nimport { LOCAL_USER_SCOPE_ID } from '../../ui-settings/local-storage-adapter.js';\nimport { useUiSettings } from '../../ui-settings/use-ui-settings.js';\nimport { savedViewSetting, type SavedViewSettingValue } from './saved-view-setting.js';\n\n/**\n * `useSavedViews` — compatibility PROJECTION over the universal UI settings\n * store (Task 8, spec §12). This hook is the ONLY place `SavedViewDef`\n * (the `@burojs/core` type) is ever constructed from an adapter entry —\n * everywhere else in the framework talks either raw adopter config\n * (`def.views.list.savedViews`) or the typed `savedViewSetting` collection.\n *\n * ### What moved, and what didn't\n *\n * User-saved views used to live directly in `localStorage`, read/written\n * synchronously by this hook. They now live in a `buro/saved-view`\n * collection opened through `useUiSettings` — by default backed by the\n * SAME browser `localStorage`, via the default local-storage\n * `UiSettingsAdapter` that `@burojs/react` auto-wires when a\n * `BuroProvider` has no `uiSettings` prop (Task 7).\n * An adopter supplying an explicit adapter (a backend, a multi-scope\n * aggregator, …) becomes the sole mutable authority for saved views —\n * nothing here writes to `localStorage` in that case, see \"Legacy\n * migration\" below.\n *\n * `adopterViews` — the static, read-only views declared on\n * `def.views.list.savedViews` — are UNCHANGED: they never went through\n * `localStorage` and don't go through the settings store either. They\n * continue to sit ALONGSIDE whatever the store returns, exactly as before.\n *\n * ### Legacy migration\n *\n * Entries previously written under `buro:saved-views:<resource>` (this\n * hook's pre-Task-8 format) must not vanish the moment an app upgrades.\n * The migration contract (spec §12):\n *\n * 1. **Visible before migration.** While a legacy entry hasn't been\n * migrated yet, it still appears in `userViews` (merged with whatever\n * the store already has).\n * 2. **Migrates on the first successful new-format persistence.** The\n * first call to `saveCurrentAsView` / `renameUserView` /\n * `deleteUserView` that reaches this hook first replays every\n * still-pending legacy entry into the store via `create()`, THEN\n * performs the caller's own operation. A legacy `page` field (if\n * present) is silently dropped by `savedViewSetting.parseValue` — see\n * that module's doc.\n * 3. **Old data is never deleted before the new write succeeds.** Each\n * legacy entry is removed from the `localStorage` envelope only\n * immediately AFTER its own `create()` call reports `created` /\n * `updated` — never speculatively, and never in a batch that could\n * leave a gap if the process is interrupted midway. If a migration\n * `create()` is `rejected` / `conflict`, migration stops there; the\n * untouched remainder (that entry and everything after it) stays in\n * `localStorage` for a retry on the next mutation.\n * 4. **Never mirrored back.** Once an entry is migrated, this hook never\n * writes it (or anything else) back to the legacy `localStorage` key\n * — the settings store is the sole mutable copy from then on.\n *\n * Migration only ever runs against the FRAMEWORK's own default local\n * scope (`LOCAL_USER_SCOPE_ID` — see `isLocalScope` below). When an\n * adopter mounts an explicit `uiSettings` store whose write scopes don't\n * include it, legacy `localStorage` data is left untouched — read, shown,\n * or migrated by nobody. Silently pushing a user's private local browser\n * data into a newly-mounted, possibly shared/backend adapter without an\n * explicit adopter-authored migration would be a far more surprising\n * failure mode than leaving inert bytes on disk; the adopter's own\n * explicit adapter is \"the only mutable settings authority\" (spec §12).\n *\n * ### Async mutation surface\n *\n * `saveCurrentAsView` / `renameUserView` / `deleteUserView` / `forkUserView`\n * are all `Promise`-returning: they `await` the store's mutation outcome and\n * throw (i.e. reject) on `rejected` / `conflict`, mirroring the old\n * contract's synchronous throw-on-quota-exceeded as closely as an\n * inherently async boundary allows. `saveCurrentAsView` still throws\n * synchronously-as-a-rejection for an empty label (defensive\n * belt-and-braces, unchanged from before).\n *\n * ### Scope/permission surface (Task 9)\n *\n * `entries` carries each store entry's `scope`/`permissions`; `writeScopes`\n * is the store's own answer to \"where may the current user create a NEW\n * entry\" (spec §5); `issues` and `pending` are the store's own\n * `snapshot.issues`/`snapshot.pending`, passed through unchanged. None of\n * these three are specific to migration or to any one adapter — they are\n * plain projections of the live `UiSettingsSnapshot`, present regardless of\n * whether legacy `localStorage` migration ever runs.\n */\n\nconst LEGACY_STORAGE_KEY_PREFIX = 'buro:saved-views:';\nconst LEGACY_STORAGE_VERSION = 1 as const;\n\n/** Wrapped legacy persisted shape — unchanged from the pre-Task-8 format. */\ninterface LegacyStoredEnvelope {\n version: typeof LEGACY_STORAGE_VERSION;\n views: SavedViewDef[];\n}\n\n/**\n * Validates a single legacy `localStorage` entry. Returns `null` for\n * malformed shapes so the caller can drop them silently. Unchanged from\n * the pre-Task-8 reader: id + label are required strings, `state` must be\n * a plain object; a legacy `state.page` is NOT checked for here — it is\n * tolerated all the way through to `savedViewSetting.parseValue`, which\n * drops it during migration.\n */\nfunction isLegacySavedViewDef(v: unknown): v is SavedViewDef {\n if (typeof v !== 'object' || v === null) return false;\n const o = v as Record<string, unknown>;\n if (typeof o.id !== 'string' || o.id.length === 0) return false;\n if (typeof o.label !== 'string') return false;\n if (typeof o.state !== 'object' || o.state === null || Array.isArray(o.state)) {\n return false;\n }\n return true;\n}\n\n/**\n * Reads + validates the legacy `buro:saved-views:<resource>` entries.\n * Handles the same three shapes the pre-Task-8 hook did (current `{\n * version: 1, views }` envelope, a defensive bare-array v0 shape, and a\n * silently-dropped future `version`). Any parse failure degrades to `[]`\n * — never throws, so stale/corrupted legacy data can never brick the page.\n */\nfunction readLegacyUserViews(resource: string): SavedViewDef[] {\n if (typeof window === 'undefined') return [];\n try {\n const raw = window.localStorage.getItem(`${LEGACY_STORAGE_KEY_PREFIX}${resource}`);\n if (raw == null) return [];\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n return parsed.filter(isLegacySavedViewDef);\n }\n if (typeof parsed === 'object' && parsed !== null) {\n const env = parsed as Record<string, unknown>;\n const version = env.version;\n if (typeof version !== 'number') return [];\n if (version > LEGACY_STORAGE_VERSION) return [];\n const views = env.views;\n if (!Array.isArray(views)) return [];\n return views.filter(isLegacySavedViewDef);\n }\n return [];\n } catch {\n return [];\n }\n}\n\n/** Rewrites the legacy envelope with a SHRUNKEN `views` list — used mid-migration, one successfully-migrated entry at a time (see the module doc's point 3). Never throws; a failed write just leaves the previous envelope in place. */\nfunction writeLegacyUserViews(resource: string, views: SavedViewDef[]): void {\n if (typeof window === 'undefined') return;\n try {\n const envelope: LegacyStoredEnvelope = { version: LEGACY_STORAGE_VERSION, views };\n window.localStorage.setItem(\n `${LEGACY_STORAGE_KEY_PREFIX}${resource}`,\n JSON.stringify(envelope),\n );\n } catch {\n // Best-effort — if this write fails, the (already-migrated-into-the-\n // store) entry simply gets re-attempted on the next mutation. The\n // ONLY consequence of a failed shrink-write is a possible duplicate\n // retry, never data loss (the store-side create already succeeded).\n }\n}\n\n/** Removes the legacy key entirely — called once every pending entry has migrated. Never throws. */\nfunction clearLegacyUserViews(resource: string): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.removeItem(`${LEGACY_STORAGE_KEY_PREFIX}${resource}`);\n } catch {\n // Best-effort — see writeLegacyUserViews.\n }\n}\n\n/**\n * Defensively coerces a raw (possibly adapter-supplied, possibly\n * pre-Task-8-legacy) value into `SavedViewDef['state']`, reusing\n * `savedViewSetting`'s own validator so there is exactly one definition of\n * \"what a saved-view value looks like\". Never throws: a malformed value\n * degrades to `{}` rather than crashing the page, matching the legacy\n * reader's posture.\n */\nfunction toSavedViewState(rawValue: unknown): SavedViewDef['state'] {\n try {\n return savedViewSetting.parseValue(rawValue) as SavedViewDef['state'];\n } catch {\n return {};\n }\n}\n\n/** Strips `page` (never persisted — see `saved-view-setting.ts`) and undefined keys from a URL-state snapshot on its way into `create()`/`update()`. */\nfunction buildCleanState(state: Partial<ResourceUrlState>): SavedViewSettingValue {\n // Built through a locally-mutable shape (`SavedViewSettingValue`'s own\n // fields are `readonly`, by design — see that module's doc) and handed\n // back as the public readonly-fielded type at the `return`, which is a\n // structural (not a mutability) check.\n const cleanState: {\n filters?: SavedViewSettingValue['filters'];\n filterGroup?: SavedViewSettingValue['filterGroup'];\n sort?: SavedViewSettingValue['sort'];\n pageSize?: SavedViewSettingValue['pageSize'];\n search?: SavedViewSettingValue['search'];\n visibleColumns?: SavedViewSettingValue['visibleColumns'];\n } = {};\n if (state.filters !== undefined) cleanState.filters = state.filters;\n if (state.filterGroup !== undefined) cleanState.filterGroup = state.filterGroup;\n if (state.sort !== undefined) cleanState.sort = state.sort;\n if (state.pageSize !== undefined) cleanState.pageSize = state.pageSize;\n if (state.search !== undefined) cleanState.search = state.search;\n if (state.visibleColumns !== undefined) cleanState.visibleColumns = state.visibleColumns;\n // `state.page` is intentionally never copied through.\n return cleanState;\n}\n\n/** Throws for `rejected` / `conflict`; a no-op for every other status. Shared by rename/delete, which never need to return an entry. */\nfunction throwIfMutationFailed(\n result: UiSettingMutationResult<SavedViewSettingValue>,\n resource: string,\n): void {\n if (result.status === 'conflict') {\n throw Object.assign(\n new Error(\n `[useSavedViews] Saved view was modified elsewhere (resource=\"${resource}\"); reload and try again.`,\n ),\n { kind: 'conflict' as const, current: result.current },\n );\n }\n if (result.status === 'rejected') {\n throw Object.assign(\n new Error(\n `[useSavedViews] Failed to persist saved view (resource=\"${resource}\"): ${\n result.issues.map((issue) => issue.message).join('; ') || 'rejected by the settings store'\n }`,\n ),\n { kind: 'rejected' as const, issues: result.issues },\n );\n }\n}\n\n/** `create()`'s success path, converted back to a `SavedViewDef`. Throws (via `throwIfMutationFailed`) on failure. */\nfunction resultToSavedViewDef(\n result: UiSettingMutationResult<SavedViewSettingValue>,\n resource: string,\n): SavedViewDef {\n throwIfMutationFailed(result, resource);\n if (result.status === 'created' || result.status === 'updated') {\n return {\n id: result.entry.id,\n label: result.entry.label ?? '',\n state: toSavedViewState(result.entry.value),\n };\n }\n // 'removed' is unreachable here in practice (no well-behaved adapter\n // returns it from create/update) — the shared `UiSettingMutationResult`\n // union just doesn't narrow per-method. Fail loudly rather than\n // fabricate a view out of nothing.\n throw new Error(\n `[useSavedViews] Unexpected mutation result status \"${result.status}\" while saving a view (resource=\"${resource}\").`,\n );\n}\n\n/**\n * One adapter-backed saved view, WITH the scope/permission/label metadata\n * new UI (Task 9) needs — unlike the plain `SavedViewDef` shape\n * `adopterViews` / `userViews` expose for old callers. Static\n * `def.views.list.savedViews` entries are intentionally NOT represented\n * here (they carry no scope or per-entry permissions — they're a single\n * read-only application source, not a settings-store entry).\n */\nexport interface SavedViewEntry {\n readonly id: string;\n readonly label: string;\n readonly state: SavedViewDef['state'];\n readonly scope: UiSettingScope;\n readonly permissions: UiSettingEntryPermissions;\n}\n\nexport interface UseSavedViewsResult {\n /**\n * Adopter-defined views from the resource config\n * (`def.views.list.savedViews`). Read-only, unaffected by this task's\n * migration — same source and shape as before.\n */\n adopterViews: SavedViewDef[];\n /**\n * The union of settings-store entries (adapter-backed) and any\n * still-pending legacy migration, with any entry whose id collides with\n * an `adopterViews` id FILTERED OUT (adopter config wins — see\n * `getViewById`) — preserved for pre-Task-8 callers exactly as before.\n * Does NOT itself contain `adopterViews`; those are a separate,\n * read-only source callers combine with this one when rendering.\n */\n userViews: SavedViewDef[];\n /**\n * The settings-store entries alone (no legacy merge, no collision\n * filter), WITH scope/permission metadata — for new UI (Task 9). Empty\n * while nothing has been saved/migrated yet.\n */\n entries: SavedViewEntry[];\n /**\n * Scopes the current user may create a NEW view in (spec §5), straight\n * from the store's `snapshot.writeScopes` — Task 9. Empty means saving is\n * unavailable; exactly one means the UI writes there without asking;\n * more than one means the UI must ask \"for whom?\" and pass the chosen\n * scope id into {@link saveCurrentAsView} / {@link forkUserView}.\n */\n writeScopes: readonly UiSettingScope[];\n /**\n * Adapter-reported issues for this collection (spec §13) — Task 9. An\n * issue never hides otherwise-valid entries; it is rendered alongside\n * them (e.g. \"some views could not be loaded\"), straight from the\n * store's `snapshot.issues`.\n */\n issues: readonly UiSettingsIssue[];\n /**\n * True until the underlying collection has produced its first settled\n * snapshot (spec §6) — Task 9. Entries already present (a synchronous\n * local adapter, or a remote adapter's cached local entries) remain\n * usable while this is true; it is not a \"hide the list\" signal.\n */\n pending: boolean;\n /**\n * Persist the current url-state snapshot as a new user view. Migrates\n * any still-pending legacy entries first (see the module doc). Resolves\n * with the persisted view (its store-assigned id).\n *\n * `scopeId` (Task 9) picks WHICH of `writeScopes` the view is created\n * in. Omit it to keep the original single-scope default: the framework's\n * own local scope when `isLocalScope`, otherwise `writeScopes[0]` — a\n * heuristic only ever appropriate when `writeScopes.length <= 1`. A\n * caller offering a real choice among several write scopes MUST pass the\n * user's selection explicitly; this hook never re-derives \"who\".\n *\n * Rejects with:\n * - `Error('[useSavedViews] label cannot be empty')` if\n * `label.trim().length === 0`.\n * - a `rejected`/`conflict`-tagged `Error` (see `throwIfMutationFailed`)\n * on a failed store mutation (quota exceeded, permission denied, no\n * writable scope, …).\n */\n saveCurrentAsView: (\n label: string,\n state: Partial<ResourceUrlState>,\n scopeId?: string,\n ) => Promise<SavedViewDef>;\n /**\n * Rename a user view by id. Adopter-view ids — and any id this hook\n * doesn't recognize — are silently ignored (a resolved no-op), matching\n * the pre-Task-8 behaviour.\n */\n renameUserView: (id: string, newLabel: string) => Promise<void>;\n /** Delete a user view by id. Adopter-view ids are silently ignored (a resolved no-op). */\n deleteUserView: (id: string) => Promise<void>;\n /**\n * Fork an existing entry into `scopeId` (spec §5: \"moving an entry\n * between scopes … is expressed as fork/copy into a writable scope\n * followed by an optional deletion when permitted\") — Task 9. Copies the\n * source entry's stored state (never the live URL state — that is\n * `saveCurrentAsView`'s job) into a brand-new, independent entry tagged\n * `forkedFrom: { entryId: id }`; the fork never receives later changes\n * from its origin. `label` defaults to the source entry's own label.\n *\n * Unlike rename/delete, an unknown `id` REJECTS rather than resolving as\n * a no-op: a fork with no source to copy from is always a caller\n * mistake, never a legitimate \"nothing to do here\" (static adopter\n * views, which have no per-entry permissions, are not forkable through\n * this method — the UI never offers Fork for them in the first place).\n */\n forkUserView: (id: string, scopeId: string, label?: string) => Promise<SavedViewDef>;\n /**\n * Resolve a view by id from either source. Adopter views win on a\n * collision (adopter config is the canonical source) — unchanged.\n */\n getViewById: (id: string) => SavedViewDef | null;\n}\n\n/**\n * Hook returning the union of adopter-defined views (from the resource\n * config) and user-saved views (from the universal UI settings store),\n * plus async mutators for the user-view set. See the module doc above for\n * the legacy-migration and async-mutation contracts.\n *\n * @example\n * const { adopterViews, userViews, saveCurrentAsView } = useSavedViews('document_document');\n */\nexport function useSavedViews(resource: string): UseSavedViewsResult {\n const app = useApp();\n\n // Adopter views from the registry — unchanged from before this task.\n const adopterViews = useMemo<SavedViewDef[]>(() => {\n const def = app.registry.get(resource);\n return (def?.views?.list?.savedViews ?? []) as SavedViewDef[];\n }, [app, resource]);\n\n const { snapshot, create, update, remove } = useUiSettings(savedViewSetting, { resource });\n\n // Whether the CURRENTLY resolved store is the framework's own default\n // local-storage adapter (Task 7) — the only scenario legacy migration\n // ever runs in. See the module doc's \"Legacy migration\" section for why\n // an adopter-supplied adapter is deliberately excluded. Stable across\n // renders for a given store: the default adapter publishes\n // `writeScopes: [LOCAL_USER_SCOPE]` synchronously from its very first\n // snapshot, so there is no mount-time flicker between the two branches.\n const isLocalScope = snapshot.writeScopes.some((s) => s.id === LOCAL_USER_SCOPE_ID);\n\n // Legacy `localStorage` reads. Hydrated in an effect (never during\n // render) for the same SSR-safety reason the pre-Task-8 hook used one:\n // `[]` on the server and on the first client render avoids a hydration\n // mismatch, and the real content arrives one tick later.\n //\n // `legacyRef` mirrors `legacyViews` synchronously so `migrateLegacyIfNeeded`\n // (below) always reads the CURRENT pending set even when called twice\n // back-to-back before a re-render lands.\n const [legacyViews, setLegacyViews] = useState<SavedViewDef[]>([]);\n const legacyRef = useRef<SavedViewDef[]>([]);\n // Single-flight guard for `migrateLegacyIfNeeded` — see its doc below.\n const migrationPromiseRef = useRef<Promise<Map<string, SavedViewEntry>> | null>(null);\n useEffect(() => {\n if (!isLocalScope) {\n legacyRef.current = [];\n setLegacyViews([]);\n return;\n }\n const initial = readLegacyUserViews(resource);\n legacyRef.current = initial;\n setLegacyViews(initial);\n }, [resource, isLocalScope]);\n\n // Settings-store entries, converted to the richer `SavedViewEntry` shape\n // (Step 3 — scope/permissions/label for new UI).\n const entries = useMemo<SavedViewEntry[]>(\n () =>\n snapshot.entries.map((entry) => ({\n id: entry.id,\n label: entry.label ?? '',\n state: toSavedViewState(entry.value),\n scope: entry.scope,\n permissions: entry.permissions,\n })),\n [snapshot.entries],\n );\n\n // `userViews` — store entries PLUS whatever legacy views haven't\n // migrated yet, minus the same adopter-id collision filter the\n // pre-Task-8 hook applied (adopter config is canonical; a colliding\n // user/legacy view is hidden with a one-time warning).\n const warnedIdsRef = useRef<Set<string>>(new Set());\n const userViews = useMemo<SavedViewDef[]>(() => {\n const combined: SavedViewDef[] = [\n ...entries.map((entry) => ({ id: entry.id, label: entry.label, state: entry.state })),\n ...legacyViews,\n ];\n if (combined.length === 0 || adopterViews.length === 0) return combined;\n const adopterIds = new Set(adopterViews.map((v) => v.id));\n const out: SavedViewDef[] = [];\n for (const v of combined) {\n if (adopterIds.has(v.id)) {\n if (!warnedIdsRef.current.has(v.id)) {\n warnedIdsRef.current.add(v.id);\n // eslint-disable-next-line no-console\n console.warn(\n `[useSavedViews] user view id \"${v.id}\" collides with an adopter-defined view; the user copy is hidden until the collision is resolved.`,\n );\n }\n continue;\n }\n out.push(v);\n }\n return out;\n }, [entries, legacyViews, adopterViews]);\n\n /**\n * The actual migration batch — one pass over `pending`, replaying every\n * view into the settings store via `create()` and shrinking (then\n * clearing) the legacy `localStorage` envelope as each one lands\n * successfully (module doc, point 3).\n *\n * `legacyRef`/`legacyViews` are committed INCREMENTALLY, right after\n * each successful `create()` — not just once at the end — so a\n * still-in-progress batch never leaves `userViews` showing a view\n * that's already landed in the store AND still sitting in the legacy\n * list (a transient double-count that a purely end-of-loop commit would\n * otherwise produce for however long the remaining entries take).\n *\n * ONLY ever called from `migrateLegacyIfNeeded`'s single-flight guard\n * below — never call this directly, or two concurrent callers can each\n * start their own pass over the SAME `pending` array and double-`create()`\n * every view.\n */\n async function runLegacyMigration(pending: SavedViewDef[]): Promise<Map<string, SavedViewEntry>> {\n const migrated = new Map<string, SavedViewEntry>();\n let remaining = pending;\n for (const view of pending) {\n const result = await create({\n scopeId: LOCAL_USER_SCOPE_ID,\n label: view.label,\n value: view.state as SavedViewSettingValue,\n });\n if (result.status !== 'created' && result.status !== 'updated') {\n // Stop here — leave this entry and everything after it in legacy\n // storage for a retry on the next mutation (data safety over\n // completeness; see the module doc, point 3).\n break;\n }\n migrated.set(view.id, {\n id: result.entry.id,\n label: result.entry.label ?? view.label,\n state: toSavedViewState(result.entry.value),\n scope: result.entry.scope,\n permissions: result.entry.permissions,\n });\n remaining = remaining.filter((v) => v !== view);\n writeLegacyUserViews(resource, remaining);\n legacyRef.current = remaining;\n setLegacyViews(remaining);\n }\n if (remaining.length === 0) {\n clearLegacyUserViews(resource);\n }\n return migrated;\n }\n\n /**\n * Single-flight guard around `runLegacyMigration`: ensures the pending\n * legacy set migrates AT MOST ONCE even when multiple mutations are\n * concurrently in-flight — e.g. two quick clicks on the manage dialog's\n * delete button, each independently calling `deleteUserView` before the\n * first click's own migration pass has resolved. Without this guard,\n * BOTH calls would read the SAME `legacyRef.current`, both loop\n * `create()` over the SAME pending views, and the store would assign a\n * fresh id to each — duplicate store entries (data duplication, not\n * loss, but still wrong).\n *\n * The FIRST caller to find legacy work starts `runLegacyMigration` and\n * publishes the in-flight promise via `migrationPromiseRef`; every\n * concurrent caller sees that ref already set and `await`s the SAME\n * promise instead of re-reading `legacyRef.current` and re-running the\n * loop. Both therefore resolve against the SAME `migratedFor` map, so\n * each can independently look up its OWN target id — two concurrent\n * deletes of two DIFFERENT pending legacy rows both succeed. The ref is\n * cleared once settled (guarded by identity, in case a brand-new\n * migration already replaced it by the time this one's `finally` runs).\n *\n * A no-op (empty map, no store call, no ref churn) when there is\n * nothing pending, or when the resolved store isn't the framework's own\n * default local scope — see the module doc.\n */\n async function migrateLegacyIfNeeded(): Promise<Map<string, SavedViewEntry>> {\n if (migrationPromiseRef.current !== null) {\n return migrationPromiseRef.current;\n }\n if (!isLocalScope) return new Map();\n const pending = legacyRef.current;\n if (pending.length === 0) return new Map();\n\n const promise = runLegacyMigration(pending);\n migrationPromiseRef.current = promise;\n try {\n return await promise;\n } finally {\n if (migrationPromiseRef.current === promise) {\n migrationPromiseRef.current = null;\n }\n }\n }\n\n async function saveCurrentAsView(\n label: string,\n state: Partial<ResourceUrlState>,\n scopeId?: string,\n ): Promise<SavedViewDef> {\n const trimmedLabel = label.trim();\n if (trimmedLabel.length === 0) {\n // Defensive belt-and-braces: the playground UI's Save button is\n // already disabled when the input is empty, but adopters wiring the\n // hook to a different surface deserve a clear failure mode.\n throw new Error('[useSavedViews] label cannot be empty');\n }\n await migrateLegacyIfNeeded();\n // Task 9: an explicit `scopeId` (the UI's own \"for whom?\" answer) always\n // wins. Only when the caller doesn't supply one do we fall back to the\n // original single-scope heuristic — correct exactly when there is at\n // most one writable scope to begin with.\n const targetScopeId =\n scopeId ?? (isLocalScope ? LOCAL_USER_SCOPE_ID : snapshot.writeScopes[0]?.id);\n if (targetScopeId === undefined) {\n throw new Error(\n `[useSavedViews] No writable scope is available to save a view for resource \"${resource}\".`,\n );\n }\n const result = await create({\n scopeId: targetScopeId,\n label: trimmedLabel,\n value: buildCleanState(state),\n });\n return resultToSavedViewDef(result, resource);\n }\n\n async function renameUserView(id: string, newLabel: string): Promise<void> {\n const migratedFor = await migrateLegacyIfNeeded();\n const current = migratedFor.get(id) ?? entries.find((entry) => entry.id === id);\n // Unknown id (never saved) or an adopter-view id: silently ignored —\n // the adopter config is canonical, matching the pre-Task-8 behaviour.\n if (current === undefined) return;\n const result = await update({\n id: current.id,\n label: newLabel,\n value: current.state as SavedViewSettingValue,\n });\n throwIfMutationFailed(result, resource);\n }\n\n async function deleteUserView(id: string): Promise<void> {\n const migratedFor = await migrateLegacyIfNeeded();\n const current = migratedFor.get(id) ?? entries.find((entry) => entry.id === id);\n if (current === undefined) return;\n const result = await remove({ id: current.id });\n throwIfMutationFailed(result, resource);\n }\n\n async function forkUserView(id: string, scopeId: string, label?: string): Promise<SavedViewDef> {\n const migratedFor = await migrateLegacyIfNeeded();\n const source = migratedFor.get(id) ?? entries.find((entry) => entry.id === id);\n if (source === undefined) {\n // Unlike rename/delete, there is no sensible \"nothing to do\" reading\n // of forking a view that doesn't exist — reject loudly instead of\n // silently resolving (see the field doc on `forkUserView`).\n throw new Error(\n `[useSavedViews] Cannot fork unknown view id \"${id}\" for resource \"${resource}\".`,\n );\n }\n const trimmedLabel = label?.trim();\n const result = await create({\n scopeId,\n label: trimmedLabel && trimmedLabel.length > 0 ? trimmedLabel : source.label,\n value: source.state as SavedViewSettingValue,\n forkedFrom: { entryId: source.id },\n });\n return resultToSavedViewDef(result, resource);\n }\n\n function getViewById(id: string): SavedViewDef | null {\n // Adopter wins on collision (canonical source of truth) — unchanged.\n const adopterHit = adopterViews.find((v) => v.id === id);\n if (adopterHit) return adopterHit;\n const userHit = userViews.find((v) => v.id === id);\n return userHit ?? null;\n }\n\n return {\n adopterViews,\n userViews,\n entries,\n writeScopes: snapshot.writeScopes,\n issues: snapshot.issues,\n pending: snapshot.pending,\n saveCurrentAsView,\n renameUserView,\n deleteUserView,\n forkUserView,\n getViewById,\n };\n}\n","import {\n EMPTY_FILTER_GROUP,\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n type SavedViewDef,\n} from '@burojs/core';\nimport type { ResourceUrlState } from '../url-state/codec.js';\nimport { dropHiddenPredicates } from '../url-state/hidden-predicates.js';\n\n/**\n * Optional defaults supplied to `applyViewToUrlState`. When the view's\n * `state.<field>` is `undefined`, the corresponding setter receives the\n * default from this object instead — and if the default is also unset,\n * falls back to the framework-level defaults documented per setter\n * below.\n *\n * Use this when the call site has page-level defaults that differ from\n * the framework defaults — e.g. the playground uses `pageSize: 10`\n * while the framework default is also 10 (no override needed). An\n * adopter rendering a 25-row default would pass `{ pageSize: 25 }`.\n *\n * `page` is deliberately excluded from `defaults`: applying a view\n * always hardcodes page one (see `applyViewToUrlState`'s doc below), so\n * a `defaults.page` would silently be ignored rather than honored — the\n * type admits only the fields the implementation actually reads.\n */\nexport interface ApplyViewToUrlStateOptions {\n defaults?: Omit<Partial<ResourceUrlState>, 'page'>;\n /**\n * The list's field view (P5 spec 3.7): a filter, group leaf or sort entry the view (or a\n * default) carries on a field for which `visible` is false is dropped BEFORE any setter is\n * called, so a view saved by a user who may see the field never writes its value into the\n * address bar, history or a chip. Absent: nothing is dropped.\n */\n visible?: (field: string) => boolean;\n}\n\n/**\n * Subset of the `useResourceUrlState` return value the helper needs.\n * Defined explicitly (not as `Pick<ReturnType<...>>`) so the helper\n * accepts both:\n * - the strongly-typed return of `useResourceUrlState()` (the playground\n * call site), AND\n * - lightweight test mocks built around `vi.fn()` shapes.\n *\n * Persisted views and URL state share the core portable AST, so this helper\n * passes the typed value through without an adapter cast.\n */\nexport interface ApplyViewUrlStateSetters {\n setFilters: (filters: readonly FilterExpression<ErasedResourceHandle>[]) => void;\n setFilterGroup: (group: FilterGroup) => void;\n setSort: (sort: ResourceUrlState['sort']) => void;\n setPage: (page: number) => void;\n setPageSize: (size: number) => void;\n setSearch: (q: string) => void;\n setVisibleColumns: (cols: string[] | null) => void;\n}\n\n/**\n * Apply a `SavedViewDef` to a `useResourceUrlState` return — REPLACE\n * pattern. Each setter is called once per tick (the hook's\n * `pendingQsRef` batches them into a single router call), so the URL\n * ends in a deterministic state matching the view's declared `state`\n * exactly. Missing fields fall back to `options.defaults`, then to the\n * framework defaults:\n *\n * **Browser history (A5).** The same-tick push wins: because\n * `setFilters`, `setFilterGroup`, `setSort`, and `setVisibleColumns` all\n * default to push, applying a view always produces ONE new history entry\n * covering the combined patch. The user can `back` once to return to\n * whatever filter/sort/columns they had before applying the view.\n *\n * - filters → []\n * - filterGroup → EMPTY_FILTER_GROUP\n * - sort → []\n * - page → 1 (ALWAYS — see below, not defaulted from the view)\n * - pageSize → 10\n * - search → ''\n * - visibleColumns → null\n *\n * **Page is not part of a saved view (spec §12).** `SavedViewDef.state`\n * has no `page` field — a view describes list *configuration*, not a\n * position within one particular query's results. Applying ANY view\n * therefore always resets to page one, unconditionally; there is no\n * `defaults.page` override for this setter (unlike every other field).\n *\n * Use this in the page's `onApply` handler:\n *\n * ```tsx\n * const urlState = useResourceUrlState(resource, { ... });\n * const applyView = useCallback((view: SavedViewDef) => {\n * applyViewToUrlState(view, urlState);\n * }, [urlState]);\n * ```\n *\n * The helper is intentionally pure — it owns no state and surfaces no\n * effects beyond the seven setter calls (filters, filterGroup, sort, page,\n * pageSize, search, visibleColumns). That keeps it trivially unit-testable\n * with a mock urlState.\n */\nexport function applyViewToUrlState(\n view: SavedViewDef,\n urlState: ApplyViewUrlStateSetters,\n options?: ApplyViewToUrlStateOptions,\n): { readonly dropped: number } {\n const d = options?.defaults ?? {};\n // Legacy views (saved before the builder shipped) carry no group; REPLACE\n // semantics mean an absent field clears, not preserves.\n const predicates = {\n filters: view.state.filters ?? d.filters ?? [],\n filterGroup: view.state.filterGroup ?? d.filterGroup ?? EMPTY_FILTER_GROUP,\n sort: view.state.sort ?? d.sort ?? [],\n };\n const kept =\n options?.visible === undefined\n ? { state: predicates, dropped: 0 }\n : dropHiddenPredicates(predicates, options.visible);\n urlState.setFilters(kept.state.filters);\n urlState.setFilterGroup(kept.state.filterGroup);\n urlState.setSort(kept.state.sort);\n // Unconditional — see the module doc's \"Page is not part of a saved\n // view\" note. No `view.state.page` to read (the field is gone from\n // `SavedViewDef.state`) and no `d.page` fallback either.\n urlState.setPage(1);\n urlState.setPageSize(view.state.pageSize ?? d.pageSize ?? 10);\n urlState.setSearch(view.state.search ?? d.search ?? '');\n // visibleColumns: `null` is a meaningful value (= \"use defaults\"),\n // so we only fall back when the view literally omits the key.\n // `view.state.visibleColumns ?? d.visibleColumns ?? null` works\n // because `null ?? X` returns X — i.e. an explicit null in the view\n // would fall through to `d.visibleColumns` and then `null`. That's\n // the desired behaviour (null === defaults at both layers).\n //\n // History note: the urlState hook resolves the same-tick history\n // mode to `push` because at least one of the called setters\n // (setFilters / setSort / setVisibleColumns) defaults to push. The\n // helper does NOT pass an explicit `{ historyMode }` because the\n // implicit \"push wins\" resolution is exactly the desired UX.\n urlState.setVisibleColumns(view.state.visibleColumns ?? d.visibleColumns ?? null);\n return { dropped: kept.dropped };\n}\n","'use client';\nimport { useCallback, useEffect, useState } from 'react';\n\n/**\n * Return shape of `useCommandPalette()`.\n *\n * - `open` — current open state (controlled by the hook).\n * - `setOpen` — set the open state directly (e.g. to close on item select).\n * - `toggle` — flip the open state. Used by the ⌘/Ctrl+K shortcut.\n */\nexport interface UseCommandPaletteResult {\n open: boolean;\n setOpen: (next: boolean) => void;\n toggle: () => void;\n}\n\n/**\n * Options for `useCommandPalette()`.\n */\nexport interface UseCommandPaletteOptions {\n /**\n * Disable the global ⌘K / Ctrl+K shortcut. Default `false` (enabled).\n * When true the hook returns the same `{ open, setOpen, toggle }` API\n * but no global keyboard listener is attached — callers can drive the\n * palette open/close from their own UI affordances.\n */\n disableShortcut?: boolean;\n}\n\n/**\n * State + keyboard wiring for the command palette.\n *\n * Returns `{ open, setOpen, toggle }`. By default attaches a window-level\n * `keydown` listener that toggles the palette on ⌘K (mac) / Ctrl+K\n * (others) and cleans up on unmount.\n *\n * Why ⌘K is safe inside inputs:\n *\n * The spec calls for \"Skip when input/textarea focused UNLESS modifier\n * held.\" Since ⌘/Ctrl+K REQUIRES a modifier, the rule is satisfied\n * by construction: the shortcut always fires, regardless of focus.\n * Any future bare-key shortcut (e.g. `/` to focus the palette input)\n * would need an explicit input-focus skip — but the v0.2 design is\n * modifier-only.\n *\n * Esc-to-close is handled by the underlying `<CommandDialog>` (Radix\n * Dialog calls `onOpenChange(false)` on Esc), so we don't need to\n * intercept Esc here. This keeps cmdk's own Esc handling intact for\n * cases where the palette has a typeahead that should clear on Esc.\n *\n * Multiple instances:\n *\n * Each `useCommandPalette()` call has its own `open` state and (unless\n * `disableShortcut: true`) its own keydown listener. Mounting two of\n * them simultaneously means ⌘K toggles BOTH — which is almost never\n * what you want. For v0.2 the recommendation is one palette per app\n * shell. Adopters that need a secondary palette (e.g. a context-scoped\n * sub-palette) should pass `disableShortcut: true` and wire opening\n * from their own UI.\n *\n * SSR:\n *\n * The keydown listener is attached inside `useEffect`, so `window` is\n * never touched during render. Safe in any RSC/SSR context.\n */\nexport function useCommandPalette(opts?: UseCommandPaletteOptions): UseCommandPaletteResult {\n const [open, setOpen] = useState(false);\n const toggle = useCallback(() => setOpen((o) => !o), []);\n const disableShortcut = opts?.disableShortcut ?? false;\n\n useEffect(() => {\n if (disableShortcut) return;\n const handler = (e: KeyboardEvent) => {\n // ⌘K (mac) or Ctrl+K (everywhere else). Modifier is required, so\n // this never fires from a bare keypress inside an input/textarea.\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n e.preventDefault();\n toggle();\n }\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [toggle, disableShortcut]);\n\n return { open, setOpen, toggle };\n}\n","'use client';\nimport { actionWhenHolds, isFlowAction } from '@burojs/core/internal';\nimport {\n type Action,\n type ActionDI,\n type ActionDataAccess,\n type ItemActionPlacement,\n type ResourceHandle,\n type RuleContext,\n planItemActions,\n} from '@burojs/core';\nimport { useMemo } from 'react';\nimport { type FlowRowControl, useFlowRowResolver } from '../flows/row-batch.js';\nimport { useApp } from './use-app.js';\nimport { useAvailabilityResolver } from './use-availability.js';\n\n/**\n * One item action, resolved for a single record on a single surface.\n *\n * Inherits `placement` (`'standalone'` | `'menu'`) and `density`\n * (`'compact'` | `'regular'` | `null`, null exactly when `placement ===\n * 'menu'`) from `ItemActionPlacement` — the render surface renders its own\n * control for `'standalone'` entries and collects `'menu'` entries into an\n * overflow menu; `density` tells a `'standalone'` control whether to show\n * just its icon or the icon plus label.\n */\nexport interface ResolvedItemAction extends ItemActionPlacement {\n variant: 'default' | 'destructive';\n disabled: boolean;\n disabledReason?: string;\n /**\n * A flow (P4-C): its control as the row decides it before any click — the flow's gate, the\n * page's batched read and its pre-click checks (`undecided` and `pending` render busy).\n */\n flow?: FlowRowControl;\n}\n\n/**\n * `data` stub for the render-time DIs used to evaluate a link's `to` and a modal's `props`\n * functions.\n *\n * Those predicates run during render and must NOT reach the backend — the real\n * backend-capable `data` is injected at dispatch time by the mounted native\n * runtime. Calling any method here throws loudly so the misuse surfaces\n * instead of silently hitting `undefined`.\n *\n * The one place this stub lives: `<ActionButton>` and this hook build the same `ActionDI`\n * shape for a link's `to` and a modal's `props` — see `buildDI` below.\n */\nfunction unavailableActionData(): never {\n throw new Error(\n 'buro: action `data` is not available to a link `to` or a modal `props` function; a write is a flow, which reads through its sources',\n );\n}\n\nexport const RENDER_TIME_DATA: ActionDataAccess = {\n one: unavailableActionData,\n list: unavailableActionData,\n many: unavailableActionData,\n createOne: unavailableActionData,\n updateOne: unavailableActionData,\n deleteOne: unavailableActionData,\n query: unavailableActionData,\n mutate: unavailableActionData,\n};\n\n/**\n * Build a minimal ActionDI for evaluating a link's `to` and a modal's `props` functions at\n * render time.\n *\n * MOVED here from `@burojs/ui-shadcn`'s `action-button.tsx` (Task 6), which\n * defined this identically as a package-private function. `useItemActions` and\n * `<ActionButton>` must evaluate `visible` off the SAME DI shape: if they built\n * two slightly different ones, a rule or predicate reading e.g. `di.ctx` could\n * answer differently between them, and this hook's list would disagree with\n * what the button actually renders for each entry — an item that appears in\n * the menu and then vanishes. `action-button.tsx` now imports this instead of\n * keeping its own copy.\n *\n * `t` defaults to the identity stub (`(key) => key`) so every EXISTING caller\n * — `visible` predicates here and in `<ActionButton>` — keeps evaluating off\n * the same render-time shape it always has. A caller evaluating a message\n * meant to reach the SCREEN (a `confirm` predicate, in particular) must pass a\n * real translator explicitly: the framework's built-in `delete` declares\n * `confirm: (di) => di.t('confirm.delete')`, and the stub used to make that\n * render the literal string `\"confirm.delete\"` instead of translated text.\n */\nexport function buildDI<TRecord>(\n resource: ResourceHandle,\n record: TRecord,\n t?: (key: string, params?: Record<string, unknown>, defaultValue?: string) => string,\n): ActionDI<TRecord> {\n return {\n resource,\n record,\n values: {} as Partial<TRecord>,\n ctx: {} as never,\n t: t ?? ((k) => k),\n get: () => undefined,\n // Render-time predicate DI: backend access is dispatch-time only.\n data: RENDER_TIME_DATA,\n };\n}\n\n/**\n * Rule-engine mode for a render surface. Container and children MUST agree:\n * when they did not, a menu rendered and its only item then vanished, because\n * a rule branching on `ctx.mode` answered the two differently.\n *\n * MOVED here from `@burojs/ui-shadcn`'s `actions/action-surface.ts` (Task 6),\n * which now re-exports this so its existing importers keep working. Widened\n * from that file's closed `ActionSurface` union to a plain `string`: surfaces\n * are an open vocabulary (`ActionSurfaces` is declaration-merged, not a fixed\n * union), and this hook's callers pass whatever surface name their own panel\n * is.\n */\nexport function modeForSurface(surface: string): RuleContext['mode'] {\n return surface === 'show' || surface === 'edit' ? surface : 'list';\n}\n\n/**\n * The single resolved list of item actions for one record on one surface.\n *\n * Hidden and denied actions are ABSENT; denied-but-shown actions arrive with\n * `disabled: true` and a reason. Order and pinning are already applied. What\n * this hook deliberately does NOT do is dispatch: label resolution, icons, the\n * confirm/checks gate and per-kind execution stay in `<ActionButton>`, which\n * every surface still uses to render one entry. A second implementation of\n * that machinery here would fork the i18n precedence rules and the checks gate.\n */\nexport function useItemActions(args: {\n resource: string;\n record: { id: string } & Record<string, unknown>;\n surface: string;\n}): readonly ResolvedItemAction[] {\n const { resource, record, surface } = args;\n const app = useApp();\n const def = app.registry.get(resource);\n const gate = useAvailabilityResolver(resource, modeForSurface(surface));\n const flowControl = useFlowRowResolver(resource);\n const items = (def?.actions?.item ?? []) as Action<unknown>[];\n\n return useMemo(() => {\n const byName = new Map(items.map((action) => [action.name, action]));\n const out: ResolvedItemAction[] = [];\n for (const placement of planItemActions(items, surface)) {\n const action = byName.get(placement.name);\n if (!action) continue;\n // A flow is gated by its own gate, its row's batch and its pre-click checks (4.17).\n if (isFlowAction(action)) {\n const control = flowControl(action.name, record);\n if (control.state === 'absent') continue;\n out.push({\n ...placement,\n variant:\n (action as { readonly variant?: string }).variant === 'destructive'\n ? 'destructive'\n : 'default',\n disabled: control.state === 'disabled',\n ...(control.state === 'disabled' && control.reason !== undefined\n ? { disabledReason: control.reason }\n : {}),\n flow: control,\n });\n continue;\n }\n const availability = gate(placement.name, record);\n if (availability.state === 'absent' || availability.state === 'hidden') continue;\n if (!actionWhenHolds(action, record)) continue;\n out.push({\n ...placement,\n variant: action.variant === 'destructive' ? 'destructive' : 'default',\n disabled: availability.state === 'disabled',\n ...(availability.state === 'disabled' && availability.reason\n ? { disabledReason: availability.reason }\n : {}),\n });\n }\n return out;\n }, [items, surface, gate, record, flowControl]);\n}\n","import { isRelationField, resourceKey } from '@burojs/core';\nimport type {\n EnumDef,\n ErasedResourceHandle,\n FilterFieldKindHint,\n FilterPredicateOp,\n ResourceDef,\n Registry,\n SortExpression,\n} from '@burojs/core';\nimport type { FilterKind } from './types.js';\n\n/**\n * Pure helpers lifted out of the demo app's list controller so\n * `@burojs/react`'s future `useResourceList` (Task B1.3b) and the app\n * can share one implementation instead of two. Moved VERBATIM — only the\n * imports/type-origins changed (see each function's note). No behaviour\n * changed.\n *\n * `kindToValueKind` (`_list-body.tsx:238`) deliberately did NOT move here:\n * it fed the old operator-picker chip's value-input type. That chip\n * mechanism (and `kindToValueKind` itself) is gone — SP2 Task 8 deleted it\n * in favor of the filter-builder region's `FilterValueControl`\n * (`@burojs/ui-shadcn`'s `list-kit/filter-builder/values/`), which derives\n * its own value-input type straight from `FilterKind` below.\n *\n * See `docs/superpowers/plans/2026-07-26-cfb1-list-controller.md`,\n * Task B1.3a.\n */\n\n/**\n * Categorisation of a column's field def into the kind of filter value\n * control it needs. This drives both `filters.available` (what the\n * filter-builder panel's field picker offers) and `FilterValueControl`'s\n * per-kind render dispatch (`@burojs/ui-shadcn`).\n *\n * The categorisation is \"best-effort\" — fields that don't match any\n * supported kind are excluded from `filters.available` entirely.\n *\n * Moved verbatim from `_list-body.tsx:153-196`. The only change is the\n * `registry` parameter's type: the original derived it as\n * `ReturnType<typeof useApp>['registry']` (a hook-shaped type, awkward to\n * import into a non-hook helper); this imports `Registry` directly from\n * `@burojs/core`, which is the exact same type `useApp()['registry']`\n * resolves to.\n */\nfunction readEnumValues(\n source: { kind?: string; type?: string; values?: unknown; ui?: { values?: unknown } } | undefined,\n): readonly string[] | null {\n if (source?.kind !== 'enum' && source?.type !== 'enum') return null;\n const raw = Array.isArray(source.values) ? source.values : source.ui?.values;\n if (!Array.isArray(raw) || raw.length === 0) return null;\n return raw.every((entry) => typeof entry === 'string') ? (raw as readonly string[]) : null;\n}\n\nexport function categorizeField(\n fieldDef: unknown,\n registry: Pick<Registry, 'get'> & { enums: { get(name: string): EnumDef | undefined } },\n): FilterKind | null {\n const source = fieldDef as\n | {\n declaration?: unknown;\n type?: string;\n format?: string;\n kind?: string;\n values?: unknown;\n opts?: { enum?: string; to?: string };\n ui?: { enum?: string; values?: unknown };\n meta?: { to?: unknown; by?: unknown; enum?: string };\n }\n | undefined;\n if (!source) return null;\n const declaration = source.declaration as\n | { type?: string; format?: string; meta?: { to?: unknown; by?: unknown; enum?: string } }\n | undefined;\n // Canonical declarations are either the field itself (modern builders) or\n // the explicit compatibility projection. Read semantic properties only\n // from that projection; legacy members are fallback for fields not lowered\n // yet.\n const canonical =\n declaration?.type !== undefined ? declaration : source.type !== undefined ? source : undefined;\n const type = canonical?.type;\n const format = canonical?.format;\n const meta = canonical?.meta;\n const legacyKind = canonical === undefined ? source.kind : undefined;\n\n // Relation first — wins over its underlying string/number storage\n // because the picker provides a much better UX than typing an FK id.\n if (isRelationField({ type, format, kind: legacyKind })) {\n const target = canonical === undefined ? (source.meta?.to ?? source.opts?.to) : meta?.to;\n let to: string | undefined;\n try {\n to =\n target === undefined ? undefined : resourceKey(target as Parameters<typeof resourceKey>[0]);\n } catch {\n to = undefined;\n }\n const by = canonical === undefined ? source.meta?.by : meta?.by;\n if (to && registry.get(to))\n return typeof by === 'string' ? { kind: 'relation', to, by } : { kind: 'relation', to };\n return null; // unregistered target — exclude from the menu\n }\n // Enum-bound string column.\n const enumName = canonical === undefined ? (source.opts?.enum ?? source.ui?.enum) : meta?.enum;\n if (enumName) {\n if (registry.enums.get(enumName)) return { kind: 'enum', enumName };\n return null; // unregistered enum — exclude\n }\n const inlineValues = readEnumValues(source);\n if (inlineValues) return { kind: 'enum-values', values: inlineValues };\n // `time` is carried, not discarded: a date-time field needs a\n // `datetime-local` control and range-first operators, and by the time\n // `FilterValueControl` dispatches there is nothing left to recover it\n // from. Emitted only when true so a plain date still deep-equals the\n // bare `{kind: 'date'}` this returned before.\n if (format === 'date-time' || legacyKind === 'dateTime') {\n return { kind: 'date', time: true };\n }\n if (format === 'date' || legacyKind === 'date') {\n return { kind: 'date' };\n }\n switch (type ?? legacyKind) {\n case 'string':\n case 'text':\n case 'email':\n case 'url':\n case 'uuid':\n return { kind: 'string' };\n case 'number':\n return { kind: 'number' };\n case 'boolean':\n return { kind: 'boolean' };\n }\n\n return null;\n}\n\n/**\n * The operators the builder offers for a field kind. First entry is the\n * default a freshly added row starts on.\n *\n * Vocabulary is the portable AST's (`FILTER_PREDICATE_OPS`), NOT the\n * narrower `FilterOperator`: builder rows are AST predicates, and `groupToExpression`\n * recognises only `isNull`/`isNotNull` as valueless.\n *\n * `isNull`/`isNotNull` are offered on every kind — \"has no value\" is a\n * question worth asking about any column, and the pair renders no value\n * control at all.\n *\n * An adopter narrows or widens this per field through\n * `views.list.filters.fields: [{ field, operators }]`; this is a default,\n * not a ceiling.\n */\nexport function operatorsForKind(kind: FilterKind): FilterPredicateOp[] {\n const nullish: FilterPredicateOp[] = ['isNull', 'isNotNull'];\n switch (kind.kind) {\n case 'enum':\n case 'enum-values':\n case 'relation':\n return ['in', 'notIn', 'eq', 'neq', ...nullish];\n case 'boolean':\n return ['eq', ...nullish];\n case 'string':\n return ['contains', 'eq', 'neq', 'startsWith', 'endsWith', ...nullish];\n case 'number':\n return ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', ...nullish];\n case 'date':\n // Same set either way; the ORDER is the point, because a freshly\n // added builder row starts on `operators[0]`. On a date-TIME field an\n // `eq` matches one exact instant — seconds and milliseconds included —\n // so it can essentially never be satisfied by a minute picked out of a\n // `datetime-local` box, and defaulting a new row to it hands the user\n // an empty list and no clue why. Range operators lead there; a plain\n // calendar date keeps `eq` first, where it means what it says.\n return kind.time\n ? ['gte', 'lte', 'gt', 'lt', 'eq', 'neq', ...nullish]\n : ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', ...nullish];\n }\n}\n\n/**\n * Converts an adopter-declared {@link FilterFieldKindHint} into the\n * `FilterKind` every filter surface in this package dispatches on.\n *\n * The two types are deliberately separate: the hint is a DECLARATION and\n * lives in `@burojs/core` beside `FilterFieldRef`; `FilterKind` is what the\n * value control switches over and lives here. This is the one place they\n * meet, so a hint can never reach a control without passing through it.\n *\n * The object arm tests the VALUE of `enum`, not `'enum' in hint`. The two\n * members carry `never` markers for each other's key\n * (see `FilterFieldKindHint`), which makes `enum` a declared-but-optional\n * property on the relation member too — so `in` does not narrow, and the\n * read comes back `string | undefined`. Testing the value narrows properly\n * and needs no cast.\n */\nexport function filterKindFromHint(hint: FilterFieldKindHint): FilterKind {\n if (typeof hint !== 'string') {\n if (typeof hint.enum === 'string') return { kind: 'enum', enumName: hint.enum };\n return { kind: 'relation', to: hint.relation };\n }\n switch (hint) {\n case 'dateTime':\n return { kind: 'date', time: true };\n case 'date':\n return { kind: 'date' };\n case 'number':\n return { kind: 'number' };\n case 'boolean':\n return { kind: 'boolean' };\n default:\n return { kind: 'string' };\n }\n}\n\n/**\n * Compute the unique union of two string arrays preserving the order of\n * the first array (extras from the second array are appended in their\n * declared order). Used by `ColumnsToggle` and by `ResourceListBody` to\n * derive `allAvailable` and the effective visible column set.\n *\n * Moved verbatim from `_list-body.tsx:542-553`. No type dependencies, so\n * nothing to adapt beyond the export.\n */\nexport function unionPreservingOrder(a: string[], b: string[] | undefined): string[] {\n if (!b || b.length === 0) return a.slice();\n const seen = new Set(a);\n const out = a.slice();\n for (const x of b) {\n if (!seen.has(x)) {\n out.push(x);\n seen.add(x);\n }\n }\n return out;\n}\n\n/** Adds a stable unique ordering field without altering a declared primary order. */\nexport function withSortTiebreaker(\n sort: SortExpression<ErasedResourceHandle>,\n def: ResourceDef | undefined,\n): SortExpression<ErasedResourceHandle> {\n if (sort.length === 0) return sort;\n const declared = def?.views?.list?.sortTiebreaker;\n if (declared === false) return sort;\n const field = declared ?? (def?.fields?.id ? 'id' : undefined);\n if (!field || sort.some((entry) => entry.field === field)) return sort;\n return [...sort, { field, direction: 'desc' }];\n}\n","import {\n type AppContext,\n type FilterFieldRef,\n type FixedFilterInput,\n type ResolvedFixedFilter,\n type ResourceDef,\n lockedFilterFields,\n normalizeFixedFilters,\n resolveFieldLabel,\n} from '@burojs/core';\nimport { useCallback, useMemo } from 'react';\nimport { useApp } from '../use-app.js';\nimport { useListAccess, usePathAccess } from '../use-field-access.js';\nimport { usePermissions, useScopeCtx } from '../use-permissions.js';\nimport { useI18nCaps } from '../use-t.js';\nimport { categorizeField, filterKindFromHint, operatorsForKind } from './helpers.js';\nimport type { FilterFieldSpec } from './types.js';\n\n/**\n * Second argument to {@link useFilterFields}.\n */\nexport interface UseFilterFieldsOptions {\n /** Call-site narrowing. Its fields are hidden from the offered list unless `{lock: false}`. */\n readonly fixedFilters?: readonly FixedFilterInput[];\n /**\n * Gates the `available`/`pinnedFields` derivation — the walk that runs\n * `categorizeField` (plus `operatorsForKind`, label resolution) over every\n * candidate field of the resource. Defaults to `true`. A caller whose\n * consuming UI isn't visible yet (e.g. the relation picker's dialog before\n * it's opened, via `useDialogFilterState`) should pass `false` to skip\n * that work on every mount / `fixedFilters`-identity change; it resolves\n * to empty arrays while disabled and recomputes in full the next render\n * where this flips back to `true` — same render the caller's UI becomes\n * visible in, so nothing it shows is stale.\n */\n readonly enabled?: boolean;\n}\n\n/** Return shape of {@link useFilterFields}. */\nexport interface FilterFieldsResult {\n /** Fields the builder offers, in declared order. Empty when the config opted out. */\n readonly available: FilterFieldSpec[];\n /** Fields declared as always-visible controls. */\n readonly pinnedFields: FilterFieldSpec[];\n /** Normalized call-site filters; entries with a `label` render as undeletable badges. */\n readonly fixed: readonly ResolvedFixedFilter[];\n /** Fields the list is already narrowed on unconditionally. */\n readonly lockedFields: ReadonlySet<string>;\n}\n\n/**\n * Derives WHICH fields a filter UI may offer for a resource.\n *\n * Lifted out of `useResourceList` because the relation picker's dialog needs\n * exactly these rules — the config whitelist, the per-field operator override,\n * the locked-field hiding — for a resource that is NOT the page's. A second\n * copy of them would drift within a month.\n *\n * Deliberately free of URL state: this hook answers \"what can be filtered\",\n * never \"what is filtered\".\n */\nexport function useFilterFields(\n resource: string,\n options?: UseFilterFieldsOptions,\n): FilterFieldsResult {\n const app = useApp();\n const listCaps = useI18nCaps(resource);\n const def: ResourceDef | undefined = app.registry.get(resource);\n const enabled = options?.enabled ?? true;\n\n // The context a function-form `filters.fields` / `filters.pinned` reads\n // (role / scope).\n //\n // ⚠️ Adapted, deliberately: `useVisibilityCtx()` builds\n // `{ permissions, scope }` FRESH on every render, which would recompute the\n // filter field chain on every render. Rebuilding the same object from the\n // same two slots, memoized on their values, is behaviourally identical and\n // stable.\n //\n // KEEP IN SYNC with `useVisibilityCtx` (`../use-permissions.ts`): if a\n // new built-in slot joins that snapshot, add it here too.\n const permissions = usePermissions();\n const scopeCtx = useScopeCtx();\n const visibilityCtx = useMemo<AppContext>(\n () => ({ permissions, scope: scopeCtx }),\n [permissions, scopeCtx],\n );\n\n /**\n * The call-site's fixed-filter narrowing (Task 7), normalized once. Feeds\n * both the composed `filter` below and the fields hidden from the filter\n * UI — a list locked to `pg = 'alcohol'` can only offer a tautology or an\n * empty result on `pg`, so that field is dropped from `available`.\n */\n const fixedFilters = useMemo(\n () => normalizeFixedFilters(options?.fixedFilters),\n [options?.fixedFilters],\n );\n const lockedFields = useMemo(() => lockedFilterFields(fixedFilters), [fixedFilters]);\n // The one list predicate (P5 spec 3.7): a field its user may not view for every row, or a\n // column a `column` rule denies, is never offered as a filter.\n const access = useListAccess(resource);\n const pathAccess = usePathAccess(resource);\n\n /**\n * Resolve one declared filter field reference (string or `{field,\n * operators?, label?}`) into a {@link FilterFieldSpec}, or `null` when\n * the field is locked, unknown, or not categorisable. Shared by\n * `available` and `pinnedFields` below so both apply the exact same\n * exclusion rules.\n *\n * `system` is deliberately NOT one of those rules. It used to be — every\n * `system: true` field was dropped from every filter surface — but that\n * had no basis in the flag's own contract (`FieldDef.system`,\n * `@burojs/core`), which speaks only about FORMS: hidden on create,\n * read-only on edit, normal on show and in list columns. Filtering was\n * never mentioned, and the exclusion made the two most ordinary questions\n * a list can be asked — \"which rows have this id\", \"which were created\n * after this\" — unaskable, while pushing adopters into a custom toolbar\n * slot to search a `system: true` identifier (`docs/lists-guide.md`).\n * A system field is an ordinary filter candidate: offered by the implicit\n * default, honoured when declared in `fields`/`pinned`, and removable the\n * same way any other field is (declare `filters.fields` without it).\n *\n * `source` distinguishes an EXPLICIT adopter declaration\n * (`'fields'`/`'pinned'`, i.e. this `ref` came from\n * `views.list.filters.fields`/`.pinned`) from the IMPLICIT default (every\n * field on the resource, when `filters.fields` is undeclared) — `null`.\n * Only the explicit case warns: the implicit default legitimately walks\n * every field the resource has, including kinds nobody asked to filter on\n * (`f.json()`, `f.file()`, an unregistered relation target) — warning\n * there fires on every recompute of a normal resource, not on adopter\n * error. An explicit declaration naming a bad or nonexistent field IS\n * adopter error, and is exactly the typo class this warning exists to\n * catch — see Task 7 fix round 2.\n */\n const specFor = useCallback(\n (ref: FilterFieldRef, source: 'fields' | 'pinned' | null): FilterFieldSpec | null => {\n const field = typeof ref === 'string' ? ref : ref.field;\n if (lockedFields.has(field)) return null;\n if (!access.columnVisible(field)) return null;\n // A relation path is offered only while its first segment is (`merchant_id.name`).\n const head = field.split('.')[0]!;\n if (head !== field && !access.columnVisible(head)) return null;\n // …and each further segment on the resource its hop leads to (`merchant_id.iban`).\n if (!pathAccess.visible(field)) return null;\n const override = typeof ref === 'string' ? undefined : ref;\n\n // A DECLARED kind wins outright, and is the only way a relation path\n // can be filtered at all: `documents.document_id` names no field on\n // this resource, so there is nothing to look up and nothing for\n // `categorizeField` to read. Checked BEFORE the field lookup rather\n // than as a fallback after it, so a declared kind also overrides a\n // same-named field — the adopter asked for this control by name.\n if (override?.kind) {\n const declaredKind = filterKindFromHint(override.kind);\n // The same rule `categorizeField` applies to a declared field: a\n // relation whose target is not registered, or an enum nobody\n // registered, cannot render a working control. Repeated here\n // because a declared kind never reaches `categorizeField` — without\n // it a typo in the target ships a picker that can never load a\n // single option, and says nothing about why.\n const unregistered =\n declaredKind.kind === 'relation' && !app.registry.get(declaredKind.to)\n ? declaredKind.to\n : declaredKind.kind === 'enum' && !app.registry.enums.get(declaredKind.enumName)\n ? declaredKind.enumName\n : undefined;\n if (unregistered !== undefined) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}' with a kind naming '${unregistered}', which is not registered.`,\n );\n }\n return null;\n }\n return {\n field,\n label: override.label ?? resolveFieldLabel(listCaps, field),\n kind: declaredKind,\n operators: override.operators ?? operatorsForKind(declaredKind),\n options: override.options,\n };\n }\n\n // A path with no declared kind. Reported on its own terms: the\n // \"not a field on this resource\" warning below would send the reader\n // hunting for a typo instead of a missing `kind`.\n if (field.includes('.')) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}', which is a relation path and needs an explicit \\`kind\\` ` +\n `(nothing on this resource can derive one for it).`,\n );\n }\n return null;\n }\n\n const fieldDef = def?.fields?.[field] as { label?: string } | undefined;\n if (!fieldDef) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}', which is not a field on this resource.`,\n );\n }\n return null;\n }\n const kind = categorizeField(fieldDef, app.registry);\n if (!kind) {\n if (source) {\n console.warn(\n `[useFilterFields] '${resource}': views.list.filters.${source} declares ` +\n `'${field}', which is not filterable (unsupported field kind).`,\n );\n }\n return null;\n }\n return {\n field,\n label: override?.label ?? resolveFieldLabel(listCaps, field, fieldDef.label),\n kind,\n operators: override?.operators ?? operatorsForKind(kind),\n options: override?.options,\n };\n },\n [def, app.registry, listCaps, lockedFields, resource, access, pathAccess],\n );\n\n /**\n * Filterable fields for the toolbar — either the declared\n * `views.list.filters.fields` whitelist (order and operator overrides\n * honored verbatim) or, by default, every field with a categorisable\n * kind in `views.list.columns` order. Fields locked by a fixed filter are\n * excluded either way; system fields are not (see `specFor`).\n *\n * Moved from `filterableColumns` (`_list-body.tsx:827-844`) and extended\n * (Task 7) to read the field whitelist/operator overrides from config\n * instead of always deriving the full column set. `false` removes the\n * filter button entirely (`declaredFields === false`).\n */\n // A bare property read used below as a `useMemo` dependency (see\n // `declaredFields`) — safe because `def` (`app.registry.get(resource)`\n // above) is a plain Map read: the registry returns the SAME object across\n // renders AND across a locale switch (nothing in `registry.ts` is\n // locale-aware), so this read is reference-stable and will never bust the\n // memo spuriously. `declaredFields` itself only carries untranslated field\n // REFS and their order, never resolved text, so it does not need to\n // recompute on a language switch either — the translated LABEL for each\n // ref is resolved downstream, per render, by `specFor` (below), whose own\n // `useCallback` deps include `listCaps` and which is what actually makes\n // `available`/`pinnedFields` re-render with fresh labels on a locale\n // change.\n const filterConfig = def?.views?.list?.filters;\n // Whether `available` below iterates an EXPLICIT `filters.fields` list\n // (warn-eligible) or the IMPLICIT every-field default (never warns —\n // see `specFor`'s doc comment).\n const fieldsExplicit = filterConfig?.fields !== undefined;\n const declaredFields = useMemo(() => {\n const declared =\n typeof filterConfig?.fields === 'function'\n ? filterConfig.fields(visibilityCtx)\n : filterConfig?.fields;\n if (declared === false) return false as const;\n return declared ?? def?.views?.list?.columns ?? Object.keys(def?.fields ?? {});\n }, [filterConfig, visibilityCtx, def]);\n\n const available = useMemo<FilterFieldSpec[]>(() => {\n // Gate FIRST, before touching `declaredFields`/`specFor` — skipping the\n // loop body is what avoids the `categorizeField` walk; see this hook's\n // `enabled` doc.\n if (!enabled) return [];\n if (declaredFields === false) return [];\n const out: FilterFieldSpec[] = [];\n for (const ref of declaredFields) {\n const spec = specFor(ref, fieldsExplicit ? 'fields' : null);\n if (spec) out.push(spec);\n }\n return out;\n }, [declaredFields, specFor, fieldsExplicit, enabled]);\n\n /**\n * Fields declared as always-visible controls beside the filter button\n * (`views.list.filters.pinned`), same resolution rules as `available`.\n */\n const pinnedFields = useMemo<FilterFieldSpec[]>(() => {\n if (!enabled) return [];\n const declared =\n typeof filterConfig?.pinned === 'function'\n ? filterConfig.pinned(visibilityCtx)\n : filterConfig?.pinned;\n if (!declared) return [];\n const out: FilterFieldSpec[] = [];\n for (const ref of declared) {\n // Always explicit — this loop only runs when the adopter declared\n // `views.list.filters.pinned` at all.\n const spec = specFor(ref, 'pinned');\n if (spec) out.push(spec);\n }\n return out;\n }, [filterConfig, visibilityCtx, specFor, enabled]);\n\n // A fresh object literal here is invisible to `useResourceList` (it\n // destructures immediately), but this hook has a second, public consumer\n // (the relation-picker dialog's `useDialogFilterState`) that may put the\n // whole result in a dependency array — which would then \"change\" every\n // render without this.\n return useMemo(\n () => ({ available, pinnedFields, fixed: fixedFilters, lockedFields }),\n [available, pinnedFields, fixedFilters, lockedFields],\n );\n}\n","import type { Availability, Registry, ResourceDef } from '@burojs/core';\nimport { hasRecordPage, hrefFor, resourceShowHref } from '@burojs/core';\n\n/**\n * Where one row points, given what its record allows.\n *\n * Extracted as a pure function so the decision is testable without a list, a\n * query client or a router.\n *\n * `disabled` collapses to the same result as `hidden`/`absent` here: a table\n * row is a LINK, and a link cannot carry a label and a toast the way a button\n * can. Dimming a whole row and hijacking its click to explain itself would be\n * worse than simply not linking it.\n */\nexport function rowHrefFor(\n registry: Pick<Registry, 'get'>,\n def: ResourceDef | undefined,\n resource: string,\n id: string,\n gate: (operation: string, record?: unknown) => Availability,\n record?: unknown,\n): string {\n // A resource without record pages (`views.show.page: false`) has no route to link to: its\n // record is reached through its quick entries. The show link lands on the page `routesTo.show`\n // names, so that resource's page decides it.\n const page = (mode: 'show' | 'edit') => def === undefined || hasRecordPage(def, mode);\n const delegate = def?.routesTo?.show;\n const showDef =\n delegate === undefined ? def : (registry.get(delegate as never) as ResourceDef | undefined);\n const showPage = def === undefined || (showDef !== undefined && hasRecordPage(showDef, 'show'));\n if (showPage && gate('show', record).state === 'available') {\n return resourceShowHref(registry as Registry, def, resource, id);\n }\n if (page('edit') && gate('edit', record).state === 'available') {\n // ⚠️ Plain `hrefFor`, NOT a `resourceEditHref` — the show branch above\n // honours `routesTo.show` and this one honours nothing, because `routesTo`\n // has no `edit` key to honour. A resource that delegates its show page\n // elsewhere and then loses `show` falls back to its OWN edit page.\n return hrefFor(registry as Registry, resource, { action: 'edit', id });\n }\n return '';\n}\n","'use client';\nimport {\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n type FixedFilterInput,\n type PortableObject,\n type ResourceDef,\n type SavedViewDef,\n type SearchDecl,\n type SortExpression,\n EMPTY_FILTER_GROUP,\n composeListFilter,\n resourceCreateHref,\n} from '@burojs/core';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { applyViewToUrlState } from '../saved-views/apply-view-to-url-state.js';\nimport { useSavedViews } from '../saved-views/use-saved-views.js';\nimport type { ResourceUrlState } from '../url-state/codec.js';\nimport type { ListState } from '../url-state/list-state-store.js';\nimport { useResourceUrlState } from '../url-state/use-resource-url-state.js';\nimport { useCount } from '../data/use-count.js';\nimport { useInfiniteList } from '../data/use-infinite-list.js';\nimport { useList } from '../data/use-list.js';\nimport { useApp } from '../use-app.js';\nimport { useAvailabilityResolver } from '../use-availability.js';\nimport { attachPolicyRows } from '../../policy-side-channel.js';\nimport { useListAccess, usePathAccess, useViewRow } from '../use-field-access.js';\nimport { filterFields } from '../url-state/hidden-predicates.js';\nimport { useFilterFields } from './use-filter-fields.js';\nimport { unionPreservingOrder, withSortTiebreaker } from './helpers.js';\nimport { rowHrefFor } from './row-href.js';\nimport type { ResourceListController, RowRecord } from './types.js';\n\n/**\n * `useResourceList` — the data-connected list controller (core flexibility\n * program, Task B1.3b). Everything a list page needs that is NOT rendering:\n * URL-state sync, column math, filter composition, the `useList` call, row\n * identity, selection, saved views and routing hrefs. Adopters get a working\n * list without re-implementing ~600 lines of glue; presentational packages\n * (`@burojs/ui-shadcn`) and app code stay free of controller logic.\n *\n * The implementation is a MOVE, not a rewrite: every unit below was lifted\n * from the demo app's `ResourceListBody` and adapted only at its\n * inputs/outputs.\n * Source line references are cited per unit so the two can be diffed.\n *\n * ---------------------------------------------------------------------\n * Router coupling — resolved.\n * ---------------------------------------------------------------------\n * This hook builds on {@link useResourceUrlState}, which used to statically\n * import `next/navigation`, pulling Next into any app that imported\n * `useResourceList` even though `next` was only an optional peer dependency\n * of `@burojs/react`. That import is gone: {@link useResourceUrlState}\n * now reads/writes location through an injected `RouterAdapter`\n * (`../router/router-adapter.js`), the same pattern already used for links\n * via `LinkComponentProvider`. Any adopter supplying a `RouterAdapterProvider`\n * — Next, react-router, or otherwise — can use this hook.\n *\n * ---------------------------------------------------------------------\n * Identity contract.\n * ---------------------------------------------------------------------\n * Re-rendering with an unchanged URL and unchanged data returns the SAME\n * object for every group (`pagination`, `filters`, `columns`, …) and the\n * same function reference for every callback. Consumers may therefore use\n * any of them as a `useMemo` / `useEffect` / `React.memo` dependency\n * without churn. See \"Identity discipline\" below for how that is achieved\n * — it does NOT come for free, because `useResourceUrlState` returns a\n * fresh object on every render.\n *\n * @see docs/superpowers/plans/2026-07-26-cfb1-list-controller.md — Task B1.3b\n */\n\n/**\n * Fallback for a resource that declares NEITHER `views.list.pageSize` NOR\n * `views.list.defaultSort` (`@burojs/core`, SP0b Task 1) — `10`, no sort.\n * `pageSize: 10` matches the literal the playground has always used; the\n * other defaults (`page: 1`, `sort: []`, `search: ''`, `filters: []`) come\n * from the url-state hook itself.\n *\n * ⚠️ This is now only the FALLBACK, not the value passed to\n * {@link useResourceUrlState} directly — see `declaredDefaults` below,\n * which reads `def.views.list.pageSize` / `.defaultSort` and falls back to\n * this constant. Kept as a named constant (rather than inlining `10`\n * there) so there is exactly one place that says what \"nothing declared\"\n * means.\n *\n * Moved verbatim from `_list-body.tsx:97`.\n */\nconst URL_STATE_DEFAULTS = { pageSize: 10 };\n\n/**\n * Page-size choices surfaced as `pagination.pageSizeOptions`.\n *\n * The pre-lift app never passed `pageSizeOptions` to `<ResourceList>`, so\n * the rendered selector used that component's own default\n * (`resource-list.tsx:188`, `[10, 25, 50, 100]`). The controller now has to\n * name a value because `ResourceListController.pagination.pageSizeOptions`\n * is non-optional — this constant reproduces that default exactly, so\n * wiring `pageSizeOptions={pagination.pageSizeOptions}` in B1.3e is a\n * no-op change. Module scope keeps the array identity stable.\n *\n * ⚠️ Base list only. A resource declaring `views.list.pageSize` outside\n * this set (e.g. `30`) gets it MERGED in — see the `pageSizeOptions` memo\n * below — otherwise the size selector would offer no option matching the\n * declared default, a gap the fixed `100` in this list happened to hide\n * for the resources this feature first shipped for.\n */\nconst PAGE_SIZE_OPTIONS = [10, 25, 50, 100];\n\n/**\n * `useList` query options. Hoisted to module scope (the app had it inline,\n * `_list-body.tsx:1299-1307`) purely for stable identity — the body is\n * unchanged.\n *\n * Keeping the previous page's rows on screen while a new filter/sort/page\n * query loads avoids dropping to the skeleton on every change: `isLoading`\n * stays false once we have any data, so the list keeps rendering the\n * (stale) table until fresh rows arrive.\n */\nconst NO_PAGES: ReadonlyArray<{ readonly data: readonly unknown[] }> = [];\n\n/** Stable empty selection — avoids a fresh `[]` identity on mount. */\nconst NO_SELECTION: string[] = [];\nconst NO_ROWS: RowRecord[] = [];\nconst NO_CACHE: Record<string, RowRecord> = {};\n/** The column set while the list's field decisions are pending: none. */\nconst NO_COLUMNS: string[] = [];\n\n/**\n * `provider::resource` keys a data provider has already answered\n * `{ total: null }` for — \"this cannot be counted here at all\". That is a\n * property of the resource↔provider mapping (no aggregate root exists);\n * no filter, page, sort or scope can change it, so the answer is worth\n * remembering.\n *\n * Module scope, because it must outlive the hook: `getCount` is\n * presence-discovered (there is deliberately no `canCount` probe, see\n * `packages/core/src/types/data-access.ts`), so without this the dead\n * affordance would come back on every remount of an uncountable list —\n * one wasted click each time the user navigates back to it.\n *\n * ⚠️ Keyed by RESOURCE NAME, never by table. `code_document_link` and\n * `code_code_document` are the same physical table under two resource\n * names, and only the resource name decides which mapping — and therefore\n * which aggregate root — applies. Note this holds the *unavailability*\n * verdict only; the counted NUMBER is never cached here (it is per-mount\n * state keyed on the full filter tuple, see `countKey` below).\n */\n\n/**\n * Second argument to {@link useResourceList}.\n *\n * Deliberately tiny: everything else the controller needs it resolves\n * itself from the registry (`def`) or from the URL. These two exist\n * because they cannot be derived — `meta` carries app-level query scope,\n * and `onReset` is the seam to state the controller does not own.\n */\nexport interface UseResourceListOptions {\n /**\n * Extra `meta` merged into the `useList` call — and therefore into the\n * react-query cache key. This is how app-level query scope (a sidebar\n * product-group / location picker, a tenant id) becomes part of the\n * cache key instead of being invisible to react-query.\n *\n * ⚠️ **The caller MUST memoize this object.** It flows into the query\n * key; a fresh object literal every render produces a fresh key every\n * render, which means a refetch loop. The playground memoizes on\n * `[scope.productGroup, scope.locationId]`.\n *\n * Merge order: controller-owned meta keys are spread FIRST, so **caller\n * keys win** on a collision. As of Task 4 (F2) the controller DOES own\n * one such key: {@link ResourceListController.providerQuery}, a level-2\n * filters-slot's own escape hatch into this same `meta`. A key here that\n * collides with a key the slot pushes through `providerQuery.set` still\n * wins — the slot silently loses that key, not the other way round — but\n * an adopter picking a `meta` key that happens to collide should know\n * that collision is possible, not assume the merge site is unreachable.\n */\n meta?: Record<string, unknown>;\n /**\n * Fired by {@link ResourceListController.filters}`.clearAll` and by\n * {@link ResourceListController.savedViews}`.apply`.\n *\n * The seam for ephemeral UI state the controller does NOT own but that\n * must reset in step with those two actions. Concretely (the case this\n * was designed for): the playground's dynamic-filter toolbar keeps its\n * own `visibleIds` set of which chips are rendered, and the pre-lift\n * `clearAllFilters` (`_list-body.tsx:1336`) and `applyView`\n * (`_list-body.tsx:950`) both reset it. Without this callback,\n * clear-all leaves stale empty chips on screen and applying a saved\n * view leaves the PREVIOUS view's chips.\n *\n * Read through a ref, so an inline arrow here does not destabilise\n * `clearAll` / `apply` identity.\n */\n onReset?: () => void;\n /**\n * Call-site narrowing the user did not choose: the parent FK of an\n * embedded list, the resource owning a picker dialog, a tab showing one\n * slice of a collection.\n *\n * Never reaches the URL — it is derived from the render context, so a\n * serialized copy would be both forgeable and stale the moment the parent\n * changes. By default each entry also HIDES its fields from the filter UI;\n * pass `{ filter, lock: false }` to keep a field available.\n *\n * ⚠️ Memoize it: it feeds the query key.\n */\n fixedFilters?: readonly FixedFilterInput[];\n /**\n * Overrides `views.list.refetchInterval` (`@burojs/core`) for a host that\n * mounts a list by hand rather than through the level-0 nav-area page —\n * the declared route can't take props, this option is the escape hatch.\n * `false` forces polling off even when the resource declares an interval;\n * omit to use the declared value untouched.\n */\n refetchInterval?: number | false;\n /**\n * Where the list keeps its state (P1b+P1c decision 58): by default the URL under the\n * resource's registry key (`?<resource>.page=2`), so bookmarks keep working; `{ url: prefix }`\n * namespaces it under another prefix; `'memory'` never writes the URL (a list inside a custom\n * block view, which must not write the record page's query string).\n */\n state?: ListState;\n /**\n * The default columns, in place of the target's `views.list.columns` (a `related-list`\n * placement's `columns`). Column rules still apply.\n */\n columns?: readonly string[];\n /** The default page size, in place of the target's `views.list.pageSize`. */\n pageSize?: number;\n /** The search, in place of the target's `views.list.search` (a placement's own search box). */\n search?: SearchDecl;\n}\n\n/**\n * Data-connected list controller for `resource`.\n *\n * ⚠️ **Precondition: `resource` MUST be registered.** `routing.createHref`\n * resolves through `resourceCreateHref` → `hrefFor`, which throws\n * `unknown node '<resource>'` for a name the registry doesn't know. This\n * is the pre-lift behaviour, and it is exactly why the playground's route\n * calls `notFound()` before mounting the list\n * (`app/(admin)/[resource]/page.tsx:15-22`). Resolve\n * `app.registry.get(resource)` and handle the miss BEFORE calling this\n * hook. (`ResourceListController.def` is typed `ResourceDef | undefined`\n * for that reason, but `undefined` is not reachable in practice.)\n *\n * ### Free-text search\n *\n * `filters.search` composes into the fetched filter set via core's\n * `searchToFilter` (`@burojs/core`), driven by `def.views.list.search`\n * (a `SearchDecl`):\n *\n * 1. Declarative form (`{ fields: [...] }`) ORs `contains` (or a per-field\n * `op` override) across the listed fields.\n * 2. Function form takes over completely — returning `null` means \"this\n * query searches nothing\", a deliberate answer, not an error.\n * 3. Undeclared (`views.list.search` absent) — the search string\n * contributes nothing.\n *\n * ⚠️ The framework adds NO numeric-id branch of its own. It used to\n * (`/^\\d+$/ → {field: 'id', op: 'eq'}` unconditionally on every resource,\n * `_list-body.tsx:1263-1267`), which decided the storage type of somebody\n * else's `id` column for them — a provider holding `id` as a\n * bigint-as-string rejected the numeric value outright. A resource that\n * wants that behaviour back declares a function `views.list.search`.\n *\n * See {@link ResourceListController.filters}`.group` and `.fixed` for the\n * other two slots `composeListFilter` (`@burojs/core`) folds together with\n * search — fixed (call-site narrowing) → pinned (`filters.set`) → search →\n * group (the filter-builder panel), in that order (Task 7).\n *\n * ### Pagination modes\n *\n * Offset (the default) and cursor, chosen by\n * `def.views.list.pagination` and surfaced as\n * {@link ResourceListController.cursor} (`null` ⇒ offset).\n *\n * | | offset | `'cursor'` |\n * |---|---|---|\n * | fetch | `useList` | `useInfiniteList` |\n * | `rows` | the current page | every page loaded so far, de-duplicated by id |\n * | advance | `pagination.setPage(n)` | `cursor.loadMore()` |\n * | `pagination.page` / `setPage` | live | inert |\n * | key | includes `currentPage` | no page number — cursor owned by `InfiniteListObserver` |\n *\n * Both hooks are called unconditionally; the inactive one is switched off\n * through `queryOptions.enabled`. See the comment at the call sites.\n *\n * ### Row identity\n *\n * See {@link ResourceListController.rows}. `def.rowId(record, index)` wins\n * when declared; otherwise the framework default is the first present of\n * `id`, `event_id`, `job_id`, else the row's index. The resolved value is\n * written ONTO the row as `id` — see the `rows` memo below for why.\n *\n * @param resource Registry name of the resource to list.\n * @param opts See {@link UseResourceListOptions}. Optional; `meta`\n * must be memoized when supplied.\n */\nexport function useResourceList(\n resource: string,\n opts?: UseResourceListOptions,\n): ResourceListController {\n const app = useApp();\n // Gates the row's drill-in target (see `rowHref` below) — `show` first,\n // falling back to `edit`, never a link when neither is reachable.\n const availability = useAvailabilityResolver(resource);\n\n // The resource def is resolved here rather than being passed in (the\n // pre-lift `ResourceListBody` took it as a prop, `_list-body.tsx:746`).\n // `registry.get` is a Map read, so the identity is stable.\n const def: ResourceDef | undefined = app.registry.get(resource);\n\n // Accumulating selection. Ids survive page, pageSize, filter, sorters and\n // search; they are dropped only where the ROWS are dropped too — the\n // resource boundary and the scope / provider-options boundary (see the\n // reset effect below) — and on unmount.\n const [selectedIds, setSelectedIds] = useState<string[]>(NO_SELECTION);\n // Snapshot of every selected row, keyed by id. A row selected on a page the\n // user has since left is not in `rows` any more; without a snapshot a bulk\n // action would silently act on fewer records than the user picked.\n const [selectedCache, setSelectedCache] = useState<Record<string, RowRecord>>(NO_CACHE);\n // Predicates the applied saved views carried on hidden fields (P5 spec 3.7).\n const [viewDropped, setViewDropped] = useState(0);\n\n // #17 — column-layout reset signal consumed by `<ResourceList>`.\n // Moved from `_list-body.tsx:765-768`.\n const [resetLayout, setResetLayout] = useState<{ token: number; mode: 'sizes' | 'all' }>({\n token: 0,\n mode: 'sizes',\n });\n\n // -------------------------------------------------------------------\n // Column math — moved from `_list-body.tsx:796-818`.\n //\n // Defaults preserve full backward compat: a resource without\n // `optionalColumns` shows no extras; without `requiredColumns` every\n // default column is treated as required (the conservative choice —\n // adopters opt into toggling by listing extras).\n //\n // A column only \"exists\" in this context if no `column` rule denies it.\n // `<ResourceList>` filters the RENDERED columns by exactly this; applying\n // it here too keeps the Columns menu honest — otherwise a denied column\n // (e.g. an admin-only one) shows up in the menu, checked, but never\n // appears in the table and toggling it does nothing.\n // -------------------------------------------------------------------\n /*\n THE ONE LIST PREDICATE (P5 spec 3.7, decision P5-18). A column naming a\n field exists only if that field is visible for EVERY row and no `column`\n rule denies it; a host column naming no field keeps the `column` rule\n alone. Both are decided with the record probe (`mode: 'list'`, `record:\n RECORD_PROBE`, and the probe as `can`'s third argument): a rule or a map\n that reads the row denies, because no single row may decide the table's\n shape. `<ResourceList>` and the filter offer read the same predicate.\n\n While the decision waits on a loading permission map the controller offers\n no column at all and reports loading — never a narrower set that would\n change once the map arrives.\n */\n const access = useListAccess(resource);\n const pathAccess = usePathAccess(resource);\n // A relation path is decided on the resources it crosses: they may still wait on the map.\n const accessPending = access.status === 'pending' || pathAccess.pending;\n const isColVisibleHere = access.columnVisible;\n /**\n * Whether a user predicate may name `field` (P5 spec 3.7): its column is visible, and a\n * relation path's first segment too. A predicate on any other field — from the URL, a saved\n * view, a pinned filter, the default sort or a search set — is dropped, never sent.\n */\n const predicateVisible = useCallback(\n (field: string): boolean => {\n const head = field.split('.')[0]!;\n return (\n access.columnVisible(head) &&\n (head === field || access.columnVisible(field)) &&\n pathAccess.visible(field)\n );\n },\n [access, pathAccess],\n );\n /**\n * ⚠️ A column naming a field the resource does not have is KEPT on purpose\n * (`isColVisibleHere` returns true for an unknown key so an app can list a\n * column it renders itself via `renderCell`). The cost is that a TYPO is\n * indistinguishable from that: `views.list.columns: ['aliass']` yields a\n * real column with a plausible humanized header, every cell blank, a\n * checked-but-dead entry in the Columns menu, and silent absence from the\n * filter toolbar. It reads as a data bug, not a schema bug, and an adopter\n * can lose a long time to it.\n *\n * So: warn, don't change the behaviour: named resource, named column,\n * deduped so a re-render cannot spam the console.\n */\n const warnedUnknownColumnsRef = useRef<Set<string>>(new Set());\n const declaredColumns = useMemo<string[]>(() => {\n if (!def) return [];\n const declared = opts?.columns ?? def.views?.list?.columns ?? Object.keys(def.fields ?? {});\n // Only when the app declared columns explicitly — the fallback is derived\n // FROM `fields`, so every key is known by construction.\n if (def.views?.list?.columns && def.fields) {\n for (const col of declared) {\n if (def.fields[col]) continue;\n const key = `${resource}::${col}`;\n if (warnedUnknownColumnsRef.current.has(key)) continue;\n warnedUnknownColumnsRef.current.add(key);\n // eslint-disable-next-line no-console\n console.warn(\n `[buro] Resource \"${resource}\": views.list.columns names \"${col}\", which is not a field on this resource. The column will render empty. Known fields: ${Object.keys(def.fields).join(', ')}.`,\n );\n }\n }\n return declared.filter(isColVisibleHere);\n }, [def, isColVisibleHere, resource, opts?.columns]);\n const optionalColumns = useMemo<string[]>(\n () => (def?.views?.list?.optionalColumns ?? []).filter(isColVisibleHere),\n [def, isColVisibleHere],\n );\n const allAvailable = useMemo<string[]>(\n () => unionPreservingOrder(declaredColumns, optionalColumns),\n [declaredColumns, optionalColumns],\n );\n const requiredColumns = useMemo<string[]>(\n () => def?.views?.list?.requiredColumns ?? declaredColumns,\n [def, declaredColumns],\n );\n\n /**\n * The filterable-field derivation (declared whitelist, per-field operator\n * overrides, pinned fields, fixed-filter normalization and locked-field\n * hiding) is lifted into {@link useFilterFields} — the relation picker's\n * dialog needs exactly these rules for a resource that is NOT the page's,\n * and a second copy of them would drift within a month. See that hook's\n * doc comment for the full derivation.\n */\n const {\n available,\n pinnedFields,\n fixed: fixedFilters,\n } = useFilterFields(resource, {\n fixedFilters: opts?.fixedFilters,\n });\n\n /**\n * Per-resource defaults for {@link useResourceUrlState} — SP0b Task 2.\n * Reads `views.list.pageSize` / `views.list.defaultSort` (`@burojs/core`,\n * Task 1) so a resource that declares either gets it as the state the\n * URL falls back to when it carries none: page size on cold load, and an\n * initial sort order before the user (or a saved view) picks one.\n *\n * `sort` is only present in the object when the resource actually\n * declares `defaultSort` — an explicit `sort: []` would ALSO be a valid\n * default, but `useResourceUrlState`'s codec only omits the `?<r>.sort=`\n * param from the URL when the current sort matches the default\n * (`sameJson`), and there is nothing to omit-match against differently\n * here: `[]` is already `HOOK_DEFAULTS.sort`. Spreading conditionally\n * keeps the common (undeclared) case textually identical to \"no sort\n * override\", rather than writing out `[]` for a value that was already\n * the hook's own default.\n *\n * `def.views.list.defaultSort` shares `SortExpression<ErasedResourceHandle>`\n * with `ResourceUrlState['sort']` (both are core's erased sort AST — see\n * `views.list.defaultSort`'s JSDoc in `@burojs/core`), so this is a\n * direct assignment, not a conversion. Verified against\n * `packages/react/src/hooks/url-state/codec.ts`'s `ResourceSort` alias.\n *\n * ⚠️ `useMemo` is REQUIRED, not decorative: `useResourceUrlState`\n * memoizes its own `codecOpts` on the IDENTITY of `opts.defaults`\n * (`use-resource-url-state.ts`'s `codecOpts` memo), and that identity\n * feeds the setter callbacks. A fresh object literal here every render\n * would recreate `codecOpts` every render, which busts setter identity\n * and the codec memo — see `URL_STATE_DEFAULTS`'s docblock above for the\n * full failure mode this hook's original comment names. Keyed on the\n * declared VALUES (not on `def`), so identity survives every render that\n * doesn't actually change the declaration.\n *\n * A resource that declares neither key returns `URL_STATE_DEFAULTS`\n * ITSELF (not a byte-identical copy) — the brief's \"keep the module\n * constant as the value for nothing declared\" taken literally, which\n * also means every undeclared resource shares one stable object across\n * mounts, not just within one.\n */\n const declaredPageSize = opts?.pageSize ?? def?.views?.list?.pageSize;\n const rawDeclaredSort = def?.views?.list?.defaultSort;\n // A default sort entry on a hidden field is removed: the sort falls back to the next entry,\n // then to the provider's own order.\n const declaredSort = useMemo(() => {\n if (rawDeclaredSort === undefined) return undefined;\n const kept = rawDeclaredSort.filter((entry) => predicateVisible(entry.field));\n return kept.length === rawDeclaredSort.length ? rawDeclaredSort : kept;\n }, [rawDeclaredSort, predicateVisible]);\n const declaredDefaults = useMemo(\n () =>\n declaredPageSize === undefined && declaredSort === undefined\n ? URL_STATE_DEFAULTS\n : {\n pageSize: declaredPageSize ?? URL_STATE_DEFAULTS.pageSize,\n ...(declaredSort ? { sort: declaredSort } : {}),\n },\n [declaredPageSize, declaredSort],\n );\n\n /**\n * URL-state hook — source of truth for the page's interactive state\n * (filters / sort / page / pageSize / search / visibleColumns). Each\n * setter writes to the URL so cold deep-links restore the view and\n * reload preserves state.\n *\n * Selection stays in local state above (ephemeral UI). Column\n * visibility lives in the URL via `?<resource>.cols=col1,col2,col3`\n * (A3); a one-shot migration below picks up the legacy\n * `buro:columns:<resource>` localStorage value the first time a\n * given resource mounts post-upgrade.\n *\n * Moved verbatim from `_list-body.tsx:893-910`. `defaults` used to be\n * the module-level `URL_STATE_DEFAULTS` literal (deliberate — the\n * url-state hook memoizes on `opts.defaults` / `opts.fieldTypes`\n * individually); it is now `declaredDefaults` (SP0b Task 2), which is\n * stable for the same reason (see that memo's docblock above).\n */\n const urlState = useResourceUrlState(resource, {\n defaults: declaredDefaults,\n ...(opts?.state === undefined ? {} : { state: opts.state }),\n predicates: { visible: predicateVisible, ready: !accessPending },\n });\n const {\n page,\n sort,\n search,\n filters: urlFilters,\n filterGroup,\n visibleColumns: urlVisibleColumns,\n } = urlState;\n const pageSize = urlState.pageSize;\n\n /**\n * Saved-views integration (A4.1-A4.3). `useSavedViews` returns the union\n * of adopter-defined views (`def.views.list.savedViews`) and user-saved\n * views (localStorage). Moved from `_list-body.tsx:929-934`; the two\n * dialogs and the toast stay in the app (see `savedViews.saveCurrent`).\n */\n const {\n adopterViews,\n userViews,\n entries: savedViewEntries,\n writeScopes: savedViewWriteScopes,\n issues: savedViewIssues,\n pending: savedViewsPending,\n saveCurrentAsView,\n renameUserView,\n deleteUserView,\n forkUserView,\n } = useSavedViews(resource);\n\n // Effective visible set: required columns are always present; the user's\n // toggled set (read from the URL) supplies the rest, intersected with\n // `allAvailable` to drop stale entries from older config or unknown ids\n // from a malformed deep link. Materialized in `allAvailable` order so\n // the table layout is stable across toggles. When the URL has no\n // `?<r>.cols=` param we fall back to the resource's declared default\n // columns so initial paint matches the server-rendered shell.\n //\n // Moved verbatim from `_list-body.tsx:992-997`.\n const visibleColumns = useMemo<string[]>(() => {\n const base = urlVisibleColumns ?? declaredColumns;\n const baseSet = new Set(base);\n const requiredSet = new Set(requiredColumns);\n return allAvailable.filter((c) => baseSet.has(c) || requiredSet.has(c));\n }, [urlVisibleColumns, declaredColumns, requiredColumns, allAvailable]);\n\n // -------------------------------------------------------------------\n // ⚠️ Identity discipline — the volatile ref.\n //\n // `useResourceUrlState` returns a FRESH object every render\n // (`use-resource-url-state.ts:375-383`), and its setters are only as\n // stable as `useRouter()` / `useSearchParams()` underneath them. A\n // naive `useCallback(…, [urlState])` — or even `[setFilters]` — is\n // therefore a new function on almost every render, which propagates\n // into every group object and defeats every downstream memo.\n //\n // The repo's answer to exactly this problem is the volatile-ref\n // pattern (`ui-shadcn/src/resource/resource-list.tsx:337-347`): one ref\n // holding everything volatile, REASSIGNED during render, read only from\n // inside event-handler callbacks that themselves have empty dep lists.\n // Handlers run after commit, so `.current` is always the latest\n // committed render's value — fresh values, frozen identity.\n //\n // ⚠️ Render-time reads must NOT go through this ref (a memo reading\n // `.current` would never invalidate). Everything the render path needs\n // is destructured above as a normal value.\n // -------------------------------------------------------------------\n const volatileRef = useRef({\n urlState,\n declaredDefaults,\n visibleColumns,\n requiredColumns,\n saveCurrentAsView,\n renameUserView,\n deleteUserView,\n forkUserView,\n onReset: opts?.onReset,\n registry: app.registry,\n def,\n resource,\n availability,\n sort,\n predicateVisible,\n refetch: (): void => {},\n // Cursor mode (B5.2). Assigned right after the two query hooks below —\n // `loadMore` reads all three so its own identity can stay frozen.\n hasNextPage: false as boolean | undefined,\n isFetchingNextPage: false,\n fetchNextPage: (): void => {},\n isCurrentData: false,\n requestCount: (): void => {},\n rowsById: new Map<string, RowRecord>(),\n });\n volatileRef.current.urlState = urlState;\n volatileRef.current.declaredDefaults = declaredDefaults;\n volatileRef.current.visibleColumns = visibleColumns;\n volatileRef.current.requiredColumns = requiredColumns;\n volatileRef.current.saveCurrentAsView = saveCurrentAsView;\n volatileRef.current.renameUserView = renameUserView;\n volatileRef.current.deleteUserView = deleteUserView;\n volatileRef.current.forkUserView = forkUserView;\n volatileRef.current.onReset = opts?.onReset;\n volatileRef.current.registry = app.registry;\n volatileRef.current.def = def;\n volatileRef.current.availability = availability;\n volatileRef.current.resource = resource;\n volatileRef.current.sort = sort;\n volatileRef.current.predicateVisible = predicateVisible;\n\n // One-shot migration of the pre-A3 `buro:columns:<resource>`\n // localStorage key to the URL's `?<r>.cols=` param. Runs once per\n // resource mount, BEFORE the user has a chance to interact with the\n // toolbar. The latest `urlVisibleColumns` is read via a ref so the\n // effect doesn't re-fire on every URL change.\n //\n // Behaviour:\n // - Legacy key absent → no-op.\n // - Legacy key present, URL has no cols → write to URL, delete key.\n // - Legacy key present, URL already has cols → URL wins; the legacy\n // key is still cleared (the URL is now the source of truth).\n //\n // Multi-tab race: the migration is per-tab and idempotent. Both\n // branches converge to the same end state — the legacy key is gone and\n // the URL holds either the migrated value or whatever was already\n // there. If two tabs race the same first-mount, the loser sees the\n // (already-cleared) legacy key as absent and no-ops. There is no path\n // where data is lost across tabs.\n //\n // Moved verbatim from `_list-body.tsx:1020-1051`.\n const urlVisibleColumnsRef = useRef(urlVisibleColumns);\n useEffect(() => {\n urlVisibleColumnsRef.current = urlVisibleColumns;\n }, [urlVisibleColumns]);\n useEffect(() => {\n if (typeof window === 'undefined') return;\n const legacyKey = `buro:columns:${resource}`;\n let legacy: string[] | null = null;\n try {\n const raw = window.localStorage.getItem(legacyKey);\n if (raw) {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((x) => typeof x === 'string')) {\n legacy = parsed as string[];\n }\n }\n } catch {\n // ignore — corrupted localStorage value is dropped on the floor\n }\n if (legacy === null) return;\n // URL wins if it already has cols — only seed the URL when empty.\n if (urlVisibleColumnsRef.current === null) {\n volatileRef.current.urlState.setVisibleColumns(legacy);\n }\n // Delete legacy regardless (URL is now source of truth).\n try {\n window.localStorage.removeItem(legacyKey);\n } catch {\n // ignore\n }\n }, [resource]);\n\n /**\n * Compose the filter sent to `useList` — the three-slot model (Task 7):\n * fixed (call-site narrowing) → pinned (URL-state column filters) →\n * search → group (the URL-state builder group), folded into one\n * expression by `composeListFilter` (`@burojs/core`) in that order.\n *\n * Moved from `_list-body.tsx:1254-1272`; the search resolution itself now\n * lives in core's `searchToFilter` (`views.list.search`, see the hook\n * JSDoc), and the fixed/group slots are new (Task 7).\n */\n const rawSearchDecl = opts?.search ?? def?.views?.list?.search;\n // A declared search set loses every field its user may not view; with none left there is no\n // search (P5 spec 3.7). A function search is checked on its output below.\n const searchDecl = useMemo(() => {\n if (rawSearchDecl === undefined || typeof rawSearchDecl === 'function') return rawSearchDecl;\n if (!Array.isArray(rawSearchDecl.fields)) return rawSearchDecl;\n const fields = rawSearchDecl.fields.filter((ref) =>\n predicateVisible(typeof ref === 'string' ? ref : ref.field),\n );\n if (fields.length === rawSearchDecl.fields.length) return rawSearchDecl;\n return fields.length === 0 ? undefined : { ...rawSearchDecl, fields };\n }, [rawSearchDecl, predicateVisible]);\n const searchEnabled = searchDecl !== undefined;\n const searchContext = useMemo(() => ({ resource, def }), [resource, def]);\n /**\n * A function search whose output names a field its user may not view (plan ruling 18): the\n * term finds nothing and nothing is requested for it — no request, no rows, no total.\n */\n const searchForbidden = useMemo(() => {\n if (typeof searchDecl !== 'function') return false;\n const term = search.trim();\n if (term === '') return false;\n let out: FilterExpression<ErasedResourceHandle> | null;\n try {\n out = searchDecl(term, searchContext);\n } catch {\n // A search that cannot say which fields it reads cannot be shown to read none of the hidden\n // ones: fail closed.\n return true;\n }\n return out != null && filterFields(out).some((field) => !predicateVisible(field));\n }, [searchDecl, search, searchContext, predicateVisible]);\n const filter = useMemo<FilterExpression<ErasedResourceHandle> | undefined>(\n () =>\n composeListFilter({\n fixed: fixedFilters,\n pinned: urlFilters,\n group: filterGroup,\n // A search that threw is forbidden (no read): it is not composed again.\n search: searchForbidden ? '' : search,\n searchDecl,\n searchContext,\n }),\n [fixedFilters, urlFilters, filterGroup, search, searchDecl, searchContext, searchForbidden],\n );\n\n /**\n * Sort, plus a UNIQUE TIEBREAKER.\n *\n * ⚠️ This used to emit the user's column alone. Sorting by a non-unique\n * column then duplicated and hid rows: SQL does not guarantee a stable order\n * among ties across separate `limit`/`offset` windows, so a row can appear on\n * two pages while another appears on none. Measured on the 2 728-row document\n * table sorted by its 9-value status column — 2 728 rows shown, only 2 152\n * distinct, 576 documents unreachable, and page 8 repeating 19 rows from\n * page 1, all while the footer asserted «Показаны 1–2 728 из 2 728».\n *\n * The tiebreaker only makes the order deterministic; it never changes which\n * rows match. Skipped when the user is already sorting by the tiebreaker\n * field, and when the resource has no such field to sort on (an append-only\n * log table need not have an `id`) — see `views.list.sortTiebreaker`.\n */\n const sorters = useMemo<SortExpression<ErasedResourceHandle>>(() => {\n const out = withSortTiebreaker(sort, def);\n // A tiebreaker on a hidden field is no sort for this user either.\n return out.every((entry) => predicateVisible(entry.field))\n ? out\n : out.filter((entry) => predicateVisible(entry.field));\n }, [sort, def, predicateVisible]);\n\n /**\n * A host's `fixedFilters` naming a field its user may not view (P5 spec 3.7, decision P5-17):\n * an author predicate is never dropped — dropping a narrowing filter fails open — so the read\n * is forbidden instead.\n */\n const fixedForbidden = useMemo(\n () =>\n fixedFilters.some((entry) =>\n filterFields(entry.filter).some((field) => !predicateVisible(field)),\n ),\n [fixedFilters, predicateVisible],\n );\n /**\n * A read this user may not make (P5 spec 3.7): no request, no rows, no total. Decided once the\n * list's access is: while it is pending the read is held anyway.\n */\n const forbidden = !accessPending && (fixedForbidden || searchForbidden);\n\n /**\n * `providerQuery` — узкий канал (Task 4 / F2), которым level-2\n * filters-слот может протолкнуть в запрос произвольный provider-блоб, не\n * имея доступа к `opts.meta` (его передаёт СТРАНИЦА, а не слот). Значение\n * непрозрачно для контроллера — он не знает и не обязан знать, что внутри.\n *\n * `undefined` по умолчанию, так и остаётся, пока слот ни разу не вызвал\n * `providerQuery.set`.\n */\n const [providerQueryValue, setProviderQueryValue] = useState<Record<string, unknown> | undefined>(\n undefined,\n );\n\n /**\n * Meta merged into the `useList` call — and therefore into the\n * react-query key. Controller-owned keys are spread FIRST so caller\n * keys win on collision: `providerQuery` (Task 4) is the first\n * controller-owned key, spread ahead of `opts.meta` below.\n * Collapses to `undefined` when empty so a caller passing nothing (and\n * a slot never touching `providerQuery`) gets the same query key it\n * would have without a meta argument at all.\n */\n const callerMeta = opts?.meta;\n const meta = useMemo<PortableObject | undefined>(() => {\n const merged = { ...providerQueryValue, ...callerMeta };\n return Object.keys(merged).length > 0 ? (merged as PortableObject) : undefined;\n }, [providerQueryValue, callerMeta]);\n\n // -------------------------------------------------------------------\n // The fetch. TWO hooks, one enabled (Task B5.2).\n //\n // ⚠️ RULES OF HOOKS — do NOT \"simplify\" this into `isCursor ? useList()\n // : useInfiniteList()`. Both hooks MUST be called on every render, in\n // this order; the inactive one is switched off through\n // `queryOptions.enabled` (see `LIST_QUERY_OPTIONS_DISABLED` /\n // `INFINITE_QUERY_OPTIONS_DISABLED`), which stops the fetch AND the\n // live-polling interval, leaving only two cheap idle observers.\n //\n // Offset and cursor descriptors are intentionally distinct: an offset\n // list owns one page while an infinite list owns an ordered page sequence.\n // Routing every list through the latter would make normal page replacement\n // and cursor accumulation indistinguishable to cache invalidation.\n //\n // Why the mode is DECLARED and not sniffed from the first response: see\n // `views.list.pagination`'s JSDoc in `@burojs/core`. Short version —\n // a single-page cursor list is indistinguishable from an offset one, and\n // flipping mode after the first response would fetch page one twice.\n // -------------------------------------------------------------------\n const isCursor = def?.views?.list?.pagination === 'cursor';\n\n /**\n * Declared live-list interval (`views.list.refetchInterval`), overridden\n * by the hook's own option for hosts that mount a list by hand.\n *\n * Cursor mode accumulates pages, so a background refetch would fight the\n * accumulator — warn once and stay static rather than silently doing\n * something the caller did not ask for.\n */\n const declaredInterval = opts?.refetchInterval ?? def?.views?.list?.refetchInterval ?? false;\n const liveInterval =\n typeof declaredInterval === 'number' && declaredInterval > 0 ? declaredInterval : null;\n const [isLivePaused, setLivePaused] = useState(false);\n const liveDisabledByCursor = liveInterval !== null && isCursor;\n useEffect(() => {\n if (liveDisabledByCursor) {\n // eslint-disable-next-line no-console\n console.warn(\n `useResourceList(\"${resource}\"): views.list.refetchInterval is ignored for a cursor list.`,\n );\n }\n }, [liveDisabledByCursor, resource]);\n const activeInterval =\n liveInterval === null || liveDisabledByCursor || isLivePaused ? false : liveInterval;\n\n // Moved verbatim from `_list-body.tsx:1293-1308` (`meta` and\n // `queryOptions` hoisted out; see `LIST_QUERY_OPTIONS`).\n //\n // ⚠️ `refetchInterval` is spread in only when a live interval is actually\n // declared (`liveInterval !== null`) — a resource that declares nothing\n // must produce a BYTE-IDENTICAL `useList` call to before this feature\n // existed, not one carrying an explicit `refetchInterval: false` (which is\n // the same value to TanStack Query, but not the same call for a test — or\n // an adopter — asserting on it).\n const offsetQuery = useList(resource, {\n pagination: { kind: 'offset', page, pageSize },\n filter,\n sort: sorters,\n providerOptionsOverride: meta,\n // Held while the list's field decisions are undecided (P5 spec 3.7).\n enabled: !isCursor && !accessPending && !forbidden,\n ...(liveInterval === null ? {} : { refetchInterval: activeInterval }),\n });\n\n /**\n * Cursor mode. The `pagination` passed to `useInfiniteList` carries no\n * page number at all (`{ kind: 'cursor', limit: pageSize }`) — the opaque\n * continuation token lives entirely inside `InfiniteListObserver`, which\n * derives it from the previous page's `pageInfo.nextCursor` and never\n * feeds it back into the descriptor. That keeps the descriptor (and its\n * query key/identity) stable across a load-more, which is what makes\n * accumulation work at all: `InfiniteListObserver` appends to its own\n * `pages` array under ONE identity instead of starting a new query per\n * token.\n *\n * ⚠️ That stability is also why the QueryClient-wide `placeholderData:\n * keepPreviousData` default cannot break this the way it broke the\n * hand-written accumulator it replaces: a placeholder is only ever\n * substituted while a query is `pending`, and a load-more never leaves\n * the current key's `success` state.\n *\n * ⚠️ `retry: false` is NOT carried over. The hand-written Schedules page\n * passed it (`schedules/page.tsx:65`); the controller has one retry\n * policy for every list it drives, which is react-query's default of 3\n * with backoff — the same policy every Hasura list in the app already\n * runs under. A cursor provider outage therefore surfaces its error\n * later than the bespoke page did. Recorded rather than papered over\n * with a `queryOptions` passthrough that would have exactly one caller.\n */\n const cursorQuery = useInfiniteList(resource, {\n pagination: { kind: 'cursor', limit: pageSize },\n filter,\n sort: sorters,\n providerOptionsOverride: meta,\n enabled: isCursor && !accessPending && !forbidden,\n });\n\n // The two results are read field-by-field rather than through a single\n // `isCursor ? cursorQuery : offsetQuery` union: TypeScript will not call\n // a method off a union of two differently-parameterised react-query\n // results, and a `refetch()` that needs a cast is a refetch nobody will\n // notice breaking.\n volatileRef.current.refetch = () => {\n if (isCursor) void cursorQuery.refetch();\n else void offsetQuery.refetch();\n };\n volatileRef.current.hasNextPage = cursorQuery.hasNextPage;\n volatileRef.current.isFetchingNextPage = cursorQuery.isFetchingNextPage;\n volatileRef.current.fetchNextPage = () => {\n void cursorQuery.fetchNextPage();\n };\n\n /**\n * The rows on screen, each coerced to `{ …record, id: string }` — the\n * current page in offset mode, **every page loaded so far** in cursor\n * mode (see {@link ResourceListController.rows}).\n *\n * ⚠️ C1 — the row-id chain. `def.rowId(record, index)` wins when\n * declared (composite identity: a Temporal workflow is\n * `${workflowId}:${runId}`, which the plain default would collide\n * across runs). Otherwise the framework default is the chain moved\n * verbatim from `_list-body.tsx:1313`: `id ?? event_id ?? job_id ??\n * String(index)`. That chain is NOT decoration — `logs_l2_job_events`\n * and `logs_l2_production_events` are ClickHouse tables with no `id`\n * column at all, so a `String(record.id)` default would render\n * `id=\"undefined\"` for every row (duplicate React keys, broken\n * selection, `list-row:…:undefined` testids) and no e2e covers them.\n *\n * The resolved value is written ONTO the row rather than exposed as a\n * separate `getRowId`, because `useBuroDataTable`'s default\n * `getRowId` (`ui-shadcn/src/data-table/use-buro-data-table.ts:159-167`)\n * reads `row.id`, and every `list-row:<resource>:<id>` /\n * `list-cell:<resource>:<id>:<col>` testid derives from it. Keeping the\n * write here is what keeps that testid surface byte-for-byte identical.\n *\n * ⚠️ Cursor mode additionally DE-DUPLICATES by resolved id, keeping the\n * first position and the last value — the exact semantics of the\n * `new Map(prev.map(…))` + `byId.set(…)` accumulator the hand-written\n * Temporal pages used (`schedules/page.tsx:79-83`). Cursor providers can\n * legitimately overlap pages when rows are inserted between fetches, and\n * a duplicate `id` here means duplicate React keys and broken selection.\n * Offset mode is deliberately left alone: no page can repeat a row, and\n * silently dropping a genuine duplicate would be a behaviour change to\n * every existing list.\n *\n * ⚠️ Both branches are inside ONE memo so the returned array identity is\n * stable while neither source changes — react-query's structural sharing\n * hands back the same `pages` array across a no-op refetch, which is what\n * keeps the controller's identity contract intact in cursor mode too.\n */\n // A forbidden read shows nothing, not the rows a placeholder kept from the last key.\n const offsetRows = forbidden ? undefined : offsetQuery.data?.data;\n const cursorPages = forbidden ? undefined : cursorQuery.data?.pages;\n const rows = useMemo<RowRecord[]>(() => {\n const rowId = def?.rowId;\n const source: readonly unknown[] = isCursor\n ? (cursorPages ?? NO_PAGES).flatMap((p) => (p.data ?? []) as unknown[])\n : (offsetRows ?? []);\n const out: RowRecord[] = [];\n const seen = isCursor ? new Map<string, number>() : null;\n source.forEach((r, i) => {\n const rec = r as Record<string, unknown>;\n const idVal = rowId ? rowId(rec, i) : (rec.id ?? rec.event_id ?? rec.job_id ?? String(i));\n const id = String(idVal);\n const row = { ...rec, id };\n const at = seen?.get(id);\n if (at !== undefined) {\n out[at] = row;\n return;\n }\n seen?.set(id, out.length);\n out.push(row);\n });\n return out;\n }, [isCursor, offsetRows, cursorPages, def]);\n\n // Row lookup for selection: `rows` is rebuilt on every page, and both the\n // snapshot cache and `selectedRecords` need id → row without a linear scan\n // per selected id.\n const rowsById = useMemo(() => {\n const map = new Map<string, RowRecord>();\n for (const row of rows) map.set(row.id, row);\n return map;\n }, [rows]);\n volatileRef.current.rowsById = rowsById;\n\n // Selection accumulates across page, pageSize, filter, sorters and search:\n // the user is building a set, and paginating must not silently empty it.\n // It IS dropped on the two boundaries where the rows themselves are dropped:\n // a different resource, and a different scope / provider-options. A cached\n // record from another tenant must never reach a bulk action.\n //\n // ⚠️ Keyed on `callerMeta` (`opts.meta`), NOT the merged `meta` above.\n // `providerQuery` is the level-2 filters-slot's own raw-query channel — it\n // is documented as a FILTER (see `isFiltered` below and the `providerQuery`\n // JSDoc), and every other filter change preserves selection. Folding it\n // into the merged `meta` that feeds this identity would make\n // `providerQuery.set(...)` the one filter that silently drops the\n // selection, contradicting that rule. The scope boundary this identity\n // exists to catch is the CALLER's scope / provider-options — a slot's raw\n // query was never that boundary.\n const selectionIdentity = useMemo(\n () => JSON.stringify([resource, callerMeta ?? null]),\n [resource, callerMeta],\n );\n // Reset DURING RENDER, not in an effect. `rows` empty out synchronously on a\n // resource/scope change, but a passive effect would not clear the selection\n // until after the commit — and for that one committed render `records` would\n // resolve snapshots belonging to the previous tenant. React re-runs this\n // component immediately on a set-during-render, so children never observe the\n // stale set.\n const [lastSelectionIdentity, setLastSelectionIdentity] = useState(selectionIdentity);\n if (lastSelectionIdentity !== selectionIdentity) {\n setLastSelectionIdentity(selectionIdentity);\n setSelectedIds(NO_SELECTION);\n setSelectedCache(NO_CACHE);\n }\n\n // Extended from `_list-body.tsx:1318` (Task 7) to include the builder group,\n // and (Task 11) the provider-query channel: a level-2 slot's raw\n // `providerQuery.set(...)` changes what the list request MEANS just as much\n // as a structured filter does, so \"is this list filtered?\" must say yes\n // while one is in force — otherwise a raw query matching zero rows renders\n // the ordinary \"no records yet / + Create\" empty state instead of \"nothing\n // matches\", and the standard filter region's \"Clear all\" stays hidden.\n const isFiltered =\n Boolean(search.trim()) ||\n urlFilters.length > 0 ||\n filterGroup.rows.length > 0 ||\n providerQueryValue !== undefined;\n\n // Count is a normal native descriptor. A controller neither chooses a\n // provider nor probes capabilities: the runtime resolves the descriptor\n // exactly as it resolves the list. `manual` keeps the observer disabled\n // until the user asks; `auto` and `live` opt in to its normal lifecycle.\n const countPolicy = def?.views?.list?.count ?? 'provided';\n const inlineTotal = isCursor ? cursorQuery.data?.pages.at(-1)?.total : offsetQuery.data?.total;\n const countQuery = useCount(resource, {\n filter,\n providerOptionsOverride: meta,\n enabled:\n !accessPending &&\n !forbidden &&\n (countPolicy === 'live' || (countPolicy === 'auto' && inlineTotal === undefined)),\n });\n const [nullCountIdentity, setNullCountIdentity] = useState<string | null>(null);\n const countIdentity = useMemo(\n () => JSON.stringify([resource, filter ?? null, meta ?? null]),\n [resource, filter, meta],\n );\n const countValue = countQuery.data?.total;\n useEffect(() => {\n if (countValue === null) setNullCountIdentity(countIdentity);\n }, [countValue, countIdentity]);\n const countIsNull = nullCountIdentity === countIdentity || countValue === null;\n const countAvailable = countPolicy === 'manual' && !countIsNull;\n volatileRef.current.requestCount = () => {\n if (countPolicy !== 'manual' || countIsNull || countQuery.isFetching) return;\n void countQuery.refetch();\n };\n const requestCount = useCallback(() => volatileRef.current.requestCount(), []);\n\n // -------------------------------------------------------------------\n // Callbacks. Every one has an EMPTY dep list and reads what it needs\n // from `volatileRef` — see \"Identity discipline\" above.\n // -------------------------------------------------------------------\n\n const setPage = useCallback((next: number) => {\n volatileRef.current.urlState.setPage(next);\n }, []);\n\n /**\n * Setting the page size also anchors back to page 1: row 41 of the old\n * size may not exist under the new one, so we avoid landing the user on\n * an empty page. Moved from the `onPageSize` closure,\n * `_list-body.tsx:1569-1574`.\n */\n const setPageSize = useCallback((size: number) => {\n volatileRef.current.urlState.setPageSize(size);\n volatileRef.current.urlState.setPage(1);\n }, []);\n\n /**\n * `providerQuery.set` (Task 4 / F2). Same \"anchor back to page 1\" move as\n * `setPageSize` above, for the same reason: the new blob changes what the\n * request MEANS, so whatever page the user was on under the old meaning\n * may not exist (or may mean something else entirely) under the new one.\n * `undefined` clears the channel — also anchored to page 1, since a\n * cleared provider query is just as much a change of query meaning as a\n * set one.\n */\n const setProviderQuery = useCallback((next: Record<string, unknown> | undefined) => {\n setProviderQueryValue(next);\n volatileRef.current.urlState.setPage(1);\n }, []);\n\n /**\n * Raw filter write. Deliberately a pass-through: the pre-lift page reset\n * pagination to page 1 on a filter change from INSIDE the TanStack\n * bridge (`setColumnFilters`, `_list-body.tsx:1104-1122`, which also\n * carries the \"skip the write when nothing actually changed\" guard).\n * That bridge stays in the app until B2, so the reset stays with it —\n * B1.3e composes `filters.set(next)` + `if (pagination.page !== 1)\n * pagination.setPage(1)` exactly as the source does.\n */\n const setFilters = useCallback((next: readonly FilterExpression<ErasedResourceHandle>[]) => {\n volatileRef.current.urlState.setFilters(next);\n }, []);\n\n /**\n * Raw builder-group write (Task 7). Same stable-identity discipline as\n * `setFilters` above — reads the live url-state through the volatile ref\n * so this callback's own identity never changes.\n */\n const setGroup = useCallback((next: FilterGroup) => {\n volatileRef.current.urlState.setFilterGroup(next);\n }, []);\n\n /**\n * Raw search write.\n *\n * ⚠️ Does NOT reset the page. The pre-lift page did `setPage(1);\n * setSearch(v)` — but from the JSX (`<ListSearchInput onCommit>`,\n * `_list-body.tsx:1382-1385`), and all JSX stays in the app for B1.\n * B1.3e must keep that composition (`onCommit={(v) => {\n * pagination.setPage(1); filters.setSearch(v); }}`), otherwise\n * searching from page 3 silently keeps the user on page 3.\n */\n const setSearch = useCallback((q: string) => {\n volatileRef.current.urlState.setSearch(q);\n }, []);\n\n /**\n * Atomically clear the free-form search, every URL-state column filter,\n * the builder group (Task 7) and the page cursor, then fire\n * `opts.onReset` for app-owned ephemeral UI (chip visibility).\n *\n * Moved from `clearAllFilters` (`_list-body.tsx:1332-1337`) with\n * `setVisibleIds(new Set())` replaced by the `onReset` seam. The\n * url-state setters fire in the same tick, so the url-state hook's\n * `pendingQsRef` merges them: each successive write observes the\n * previous one and the LAST URL is the fully-cleared one.\n *\n * ⚠️ Also clears `providerQuery` (Task 11): `setProviderQueryValue` is a\n * `useState` setter, which React guarantees a stable identity for across\n * renders — the same reason `providerQuery.set` itself (below) calls it\n * directly instead of going through `volatileRef`. Without this, \"Clear\n * all\" would leave a level-2 slot's raw provider query silently in force\n * even though {@link isFiltered} (which now factors it in) just told the\n * user there was nothing left to clear.\n */\n const clearAll = useCallback(() => {\n const { urlState: u, onReset } = volatileRef.current;\n u.setSearch('');\n u.setFilters([]);\n u.setFilterGroup(EMPTY_FILTER_GROUP);\n u.setPage(1);\n setProviderQueryValue(undefined);\n onReset?.();\n }, []);\n\n const setSort = useCallback((next: ResourceUrlState['sort']) => {\n volatileRef.current.urlState.setSort(next);\n }, []);\n\n /**\n * Header-click sort handler: the 3-click toggle. Moved verbatim from\n * the `<ResourceList onSort>` closure, `_list-body.tsx:1594-1614`.\n */\n const toggleSort = useCallback((field: string, direction?: 'asc' | 'desc' | null) => {\n const { urlState: u, sort: current } = volatileRef.current;\n u.setPage(1);\n // Explicit direction from the header menu wins; `undefined` keeps the\n // legacy toggle for any caller that still relies on it.\n if (direction !== undefined) {\n u.setSort(direction === null ? [] : [{ field, direction }]);\n return;\n }\n // The url-state hook's setSort accepts a value (not an updater), so we\n // branch off the current `sort` snapshot:\n // - new field → asc\n // - same field, currently asc → desc\n // - same field, currently desc → null (3rd click clears)\n const currentEntry = current[0];\n if (currentEntry?.field !== field) {\n u.setSort([{ field, direction: 'asc' }]);\n } else if (currentEntry.direction === 'asc') {\n u.setSort([{ field, direction: 'desc' }]);\n } else {\n u.setSort([]);\n }\n }, []);\n\n const setVisible = useCallback((next: string[] | undefined) => {\n volatileRef.current.urlState.setVisibleColumns(next ?? null);\n }, []);\n\n /**\n * Header-menu «hide»: drop the column from the visible set unless it is\n * a required column. Moved verbatim from the `<ResourceList\n * onHideColumn>` closure, `_list-body.tsx:1588-1593`.\n */\n const hide = useCallback((field: string) => {\n const { requiredColumns: required, visibleColumns: visible, urlState: u } = volatileRef.current;\n if (required.includes(field)) return;\n u.setVisibleColumns(visible.filter((c) => c !== field));\n }, []);\n\n /**\n * Both Columns-menu footer actions, parameterized (see the contract note\n * on {@link ResourceListController.columns}`.restoreDefaults`):\n * - `'sizes'` → the old `onResetSizes` (`_list-body.tsx:1455`): bump\n * the token in sizes mode only.\n * - `'all'` (default) → the old `onRestoreDefaults`\n * (`_list-body.tsx:1456-1461`): sizes + pins + order via the token,\n * AND clear visibility, AND clear sort.\n */\n const restoreDefaults = useCallback((mode: 'sizes' | 'all' = 'all') => {\n setResetLayout((r) => ({ token: r.token + 1, mode }));\n if (mode === 'all') {\n volatileRef.current.urlState.setVisibleColumns(null);\n volatileRef.current.urlState.setSort([]);\n }\n }, []);\n\n const clearSelection = useCallback(() => {\n setSelectedIds(NO_SELECTION);\n setSelectedCache(NO_CACHE);\n }, []);\n\n const setSelection = useCallback((ids: string[]) => {\n setSelectedIds(ids);\n // The cache is rebuilt from the incoming set on every change: newly\n // selected ids get a snapshot from the current page, kept ids keep the\n // one they already had, and deselected ids are pruned — so the cache\n // never outgrows the selection.\n setSelectedCache((prev) => {\n const currentRowsById = volatileRef.current.rowsById;\n const next: Record<string, RowRecord> = {};\n for (const id of ids) {\n const row = currentRowsById.get(id) ?? prev[id];\n if (row) next[id] = row;\n }\n const prevKeys = Object.keys(prev);\n const unchanged =\n prevKeys.length === Object.keys(next).length &&\n prevKeys.every((key) => prev[key] === next[key]);\n return unchanged ? prev : next;\n });\n }, []);\n\n /**\n * Apply a saved view — REPLACE pattern: every URL-state field is\n * unconditionally rewritten from the view's declared state, falling\n * back to the framework defaults for fields the view doesn't mention.\n * The url-state hook's same-tick batching merges all six setters.\n *\n * Also fires `opts.onReset` so app-owned chip visibility resets in step\n * — chips for fields the new view doesn't filter on should disappear,\n * and the toolbar re-adds chips for the new filter set on its own.\n *\n * ⚠️ SP0b Task 2 — reads `volatileRef.current.declaredDefaults`, the\n * SAME object passed to `useResourceUrlState` above, not the module\n * constant `URL_STATE_DEFAULTS`. A view that doesn't mention `pageSize`\n * (most don't — it's rarely part of what a saved view is FOR) must reset\n * to the RESOURCE's declared page size, not to a hardcoded framework\n * `10`; passing a second, independently-hardcoded default here would\n * silently drop the user back to 10 rows the moment they applied any\n * view on a resource that declared 100 — a regression that surfaces\n * three clicks in (apply → observe fine → apply a plainer view → page\n * size quietly changes) and is easy to miss in review.\n *\n * Moved from `applyView`, `_list-body.tsx:939-953`\n * (`setVisibleIds(new Set())` → the `onReset` seam).\n */\n const applyView = useCallback((view: SavedViewDef) => {\n const { dropped } = applyViewToUrlState(view, volatileRef.current.urlState, {\n defaults: volatileRef.current.declaredDefaults,\n visible: volatileRef.current.predicateVisible,\n });\n if (dropped > 0) setViewDropped((count) => count + dropped);\n volatileRef.current.onReset?.();\n }, []);\n\n /**\n * Snapshot the CURRENT url state and persist it as a new user view. No\n * `page` in the snapshot — a saved view is never a position within a\n * query's results (spec §12); `useSavedViews().saveCurrentAsView` drops\n * it unconditionally even if it were passed.\n *\n * ⚠️ I8 — this **rejects** (Task 8: the settings store is async, so\n * this whole chain is now too). `useSavedViews().saveCurrentAsView`\n * rejects on an empty label and on a failed store mutation (quota /\n * permission denied / conflict, `use-saved-views.ts`), and that\n * propagates unchanged. The `await` + try/catch, the toast, the label\n * input and the two dialogs all stay in the app (`handleSaveConfirm`,\n * `_list-body.tsx:960-978`) — no `@burojs/ui-shadcn` `toast` import\n * may cross into this package.\n *\n * Moved from `handleSaveConfirm`, minus the toast/label/dialog handling.\n */\n const saveCurrent = useCallback((label: string, scopeId?: string): Promise<SavedViewDef> => {\n const { urlState: u, saveCurrentAsView: save } = volatileRef.current;\n return save(\n label,\n {\n filters: u.filters,\n filterGroup: u.filterGroup,\n sort: u.sort,\n pageSize: u.pageSize,\n search: u.search,\n visibleColumns: u.visibleColumns,\n },\n scopeId,\n );\n }, []);\n\n const renameUser = useCallback((id: string, label: string): Promise<void> => {\n return volatileRef.current.renameUserView(id, label);\n }, []);\n\n const deleteUser = useCallback((id: string): Promise<void> => {\n return volatileRef.current.deleteUserView(id);\n }, []);\n\n /** Fork an entry into `scopeId` (Task 9 — spec §5's \"fork/copy into a writable scope\"). */\n const forkView = useCallback(\n (id: string, scopeId: string, label?: string): Promise<SavedViewDef> => {\n return volatileRef.current.forkUserView(id, scopeId, label);\n },\n [],\n );\n\n const refetch = useCallback(() => {\n volatileRef.current.refetch();\n }, []);\n\n const pauseLive = useCallback(() => setLivePaused(true), []);\n const resumeLive = useCallback(() => setLivePaused(false), []);\n\n /**\n * Cursor-mode load-more (B5.2). Guarded here rather than at the call\n * site so a consumer can wire it straight to `onClick` — a double-click\n * or a click during the fetch is a no-op, not a second page skipped.\n *\n * `hasNextPage` (not `next !== null`) is the gate on purpose: it is\n * react-query's own verdict, computed from the REAL page array, so while\n * a new query key's first page is in flight — the window in which\n * `placeholderData` is showing the previous key's pages — it is `false`\n * and this correctly refuses to advance a cursor that belongs to a query\n * that no longer exists.\n */\n const loadMore = useCallback(() => {\n const v = volatileRef.current;\n if (!v.hasNextPage || v.isFetchingNextPage) return;\n v.fetchNextPage();\n }, []);\n\n // `availability` is read through the volatile ref for the same reason every\n // other callback here is: this function must keep a stable identity or the\n // memoized table body re-renders on every parent render.\n const rowHref = useCallback((row: RowRecord) => {\n if (!volatileRef.current.isCurrentData) return undefined;\n const { registry, def: d, resource: r, availability: gate } = volatileRef.current;\n // The gate is policy: it reads the row as read, whichever form (projected or not) the caller\n // holds (P5 spec 3.6.6).\n const raw = volatileRef.current.rowsById.get(String(row.id)) ?? row;\n return rowHrefFor(registry, d, r, String(row.id), gate, raw);\n }, []);\n\n // -------------------------------------------------------------------\n // Groups. Each is memoized on its own state values; the callbacks above\n // are permanently stable, so a group only changes when its DATA does.\n // -------------------------------------------------------------------\n\n const isLoading =\n accessPending || (!forbidden && (isCursor ? cursorQuery.isLoading : offsetQuery.isLoading));\n const isFetching = isCursor ? cursorQuery.isFetching : offsetQuery.isFetching;\n const isPlaceholderData = isCursor\n ? cursorQuery.isPlaceholderData\n : offsetQuery.isPlaceholderData;\n const isCurrentData = isCursor ? cursorQuery.isCurrentData : offsetQuery.isCurrentData;\n volatileRef.current.isCurrentData = isCurrentData;\n // Pre-resolved to `null` when there is no error (`_list-body.tsx:1577`).\n const rawError = isCursor ? cursorQuery.error : offsetQuery.error;\n const error = rawError ? (rawError as unknown as Error) : null;\n const queryGroup = useMemo(\n () => ({ isLoading, isFetching, isPlaceholderData, isCurrentData, error, refetch }),\n [isLoading, isFetching, isPlaceholderData, isCurrentData, error, refetch],\n );\n\n // The provider's own count when it reports one, otherwise whatever the\n // user asked for on demand. ONE field, ONE absent-sentinel — see the\n // contract note on `pagination.total`.\n //\n // In cursor mode the LAST page carries it: a token provider that can\n // count at all reports the same total on every page, and reading the\n // freshest one means a total that moves as rows are added is not frozen\n // at page one. Temporal reports none, so this is `undefined` there and\n // the unknown-total contract holds unchanged.\n const lastCursorPage = cursorPages?.[cursorPages.length - 1];\n const total =\n forbidden || countPolicy === 'off'\n ? undefined\n : countPolicy === 'provided'\n ? inlineTotal\n : countValue === null\n ? undefined\n : (inlineTotal ?? countValue);\n /**\n * `PAGE_SIZE_OPTIONS` plus the declared `views.list.pageSize`, merged in\n * when it isn't already one of the four base choices — otherwise a\n * resource declaring e.g. `pageSize: 30` gets a size selector with no\n * option matching its own default. Identity stays `PAGE_SIZE_OPTIONS`\n * itself (module scope) for every resource that declares nothing, or\n * whose declared value already appears in the base list.\n */\n const pageSizeOptions = useMemo(\n () =>\n declaredPageSize !== undefined && !PAGE_SIZE_OPTIONS.includes(declaredPageSize)\n ? [...PAGE_SIZE_OPTIONS, declaredPageSize].sort((a, b) => a - b)\n : PAGE_SIZE_OPTIONS,\n [declaredPageSize],\n );\n const pagination = useMemo(\n () => ({\n page,\n pageSize,\n pageSizeOptions,\n total,\n setPage,\n setPageSize,\n }),\n [page, pageSize, pageSizeOptions, total, setPage, setPageSize],\n );\n\n /**\n * The cursor group — `null` for every offset list, which is the\n * discriminator the contract documents.\n *\n * `next` is ANDed with react-query's `hasNextPage` so the token and the\n * ability to spend it can never disagree: a consumer rendering\n * `next !== null` and calling `loadMore()` always gets a page.\n *\n * ⚠️ Memoized, and `cursor` is a dep of the root memo below. An inline\n * `{ … }` literal would return a fresh object on every render and break\n * the identity contract at the root — which\n * `use-resource-list.test.tsx`'s three-re-render `Object.is` assertion\n * would catch, but only after it had already shipped a re-render storm\n * into every consumer's `useMemo` deps.\n */\n const cursorNext =\n isCursor && cursorQuery.hasNextPage ? (lastCursorPage?.pageInfo?.nextCursor ?? null) : null;\n const isLoadingMore = isCursor && cursorQuery.isFetchingNextPage;\n const cursor = useMemo(\n () => (isCursor ? { next: cursorNext, loadMore, isLoadingMore } : null),\n [isCursor, cursorNext, loadMore, isLoadingMore],\n );\n\n /**\n * The live-polling slice — present only when an interval is both declared\n * and applicable (offset pagination). `pause`/`resume` are permanently\n * stable (see `pauseLive`/`resumeLive` above), so this group changes only\n * when `isPaused` does, and is `undefined` (not present-but-inert) for\n * every resource that doesn't opt in — see the contract note on\n * `ResourceListController.live`.\n */\n const live = useMemo(\n () =>\n liveInterval !== null && !liveDisabledByCursor\n ? { intervalMs: liveInterval, isPaused: isLivePaused, pause: pauseLive, resume: resumeLive }\n : undefined,\n [liveInterval, liveDisabledByCursor, isLivePaused, pauseLive, resumeLive],\n );\n\n // `requestCount` is permanently stable, so this group changes only when\n // the affordance's own two booleans do — an inline literal here would\n // break the controller's identity contract on every render.\n const count = useMemo(\n () => ({ available: countAvailable, isLoading: countQuery.isFetching, request: requestCount }),\n [countAvailable, countQuery.isFetching, requestCount],\n );\n\n const filtersGroup = useMemo(\n () => ({\n value: urlFilters,\n set: setFilters,\n available,\n search,\n setSearch,\n ...(searchDecl === undefined ? {} : { searchDecl }),\n searchEnabled,\n isFiltered,\n clearAll,\n group: filterGroup,\n setGroup,\n fixed: fixedFilters,\n pinnedFields,\n }),\n [\n urlFilters,\n setFilters,\n available,\n search,\n setSearch,\n searchDecl,\n searchEnabled,\n isFiltered,\n clearAll,\n filterGroup,\n setGroup,\n fixedFilters,\n pinnedFields,\n ],\n );\n\n const sorting = useMemo(\n () => ({ value: sort, set: setSort, toggle: toggleSort }),\n [sort, setSort, toggleSort],\n );\n\n const providerQuery = useMemo(\n () => ({ value: providerQueryValue, set: setProviderQuery }),\n [providerQueryValue, setProviderQuery],\n );\n\n const columns = useMemo(\n () => ({\n // Undecided: no column set at all (the table draws its skeleton), never a narrower one.\n all: accessPending ? NO_COLUMNS : allAvailable,\n visible: accessPending ? NO_COLUMNS : visibleColumns,\n required: accessPending ? NO_COLUMNS : requiredColumns,\n optional: accessPending ? NO_COLUMNS : optionalColumns,\n defaultVisible: accessPending ? NO_COLUMNS : declaredColumns,\n setVisible,\n hide,\n resetLayout,\n restoreDefaults,\n }),\n [\n accessPending,\n allAvailable,\n visibleColumns,\n requiredColumns,\n optionalColumns,\n declaredColumns,\n setVisible,\n hide,\n resetLayout,\n restoreDefaults,\n ],\n );\n\n // Selected records: the current page's row wins (it is fresh), a snapshot\n // covers everything the user picked on a page they have since left. An id\n // with neither is kept in `ids` but has no record to contribute, so\n // `records.length` can be shorter than `ids.length`.\n const selectedRecords = useMemo(() => {\n if (selectedIds.length === 0) return NO_ROWS;\n const out: RowRecord[] = [];\n for (const id of selectedIds) {\n const row = rowsById.get(id) ?? selectedCache[id];\n if (row) out.push(row);\n }\n return out;\n }, [rowsById, selectedCache, selectedIds]);\n const selection = useMemo(\n () => ({\n ids: selectedIds,\n records: selectedRecords,\n set: setSelection,\n clear: clearSelection,\n }),\n [selectedIds, selectedRecords, setSelection, clearSelection],\n );\n\n const savedViews = useMemo(\n () => ({\n adopter: adopterViews,\n user: userViews,\n entries: savedViewEntries,\n writeScopes: savedViewWriteScopes,\n issues: savedViewIssues,\n pending: savedViewsPending,\n apply: applyView,\n saveCurrent,\n renameUser,\n deleteUser,\n forkView,\n }),\n [\n adopterViews,\n userViews,\n savedViewEntries,\n savedViewWriteScopes,\n savedViewIssues,\n savedViewsPending,\n applyView,\n saveCurrent,\n renameUser,\n deleteUser,\n forkView,\n ],\n );\n\n // Predicates on hidden fields the address and the applied saved views lost (P5 spec 3.7): the\n // filter bar says so once, with no field name or value.\n const droppedPredicates = urlState.droppedPredicates + viewDropped;\n\n // `createHref` is a plain string, so value equality is identity here.\n const createHref = resourceCreateHref(app.registry, def, resource);\n const routing = useMemo(() => ({ createHref, rowHref }), [createHref, rowHref]);\n // A list row as view code may read it (P5 spec 3.6.6, plan ruling 9): `rows` stay as read for\n // selection, bulk and item-action gates (policy).\n const viewRow = useViewRow(resource);\n // `rows` is what view code renders: every row projected by its user's field access. The rows as\n // read stay with policy (selection, item-action gates), through the side channel.\n const viewRows = useMemo(() => rows.map((row) => viewRow(row)), [rows, viewRow]);\n\n const controller = useMemo(\n () => ({\n resource,\n def,\n access,\n droppedPredicates,\n isForbidden: forbidden,\n viewRow,\n rows: viewRows,\n query: queryGroup,\n pagination,\n live,\n cursor,\n count,\n filters: filtersGroup,\n sorting,\n columns,\n selection,\n savedViews,\n routing,\n providerQuery,\n }),\n [\n resource,\n def,\n access,\n droppedPredicates,\n forbidden,\n viewRow,\n viewRows,\n queryGroup,\n pagination,\n live,\n cursor,\n count,\n filtersGroup,\n sorting,\n columns,\n selection,\n savedViews,\n routing,\n providerQuery,\n ],\n );\n return attachPolicyRows(controller, rows);\n}\n","'use client';\nimport { type ReactElement, type ReactNode, createContext, useContext } from 'react';\nimport type { ResourceListController } from './types.js';\n\n/**\n * `ResourceListProvider` + `useResourceListContext` (core flexibility\n * program, Task B1.3c). This is the seam a later sub-project's list\n * \"slots\" (search box, filter toolbar, pagination footer, column menu, …)\n * will read the controller through, instead of a prop chain threaded by\n * hand through every intermediate component.\n *\n * The reason this earns its own task rather than being folded into\n * `useResourceList` itself (B1.3b): a slot built against\n * `useResourceListContext()` can be unit-tested by mounting\n * `<ResourceListProvider value={handWrittenStub}>` around it — no\n * `BuroProvider` or other app-level provider, no data provider, no\n * `next/navigation` mock, and no real `useResourceList` call at all — the\n * provider only ever hands out whatever `value` it was given. See\n * `tests/use-resource-list-context.test.tsx` for the proof; that\n * testability is the entire point of this file.\n *\n * @see docs/superpowers/plans/2026-07-26-cfb1-list-controller.md — Task B1.3c\n */\n\n/**\n * `null` means \"no provider mounted\". Not exported: consumers go through\n * {@link ResourceListProvider} to write and {@link useResourceListContext}\n * to read, matching this package's existing provider/hook pairs (compare\n * `AppContext` / `useApp`, `../context.js`).\n */\nconst ResourceListContext = createContext<ResourceListController | null>(null);\n\nexport interface ResourceListProviderProps {\n /**\n * The controller to hand to the tree beneath — typically the return\n * value of `useResourceList(resource, opts)`, but a plain hand-written\n * object satisfying {@link ResourceListController} works exactly as\n * well (that substitutability is what makes slot unit tests cheap).\n */\n value: ResourceListController;\n children?: ReactNode;\n}\n\n/**\n * Makes a {@link ResourceListController} available to the component tree\n * beneath it via {@link useResourceListContext}.\n */\nexport function ResourceListProvider({ value, children }: ResourceListProviderProps): ReactElement {\n return <ResourceListContext.Provider value={value}>{children}</ResourceListContext.Provider>;\n}\n\n/**\n * Read the nearest {@link ResourceListController} mounted via\n * {@link ResourceListProvider}. Throws when no provider is mounted rather\n * than degrading to an optional return: a slot has nothing meaningful to\n * render without a controller, so failing loudly at the read site beats\n * every caller re-deriving its own \"is this undefined?\" guard.\n */\nexport function useResourceListContext(): ResourceListController {\n const ctx = useContext(ResourceListContext);\n if (!ctx) {\n throw new Error('[useResourceListContext] must be used within a ResourceListProvider');\n }\n return ctx;\n}\n","'use client';\nimport type { UIPresentResult } from '@burojs/core';\nimport { useCallback, useContext } from 'react';\nimport { DismissRegistryContext, DismissScopeContext } from '../navigation/dismiss-scope.js';\nimport { useUIPresentationRuntime } from './context.js';\nimport { useOptionalPresentationMount } from './mount.js';\nimport { BLOCK_COMPONENT, type BlockScreenProps } from './ui-presentations.js';\nimport { findInvalidOptionsMessage, useCurrentUIActivation } from './use-ui-present.js';\n\n/** What a modal action opens (P7 3.16): the block screen's props, in a dialog or a sheet. */\nexport interface PresentBlockInput extends BlockScreenProps {\n readonly host: 'dialog' | 'sheet';\n /** The activation the block is opened under; the ambient one when omitted. */\n readonly activation?: Partial<ReturnType<typeof useCurrentUIActivation>>;\n}\n\n/**\n * @internal Opens a modal action's block in the UI kit's `screens.block` (P7 3.16): the framework's\n * own opener for the reserved `buro:block` key, which an app's `useUIPresent` refuses. The opener's\n * dismiss scope becomes the overlay's parent, as for every overlay (P3-30), so closing a quick\n * sheet asks about a dirty block above it. `{ ok: false }` when nothing could be presented.\n */\nexport function usePresentBlock(): (input: PresentBlockInput) => UIPresentResult {\n const runtime = useUIPresentationRuntime();\n const mount = useOptionalPresentationMount();\n const registry = useContext(DismissRegistryContext);\n const enclosing = useContext(DismissScopeContext);\n const ambient = useCurrentUIActivation();\n return useCallback(\n (input: PresentBlockInput): UIPresentResult => {\n if (mount !== null && mount.mode === 'app' && !mount.registry.isMounted()) {\n console.error(\n '[burojs] A modal action opened nothing: BuroProvider is in presentations=\"app\" mode but no <BuroPresentationOutlet/> is mounted.',\n );\n return Object.freeze({ ok: false, code: 'outlet-missing' as const });\n }\n const { host, activation, ...props } = input;\n const options = typeof input.label === 'string' ? { title: input.label } : {};\n // The host's options contract is the same one `useUIPresent` enforces (and refuses with the\n // same code): a host that does not declare `title` is not handed one.\n const schema = mount?.hosts[host]?.optionsSchema;\n if (schema !== undefined) {\n const message = findInvalidOptionsMessage(BLOCK_COMPONENT, host, schema, options);\n if (message !== null) {\n console.error(message);\n return Object.freeze({ ok: false, code: 'invalid-options' as const });\n }\n }\n const presented = runtime.present({\n component: BLOCK_COMPONENT,\n host,\n props: props as unknown as Record<string, unknown>,\n options,\n activation: { ...ambient, ...activation },\n });\n if (presented.ok && registry !== null && enclosing !== null)\n registry.recordParent(presented.instance.id, enclosing.id);\n return presented;\n },\n [runtime, mount, registry, enclosing, ambient],\n );\n}\n","import type { BlockImplementation } from '../blocks/implementation.js';\nimport { useBlockImplementations } from '../blocks/context.js';\n\n/**\n * @internal The app's view of the block a flow's `then.open` names (P4 spec 4.13), by its\n * `<namespace>:<name>` id, from the catalog mounted in `<BuroProvider blockImplementations>`;\n * `undefined` when the app implements none (the UI kit falls back to its own).\n */\nexport function useFlowOpenImplementation(id: string): BlockImplementation<unknown> | undefined {\n const catalog = useBlockImplementations();\n return Object.hasOwn(catalog, id) ? (catalog[id] as BlockImplementation<unknown>) : undefined;\n}\n","import { resolveActionSurfaceMode } from '@burojs/core';\nimport type { ActionFlow, ResourceDef } from '@burojs/core';\n\n/** The surfaces a resource-level flow can be drawn on, besides the record ones (P7-31). */\nexport type ResourceFlowSurface = 'list';\n\n/**\n * The resource-level flows (`actions.resource`) a resource draws on `surface`, in the order its\n * toolbar shows them: `order` first (ascending; a flow without one keeps its declaration\n * position among the unordered), then declaration order. A flow whose `surfaces` resolve to\n * `false` on `surface` is left out; the rest are `'menu'` or a prominent mode.\n */\nexport function resourceFlowsOn(\n def: Pick<ResourceDef, 'actions'>,\n surface: ResourceFlowSurface,\n): readonly ActionFlow[] {\n const declared = (def.actions?.resource ?? []) as readonly unknown[];\n return declared\n .map((entry, index) => ({ entry, index }))\n .filter(\n (item): item is { entry: ActionFlow; index: number } =>\n (item.entry as { kind?: unknown } | null)?.kind === 'flow' &&\n resolveActionSurfaceMode((item.entry as ActionFlow).surfaces, surface) !== false,\n )\n .sort(\n (a, b) =>\n (a.entry.order ?? Number.POSITIVE_INFINITY) - (b.entry.order ?? Number.POSITIVE_INFINITY) ||\n a.index - b.index,\n )\n .map((item) => item.entry);\n}\n","/**\n * Shallow merge of components objects. Overrides keys win; both inputs unchanged.\n */\nexport function mergeComponents<\n TBase extends Record<string, unknown>,\n TOver extends Record<string, unknown>,\n>(base: TBase, overrides: TOver): TBase & TOver {\n return { ...base, ...overrides };\n}\n","import {\n type AppRuntime,\n canonicalEntityNodeKey,\n leafBasePath,\n recordEntries,\n resolveStaticAvailability,\n} from '@burojs/core';\nimport type { ReactElement } from 'react';\n\n/** A resource's list/show/edit/create route. */\nexport interface ResourceRouteDescriptor {\n resource: string;\n action: 'list' | 'show' | 'edit' | 'create' | 'flow';\n path: string;\n}\n\n/** A custom (non-resource) page's single route. */\nexport interface CustomPageRouteDescriptor {\n page: string;\n action: 'page';\n path: string;\n}\n\nexport type RouteDescriptor = ResourceRouteDescriptor | CustomPageRouteDescriptor;\n\n/**\n * Every URL the app expects to exist, for a host that mounts routes at\n * runtime (react-router, TanStack Router) rather than from files.\n *\n * Paths come from `leafBasePath` — the SAME derivation `hrefFor` uses for the\n * sidebar. That is the whole point: a resource or page inside nav groups gets\n * a nested URL (`/settings/integrations/webhook`), and if this function\n * derived its own simpler path the sidebar would link somewhere no route was\n * registered. Under Next the two could not drift, because routes are files the\n * app author places in the nested folder by hand; a runtime host mounts\n * exactly what this returns, so the two derivations have to be one derivation.\n *\n * Custom pages are included. They are a separate registry namespace, but a\n * runtime host still needs a route for each one, and their URLs derive from\n * the same group chain.\n */\nexport function generateRouteDescriptors(app: AppRuntime): RouteDescriptor[] {\n const descriptors: RouteDescriptor[] = [];\n for (const def of app.registry.list()) {\n const ref = def.ref;\n const resourceKey = canonicalEntityNodeKey(def);\n const base = leafBasePath(app.registry, def);\n // The STATIC form: route generation has no user, no record and no scope,\n // so it can only honour what is true for everyone. A dynamic denial dims\n // affordances; it does not remove routes.\n // `views.show.page: false` removes the three record routes too (`recordEntries`): its record\n // is reached through its quick entries only.\n const entries = recordEntries(def);\n const has = (op: 'show' | 'edit' | 'create') =>\n entries.page[op] &&\n resolveStaticAvailability(app.registry, (ref ?? def.name) as string, op).state ===\n 'available';\n\n descriptors.push({ resource: resourceKey, action: 'list', path: base });\n if (has('show'))\n descriptors.push({ resource: resourceKey, action: 'show', path: `${base}/:id` });\n if (has('edit'))\n descriptors.push({ resource: resourceKey, action: 'edit', path: `${base}/:id/edit` });\n if (has('create'))\n descriptors.push({ resource: resourceKey, action: 'create', path: `${base}/create` });\n // A page-hosted flow lives at `<record route>/<flow name>` (P6): one route for the flows that\n // could host a page (an item flow with a form or a review; a granted layer may set `host`),\n // which the page answers itself — not-found unless that flow exists and hosts a page.\n const pageCandidate = (def.actions?.item as readonly unknown[] | undefined)?.some((action) => {\n const flow = action as { kind?: unknown; form?: unknown; review?: unknown } | null;\n return flow?.kind === 'flow' && (flow.form !== undefined || flow.review !== undefined);\n });\n if (pageCandidate === true && (has('show') || has('edit')))\n descriptors.push({ resource: resourceKey, action: 'flow', path: `${base}/:id/:flow` });\n }\n for (const page of app.registry.customPages.list()) {\n const pageKey = canonicalEntityNodeKey(page);\n descriptors.push({\n page: pageKey,\n action: 'page',\n path: leafBasePath(app.registry, page),\n });\n }\n return descriptors;\n}\n\n/** Narrowing helper — `action: 'page'` is the discriminant. */\nexport function isCustomPageRoute(d: RouteDescriptor): d is CustomPageRouteDescriptor {\n return d.action === 'page';\n}\n\n/**\n * <BuroRoutes> placeholder. In v0.1, route mounting is on the user;\n * use generateRouteDescriptors to produce route descriptors and mount via\n * react-router or Next App Router. Full integration arrives in Plan 7.\n */\nexport function BuroRoutes(): ReactElement {\n return <></>;\n}\n","export const en = {\n validation: {\n requiredHint: '(required)',\n required: 'This field is required',\n string: {\n minLength: 'Too short',\n maxLength: 'Too long',\n pattern: 'Invalid format',\n },\n constraint: { invalid: 'Invalid value' },\n number: {\n minimum: 'Value is too small',\n maximum: 'Value is too large',\n exclusiveMinimum: 'Value is too small',\n exclusiveMaximum: 'Value is too large',\n multipleOf: 'Value is not an allowed step',\n },\n array: {\n minItems: 'Too few items',\n maxItems: 'Too many items',\n uniqueItems: 'Items must be unique',\n },\n validator: { invalid: 'Invalid value', exception: 'Validation failed' },\n schema: { invalid: 'Invalid value', exception: 'Validation failed' },\n resource: { invalid: 'Invalid value' },\n type: {\n string: 'Must be text',\n number: 'Must be a number',\n boolean: 'Must be yes or no',\n array: 'Must be a list',\n object: 'Must be an object',\n },\n },\n actions: {\n close: 'Close',\n clearSelection: 'Clear',\n create: 'Create',\n edit: 'Edit',\n delete: 'Delete',\n show: 'Open',\n auditLog: 'Audit log',\n save: 'Save',\n cancel: 'Cancel',\n refresh: 'Refresh',\n submit: 'Submit',\n ok: 'OK',\n confirm: 'Confirm',\n back: 'Back',\n next: 'Next',\n retry: 'Retry',\n saving: 'Saving…',\n creating: 'Creating…',\n submitting: 'Submitting…',\n validating: 'Validating…',\n // Overflow-menu chrome (Workstream B — actions overflow).\n more: 'More',\n column: 'Actions',\n openMenu: 'Open row actions menu',\n },\n confirm: {\n delete: 'Are you sure you want to delete?',\n deleteMany_one: 'Are you sure you want to delete {{count}} record?',\n deleteMany_few: 'Are you sure you want to delete {{count}} records?',\n deleteMany_many: 'Are you sure you want to delete {{count}} records?',\n deleteMany_other: 'Are you sure you want to delete {{count}} records?',\n discardChanges: 'Discard unsaved changes?',\n ok: 'OK',\n confirm: 'Confirm',\n },\n checks: {\n // Already neutral across surfaces (save / action / delete) — kept\n // verbatim; see the RU bundle's note, where the save-specific wording\n // had to be fixed.\n dialogTitle: 'Please review',\n proceed: 'Continue anyway',\n back: 'Go back',\n blocked: 'Cannot continue',\n couldNotVerify: 'Could not verify \"{{checkId}}\"',\n notVerified: 'Check \"{{checkId}}\" failed to run',\n parseError: 'Check \"{{checkId}}\" has an invalid condition: {{detail}}',\n },\n table: {\n selectedCount_one: '{{count}} selected',\n selectedCount_few: '{{count}} selected',\n selectedCount_many: '{{count}} selected',\n selectedCount_other: '{{count}} selected',\n empty: 'No records',\n loading: 'Loading…',\n rowsSelected_one: '{{count}} selected',\n rowsSelected_few: '{{count}} selected',\n rowsSelected_many: '{{count}} selected',\n rowsSelected_other: '{{count}} selected',\n selectAllRows: 'Select all rows',\n selectRow: 'Select row',\n },\n boolean: {\n yes: 'Yes',\n no: 'No',\n active: 'Active',\n inactive: 'Inactive',\n },\n pagination: {\n showingUnknownTotal: 'Showing {{from}}–{{to}}',\n // The on-demand row-count trigger (Task B4.3). Deliberately the ONLY new\n // key: on success the total lands in `pagination.total` and `showing`\n // above renders the answer, and while the request is in flight the label\n // is replaced by a spinner in place — so there is neither a result string\n // nor a loading string to translate.\n countRows: 'Count rows',\n // Cursor (opaque-token) pagination — `<CursorLoadMore>` (Task B5.3).\n // A token list has no page count and no last page, so there is nothing\n // to number: the only affordance is \"give me the next page\".\n loadMore: 'Load more',\n loadingMore: 'Loading…',\n emptyPage: 'No records on this page',\n pageOnly: 'Page {{page}}',\n previous: 'Previous',\n next: 'Next',\n prev: 'Prev',\n pageOf: 'Page {{page}} of {{total}}',\n showing: 'Showing {{from}}–{{to}} of {{total}}',\n rowsPerPage: 'Rows per page',\n firstPage: 'Go to first page',\n previousPage: 'Go to previous page',\n nextPage: 'Go to next page',\n lastPage: 'Go to last page',\n },\n filters: {\n // Comparison operators stay as SYMBOLS in both locales. The round-6 finding\n // was about English WORDS («contains», «starts with») leaking into a Russian\n // UI; `>` `≥` `<` `≤` are mathematical notation, not English — they need no\n // translation, they are unambiguous, and they fit a narrow filter chip where\n // «больше или равно» does not. Translating them was an over-correction.\n operators: {\n eq: 'equals',\n ne: 'not equals',\n gt: '>',\n gte: '≥',\n lt: '<',\n lte: '≤',\n in: 'in',\n nin: 'not in',\n contains: 'contains',\n ncontains: 'not contains',\n between: 'between',\n nbetween: 'not between',\n null: 'is empty',\n nnull: 'is not empty',\n startswith: 'starts with',\n endswith: 'ends with',\n // The AST predicate vocabulary (`FilterPredicateOp`, `@burojs/core`)\n // used by the filter-builder row (Task 5) — newer and differently\n // named than the `FilterOperator` set above (`ne`/`nin`/`startswith`),\n // which stays as-is because `DataTableOperatorFilter` still reads it.\n // `eq`/`gt`/`gte`/`lt`/`lte`/`in`/`contains` are shared by both sets.\n neq: 'not equals',\n notIn: 'not in',\n startsWith: 'starts with',\n endsWith: 'ends with',\n isNull: 'is empty',\n isNotNull: 'is not empty',\n },\n clearAll: 'Clear filters',\n apply: 'Apply',\n clear: 'Clear',\n // Filter-builder panel (Task 6). Distinct from `clear` above (a per-row\n // value control's own \"clear this value\" action) — `reset` empties the\n // WHOLE draft but, unlike `clearAll`, does not apply anything; the user\n // still presses `apply` to make the empty state take effect.\n reset: 'Reset',\n // Filter button label (Task 6), e.g. \"Filters\" + the applied-row count.\n title: 'Filters',\n // An `in`/`notIn` predicate's array value on an applied-filter badge\n // (Task 6) — too many picks to list, so the badge reads \"`n` selected\"\n // instead.\n selectedCount_one: '{{count}} selected',\n selectedCount_few: '{{count}} selected',\n selectedCount_many: '{{count}} selected',\n selectedCount_other: '{{count}} selected',\n is: 'is',\n isNot: 'is not',\n contains: 'contains',\n // Generic aria-label / placeholder / empty-selection text for a builder\n // row's value control (`filter-value-control.tsx` and its four\n // implementations) — deliberately field-agnostic, unlike `operators.*`.\n value: 'Value',\n // Field-aware accessible name for the SAME value controls (SP2\n // final-review finding 7) — used instead of `value` above whenever the\n // caller has a field label to give (every builder row; every pinned\n // control). `{{field}}` interpolates `FilterFieldSpec.label`.\n valueFor: 'Value for {{field}}',\n // aria-labels for a builder row's field/operator `Select` triggers\n // (finding 7) — otherwise two adjacent comboboxes per row announce as\n // unlabelled to a screen reader, indistinguishable from each other and\n // from every other row's.\n field: 'Field',\n operator: 'Operator',\n // Filter-builder group chrome (Task 5) — `where` precedes the first\n // row, `and`/`or` label the group's join (a toggle on row 2, read-only\n // text after). Task 6's `describeRow` reuses `and`/`or` to join a\n // folded nested group's rows on an applied-filter badge.\n where: 'Where',\n and: 'and',\n or: 'or',\n // Accessible name for that toggle. Its visible text is the single word\n // `and`/`or` — in Russian a single LETTER — which names neither what the\n // control is nor what pressing it does.\n toggleJoin: 'Join: {{current}} — activate to switch to {{next}}',\n addRow: 'Add filter',\n addGroup: 'Add group',\n removeRow: 'Remove filter',\n removeGroup: 'Remove group',\n },\n errors: {\n required: 'Required',\n invalid: 'Invalid value',\n failed: 'Validation failed',\n validatorFailed: 'Could not validate the form. Please try again.',\n },\n // A field leaf its user may see the label of but not the value (P5 spec 3.6).\n access: {\n restricted: 'No access',\n },\n // List-page chrome (empty / loading / error states). `{{items}}` is the\n // resource plural label, `{{item}}` the singular — both interpolated by the\n // caller (already lowercased where the original literal lowercased).\n list: {\n loadingShort: 'Loading…',\n notRegistered: 'Resource not registered',\n loading: 'Loading {{items}}…',\n errorTitle: 'Something went wrong',\n errorBody: 'Failed to load data. Please try again.',\n errorDetails: 'Details',\n emptyTitle: 'No {{items}} yet',\n emptyBody: 'Get started by creating your first {{item}}.',\n emptyBodyReadOnly: 'They will appear here once they are added.',\n emptyFilteredTitle: 'No matching {{items}}',\n emptyFilteredBody:\n 'No {{items}} match the current filter. Try clearing the filter to see everything.',\n clearFilter: 'Clear filter',\n create: '+ Create {{item}}',\n // A typed resource's discriminator cell: the row's value matches no\n // declared type (null, empty, or a token the app doesn't know).\n templateUnknown: 'Unknown',\n // Generic search-box placeholder/label for a resource whose `views.list.search`\n // is a resolver (no single field to name — see `toolbar.searchBy` for the\n // declarative-field form).\n search: 'Search',\n // The filter bar's notice when predicates on fields the user may not view were dropped\n // (P5 spec 3.7): no field name, no value.\n predicatesDropped: 'Some saved filters were not applied',\n flowsMenu: 'More actions',\n },\n // A `related-list` timeline (`view: 'timeline'`).\n timeline: {\n empty: 'No entries',\n undated: 'Undated',\n },\n // Sidebar top-level group label.\n breadcrumbs: {\n create: 'Create',\n edit: 'Edit',\n },\n nav: {\n skipToContent: 'Skip to content',\n resources: 'Resources',\n main: 'Main navigation',\n breadcrumb: 'Breadcrumb',\n // Accessible name for the sidebar toggle, whose `title` also renders as a\n // hover tooltip.\n toggleSidebar: 'Toggle sidebar',\n label: 'Navigation',\n },\n shell: {\n refresh: 'Refresh',\n help: 'Help',\n scopeSwitcher: 'Switch',\n scopePlaceholder: 'Select…',\n account: 'Account',\n },\n theme: {\n label: 'Theme',\n light: 'Light',\n dark: 'Dark',\n system: 'System',\n },\n language: {\n label: 'Language',\n },\n // PageHeader back-link + computed titles.\n pageHeader: {\n backTo: 'Back to {{label}}',\n editTitle: 'Edit {{label}}',\n editTitleNamed: 'Edit {{label}}: {{name}}',\n createTitle: 'Create {{label}}',\n },\n router: {\n emptyTitle: 'Nothing here',\n emptyBody: 'This page has no registered content.',\n notFoundTitle: 'Page not found',\n notFoundBody: \"This route doesn't match any registered page.\",\n // Record routes (`<RecordPage>`, P0). Neutral sentences under the page's\n // own title: `forbidden` and `not-found` share one (no existence oracle).\n recordLoading: 'Loading…',\n recordNotFound: 'This record does not exist, or you do not have access to it.',\n recordSessionExpired: 'Your session has expired. Sign in again to continue.',\n recordError: 'The record could not be loaded.',\n },\n notifications: {\n region: 'Notifications',\n },\n create: {\n pickType: 'Pick a type to continue.',\n unsupportedType: 'Unsupported type',\n unsupportedTypeHint: 'The type “{{type}}” is not registered for this resource.',\n backToPicker: 'Back to picker',\n /** The built-in type offer of a typed create (P1b+P1c decision 24). */\n typeOffer: {\n title: 'Choose a type',\n hint: 'The type decides which fields the record has.',\n empty: 'No type can be created here.',\n change: 'Change type',\n },\n },\n // `<TaskRunPanel>` — progress and partial failure for work long enough to\n // watch. `partial` is the state nothing else in this framework names: the run\n // finished and still left units behind, which is neither a success nor a\n // failure and must not be reported as either.\n taskRun: {\n idle: 'Not started',\n running: 'Running',\n complete: 'Finished',\n partial: 'Finished, with refusals',\n stopped: 'Stopped',\n cancelled: 'Cancelled',\n count: '{{completed}} of {{total}}',\n countUnknownTotal: '{{completed}} done',\n },\n // Login / auth surfaces.\n auth: {\n invalidEmail: 'Invalid email',\n passwordRequired: 'Password required',\n invalidCredentials: 'Incorrect email or password.',\n signOut: 'Sign out',\n signIn: 'Sign in',\n signingIn: 'Signing in…',\n email: 'Email',\n password: 'Password',\n },\n // List / data-table toolbar controls.\n toolbar: {\n clearAll: 'Clear all',\n clearAllAria_one: 'Clear {{count}} active filter',\n clearAllAria_few: 'Clear {{count}} active filters',\n clearAllAria_many: 'Clear {{count}} active filters',\n clearAllAria_other: 'Clear {{count}} active filters',\n addFilter: 'Add filter',\n filterBy: 'Filter by',\n columns: 'Columns',\n views: 'Views',\n viewsDefaults: 'Defaults',\n // The framework's own local-user scope (`buro:local-user`, Task 9)\n // — its data-layer label is a hardcoded placeholder (\"My settings\");\n // the UI recognizes that EXACT scope id and renders this reactive key\n // instead. Also doubles as the option label in the \"for whom?\" scope\n // picker. Every OTHER (adopter-supplied) scope label renders as-provided,\n // never through this key.\n viewsMyScope: 'Just me',\n viewsSaveCurrent: 'Save current view…',\n viewsManage: 'Manage views…',\n // Saved-view dialogs rendered by `<ResourceListPage>` — the\n // save-current prompt and the manage/delete list.\n viewsSaveTitle: 'Save current view',\n viewsSaveDescription:\n 'Pick a label. The view captures the current filters, sort, search, and visible columns.',\n viewsSavePlaceholder: 'e.g. Errors this week',\n viewsSaved: 'Saved view “{{label}}”',\n viewsSaveFailed: 'Could not save view (storage full or unavailable)',\n viewsDeleteFailed: 'Could not delete view (storage full or unavailable)',\n viewsManageTitle: 'Manage saved views',\n viewsManageDescription:\n 'Delete views you no longer need. Adopter-defined defaults are not editable here.',\n viewsManageEmpty: 'No saved views yet.',\n // Scope-selection dialog (Task 9, spec §5) — shown when saving/forking\n // a view and more than one write scope is available (\"for whom?\").\n viewsScopeDialogTitle: 'Save for…',\n viewsScopeDialogDescription: 'Choose where this view should be saved.',\n // Per-entry actions (Task 9), gated by `entry.permissions`.\n viewsRename: 'Rename',\n viewsRenameTitle: 'Rename view',\n viewsRenameDescription: 'Pick a new label for this view.',\n viewsRenameFailed: 'Could not rename view (storage full or unavailable)',\n viewsFork: 'Fork',\n viewsForkFailed: 'Could not fork view (storage full or unavailable)',\n // Shown next to an entry whose permissions grant none of update/remove/\n // fork — the adapter has made it immutable for this user.\n viewsReadOnly: 'Read-only',\n // Adapter-reported issues (Task 9, spec §13) — rendered without hiding\n // the otherwise-valid entries that loaded fine.\n viewsIssuesNotice: 'Some views could not be loaded.',\n resetToDefaults: 'Reset to defaults',\n resetSizes: 'Reset column widths',\n restoreDefaults: 'Restore defaults',\n search: 'Search {{name}}…',\n searchBy: 'Search by {{name}}…',\n // Live-list pause toggle. Rendered only for a resource that declares\n // `views.list.refetchInterval` — a page that changes under the\n // operator's hands has to say so, and let them stop it.\n liveOn: 'Auto-refresh: on',\n liveOff: 'Auto-refresh: off',\n },\n // Shared field-input chrome (select / combobox / enum pickers).\n field: {\n misconfigured: 'This field is misconfigured',\n removeFile: 'Remove file',\n pickFile: 'Pick or drop a file',\n dropHint: 'Click to pick a file or drag-and-drop',\n dismiss: 'Dismiss',\n waitingForSave: 'waiting for save',\n select: 'Select…',\n loading: 'Loading…',\n },\n // Form chrome (system-field disclosure on create/edit/show forms).\n form: {\n systemFields: 'System fields (read-only)',\n validating: 'Validating',\n },\n // Relation picker (typeahead combobox on edit/create forms).\n relation: {\n select: 'Select {{name}}…',\n failed: 'Failed to load options.',\n noResults: 'No results.',\n /** A lazy `by` relation whose key names no row, found when it is clicked (P3). */\n unavailable: 'Not available',\n },\n // Command palette (⌘K) chrome — group headings, search placeholder, and\n // the empty-state + footer hints rendered by the `<CommandPalette*>` family\n // in @burojs/ui-shadcn. Each component falls back to these English\n // defaults when rendered outside a `BuroProvider`.\n columnMenu: {\n sortSection: 'Sort',\n sortAsc: 'Ascending',\n sortDesc: 'Descending',\n clearSort: 'Clear',\n pinSection: 'Pin',\n pinLeft: 'Left',\n pinRight: 'Right',\n unpin: 'Unpin',\n moveSection: 'Move',\n moveLeft: 'Left',\n moveRight: 'Right',\n hide: 'Hide column',\n },\n navGuard: {\n title: 'Unsaved changes',\n body: 'You have unsaved changes on this page. If you leave now, they will be lost.',\n stay: 'Stay',\n leave: 'Leave without saving',\n discard: 'Discard changes',\n },\n navigation: {\n unsavedAction: 'An action on this screen has unsaved input',\n },\n relationPicker: {\n viewAll: 'Open list',\n clear: 'Clear',\n advancedSearch: 'Advanced search',\n title: 'Select: {{name}}',\n view: 'View',\n create: '+ Create',\n createdNotFitting: 'The record was created but does not fit this field',\n createdNotSelected: 'The record was created but could not be selected',\n chooseFirst: 'Choose {{label}} first',\n cannotSearchBy: 'You cannot search by {{label}}',\n notMatching: 'Does not match the current filter',\n select: 'Select',\n prev: 'Prev',\n next: 'Next',\n page: 'Page {{page}}',\n },\n draft: {\n found: 'Draft found from {{time}}.',\n restorePrompt: 'Restore?',\n restore: 'Restore',\n discard: 'Discard',\n recordChanged: 'Record changed since your draft',\n timeAgoMoment: 'a moment ago',\n timeAgoMinutes_one: '{{count}} minute ago',\n timeAgoMinutes_few: '{{count}} minutes ago',\n timeAgoMinutes_many: '{{count}} minutes ago',\n timeAgoMinutes_other: '{{count}} minutes ago',\n timeAgoHours_one: '{{count}} hour ago',\n timeAgoHours_few: '{{count}} hours ago',\n timeAgoHours_many: '{{count}} hours ago',\n timeAgoHours_other: '{{count}} hours ago',\n timeAgoDays_one: '{{count}} day ago',\n timeAgoDays_few: '{{count}} days ago',\n timeAgoDays_many: '{{count}} days ago',\n timeAgoDays_other: '{{count}} days ago',\n timeAgoRecently: 'recently',\n },\n commandPalette: {\n title: 'Command Palette',\n description: 'Search and run actions.',\n actions: 'Actions',\n create: 'Create',\n createNew: 'Create new',\n recent: 'Recent',\n records: 'Records',\n resources: 'Resources',\n pages: 'Pages',\n search: 'Search…',\n empty: 'No matches found.',\n emptyHint: 'Try a different search or open a resource from the navigation.',\n navigate: 'Navigate',\n select: 'Select',\n close: 'Close',\n // Header trigger chip that opens the palette.\n trigger: 'Search',\n triggerHint: 'Open command palette (⌘K / Ctrl+K)',\n searchEverything: 'Search resources, pages, records, actions…',\n },\n // Rich-text editor toolbar. These are all `aria-label`s (plus the link\n // dialog), so they are announced by screen readers — user-facing text that\n // shipped hardcoded in English. Keyboard hints stay literal in both locales.\n richText: {\n loadingDisplay: 'Loading rich text display',\n loadingEditor: 'Loading rich text editor',\n toolbar: 'Rich text formatting',\n bold: 'Bold (Ctrl+B)',\n italic: 'Italic (Ctrl+I)',\n paragraph: 'Paragraph (Ctrl+Alt+0)',\n heading1: 'Heading 1 (Ctrl+Alt+1)',\n heading2: 'Heading 2 (Ctrl+Alt+2)',\n heading3: 'Heading 3 (Ctrl+Alt+3)',\n bulletList: 'Bullet list (Ctrl+Shift+8)',\n orderedList: 'Ordered list (Ctrl+Shift+7)',\n editLink: 'Edit link (Ctrl+K)',\n insertLink: 'Insert link (Ctrl+K)',\n addLinkTitle: 'Add link',\n url: 'URL',\n },\n // Contextual-documentation chrome. Namespaced `docPanel`, deliberately NOT\n // `doc`: the `resolveKey` chain falls through to `common.<key>` as its last\n // step, so a `common.doc.summary` here would make EVERY undocumented entity\n // in the app sprout a popover.\n docPanel: {\n openFor: 'Help: {{name}}',\n opensInNewTab: '(opens in a new tab)',\n readMore: 'Read more',\n title: 'Help',\n topics: 'Topics',\n back: 'Back to the list',\n close: 'Close help',\n loading: 'Loading…',\n loadFailed: 'This article could not be loaded.',\n empty: 'Nothing is documented here yet.',\n noTranslation: 'Not translated yet — showing the {{locale}} version.',\n kindExplanation: 'About',\n kindHowTo: 'How to',\n kindFaq: 'Common questions',\n kindReference: 'Reference',\n search: 'Search help',\n glossary: 'Glossary',\n areas: 'Areas',\n copyLink: 'Copy link to this section',\n linkCopied: 'Link copied',\n openForArea: 'Help for this section',\n expand: 'Expand to the full page',\n collapse: 'Collapse the panel',\n pickTopic: 'Pick a topic to read it.',\n noMatches: 'Nothing matches that.',\n },\n // The availability gate's own chrome: the generic denial toast shown when a\n // rule disables an action/field but supplies no `reason` of its own.\n availability: {\n denied: \"This action isn't available\",\n },\n // `<ExportDialog>` (`@burojs/ui-shadcn`) and its background/cancel close\n // flow.\n //\n // A format's own NAME (`ExportFormat.label`, 'CSV') renders as declared —\n // format names are proper nouns. A format's OPTION FIELDS resolve by\n // convention under `export.format.<formatId>.<field>.label` and\n // `.option.<value>` (`localizeFormatOptions`, `@burojs/ui-shadcn`), so the\n // delimiter field of `csvFormat()` reads its strings from here.\n export: {\n format: {\n csv: {\n preset: {\n label: 'Delimiter',\n option: {\n semicolon: 'Semicolon (;)',\n comma: 'Comma (,)',\n tab: 'Tab',\n },\n },\n },\n },\n dialog: {\n titleFilter_one: 'Export {{count}} row by current filter',\n titleFilter_few: 'Export {{count}} rows by current filter',\n titleFilter_many: 'Export {{count}} rows by current filter',\n titleFilter_other: 'Export {{count}} rows by current filter',\n /** `estimatedCount` is optional on `ExportDialogProps` — shown when a filter-scope export has no known row estimate. */\n titleFilterUnknownCount: 'Export rows by current filter',\n titleSelected_one: 'Export {{count}} selected row',\n titleSelected_few: 'Export {{count}} selected rows',\n titleSelected_many: 'Export {{count}} selected rows',\n titleSelected_other: 'Export {{count}} selected rows',\n /** Defensive fallback: Task 8 gates the trigger on `available` before opening, so this is only reachable from a direct/programmatic mount. */\n unavailable: 'Export is not available for this resource.',\n /** Shown in place of the format selector while a deferred exporter registration (`ExporterLoader`) is still loading. */\n loading: 'Preparing export…',\n format: 'Format',\n columns: 'Columns',\n columnsVisible: 'As on the page',\n columnsAll: 'All columns',\n sortWarning: 'Sorting is not applied to the exported file.',\n start: 'Start export',\n progressIndeterminate: 'Exporting…',\n progress: 'Exporting… {{done}}/{{total}}',\n download: 'Download',\n failed: 'Export failed',\n canceled: 'Export canceled.',\n confirmCloseTitle: 'Export in progress',\n confirmCloseMessage:\n 'The export is still running. Stop it, or let it continue in the background?',\n stop: 'Stop export',\n continue: 'Continue in background',\n },\n continuesInBackground: 'The export continues in the background.',\n /** Toolbar/bulk-bar Export entry points (Task 8). Shared by both — the same action, two scopes. */\n button: {\n label: 'Export',\n },\n /** `useExportRunWatcher()` background-completion toasts (Task 8). */\n toast: {\n succeeded: 'Export ready',\n download: 'Download',\n failed: 'Export failed: {{message}}',\n },\n },\n // Success notification for the framework-synthesized built-in item actions\n // (`withBuiltinItemActions`) — currently just `delete`.\n notify: {\n deleted: 'Record deleted',\n },\n // The built-in record frame (P1b+P1c).\n record: {\n copyId: 'Copy ID',\n },\n /** A quick overlay's header (P3): Back to the previous entry, close, open the record's page. */\n quick: {\n back: 'Back to {{title}}',\n close: 'Close',\n openAsPage: 'Open as page',\n },\n /** A peek: the hover preview of a related record (P3). */\n peek: {\n failed: \"Couldn't load\",\n unavailable: 'Not available',\n },\n // The record-screen renderer (P1b+P1c): a node whose data could not be read.\n /** A block placement's framework chrome (P1b+P1c section 8.1). */\n block: {\n failed: 'This section could not be loaded.',\n sessionExpired: 'Your session has expired. Sign in again to continue.',\n notImplemented: 'This section is not available.',\n },\n facts: {\n empty: 'No data',\n },\n screen: {\n failed: 'This section could not be loaded.',\n /** A tab's, step's or collapsed panel's badge: errors, not fields. */\n errorCount_one: '{{count}} error',\n errorCount_few: '{{count}} errors',\n errorCount_many: '{{count}} errors',\n errorCount_other: '{{count}} errors',\n expand: 'Expand',\n collapse: 'Collapse',\n },\n /** A create wizard (a `steps` node in create). */\n steps: {\n progress: 'Progress',\n next: 'Next',\n back: 'Back',\n current: 'Step {{index}} of {{count}}',\n },\n /** A flow's host and outcomes (P4 spec 4.22). */\n flow: {\n submit: 'Submit',\n back: 'Back',\n next: 'Next',\n checkAgain: 'Check again',\n close: 'Close',\n resend: 'Resend',\n sendAsNew: 'Send as new',\n sendAsNewConfirm: 'This may apply the change twice. Send it as a new request?',\n startOver: \"I've checked — start over\",\n forget: \"I've checked — forget it\",\n couldNotCheck: \"Couldn't check\",\n couldNotReread: \"Couldn't re-read the record. Nothing was sent.\",\n unavailable: 'Not allowed.',\n busyElsewhere: 'This action is running in another tab.',\n notAvailable: 'This action is not available',\n noLongerApplies: 'This action no longer applies',\n discard: 'Discard',\n done: 'Done',\n reset: 'Reset',\n rejected: {\n validation: 'The server refused the values. Nothing was saved.',\n conflict: 'Someone else changed this record. Nothing was saved.',\n forbidden: 'You are not allowed to do this. Nothing was saved.',\n notFound: 'This record is no longer available.',\n precondition: 'The record changed. Nothing was sent.',\n gone: 'This record is no longer available.',\n },\n failed: 'The request could not be sent. Nothing was saved.',\n unknown: 'The request timed out. It may have been applied. Nothing was resent.',\n unknownUnhandled: 'Check the record before trying again.',\n resultUnavailable: 'Done; the result is not available here.',\n bulkSummary_one: '{{count}} record processed',\n bulkSummary_few: '{{count}} records processed',\n bulkSummary_many: '{{count}} records processed',\n bulkSummary_other: '{{count}} records processed',\n bulkLimit_one: 'Select at most {{count}} record.',\n bulkLimit_few: 'Select at most {{count}} records.',\n bulkLimit_many: 'Select at most {{count}} records.',\n bulkLimit_other: 'Select at most {{count}} records.',\n bulkUnresolved: 'Skipped: an earlier request for it may have been applied.',\n bulkNotAttempted: 'Not attempted.',\n },\n /** A flow's review step (P4 spec 4.4). */\n review: {\n changed: 'changed',\n },\n} as const;\n","export const ru = {\n validation: {\n requiredHint: '(обязательное)',\n required: 'Обязательное поле',\n string: {\n minLength: 'Слишком короткое значение',\n maxLength: 'Слишком длинное значение',\n pattern: 'Неверный формат',\n },\n constraint: { invalid: 'Неверное значение' },\n number: {\n minimum: 'Слишком маленькое значение',\n maximum: 'Слишком большое значение',\n exclusiveMinimum: 'Слишком маленькое значение',\n exclusiveMaximum: 'Слишком большое значение',\n multipleOf: 'Недопустимый шаг значения',\n },\n array: {\n minItems: 'Слишком мало элементов',\n maxItems: 'Слишком много элементов',\n uniqueItems: 'Элементы должны быть уникальными',\n },\n validator: { invalid: 'Неверное значение', exception: 'Проверка не пройдена' },\n schema: { invalid: 'Неверное значение', exception: 'Проверка не пройдена' },\n resource: { invalid: 'Неверное значение' },\n type: {\n string: 'Должно быть текстом',\n number: 'Должно быть числом',\n boolean: 'Должно быть «да» или «нет»',\n array: 'Должно быть списком',\n object: 'Должно быть объектом',\n },\n },\n actions: {\n close: 'Закрыть',\n clearSelection: 'Снять выделение',\n create: 'Создать',\n edit: 'Изменить',\n delete: 'Удалить',\n show: 'Открыть',\n auditLog: 'Журнал аудита',\n save: 'Сохранить',\n cancel: 'Отмена',\n refresh: 'Обновить',\n submit: 'Отправить',\n ok: 'ОК',\n confirm: 'Подтвердить',\n back: 'Назад',\n next: 'Далее',\n retry: 'Повторить',\n saving: 'Сохранение…',\n creating: 'Создание…',\n submitting: 'Отправка…',\n validating: 'Проверка…',\n // Overflow-menu chrome (Workstream B — actions overflow).\n more: 'Ещё',\n column: 'Действия',\n openMenu: 'Открыть меню действий',\n },\n confirm: {\n delete: 'Удалить запись?',\n deleteMany_one: 'Удалить {{count}} запись?',\n deleteMany_few: 'Удалить {{count}} записи?',\n deleteMany_many: 'Удалить {{count}} записей?',\n deleteMany_other: 'Удалить {{count}} записи?',\n discardChanges: 'Отменить изменения?',\n ok: 'ОК',\n confirm: 'Подтвердить',\n },\n checks: {\n // Neutral across surfaces: the SAME dialog gates saves, actions and\n // deletes (`CheckConfirmDialog`), so a save-specific title read wrong\n // above «Удалить: X?» on the delete surface. A host that wants\n // surface-specific wording passes `title` to the dialog (the action\n // button does exactly that, with the action's own label).\n dialogTitle: 'Проверьте перед продолжением',\n proceed: 'Всё равно продолжить',\n back: 'Вернуться',\n blocked: 'Продолжить нельзя',\n couldNotVerify: 'Не удалось проверить «{{checkId}}»',\n notVerified: 'Проверка «{{checkId}}» не выполнилась',\n parseError: 'Правило «{{checkId}}» задано неверно: {{detail}}',\n },\n table: {\n selectedCount_one: 'Выбрано: {{count}}',\n selectedCount_few: 'Выбрано: {{count}}',\n selectedCount_many: 'Выбрано: {{count}}',\n selectedCount_other: 'Выбрано: {{count}}',\n empty: 'Нет записей',\n loading: 'Загрузка…',\n rowsSelected_one: 'Выбрано: {{count}}',\n rowsSelected_few: 'Выбрано: {{count}}',\n rowsSelected_many: 'Выбрано: {{count}}',\n rowsSelected_other: 'Выбрано: {{count}}',\n selectAllRows: 'Выбрать все строки',\n selectRow: 'Выбрать строку',\n },\n boolean: {\n yes: 'Да',\n no: 'Нет',\n active: 'Активно',\n inactive: 'Неактивно',\n },\n pagination: {\n showingUnknownTotal: 'Показаны {{from}}–{{to}}',\n countRows: 'Посчитать',\n loadMore: 'Показать ещё',\n loadingMore: 'Загрузка…',\n emptyPage: 'На этой странице нет записей',\n pageOnly: 'Стр. {{page}}',\n previous: 'Назад',\n next: 'Вперёд',\n prev: 'Назад',\n pageOf: 'Стр. {{page}} из {{total}}',\n showing: 'Показаны {{from}}–{{to}} из {{total}}',\n rowsPerPage: 'Строк на странице',\n firstPage: 'В начало',\n previousPage: 'Предыдущая страница',\n nextPage: 'Следующая страница',\n lastPage: 'В конец',\n },\n filters: {\n // Comparison operators stay as SYMBOLS in both locales. The round-6 finding\n // was about English WORDS («contains», «starts with») leaking into a Russian\n // UI; `>` `≥` `<` `≤` are mathematical notation, not English — they need no\n // translation, they are unambiguous, and they fit a narrow filter chip where\n // «больше или равно» does not. Translating them was an over-correction.\n operators: {\n eq: 'равно',\n ne: 'не равно',\n gt: '>',\n gte: '≥',\n lt: '<',\n lte: '≤',\n in: 'входит в',\n nin: 'не входит в',\n contains: 'содержит',\n ncontains: 'не содержит',\n between: 'между',\n nbetween: 'не между',\n null: 'не заполнено',\n nnull: 'заполнено',\n startswith: 'начинается с',\n endswith: 'заканчивается на',\n // AST predicate vocabulary (`FilterPredicateOp`) — see the matching\n // comment in en.ts. `eq`/`gt`/`gte`/`lt`/`lte`/`in`/`contains` are\n // shared with the set above.\n neq: 'не равно',\n notIn: 'не входит в',\n startsWith: 'начинается с',\n endsWith: 'заканчивается на',\n isNull: 'не заполнено',\n isNotNull: 'заполнено',\n },\n clearAll: 'Сбросить фильтры',\n apply: 'Применить',\n clear: 'Сбросить',\n // Filter-builder panel (Task 6) — see the matching comment in en.ts:\n // empties the whole draft without applying it.\n reset: 'Сбросить',\n title: 'Фильтры',\n selectedCount_one: 'Выбрано: {{count}}',\n selectedCount_few: 'Выбрано: {{count}}',\n selectedCount_many: 'Выбрано: {{count}}',\n selectedCount_other: 'Выбрано: {{count}}',\n is: 'равно',\n isNot: 'не равно',\n contains: 'содержит',\n value: 'Значение',\n // See the matching comment in en.ts (SP2 final-review finding 7).\n valueFor: 'Значение для {{field}}',\n field: 'Поле',\n operator: 'Оператор',\n where: 'Где',\n and: 'и',\n or: 'или',\n // See the matching comment in en.ts.\n toggleJoin: 'Связка: {{current}} — нажмите, чтобы переключить на {{next}}',\n addRow: 'Добавить фильтр',\n addGroup: 'Добавить группу',\n removeRow: 'Удалить фильтр',\n removeGroup: 'Удалить группу',\n },\n errors: {\n required: 'Обязательное поле',\n invalid: 'Неверное значение',\n // Fallback when an adopter validator throws, or a schema reports an issue\n // with no message of its own. Shipped as English 'Validation failed'.\n failed: 'Проверка не пройдена',\n validatorFailed: 'Не удалось проверить форму. Попробуйте ещё раз.',\n },\n // A field leaf its user may see the label of but not the value (P5 spec 3.6).\n access: {\n restricted: 'Нет доступа',\n },\n // List-page chrome (empty / loading / error states). `{{items}}` is the\n // resource plural label, `{{item}}` the singular — both interpolated by the\n // caller (already lowercased where the original literal lowercased).\n list: {\n loadingShort: 'Загрузка…',\n notRegistered: 'Ресурс не зарегистрирован',\n loading: 'Загрузка…',\n errorTitle: 'Что-то пошло не так',\n errorBody: 'Не удалось загрузить данные. Попробуйте ещё раз.',\n errorDetails: 'Подробности',\n emptyTitle: 'Пока нет записей',\n emptyBody: 'Создайте первую запись, чтобы начать.',\n emptyBodyReadOnly: 'Записи появятся здесь, когда их добавят.',\n emptyFilteredTitle: 'Ничего не найдено',\n emptyFilteredBody:\n 'Ни одна запись не соответствует текущему фильтру. Сбросьте фильтр, чтобы увидеть все.',\n clearFilter: 'Сбросить фильтр',\n create: '+ Создать {{item}}',\n // A typed resource's discriminator cell: the row's value matches no\n // declared type (null, empty, or a token the app doesn't know).\n templateUnknown: 'Неизвестный',\n // Generic search-box placeholder/label for a resource whose `views.list.search`\n // is a resolver (no single field to name — see `toolbar.searchBy` for the\n // declarative-field form).\n search: 'Поиск',\n predicatesDropped: 'Некоторые сохранённые фильтры не применены',\n flowsMenu: 'Ещё действия',\n },\n // A `related-list` timeline (`view: 'timeline'`).\n timeline: {\n empty: 'Нет записей',\n undated: 'Без даты',\n },\n // Sidebar top-level group label.\n breadcrumbs: {\n create: 'Создание',\n edit: 'Изменение',\n },\n nav: {\n skipToContent: 'Перейти к содержимому',\n resources: 'Ресурсы',\n main: 'Основная навигация',\n breadcrumb: 'Хлебные крошки',\n // Accessible name for the sidebar toggle, whose `title` also renders as a\n // hover tooltip.\n toggleSidebar: 'Свернуть меню',\n // Accessible name for the mobile nav sheet (a Radix Dialog, which\n // requires a title). Screen-reader-only, and it was English.\n label: 'Навигация',\n },\n shell: {\n refresh: 'Обновить',\n help: 'Справка',\n scopeSwitcher: 'Переключить',\n scopePlaceholder: 'Выберите…',\n account: 'Учётная запись',\n },\n theme: {\n label: 'Тема',\n light: 'Светлая',\n dark: 'Тёмная',\n system: 'Системная',\n },\n language: {\n label: 'Язык',\n },\n // PageHeader back-link + computed titles.\n pageHeader: {\n // Deliberately does NOT interpolate the resource label. The label is\n // nominative («Документы»), while «Назад к …» requires the dative\n // («к документам») — and a framework has no business shipping a Russian\n // declension engine to fix one link. Naming the destination generically is\n // correct in every case and reads naturally; EN keeps the label, where\n // «Back to Documents» needs no inflection.\n backTo: 'Назад к списку',\n editTitle: 'Изменить {{label}}',\n editTitleNamed: 'Изменить {{label}}: {{name}}',\n // Colon form on purpose: `label` is capitalised for standalone\n // headings («Документ»), so «Создать Документ» reads wrong mid-sentence,\n // and auto-lowercasing a label is not safe in general. The colon also\n // scales to a typed create — «Создать: Заказ кодов».\n createTitle: 'Создать: {{label}}',\n },\n // Fallback states rendered by the resource page router when a route\n // resolves to nothing. Both shipped as hardcoded English.\n router: {\n emptyTitle: 'Здесь пока пусто',\n emptyBody: 'Для этой страницы не зарегистрировано содержимое.',\n notFoundTitle: 'Страница не найдена',\n notFoundBody: 'Этот адрес не соответствует ни одной зарегистрированной странице.',\n recordLoading: 'Загрузка…',\n recordNotFound: 'Запись не найдена или у вас нет к ней доступа.',\n recordSessionExpired: 'Сеанс истёк. Войдите снова, чтобы продолжить.',\n recordError: 'Не удалось загрузить запись.',\n },\n notifications: {\n region: 'Уведомления',\n },\n create: {\n pickType: 'Выберите тип, чтобы продолжить.',\n unsupportedType: 'Неподдерживаемый тип',\n unsupportedTypeHint: 'Тип «{{type}}» не зарегистрирован для этого ресурса.',\n backToPicker: 'Назад к выбору типа',\n typeOffer: {\n title: 'Выберите тип',\n hint: 'От типа зависит, какие поля есть у записи.',\n empty: 'Здесь нельзя создать запись ни одного типа.',\n change: 'Сменить тип',\n },\n },\n // `<TaskRunPanel>` — see en.ts.\n taskRun: {\n idle: 'Не запущено',\n running: 'Выполняется',\n complete: 'Готово',\n partial: 'Готово, часть не выполнена',\n stopped: 'Остановлено',\n cancelled: 'Отменено',\n count: '{{completed}} из {{total}}',\n countUnknownTotal: 'выполнено: {{completed}}',\n },\n // Login / auth surfaces.\n auth: {\n invalidEmail: 'Некорректный адрес',\n passwordRequired: 'Введите пароль',\n invalidCredentials: 'Неверный адрес или пароль.',\n signOut: 'Выйти',\n signIn: 'Войти',\n signingIn: 'Вход…',\n email: 'Эл. почта',\n password: 'Пароль',\n },\n // List / data-table toolbar controls.\n toolbar: {\n clearAll: 'Очистить всё',\n clearAllAria_one: 'Очистить фильтры: {{count}}',\n clearAllAria_few: 'Очистить фильтры: {{count}}',\n clearAllAria_many: 'Очистить фильтры: {{count}}',\n clearAllAria_other: 'Очистить фильтры: {{count}}',\n addFilter: 'Добавить фильтр',\n filterBy: 'Фильтровать по',\n columns: 'Колонки',\n views: 'Представления',\n viewsDefaults: 'По умолчанию',\n // The framework's own local-user scope (`buro:local-user`, Task 9)\n // — its data-layer label is a hardcoded placeholder (\"My settings\");\n // the UI recognizes that EXACT scope id and renders this reactive key\n // instead. Also doubles as the option label in the \"for whom?\" scope\n // picker. Every OTHER (adopter-supplied) scope label renders as-provided,\n // never through this key.\n viewsMyScope: 'Только я',\n viewsSaveCurrent: 'Сохранить текущее…',\n viewsManage: 'Управление представлениями…',\n // Saved-view dialogs rendered by `<ResourceListPage>` — the\n // save-current prompt and the manage/delete list.\n viewsSaveTitle: 'Сохранить текущее представление',\n viewsSaveDescription:\n 'Укажите название. Представление сохранит текущие фильтры, сортировку, поиск и набор колонок.',\n viewsSavePlaceholder: 'например, Ошибки за неделю',\n viewsSaved: 'Представление «{{label}}» сохранено',\n viewsSaveFailed: 'Не удалось сохранить представление (хранилище переполнено или недоступно)',\n viewsDeleteFailed: 'Не удалось удалить представление (хранилище переполнено или недоступно)',\n viewsManageTitle: 'Управление представлениями',\n viewsManageDescription:\n 'Удалите ненужные представления. Встроенные по умолчанию здесь не редактируются.',\n viewsManageEmpty: 'Пока нет сохранённых представлений.',\n // Scope-selection dialog (Task 9, spec §5) — shown when saving/forking\n // a view and more than one write scope is available (\"for whom?\").\n viewsScopeDialogTitle: 'Сохранить для…',\n viewsScopeDialogDescription: 'Выберите, куда сохранить это представление.',\n // Per-entry actions (Task 9), gated by `entry.permissions`.\n viewsRename: 'Переименовать',\n viewsRenameTitle: 'Переименовать представление',\n viewsRenameDescription: 'Укажите новое название для этого представления.',\n viewsRenameFailed:\n 'Не удалось переименовать представление (хранилище переполнено или недоступно)',\n viewsFork: 'Копировать себе',\n viewsForkFailed: 'Не удалось скопировать представление (хранилище переполнено или недоступно)',\n // Shown next to an entry whose permissions grant none of update/remove/\n // fork — the adapter has made it immutable for this user.\n viewsReadOnly: 'Только для чтения',\n // Adapter-reported issues (Task 9, spec §13) — rendered without hiding\n // the otherwise-valid entries that loaded fine.\n viewsIssuesNotice: 'Не удалось загрузить некоторые представления.',\n resetToDefaults: 'Сбросить настройки',\n resetSizes: 'Сбросить размеры колонок',\n restoreDefaults: 'Восстановить по умолчанию',\n search: 'Поиск: {{name}}…',\n searchBy: 'Поиск по: {{name}}…',\n // Live-list pause toggle. Rendered only for a resource that declares\n // `views.list.refetchInterval` — a page that changes under the\n // operator's hands has to say so, and let them stop it.\n liveOn: 'Авто-обновление: вкл',\n liveOff: 'Авто-обновление: выкл',\n },\n // Shared field-input chrome (select / combobox / enum pickers).\n field: {\n misconfigured: 'Это поле настроено неверно',\n removeFile: 'Удалить файл',\n pickFile: 'Выберите файл или перетащите его сюда',\n dropHint: 'Нажмите, чтобы выбрать файл, или перетащите его сюда',\n dismiss: 'Скрыть',\n waitingForSave: 'ожидает сохранения',\n select: 'Выберите…',\n loading: 'Загрузка…',\n },\n // Form chrome (system-field disclosure on create/edit/show forms).\n form: {\n systemFields: 'Системные поля (только чтение)',\n validating: 'Проверка',\n },\n // Relation picker (typeahead combobox on edit/create forms).\n relation: {\n // The field's own label sits directly above the control, so repeating it\n // inside the placeholder is redundant — and in Russian it also forces a\n // case the template cannot decline («Выберите: локация…»). Same wording as\n // `field.select` keeps every picker on the form consistent.\n select: 'Выберите…',\n failed: 'Не удалось загрузить варианты.',\n noResults: 'Ничего не найдено.',\n /** A lazy `by` relation whose key names no row, found when it is clicked (P3). */\n unavailable: 'Недоступно',\n },\n // Command palette (⌘K) chrome — group headings, search placeholder, and\n // the empty-state + footer hints rendered by the `<CommandPalette*>` family\n // in @burojs/ui-shadcn. Each component falls back to the English defaults\n // (en.ts) when rendered outside a `BuroProvider`.\n columnMenu: {\n sortSection: 'Сортировка',\n sortAsc: 'По возрастанию',\n sortDesc: 'По убыванию',\n clearSort: 'Сбросить',\n pinSection: 'Закрепление',\n pinLeft: 'Слева',\n pinRight: 'Справа',\n unpin: 'Открепить',\n moveSection: 'Перемещение',\n moveLeft: 'Влево',\n moveRight: 'Вправо',\n hide: 'Скрыть колонку',\n },\n navGuard: {\n title: 'Несохранённые изменения',\n body: 'На этой странице есть несохранённые изменения. Если уйти сейчас, они будут потеряны.',\n stay: 'Остаться',\n leave: 'Уйти без сохранения',\n discard: 'Отменить изменения',\n },\n navigation: {\n unsavedAction: 'В действии на этом экране есть несохранённые данные',\n },\n relationPicker: {\n viewAll: 'Открыть список',\n clear: 'Очистить',\n advancedSearch: 'Расширенный поиск',\n title: 'Выбор: {{name}}',\n view: 'Открыть',\n create: '+ Создать',\n createdNotFitting: 'Запись создана, но не подходит для этого поля',\n createdNotSelected: 'Запись создана, но её не удалось выбрать',\n chooseFirst: 'Сначала выберите {{label}}',\n cannotSearchBy: 'Нельзя искать по {{label}}',\n notMatching: 'Не соответствует текущему фильтру',\n select: 'Выбрать',\n prev: 'Назад',\n next: 'Вперёд',\n page: 'Стр. {{page}}',\n },\n draft: {\n found: 'Найден черновик, сохранённый {{time}}.',\n restorePrompt: 'Восстановить?',\n restore: 'Восстановить',\n discard: 'Отклонить',\n recordChanged: 'Запись изменилась после сохранения черновика',\n timeAgoMoment: 'только что',\n timeAgoMinutes_one: '{{count}} минуту назад',\n timeAgoMinutes_few: '{{count}} минуты назад',\n timeAgoMinutes_many: '{{count}} минут назад',\n timeAgoMinutes_other: '{{count}} минуты назад',\n timeAgoHours_one: '{{count}} час назад',\n timeAgoHours_few: '{{count}} часа назад',\n timeAgoHours_many: '{{count}} часов назад',\n timeAgoHours_other: '{{count}} часа назад',\n timeAgoDays_one: '{{count}} день назад',\n timeAgoDays_few: '{{count}} дня назад',\n timeAgoDays_many: '{{count}} дней назад',\n timeAgoDays_other: '{{count}} дня назад',\n timeAgoRecently: 'недавно',\n },\n commandPalette: {\n title: 'Палитра команд',\n description: 'Поиск и запуск действий.',\n actions: 'Действия',\n create: 'Создать',\n createNew: 'Создать',\n recent: 'Недавние',\n records: 'Записи',\n resources: 'Разделы',\n pages: 'Страницы',\n search: 'Поиск…',\n empty: 'Ничего не найдено',\n emptyHint: 'Измените запрос или откройте раздел из навигации.',\n navigate: 'Навигация',\n select: 'Выбрать',\n close: 'Закрыть',\n // Header trigger chip that opens the palette.\n trigger: 'Поиск',\n triggerHint: 'Открыть командную панель (⌘K / Ctrl+K)',\n searchEverything: 'Поиск по разделам, страницам, записям и действиям…',\n },\n // Rich-text editor toolbar. These are all `aria-label`s (plus the link\n // dialog), so they are announced by screen readers — user-facing text that\n // shipped hardcoded in English. Keyboard hints stay literal in both locales.\n richText: {\n loadingDisplay: 'Загрузка форматированного текста',\n loadingEditor: 'Загрузка редактора форматированного текста',\n toolbar: 'Форматирование текста',\n bold: 'Полужирный (Ctrl+B)',\n italic: 'Курсив (Ctrl+I)',\n paragraph: 'Абзац (Ctrl+Alt+0)',\n heading1: 'Заголовок 1 (Ctrl+Alt+1)',\n heading2: 'Заголовок 2 (Ctrl+Alt+2)',\n heading3: 'Заголовок 3 (Ctrl+Alt+3)',\n bulletList: 'Маркированный список (Ctrl+Shift+8)',\n orderedList: 'Нумерованный список (Ctrl+Shift+7)',\n editLink: 'Изменить ссылку (Ctrl+K)',\n insertLink: 'Вставить ссылку (Ctrl+K)',\n addLinkTitle: 'Добавить ссылку',\n url: 'URL',\n },\n // See the matching comment in en.ts: namespaced `docPanel`, not `doc` —\n // otherwise a `common.doc.summary` would make every undocumented entity\n // sprout a popover.\n docPanel: {\n openFor: 'Справка: {{name}}',\n opensInNewTab: '(открывается в новой вкладке)',\n readMore: 'Подробнее',\n title: 'Справка',\n topics: 'Разделы',\n back: 'К списку разделов',\n close: 'Закрыть справку',\n loading: 'Загрузка…',\n loadFailed: 'Не удалось загрузить статью.',\n empty: 'Здесь пока ничего не задокументировано.',\n noTranslation: 'Перевода пока нет — показан вариант на {{locale}}.',\n kindExplanation: 'О сущности',\n kindHowTo: 'Как сделать',\n kindFaq: 'Частые вопросы',\n kindReference: 'Справочник',\n search: 'Поиск по справке',\n glossary: 'Глоссарий',\n areas: 'Разделы',\n copyLink: 'Скопировать ссылку на этот раздел',\n linkCopied: 'Ссылка скопирована',\n openForArea: 'Справка по этому разделу',\n expand: 'Развернуть на всю страницу',\n collapse: 'Свернуть панель',\n pickTopic: 'Выберите раздел, чтобы прочитать.',\n noMatches: 'Ничего не найдено.',\n },\n // The availability gate's own chrome: the generic denial toast shown when a\n // rule disables an action/field but supplies no `reason` of its own.\n availability: {\n denied: 'Действие недоступно',\n },\n // `<ExportDialog>` (`@burojs/ui-shadcn`) and its background/cancel close\n // flow.\n //\n // A format's own NAME (`ExportFormat.label`, 'CSV') renders as declared —\n // format names are proper nouns. A format's OPTION FIELDS resolve by\n // convention under `export.format.<formatId>.<field>.label` and\n // `.option.<value>` (`localizeFormatOptions`, `@burojs/ui-shadcn`), so the\n // delimiter field of `csvFormat()` reads its strings from here.\n export: {\n format: {\n csv: {\n preset: {\n label: 'Разделитель',\n option: {\n semicolon: 'Точка с запятой (;)',\n comma: 'Запятая (,)',\n tab: 'Табуляция',\n },\n },\n },\n },\n dialog: {\n titleFilter_one: 'Экспорт {{count}} строки по текущему фильтру',\n titleFilter_few: 'Экспорт {{count}} строк по текущему фильтру',\n titleFilter_many: 'Экспорт {{count}} строк по текущему фильтру',\n titleFilter_other: 'Экспорт {{count}} строки по текущему фильтру',\n /** `estimatedCount` is optional on `ExportDialogProps` — shown when a filter-scope export has no known row estimate. */\n titleFilterUnknownCount: 'Экспорт строк по текущему фильтру',\n titleSelected_one: 'Экспорт {{count}} выбранной строки',\n titleSelected_few: 'Экспорт {{count}} выбранных строк',\n titleSelected_many: 'Экспорт {{count}} выбранных строк',\n titleSelected_other: 'Экспорт {{count}} выбранной строки',\n /** Defensive fallback: Task 8 gates the trigger on `available` before opening, so this is only reachable from a direct/programmatic mount. */\n unavailable: 'Экспорт недоступен для этого ресурса.',\n /** Shown in place of the format selector while a deferred exporter registration (`ExporterLoader`) is still loading. */\n loading: 'Подготовка экспорта…',\n format: 'Формат',\n columns: 'Колонки',\n columnsVisible: 'Как на странице',\n columnsAll: 'Все колонки',\n sortWarning: 'Сортировка не применяется к экспортируемому файлу.',\n start: 'Начать экспорт',\n progressIndeterminate: 'Экспорт…',\n progress: 'Экспорт… {{done}}/{{total}}',\n download: 'Скачать',\n failed: 'Экспорт завершился с ошибкой',\n canceled: 'Экспорт отменён.',\n confirmCloseTitle: 'Экспорт выполняется',\n confirmCloseMessage: 'Экспорт всё ещё выполняется. Остановить его или продолжить в фоне?',\n stop: 'Остановить экспорт',\n continue: 'Продолжить в фоне',\n },\n continuesInBackground: 'Экспорт продолжается в фоне.',\n /** Toolbar/bulk-bar Export entry points (Task 8). Shared by both — the same action, two scopes. */\n button: {\n label: 'Экспорт',\n },\n /** `useExportRunWatcher()` background-completion toasts (Task 8). */\n toast: {\n succeeded: 'Экспорт готов',\n download: 'Скачать',\n failed: 'Экспорт завершился с ошибкой: {{message}}',\n },\n },\n // Success notification for the framework-synthesized built-in item actions\n // (`withBuiltinItemActions`) — currently just `delete`.\n notify: {\n deleted: 'Запись удалена',\n },\n // The built-in record frame (P1b+P1c).\n record: {\n copyId: 'Скопировать ID',\n },\n /** A quick overlay's header (P3): Back to the previous entry, close, open the record's page. */\n quick: {\n back: 'Назад к «{{title}}»',\n close: 'Закрыть',\n openAsPage: 'Открыть страницей',\n },\n peek: {\n failed: 'Не удалось загрузить',\n unavailable: 'Недоступно',\n },\n // The record-screen renderer (P1b+P1c): a node whose data could not be read.\n /** A block placement's framework chrome (P1b+P1c section 8.1). */\n block: {\n failed: 'Не удалось загрузить раздел.',\n sessionExpired: 'Сессия истекла. Войдите снова, чтобы продолжить.',\n notImplemented: 'Этот раздел недоступен.',\n },\n facts: {\n empty: 'Нет данных',\n },\n screen: {\n failed: 'Не удалось загрузить раздел.',\n /** A tab's, step's or collapsed panel's badge: errors, not fields. */\n errorCount_one: '{{count}} ошибка',\n errorCount_few: '{{count}} ошибки',\n errorCount_many: '{{count}} ошибок',\n errorCount_other: '{{count}} ошибки',\n expand: 'Развернуть',\n collapse: 'Свернуть',\n },\n /** A create wizard (a `steps` node in create). */\n steps: {\n progress: 'Ход заполнения',\n next: 'Далее',\n back: 'Назад',\n current: 'Шаг {{index}} из {{count}}',\n },\n /** A flow's host and outcomes (P4 spec 4.22). */\n flow: {\n submit: 'Отправить',\n back: 'Назад',\n next: 'Далее',\n checkAgain: 'Проверить снова',\n close: 'Закрыть',\n resend: 'Отправить повторно',\n sendAsNew: 'Отправить как новый',\n sendAsNewConfirm: 'Изменение может примениться дважды. Отправить как новый запрос?',\n startOver: 'Я проверил — начать заново',\n forget: 'Я проверил — забыть',\n couldNotCheck: 'Не удалось проверить',\n couldNotReread: 'Не удалось перечитать запись. Ничего не отправлено.',\n unavailable: 'Недоступно.',\n busyElsewhere: 'Это действие выполняется в другой вкладке.',\n notAvailable: 'Это действие недоступно',\n noLongerApplies: 'Это действие больше не применимо',\n discard: 'Отменить',\n done: 'Готово',\n reset: 'Сбросить',\n rejected: {\n validation: 'Сервер отклонил значения. Ничего не сохранено.',\n conflict: 'Запись изменил кто-то другой. Ничего не сохранено.',\n forbidden: 'У вас нет прав на это действие. Ничего не сохранено.',\n notFound: 'Эта запись больше недоступна.',\n precondition: 'Запись изменилась. Ничего не отправлено.',\n gone: 'Эта запись больше недоступна.',\n },\n failed: 'Не удалось отправить запрос. Ничего не сохранено.',\n unknown: 'Время ожидания истекло. Изменение могло примениться. Повторно ничего не отправлено.',\n unknownUnhandled: 'Проверьте запись, прежде чем пробовать снова.',\n resultUnavailable: 'Готово; результат здесь недоступен.',\n bulkSummary_one: 'Обработана {{count}} запись',\n bulkSummary_few: 'Обработано {{count}} записи',\n bulkSummary_many: 'Обработано {{count}} записей',\n bulkSummary_other: 'Обработано {{count}} записи',\n bulkLimit_one: 'Выберите не больше {{count}} записи.',\n bulkLimit_few: 'Выберите не больше {{count}} записей.',\n bulkLimit_many: 'Выберите не больше {{count}} записей.',\n bulkLimit_other: 'Выберите не больше {{count}} записей.',\n bulkUnresolved: 'Пропущено: прежний запрос мог уже примениться.',\n bulkNotAttempted: 'Не выполнялось.',\n },\n /** A flow's review step (P4 spec 4.4). */\n review: {\n changed: 'изменено',\n },\n} as const;\n","import type { ValidationIssue } from '@burojs/core';\n\n/** What {@link resolveValidationMessage} reads besides the issue. */\nexport interface ValidationMessageContext {\n /** A translator that returns the key itself on a miss (`useTranslate`, `useT`). */\n readonly t: (key: string, options?: { params?: Record<string, unknown> }) => string;\n /** `resources.<r>.fields.<f>` (a flow form's: `resources.<r>.actions.<name>.fields.<f>`); absent for a form-level issue. */\n readonly fieldKey?: string;\n}\n\n/**\n * The one text of a validation issue, resolved at render so a locale switch\n * reaches it. A lookup hits when `t` returns something other than the key:\n *\n * 1. `${fieldKey}.validation.${code}` — the author's per-field override;\n * 2. `message.key`, when it is not `validation.${code}` (a server or semantic key);\n * 3. `message.default` — the schema's, validator's or server's own text;\n * 4. `validation.${code}` — the framework's text for a built-in code;\n * 5. `errors.failed`.\n *\n * Built-in constraint issues carry no `default`, so step 4 answers them in\n * every locale; an issue with its own `default` keeps it unless step 1 hits.\n */\nexport function resolveValidationMessage(\n issue: Pick<ValidationIssue, 'code' | 'message' | 'params'>,\n context: ValidationMessageContext,\n): string {\n const { t, fieldKey } = context;\n const params = issue.params as Record<string, unknown> | undefined;\n const lookup = (key: string): string | undefined => {\n const text = t(key, params === undefined ? undefined : { params });\n return text === key ? undefined : text;\n };\n const code = issue.code;\n const canonical = code === '' ? undefined : `validation.${code}`;\n if (fieldKey !== undefined && canonical !== undefined) {\n const own = lookup(`${fieldKey}.${canonical}`);\n if (own !== undefined) return own;\n }\n const key = issue.message.key;\n if (key !== canonical) {\n const semantic = lookup(key);\n if (semantic !== undefined) return semantic;\n }\n if (typeof issue.message.default === 'string') return issue.message.default;\n if (canonical !== undefined) {\n const common = lookup(canonical);\n if (common !== undefined) return common;\n }\n return t('errors.failed');\n}\n","import { useCallback } from 'react';\nimport { useOptionalRouterAdapter } from '../router/router-adapter.js';\nimport { writeSearchParams } from './write-search-params.js';\n\n/**\n * Writes in-page URL state (a record tab, list state): `update` edits a copy\n * of the current search params, and the result is written on the same\n * pathname, by default with `replace`. Never asks the navigation guard and\n * never changes the pathname; a navigation to another page goes through\n * `useRouteNavigate`. Without a router adapter it does nothing.\n */\nexport function useSearchParamsWriter(): (\n update: (params: URLSearchParams) => void,\n options?: { readonly history?: 'push' | 'replace' },\n) => void {\n const adapter = useOptionalRouterAdapter();\n return useCallback(\n (update, options = {}) => {\n if (adapter === null) return;\n const next = new URLSearchParams(adapter.searchParams);\n update(next);\n const query = next.toString();\n writeSearchParams(\n adapter,\n query === '' ? adapter.pathname : `${adapter.pathname}?${query}`,\n options.history ?? 'replace',\n );\n },\n [adapter],\n );\n}\n","import type { ExportHandle } from '@burojs/core';\n\nexport interface ExportRunEntry {\n readonly runId: string;\n readonly resource: string;\n readonly exporterId: string;\n readonly formatId: string;\n readonly startedAt: number;\n /** State/subscribe/cancel/resume all live on the handle — the store only observes it. */\n readonly handle: ExportHandle;\n}\n\nlet runIdFallbackCounter = 0;\n\n/**\n * Collision-resistant run id. Prefers `crypto.randomUUID`; falls back when\n * unavailable — `crypto.randomUUID` is secure-context-only in browsers, and\n * this repo already guards it for exactly that reason (see\n * `packages/react/src/ui-settings/local-storage-adapter.ts`'s `newLocalId`,\n * `packages/file-storage/src/adapters/supabase.ts`). Exported so\n * `use-export.ts`'s `useResourceExport().start()` can call it as a\n * pre-flight probe BEFORE running the exporter (see the comment there) — an\n * id-generation failure must never leave a live, unregistered export run.\n */\nexport function createExportRunId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n runIdFallbackCounter += 1;\n return `export-run-${Date.now().toString(36)}-${runIdFallbackCounter.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Lease-scoped registry of export runs for one app (one instance per\n * `DataRuntimeContextValue` — see `getExportRunsStore` in `use-export.ts`),\n * so every consumer — the export trigger that started a run and a future\n * header indicator (REF-15) — observes the same list. It survives session\n * and scope transitions: a run started under a previous scope stays in\n * `list()` until dismissed or the lease itself is disposed — the store has\n * no session/scope awareness at all.\n *\n * The store only ever *observes* handles (`subscribe`/`getState`); it never\n * calls `set` and tolerates a handle that is already terminal when it\n * arrives (subscribing to a terminal handle is safe — see\n * `packages/export/src/handle.ts` — it simply never fires again).\n *\n * Per-entry handle subscriptions are lazy and reference-counted against the\n * store's OWN subscriber count: nothing is attached until someone is\n * listening, and everything is detached the moment nobody is. This is what\n * keeps a store with zero live consumers (e.g. between two component mounts)\n * from leaking a live subscription into every export's handle forever.\n */\nexport class ExportRunsStore {\n readonly #entries: ExportRunEntry[] = [];\n #snapshot: readonly ExportRunEntry[] | null = null;\n readonly #listeners = new Set<() => void>();\n readonly #handleUnsubscribes = new Map<string, () => void>();\n\n start = (entry: Omit<ExportRunEntry, 'runId' | 'startedAt'>): ExportRunEntry => {\n const full: ExportRunEntry = {\n ...entry,\n runId: createExportRunId(),\n startedAt: Date.now(),\n };\n this.#entries.push(full);\n if (this.#listeners.size > 0) this.#attachHandle(full);\n this.#invalidate();\n this.#notify();\n return full;\n };\n\n /** Stable snapshot: the same array identity across calls until something\n * changes (`useSyncExternalStore` requires this to avoid re-render loops).\n * Frozen so a consumer's in-place `.sort()`/`.push()` on the (typed\n * `readonly`, but not runtime-enforced without this) array can never\n * corrupt the cached snapshot silently. */\n list = (): readonly ExportRunEntry[] => {\n if (this.#snapshot === null) this.#snapshot = Object.freeze(this.#entries.slice());\n return this.#snapshot;\n };\n\n subscribe = (cb: () => void): (() => void) => {\n const wasEmpty = this.#listeners.size === 0;\n this.#listeners.add(cb);\n if (wasEmpty) {\n for (const entry of this.#entries) this.#attachHandle(entry);\n }\n return () => {\n this.#listeners.delete(cb);\n if (this.#listeners.size === 0) this.#detachAll();\n };\n };\n\n dismiss = (runId: string): void => {\n const index = this.#entries.findIndex((entry) => entry.runId === runId);\n if (index === -1) return;\n this.#entries.splice(index, 1);\n this.#detachHandle(runId);\n this.#invalidate();\n this.#notify();\n };\n\n #attachHandle(entry: ExportRunEntry): void {\n if (this.#handleUnsubscribes.has(entry.runId)) return;\n const unsubscribe = entry.handle.subscribe(() => {\n this.#invalidate();\n this.#notify();\n });\n this.#handleUnsubscribes.set(entry.runId, unsubscribe);\n }\n\n #detachHandle(runId: string): void {\n const unsubscribe = this.#handleUnsubscribes.get(runId);\n if (unsubscribe === undefined) return;\n unsubscribe();\n this.#handleUnsubscribes.delete(runId);\n }\n\n #detachAll(): void {\n for (const unsubscribe of this.#handleUnsubscribes.values()) unsubscribe();\n this.#handleUnsubscribes.clear();\n }\n\n #invalidate(): void {\n this.#snapshot = null;\n }\n\n #notify(): void {\n for (const listener of [...this.#listeners]) listener();\n }\n}\n","import {\n type AppExportConfig,\n type CountResult,\n type DataError,\n EXPORT_ERROR_CODES,\n type ErasedResourceHandle,\n type ExportFormat,\n type ExportRequest,\n type Exporter,\n type ExporterContext,\n type ExporterDataAccess,\n type ExporterLoader,\n type ListAccess,\n type ListResult,\n type ResourceExportSetting,\n createQueryDescriptor,\n normalizeDataError,\n normalizeEntityRef,\n resolveDescriptorLocale,\n resolveExporter,\n} from '@burojs/core';\nimport { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from 'react';\n\nimport { useDataRuntime } from '../data/context.js';\nimport { executeQuery } from '../data/query-execution.js';\nimport type { DataRuntimeContextValue } from '../data/runtime.js';\nimport { type PathAccess, useListAccess, usePathAccess } from '../hooks/use-field-access.js';\nimport { filterFields } from '../hooks/url-state/hidden-predicates.js';\nimport { useLocale } from '../hooks/use-t.js';\n\nimport { type ExportRunEntry, ExportRunsStore, createExportRunId } from './runs-store.js';\n\n/**\n * One `ExportRunsStore` per app. `useDataRuntime()` returns the SAME\n * `DataRuntimeContextValue` object for the whole tree — it is created once\n * (`createDataRuntime`) and handed to `<BuroProvider dataRuntime={...}>` at\n * the app's root — so keying this lazily-populated map by that identity\n * gives every component in the app the one shared store REF-15's future\n * header indicator depends on, without either module-global mutable state\n * outside React's control or a per-component `useMemo` (which would create\n * an independent store per mount point).\n */\nconst runsStores = new WeakMap<DataRuntimeContextValue, ExportRunsStore>();\n\nfunction getExportRunsStore(runtime: DataRuntimeContextValue): ExportRunsStore {\n let store = runsStores.get(runtime);\n if (store === undefined) {\n store = new ExportRunsStore();\n runsStores.set(runtime, store);\n }\n return store;\n}\n\n/** All export runs for the current app, live-updated as runs start, progress,\n * and finish. Backed by the one `ExportRunsStore` for this app (see above) —\n * every component calling this hook observes the same list. */\nexport function useExportRuns(): readonly ExportRunEntry[] {\n const runtime = useDataRuntime();\n const store = getExportRunsStore(runtime);\n // `store.subscribe`/`store.list` are bound arrow properties on the store\n // instance (stable per-store), so they can be passed directly — no\n // memoized wrapper closure is needed to keep useSyncExternalStore from\n // resubscribing on every render.\n return useSyncExternalStore(store.subscribe, store.list, store.list);\n}\n\n/** Removes a run from the app's shared `ExportRunsStore`. A separate hook\n * (rather than widening `useExportRuns`'s return, which the brief fixes as\n * a plain array) so the frozen `useExportRuns` surface never has to grow a\n * second shape. `store.dismiss` is a stable bound arrow property, so the\n * returned function is referentially stable across renders. */\nexport function useDismissExportRun(): (runId: string) => void {\n const runtime = useDataRuntime();\n const store = getExportRunsStore(runtime);\n return store.dismiss;\n}\n\n/** The names a sort expression addresses, whatever its shape (a field, or a list of them). */\nfunction sortFields(sort: unknown): readonly string[] {\n if (Array.isArray(sort)) return sort.flatMap(sortFields);\n if (sort !== null && typeof sort === 'object') {\n const field = (sort as { readonly field?: unknown }).field;\n return typeof field === 'string' ? [field] : [];\n }\n return [];\n}\n\n/**\n * Fails closed (P5 spec 3.8): a run names only columns, filter fields and sort fields the user\n * may view, by the same predicate the list reads. A decision still pending refuses as well.\n * Nothing is read before the refusal.\n */\nfunction refuseHidden(\n request: Omit<ExportRequest, 'resource'>,\n access: ListAccess,\n pathAccess: PathAccess,\n): void {\n if (access.status === 'pending' || pathAccess.pending) {\n throw {\n kind: 'validation',\n code: EXPORT_ERROR_CODES.accessPending,\n message: 'Export access is not decided yet.',\n } satisfies DataError;\n }\n const visible = (field: string): boolean => {\n const head = field.split('.')[0] as string;\n return (\n access.columnVisible(head) &&\n (head === field || access.columnVisible(field)) &&\n pathAccess.visible(field)\n );\n };\n if (Array.isArray(request.columns) && !request.columns.every(visible)) {\n throw {\n kind: 'validation',\n code: EXPORT_ERROR_CODES.columnsHidden,\n message: 'An export request names a column the user may not view.',\n } satisfies DataError;\n }\n const target = request.target;\n if (target?.kind === 'filter') {\n const named = [\n ...(target.filter === undefined ? [] : filterFields(target.filter)),\n ...sortFields(target.sort),\n ];\n if (!named.every(visible)) {\n throw {\n kind: 'validation',\n code: EXPORT_ERROR_CODES.predicateHidden,\n message: 'An export request filters or sorts on a field the user may not view.',\n } satisfies DataError;\n }\n }\n}\n\nfunction resourceHandle(resource: string): ErasedResourceHandle {\n return { kind: 'resource', ref: normalizeEntityRef(resource) } as ErasedResourceHandle;\n}\n\n/**\n * Drops own keys whose value is `undefined`.\n *\n * ⚠️ SHALLOW, deliberately narrow — precise about what it closes, not a\n * general portable-value sanitizer:\n * - Strips undefined-valued keys off the TOP-LEVEL `args` object only\n * (`pagination`/`filter`/`sort`/`projection` — `list`/`count`'s own flat\n * parameter shape). This is exactly the failure\n * the since-deleted `apps/playground`'s export browser spec caught live:\n * a `{kind:'filter'}`\n * target with no active filter and no active sort — the default,\n * unfiltered/unsorted list export — handing `{filter: undefined, sort:\n * undefined}` straight to `createQueryDescriptor`, which runs the WHOLE\n * object through `clonePortableValue` (`packages/core`). That function\n * rejects an object whose OWN keys include one whose VALUE is\n * `undefined` — no representation for \"present but meaningless,\" only\n * \"absent\" — hence \"Portable value must contain only JSON-compatible\n * data.\" for every such call.\n * - Does NOT walk into `filter`/`sort` themselves. An `Exporter` (a PUBLIC\n * seam any adopter can implement) that builds a filter expression whose\n * OWN leaf carries an undefined value — e.g. `{ field: 'x', op: 'eq',\n * value: undefined }` — still trips `clonePortableValue` when that\n * nested object reaches it; this function only protects the outer args\n * shape, not arbitrary caller-constructed filter/sort ASTs.\n *\n * `createPaginatedExporter` (`@burojs/export`) now takes the matching care\n * at its own call sites for exactly the values it itself builds\n * (`target.filter`/`target.sort`; `request.columns` is always present, a\n * request without it is refused before any read), so this boundary and\n * that exporter agree on the common case; a hypothetical future exporter\n * that constructs a filter/sort value with an undefined LEAF would need its\n * own discipline (or a deeper walk added here) — that residual case is\n * open, not silently closed by this change.\n */\nfunction dropUndefinedValues<T extends Record<string, unknown>>(value: T): Partial<T> {\n const out: Partial<T> = {};\n for (const key of Object.keys(value) as (keyof T)[]) {\n if (value[key] !== undefined) out[key] = value[key];\n }\n return out;\n}\n\n/**\n * Resource-scoped `ExporterDataAccess`, narrowed to `list`/`count` and bound\n * to one resource. Mirrors the REAL query-descriptor construction path —\n * `use-standard-query-descriptor.ts:65-78` (`useList`/`useCount`/`useOne`/\n * `useMany`/`useInfiniteList`), not `action-data-access.ts`'s `resourceBase`\n * — same readiness wait, same registry projection lookup, same binding\n * resolution, same descriptor identity fields (`providerId`, `ref`,\n * `resource`, `sessionKey`, `scopeKey`, `bindingRevision`, `providerOptions`,\n * `dependencies`) — so an exporter's `list`/`count` calls land in the exact\n * cache/generation partition (`queryKeyFor` clones the whole descriptor into\n * the cache key with no field allowlist) that `useList`/`useCount` do for\n * the same resource. Never a second hand-rolled path.\n *\n * Deliberately does NOT include `idField`: it is declared only on the\n * mutation descriptor shapes (`CreateOneDescriptorShape` etc.,\n * `packages/core/src/data/descriptors.ts`), not on `list`/`count`/`one`/\n * `many` — `resourceBase` in `action-data-access.ts` carries it into every\n * descriptor kind uniformly (a pre-existing, out-of-scope quirk there), but\n * copying that here would make an export read canonicalize to a different\n * cache key than the equivalent `useList`/`useCount` call, which is exactly\n * the identity mismatch this mirror exists to prevent. (`ExporterContext\n * .idField`, used by `createPaginatedExporter` to build the bulk `in`\n * predicate on the right column, is unrelated and unaffected — see `start()`\n * below.)\n */\nfunction createExporterDataAccess(\n runtime: DataRuntimeContextValue,\n handle: ErasedResourceHandle,\n /**\n * The active locale, captured by the calling HOOK (this factory is not one).\n * Threaded rather than omitted so the parity claimed above survives the\n * locale axis: for a resource declaring `data.localeVarying`, an export read\n * must land in the same per-locale cache partition — and fetch the same\n * language — as the `useList`/`useCount` it mirrors.\n */\n locale: string,\n): ExporterDataAccess {\n async function identity() {\n const session = await runtime.waitUntilReady();\n const projection = runtime.app.registry.get(handle);\n if (projection === undefined) {\n throw {\n kind: 'configuration',\n code: 'export-resource-unavailable',\n message: `Resource '${handle.ref.namespace}:${handle.ref.id}' is unavailable.`,\n } satisfies DataError;\n }\n const binding = runtime.app.resolveDataBinding(handle);\n return {\n providerId: binding.providerId,\n ref: binding.ref,\n resource: binding.resource,\n sessionKey: session.sessionKey,\n scopeKey: session.scopeKey,\n ...resolveDescriptorLocale(projection.data, locale),\n bindingRevision: runtime.app.runtime.getSnapshot().manifest.snapshotId,\n ...(projection.data?.providerOptions === undefined\n ? {}\n : { providerOptions: projection.data.providerOptions }),\n ...(projection.data?.dependencies === undefined\n ? {}\n : { dependencies: projection.data.dependencies }),\n };\n }\n\n return Object.freeze({\n async list(args: Parameters<ExporterDataAccess['list']>[0]) {\n const descriptor = createQueryDescriptor({\n ...(await identity()),\n kind: 'list',\n ...dropUndefinedValues(args),\n } as never);\n return executeQuery({ descriptor, runtime, signal: new AbortController().signal }) as Promise<\n ListResult<Record<string, unknown>>\n >;\n },\n async count(args: Parameters<ExporterDataAccess['count']>[0]) {\n const descriptor = createQueryDescriptor({\n ...(await identity()),\n kind: 'count',\n ...dropUndefinedValues(args),\n } as never);\n return executeQuery({\n descriptor,\n runtime,\n signal: new AbortController().signal,\n }) as Promise<CountResult>;\n },\n });\n}\n\n/** Transient provider-registry lifecycle codes (`packages/react/src/data/provider-registry.ts`):\n * the registry hasn't started yet, is mid-transition, or has been disposed.\n * All three self-resolve — the tree re-renders on the next `dataSession`\n * publish and this gets recomputed — so they stay silent. Everything else\n * (an unregistered provider id, a binding that names a provider the app\n * never wired up, a bug inside a provider's own `.exporter` getter) is a\n * real misconfiguration or defect and gets a `console.warn` instead of\n * vanishing into a silent fallback. */\nconst TRANSIENT_PROVIDER_CODES = new Set([\n 'not-started',\n 'provider-transitioning',\n 'registry-disposed',\n]);\n\n/** Dedup key for the provider-exporter-lookup `console.warn` below: one\n * report per (resource, code), not one per render. The hook re-renders on\n * every `dataSession` publish (see `useResourceExport`), so a persistently\n * broken binding would otherwise warn on every render of every component\n * using it. */\nconst reportedProviderExporterFailures = new Set<string>();\n\n/** The provider-bundled exporter for a resource, for both ownership modes.\n * `ResolvedDataBinding.provider` is present only for a BORROWED registration\n * (`packages/core/src/data-binding.ts`) — the uniform accessor for both owned\n * and borrowed providers is the started instance from the react provider\n * registry. */\nfunction resolveProviderExporter(\n runtime: DataRuntimeContextValue,\n handle: ErasedResourceHandle,\n resource: string,\n): Exporter | undefined {\n try {\n const binding = runtime.app.resolveDataBinding(handle);\n return runtime.providers.resolve(binding.providerId).provider.exporter;\n } catch (thrown) {\n const code = (thrown as { readonly code?: string } | undefined)?.code;\n if (code === undefined || !TRANSIENT_PROVIDER_CODES.has(code)) {\n const key = `${resource}::${code ?? ''}`;\n if (!reportedProviderExporterFailures.has(key)) {\n reportedProviderExporterFailures.add(key);\n console.warn('[buro] useResourceExport: provider-bundled exporter lookup failed', thrown);\n }\n }\n return undefined;\n }\n}\n\n/** Dedup key for the resolution-failure `console.error` below: one report\n * per (resource, attempted exporter id), not one per render. */\nconst reportedExportResolutionErrors = new Set<string>();\n\n/**\n * The exporter id the app-config half of the resolution chain would look up —\n * the resource's own `export.exporter` override, else `export.default`.\n *\n * Used for two things: the resolution-failure report below, and the cache key\n * of a deferred (`ExporterLoader`) registration. Both are only ever consulted\n * when the chain actually went through `AppExportConfig.exporters`: a\n * provider-bundled exporter is a ready instance reached without an id (it\n * needs no loading and can never fail to resolve), and `export: false`\n * short-circuits before any lookup.\n */\nfunction attemptedExporterId(\n appExport: AppExportConfig | undefined,\n resourceExportSetting: ResourceExportSetting | undefined,\n): string | undefined {\n return resourceExportSetting !== false && resourceExportSetting?.exporter !== undefined\n ? resourceExportSetting.exporter\n : appExport?.default;\n}\n\n/**\n * `resolveExporter` (`packages/core/src/export/resolve.ts`) does not merely\n * return `undefined` for \"nothing configured\" — it THROWS a `configuration`\n * `DataError` when a named id (a resource's `export.exporter` override, or\n * the app's `export.default`) is not registered. Left unguarded, a typo in\n * either setting crashes the render of every component using this hook.\n * `use-standard-query-descriptor.ts:47-64` sets the precedent: catch,\n * normalize, surface as data rather than an exception.\n */\nfunction resolveExporterSafe(\n appExport: AppExportConfig | undefined,\n resourceExportSetting: ResourceExportSetting | undefined,\n providerExporter: Exporter | undefined,\n resource: string,\n): {\n readonly resolved: Exporter | ExporterLoader | undefined;\n readonly error: DataError | undefined;\n} {\n try {\n return {\n resolved: resolveExporter(appExport, resourceExportSetting, providerExporter),\n error: undefined,\n };\n } catch (thrown) {\n const error = normalizeDataError(thrown);\n const attemptedId = attemptedExporterId(appExport, resourceExportSetting);\n const key = `${resource}::${attemptedId ?? ''}`;\n if (!reportedExportResolutionErrors.has(key)) {\n reportedExportResolutionErrors.add(key);\n console.error(\n `[buro] useResourceExport('${resource}'): exporter '${attemptedId ?? ''}' failed to resolve — ${error.message}`,\n error,\n );\n }\n return { resolved: undefined, error };\n }\n}\n\n/**\n * One in-flight-or-settled load per (app, exporter id).\n *\n * Same keying idiom (and the same reasoning) as `runsStores` above: the\n * `DataRuntimeContextValue` identity IS the app instance, so two dialogs for\n * the same resource — the toolbar's filter-scope one and the bulk bar's\n * ids-scope one — share one entry and therefore ONE `import()`. The stored\n * value is the PROMISE, not merely the settled instance: without that, a\n * second dialog mounting while the first load is still in flight would find\n * nothing cached and start a second one.\n */\nconst exporterLoads = new WeakMap<DataRuntimeContextValue, Map<string, ExporterLoadEntry>>();\n\ninterface ExporterLoadEntry {\n readonly promise: Promise<Exporter>;\n /** Set once the promise fulfils — the synchronous read path for renders\n * that happen after the load finished (including a brand-new component\n * mounting into an app that already loaded this exporter). */\n instance?: Exporter;\n}\n\nfunction exporterLoadsFor(runtime: DataRuntimeContextValue): Map<string, ExporterLoadEntry> {\n let cache = exporterLoads.get(runtime);\n if (cache === undefined) {\n cache = new Map();\n exporterLoads.set(runtime, cache);\n }\n return cache;\n}\n\n/** Dedup key for the load-failure `console.error`: one report per EXPORTER ID,\n * with no resource in it — unlike the two report sets above, which are\n * per-(resource, …) because a misconfigured resource is what they describe. A\n * loader failing is a module-fetch failure of one registration: it is identical\n * for every resource pointing at that id, and `startExporterLoad` is called\n * with no resource in scope precisely because none is relevant. A retry that\n * fails again stays quiet in the console — the failure is surfaced as `error`\n * on the hook result either way. */\nconst reportedExporterLoadFailures = new Set<string>();\n\nfunction exporterLoadFailure(exporterId: string, thrown: unknown): DataError {\n return {\n kind: 'transport',\n code: EXPORT_ERROR_CODES.exporterLoadFailed,\n message: `Exporter '${exporterId}' failed to load: ${normalizeDataError(thrown).message}`,\n retryable: true,\n cause: thrown,\n };\n}\n\n/**\n * Starts (or joins) the load of a deferred exporter registration.\n *\n * A REJECTED load is deliberately not kept: the entry is removed from the\n * cache the moment it fails, so the next attempt runs the loader again — and\n * because the dialog asks to load per OPEN (`{ load: open }`), reopening it is\n * such an attempt. A failed `import()` is usually a network or deploy artefact\n * (a stale chunk hash, an offline tab), i.e. exactly the class of failure a\n * retry fixes — caching it would turn one bad fetch into a dead export for the\n * rest of the session. The rejection is still delivered to everyone already\n * awaiting THIS attempt (they hold the promise), so no caller is left hanging.\n */\nfunction startExporterLoad(\n runtime: DataRuntimeContextValue,\n exporterId: string,\n loader: ExporterLoader,\n): ExporterLoadEntry {\n const cache = exporterLoadsFor(runtime);\n const existing = cache.get(exporterId);\n if (existing !== undefined) return existing;\n\n const entry: { promise: Promise<Exporter>; instance?: Exporter } = {\n // Replaced below, before anything can observe it; a placeholder is needed\n // because the promise's own handlers close over `entry`.\n promise: undefined as unknown as Promise<Exporter>,\n };\n entry.promise = (async () => loader())().then(\n (exporter) => {\n entry.instance = exporter;\n return exporter;\n },\n (thrown: unknown) => {\n if (cache.get(exporterId) === entry) cache.delete(exporterId);\n const error = exporterLoadFailure(exporterId, thrown);\n if (!reportedExporterLoadFailures.has(exporterId)) {\n reportedExporterLoadFailures.add(exporterId);\n console.error(`[buro] useResourceExport: ${error.message}`, thrown);\n }\n throw error;\n },\n );\n cache.set(exporterId, entry);\n return entry;\n}\n\n/** The already-loaded instance for a deferred registration, or `undefined` —\n * a synchronous cache peek that NEVER invokes the loader. */\nfunction peekLoadedExporter(\n runtime: DataRuntimeContextValue,\n exporterId: string | undefined,\n): Exporter | undefined {\n if (exporterId === undefined) return undefined;\n return exporterLoads.get(runtime)?.get(exporterId)?.instance;\n}\n\n/** Per-hook load outcome — SETTLED states only; \"loading\" is derived during\n * render (see the hook), so there is no in-flight state to keep in sync. Keyed\n * by exporter id so a resource whose override changes mid-life never shows the\n * previous exporter's outcome. */\ntype ExporterLoadOutcome =\n | { readonly status: 'loaded'; readonly exporterId: string; readonly exporter: Exporter }\n | { readonly status: 'failed'; readonly exporterId: string; readonly error: DataError };\n\nexport interface UseResourceExportOptions {\n /**\n * Invoke a deferred (`ExporterLoader`) registration — i.e. actually fetch\n * the exporter's chunk. Default `false`: `available`, which is all the\n * toolbar/bulk-bar triggers read, is answerable from the registration\n * alone, and gating those renders on a chunk fetch would defeat the whole\n * point of registering a loader. Only a surface that is about to run an\n * export (the export dialog) passes `true`.\n */\n readonly load?: boolean;\n}\n\nexport interface UseResourceExportResult {\n /**\n * An exporter is registered for this resource — `true` for a ready\n * `Exporter` AND for a not-yet-loaded `ExporterLoader`, since both mean\n * \"this resource can be exported\". Answered without invoking a loader.\n *\n * Flips back to `false` if a load that WAS attempted (`load: true`) failed,\n * with `error` explaining why: at that point this surface genuinely has no\n * exporter to offer. Not permanent — the failed attempt is not cached, so the\n * next attempt retries (for the framework's dialog, that is simply reopening\n * it: it asks to load per open). A consumer that never asked to load is\n * unaffected throughout.\n */\n readonly available: boolean;\n /** A deferred registration for this resource is loading right now — true\n * from the FIRST render that asks to load, not one commit later, so a surface\n * gated on it never paints an empty form first. Only ever `true` for a caller\n * that passed `load: true`. While it is, `formats` is empty and `exporter` is\n * absent. */\n readonly loading: boolean;\n readonly exporter?: Exporter;\n /** Present only when `resolveExporter` itself threw (an unregistered\n * exporter id in a resource override or the app default) or when a\n * deferred registration failed to load — the reason `available` is\n * `false`, for Task 8 to show instead of a bare \"no export\". */\n readonly error?: DataError;\n readonly formats: readonly ExportFormat[];\n /**\n * Starts an export run. SYNCHRONOUS by contract (both entry points and the\n * dialog build on that), so it cannot wait for a deferred registration: if\n * the exporter has not loaded yet it throws an `export/exporter-not-loaded`\n * `DataError` naming the resource. Callers gate their start affordance on\n * `loading` (the dialog disables Start) rather than relying on this guard.\n */\n start(request: Omit<ExportRequest, 'resource'>): ExportRunEntry;\n /**\n * Fire-and-forget: begins loading a deferred registration without this\n * caller having to switch to `load: true` (it will not re-render on\n * completion). Meant for hover/focus prefetch on an export trigger, so the\n * chunk is usually already there when the dialog mounts. A no-op when the\n * exporter is already loaded, was registered as a ready instance, or\n * nothing resolves.\n */\n prefetch(): void;\n}\n\n/**\n * Resolves the exporter for one resource through the core resolution chain\n * (`resolveExporter`, guarded — see `resolveExporterSafe`) and exposes a\n * `start()` that builds the `ExporterContext` (data access + `idField`),\n * runs the exporter, and registers the resulting run in the app's shared\n * `ExportRunsStore`.\n *\n * `available` is `false` whenever nothing resolves — including a resource\n * `export: false` setting (which `resolveExporter` itself treats as \"no\n * exporter\", no throw), a resolution failure, and a deferred registration\n * whose load was attempted and failed (`error` is set in all but the first\n * case). It can flip from `false` to `true` after mount: before the data\n * session is ready, a provider-bundled exporter is unreachable (see\n * `resolveProviderExporter`), and the hook re-renders once the session\n * becomes ready.\n *\n * The returned object, `formats`, and `start` are memoized so Tasks 7-8 can\n * use them as `useEffect`/`useMemo` dependencies without a re-render loop.\n *\n * ## Deferred registrations\n *\n * `AppExportConfig.exporters` may register an `ExporterLoader` (`() =>\n * Promise<Exporter>`) instead of a ready `Exporter`, so an app's exporter\n * factories stay out of its initial JS. This hook is the only place that ever\n * invokes one, and only when the caller passes `{ load: true }` — `available`\n * is deliberately answerable from the registration alone. See\n * {@link UseResourceExportOptions.load}.\n */\nexport function useResourceExport(\n resource: string,\n opts: UseResourceExportOptions = {},\n): UseResourceExportResult {\n const shouldLoad = opts.load === true;\n const runtime = useDataRuntime();\n const store = getExportRunsStore(runtime);\n // Captured here because `start` (and the data access it builds) is not a\n // hook. See `createExporterDataAccess`.\n const locale = useLocale();\n // The list's own predicate decides what a run may name (P5 spec 3.8).\n const access = useListAccess(resource);\n const pathAccess = usePathAccess(resource);\n // Re-render on session transitions so a provider-bundled exporter that was\n // unreachable before the session was ready gets picked up once it is.\n useSyncExternalStore(\n runtime.dataSession.subscribe,\n runtime.dataSession.getState,\n runtime.dataSession.getState,\n );\n\n const handle = useMemo(() => resourceHandle(resource), [resource]);\n const projection = runtime.app.registry.get(handle);\n const resourceExportSetting = projection?.export;\n const providerExporter = resolveProviderExporter(runtime, handle, resource);\n const { resolved, error: resolutionError } = resolveExporterSafe(\n runtime.app.exportConfig,\n resourceExportSetting,\n providerExporter,\n resource,\n );\n\n // `typeof === 'function'` IS the whole discrimination between the two\n // registration forms (`AppExportConfig.exporters`): an `Exporter` is an\n // object carrying methods, an `ExporterLoader` is a function. Split into two\n // separately-typed locals rather than casting later.\n const loader: ExporterLoader | undefined = typeof resolved === 'function' ? resolved : undefined;\n const instanceExporter: Exporter | undefined =\n typeof resolved === 'function' ? undefined : resolved;\n const loaderId =\n loader === undefined\n ? undefined\n : attemptedExporterId(runtime.app.exportConfig, resourceExportSetting);\n\n const [outcome, setOutcome] = useState<ExporterLoadOutcome | undefined>(undefined);\n /** The load outcome for the exporter id resolving RIGHT NOW — a stale one\n * from a previous id (a resource override that changed) is ignored. */\n const ownOutcome = outcome?.exporterId === loaderId ? outcome : undefined;\n\n // `shouldLoad` is a REAL dep, not a constant: the export dialog passes\n // `{ load: open }`, so this effect re-runs on every open. That is what makes a\n // failed load recoverable — reopening the dialog runs the loader again and the\n // fresh attempt's outcome replaces the stale `'failed'` one. It was not always\n // so: with `{ load: true }` (plus a dialog kept mounted after close) all four\n // deps were constant for the app's lifetime, the effect ran exactly once per\n // mount, and one rejected load left that surface permanently unavailable until\n // a route change unmounted it — while the changeset and the adopter guide both\n // promised that reopening retries. Do not turn `shouldLoad` back into a\n // literal.\n useEffect(() => {\n if (!shouldLoad || loader === undefined || loaderId === undefined) return;\n const cached = peekLoadedExporter(runtime, loaderId);\n if (cached !== undefined) {\n setOutcome({ status: 'loaded', exporterId: loaderId, exporter: cached });\n return;\n }\n let live = true;\n // Clear any outcome from a previous attempt at this same id before starting\n // a new one, so a reopen after a failure does not show the dead attempt's\n // error while the retry is in flight.\n setOutcome(undefined);\n // `startExporterLoad` dedupes by (app, exporter id), so a second dialog\n // for the same resource — or a StrictMode remount — joins this same\n // promise instead of fetching the chunk twice.\n startExporterLoad(runtime, loaderId, loader).promise.then(\n (loaded) => {\n if (live) setOutcome({ status: 'loaded', exporterId: loaderId, exporter: loaded });\n },\n (thrown: unknown) => {\n if (live)\n setOutcome({ status: 'failed', exporterId: loaderId, error: normalizeDataError(thrown) });\n },\n );\n return () => {\n live = false;\n };\n }, [shouldLoad, loader, loaderId, runtime]);\n\n // The cache peek comes FIRST so a component that mounts into an app which\n // already loaded this exporter (a second dialog, or this one reopened) is\n // never shown a loading state for work that is already done — including the\n // `load: false` triggers, which get the loaded instance for free but never\n // cause a load.\n //\n // ⚠️ This is an impure read of module-level state during render, with no\n // subscription. The VALUE is monotonic (absent → present, never back), so it\n // can never regress and no render sees a torn exporter. What it does NOT give\n // is agreement WITHIN one commit: if the load settles between two components\n // rendering in the same pass, the earlier one can see `undefined` while the\n // later sees the instance. Harmless here — the earlier one is a\n // trigger/dialog that shows \"loading\" and re-renders on the state update the\n // very same promise handler queues (or, for a `load: false` caller, on its\n // next render for any reason) — but it is a real tearing window, not an\n // absence of one, and anything moved onto this peek must be able to tolerate\n // it.\n const loadedExporter =\n loader === undefined\n ? undefined\n : (peekLoadedExporter(runtime, loaderId) ??\n (ownOutcome?.status === 'loaded' ? ownOutcome.exporter : undefined));\n const exporter = instanceExporter ?? loadedExporter;\n // A load error is reported ONLY while there is no exporter to use. Otherwise\n // a `prefetch()` that succeeded after an earlier attempt failed would leave\n // this result carrying `exporter` AND `error` at once — a shape that says two\n // contradictory things about the same resource. Made impossible rather than\n // merely unobservable: `resolutionError` cannot coexist with an exporter\n // either (a resolution throw means nothing resolved, so there is no loader and\n // no instance), so `error` and `exporter` are mutually exclusive by\n // construction.\n const loadError =\n exporter === undefined && ownOutcome?.status === 'failed' ? ownOutcome.error : undefined;\n const error = resolutionError ?? loadError;\n // Derived during RENDER, not from an effect-set 'loading' state: a caller that\n // asked to load and has neither an exporter nor a failure IS loading, whether\n // or not the effect has fired yet. Computing it from state instead cost an\n // extra frame — the first render of a freshly opened dialog reported\n // `loading: false` with `formats: []`, so it painted an empty form before the\n // \"preparing\" affordance appeared one commit later.\n const loading =\n shouldLoad && loader !== undefined && exporter === undefined && error === undefined;\n // A registered-but-unloaded loader still means \"this resource can be\n // exported\" — that is the whole point of the deferred form. A load that was\n // attempted and FAILED does not (see `UseResourceExportResult.available`).\n const available = exporter !== undefined || (loader !== undefined && loadError === undefined);\n\n const formats = useMemo(() => exporter?.formats({ resource }) ?? [], [exporter, resource]);\n\n const prefetch = useCallback(() => {\n if (loader === undefined || loaderId === undefined) return;\n if (peekLoadedExporter(runtime, loaderId) !== undefined) return;\n // Fire-and-forget, so the rejection must be absorbed HERE or it becomes an\n // unhandled promise rejection: this caller does not observe the outcome.\n // Nothing is lost — the failed entry is dropped from the cache, the\n // load-failure `console.error` already fired, and the dialog's own\n // `load: true` attempt reports it as `error`.\n void startExporterLoad(runtime, loaderId, loader).promise.catch(() => undefined);\n }, [loader, loaderId, runtime]);\n\n const start = useCallback(\n (request: Omit<ExportRequest, 'resource'>): ExportRunEntry => {\n if (exporter === undefined) {\n if (error !== undefined) throw error;\n // A deferred registration that has not finished loading. `start` is\n // synchronous by contract, so it cannot wait — it names the cause\n // instead of failing as a bare \"no exporter\", which would be actively\n // misleading (one IS registered).\n if (loader !== undefined) {\n throw {\n kind: 'configuration',\n code: EXPORT_ERROR_CODES.exporterNotLoaded,\n message: `The exporter for resource '${resource}' has not finished loading — start() is synchronous and cannot wait for it. Gate the start affordance on \\`useResourceExport(resource, { load: true }).loading\\`.`,\n } satisfies DataError;\n }\n throw {\n kind: 'configuration',\n code: EXPORT_ERROR_CODES.noExporter,\n message: `No exporter is available for resource '${resource}'.`,\n } satisfies DataError;\n }\n // Generate (and validate) the run id BEFORE the exporter starts doing\n // real work: `crypto.randomUUID` can throw in a non-secure-context\n // browser, and if that happened AFTER `exporter.start(...)` the run\n // would already be live — consuming backend work for a job exporter —\n // yet never make it into the store, so it would be unobservable and\n // uncancelable. This probe result is discarded; `store.start` below\n // generates the id it actually commits. Both calls run synchronously\n // back-to-back with no state change between them, so if the probe\n // succeeds the real one cannot then fail.\n refuseHidden(request, access, pathAccess);\n createExportRunId();\n const idField = projection?.data?.idField ?? 'id';\n const data = createExporterDataAccess(runtime, handle, locale);\n const ctx: ExporterContext = { resource, data, idField };\n const fullRequest: ExportRequest = { ...request, resource };\n const exportHandle = exporter.start(fullRequest, ctx);\n return store.start({\n resource,\n exporterId: exporter.id,\n formatId: fullRequest.format.id,\n handle: exportHandle,\n });\n },\n [\n exporter,\n error,\n loader,\n resource,\n projection,\n handle,\n runtime,\n store,\n locale,\n access,\n pathAccess,\n ],\n );\n\n return useMemo(\n () => ({\n available,\n loading,\n ...(exporter === undefined ? {} : { exporter }),\n ...(error === undefined ? {} : { error }),\n formats,\n start,\n prefetch,\n }),\n [available, loading, exporter, error, formats, start, prefetch],\n );\n}\n","// Constants\nexport const PACKAGE_NAME = '@burojs/react' as const;\nexport const PACKAGE_VERSION = '0.0.0' as const;\n\n// Core data-session contract\nexport { createDataSession } from '@burojs/core';\nexport type {\n DataSessionController,\n DataSessionState,\n DataSessionTransitionParticipant,\n} from '@burojs/core';\n\n// Native React data runtime\nexport {\n createDataRuntime,\n createDataRuntimeTransitionParticipant,\n type CreateDataRuntimeOptions,\n type CreateDataRuntimeTransitionParticipantOptions,\n type DataRuntimeContextValue,\n type DataRuntimeLease,\n type DataRuntimeTransitionParticipant,\n} from './data/runtime.js';\nexport { useDataRuntime, useOptionalDataRuntime } from './data/context.js';\nexport {\n dehydrateBuroData,\n disposeBuroRequest,\n hydrateBuroData,\n serializeBuroHydration,\n validateBuroHydration,\n type BuroDehydratedData,\n} from './data/ssr.js';\nexport {\n createAuthController,\n type AuthController,\n type CreateAuthControllerOptions,\n} from './auth/controller.js';\nexport { useIdentity, useIsAuthenticated, useLogin, useLogout } from './hooks/auth/use-auth.js';\nexport { useOptionalAuthController } from './auth/context.js';\nexport { useList, type UseListOptions } from './hooks/data/use-list.js';\nexport { useOne, type UseOneOptions } from './hooks/data/use-one.js';\nexport { retryRecordRead } from './hooks/data/retry-record-read.js';\nexport { useMany, type UseManyOptions } from './hooks/data/use-many.js';\nexport { useCount, type UseCountOptions } from './hooks/data/use-count.js';\nexport {\n useInfiniteList,\n type InfiniteListData,\n type NativeInfiniteListResult,\n type UseInfiniteListOptions,\n} from './hooks/data/use-infinite-list.js';\nexport { resolveCountExecution, type CountExecution } from './data/count-policy.js';\nexport { useCustomQuery, type UseCustomQueryOptions } from './hooks/data/use-custom-query.js';\nexport type { NativeQueryOptions, NativeQueryResult } from './hooks/data/use-query-descriptor.js';\nexport {\n buroMutationOptions,\n type NativeMutationOptions,\n} from './data/mutation-options.js';\nexport {\n useCreateOne,\n type UseCreateOneOptions,\n} from './hooks/data/use-create.js';\nexport {\n useUpdateOne,\n useUpdateMany,\n type UseUpdateOneOptions,\n type UseUpdateManyOptions,\n} from './hooks/data/use-update.js';\nexport {\n useDeleteOne,\n useDeleteMany,\n type UseDeleteOneOptions,\n type UseDeleteManyOptions,\n} from './hooks/data/use-delete.js';\nexport {\n useCustomMutation,\n type UseCustomMutationOptions,\n} from './hooks/data/use-custom-mutation.js';\n\n// Provider + contexts\nexport { BuroProvider, type BuroProviderProps } from './provider.js';\nexport { type AppAudit, useAudit } from './audit/context.js';\nexport {\n UiSettingsProvider,\n useUiSettings,\n type UiSettingsProviderProps,\n type UseUiSettingsCollectionResult,\n type UseUiSettingsResult,\n type UseUiSettingsSingletonResult,\n} from './ui-settings/index.js';\nexport {\n hydrateManifest,\n createManifestHydrationScope,\n type InitialManifest,\n type ManifestHydration,\n type ManifestHydrationScope,\n} from './runtime/manifest-hydration.js';\nexport {\n BuroRuntimeProvider,\n useApplicationSnapshot,\n useLayerRuntime,\n useLayerStatus,\n useProjection,\n type BuroRuntimeProviderProps,\n} from './runtime.js';\n/** @internal The app's block catalogue for a flow's form and review tree (P4-D). */\nexport { useFlowFormCatalog } from './runtime.js';\nexport {\n ComponentsContext,\n DEFAULT_LANGUAGE_STORAGE_KEY,\n I18nContext,\n ResourceContext,\n TestIdContext,\n} from './context.js';\nexport { createRuntimeActionDataAccess } from './data/action-data-access.js';\n\n// Hooks\nexport { useApp } from './hooks/use-app.js';\nexport { useResource } from './hooks/use-resource.js';\nexport {\n RecordCodecError,\n createResourceRecordCodec,\n normalizeServerRecordIssues,\n type RecordCodecOutcome,\n type ResourceRecordCodec,\n} from '@burojs/core';\nexport { composeBlockImplementations, implementBlock } from './blocks/implementation.js';\nexport {\n composeFrameImplementations,\n type FrameImplementation,\n type FrameImplementationCatalog,\n type FrameNodeAttributes,\n type FrameStep,\n type FrameTab,\n type FrameTranslate,\n type FrameViewProps,\n implementFrame,\n type ListFrameViewProps,\n type PageFrameViewProps,\n type PanelFrameViewProps,\n type PeekFrameViewProps,\n type RecordFrameSlots,\n type RecordFrameViewProps,\n type StepsFrameViewProps,\n type TabsFrameViewProps,\n} from './frames/index.js';\n/** @internal The app's frame catalogue (the kit's frame renderer reads it). */\nexport { useFrameImplementations } from './frames/context.js';\n/** @internal The frame pieces' mount recorder (runtime obligations, `checkFrame`). */\nexport {\n FrameCheckContext,\n type FrameCheckValue,\n type FramePiece,\n useFramePiece,\n} from './frames/check-context.js';\n/** @internal A frame view's `t` (`frames.<id>.*`). */\nexport { useFrameT } from './frames/use-frame-t.js';\nexport { usePlacement, type PlacementView } from './blocks/use-placement.js';\n/** @internal The custom page host's resolver and planner (`@burojs/ui-shadcn`'s page route). */\nexport {\n type PageScreen,\n usePageScreen,\n} from './forms/controller/use-page-screen.js';\n/** @internal The `route` source a record route or a page host provides to the screen below. */\nexport { RouteSourceContext } from './forms/controller/route-source.js';\nexport { useRouteListImplementation } from './blocks/use-route-list-implementation.js';\nexport type { PlacementRuntime } from './forms/controller/placements.js';\nexport type {\n BlockDataEntryName,\n BlockImplementation,\n BlockImplementationCatalog,\n BlockViewPropValues,\n BlockViewProps,\n} from './blocks/implementation.js';\nexport {\n FieldImplementationProvider,\n useFieldImplementationCatalog,\n EMPTY_FIELD_IMPLEMENTATIONS,\n composeFieldImplementations,\n resolveFieldImplementation,\n useFieldImplementation,\n defineFieldWithImplementation,\n fieldImplementation,\n useCandidatesAccess,\n useFieldMeta,\n useFieldMetaSources,\n} from './fields/index.js';\nexport type {\n CollectionDisplayProps,\n CollectionInputProps,\n FieldAccessibilityIds,\n FieldImplementation,\n FieldImplementationLayout,\n FieldI18n,\n FieldImplementationComponent,\n FieldImplementationDiagnostic,\n FieldImplementationCatalog,\n FieldImplementationMap,\n FieldImplementationSource,\n FieldPresentation,\n FieldRenderContext,\n FieldRenderSurface,\n FieldTestIds,\n FieldUiHints,\n ResolvedFieldImplementation,\n ScalarDisplayProps,\n ScalarInputProps,\n UseFieldImplementationArgs,\n DefinedField,\n CandidatesAccess,\n FieldMetaState,\n} from './fields/index.js';\nexport { useDoc } from './hooks/use-doc.js';\nexport {\n DocsProvider,\n useDocPanel,\n useDocTopic,\n useDocTopics,\n useDocsConfig,\n useDocScopes,\n useDocTrailScopes,\n useHasDocTopics,\n usePublishDocVariant,\n useTrailHasDocs,\n useDocumentedScopes,\n type DocumentedScope,\n} from './hooks/use-doc-panel.js';\nexport type {\n DocPanelApi,\n DocPanelTarget,\n DocScopeView,\n DocTopicView,\n} from './hooks/use-doc-panel.js';\nexport { useCurrentResource } from './hooks/use-current-resource.js';\nexport { useCtx } from './hooks/use-ctx.js';\nexport {\n usePermissions,\n useScopeCtx,\n useVisibilityCtx,\n useOptionalVisibilityCtx,\n} from './hooks/use-permissions.js';\nexport { useCapability, useCapabilityResolver } from './hooks/use-capability.js';\nexport { filterFields } from './hooks/url-state/hidden-predicates.js';\nexport { useFieldAccess, useListAccess, useViewRow } from './hooks/use-field-access.js';\nexport {\n useProjectedRecord,\n useProjectedTitle,\n type ProjectedRecord,\n} from './hooks/use-projected-record.js';\n/** @internal Policy reads the controllers' raw data through these; view code never does. */\nexport { policyRecordOf, policyRowsOf } from './policy-side-channel.js';\nexport type { CapabilityResolver, UseCapabilityArgs } from './hooks/use-capability.js';\nexport {\n useAvailability,\n useAvailabilityGate,\n useAvailabilityResolver,\n} from './hooks/use-availability.js';\nexport { useAppActions } from './hooks/use-app-actions.js';\nexport type { AppActionEntry } from './hooks/use-app-actions.js';\nexport { useSetSlice } from './hooks/use-set-slice.js';\nexport {\n useT,\n useOptionalT,\n useLocale,\n useOptionalLocale,\n useChangeLocale,\n useLanguageStorageKey,\n useTranslate,\n useI18nCaps,\n useResourceI18n,\n} from './hooks/use-t.js';\nexport { useComponent, useDefaultComponent } from './hooks/use-component.js';\nexport { useTestIds, type TestIdBuilder } from './hooks/use-test-ids.js';\nexport { useRecordTitle } from './hooks/use-record-title.js';\nexport {\n useTaskRun,\n type TaskRunController,\n type TaskRunReporter,\n type UseTaskRunOptions,\n} from './hooks/use-task-run.js';\nexport { useChecks, type UseChecksOptions, type UseChecksResult } from './checks/use-checks.js';\nexport {\n useCheckGate,\n type CheckGateRequest,\n type CheckGateState,\n type UseCheckGateResult,\n} from './checks/use-check-gate.js';\nexport { useRefresh, type UseRefreshResult } from './hooks/use-refresh.js';\nexport { useLocalStorage } from './hooks/use-local-storage.js';\nexport {\n RouterAdapterProvider,\n useRouterAdapter,\n useOptionalRouterAdapter,\n type RouterAdapter,\n type RouterAdapterProviderProps,\n} from './hooks/router/router-adapter.js';\nexport { useDebouncedValue } from './hooks/use-debounced-value.js';\nexport {\n useFileField,\n formatBytes,\n matchesAccept,\n type FileItem,\n type FileItemStatus,\n type UseFileFieldArgs,\n type UseFileFieldResult,\n} from './hooks/file/use-file-field.js';\nexport { useFileStorage, useOptionalFileStorage } from './hooks/file/use-file-storage.js';\nexport {\n useFileUrls,\n type UseFileUrlsOpts,\n type UseFileUrlsResult,\n} from './hooks/file/use-file-urls.js';\nexport {\n createUrlCache,\n sharedUrlCache,\n RESOLVE_COOLDOWN_MS,\n type UrlCache,\n} from './hooks/file/url-cache.js';\nexport { useEnumValues, type UseEnumValuesResult } from './hooks/use-enum-values.js';\nexport {\n RELATION_BATCH_MAX_PAGE,\n useRelatedRecord,\n type UseRelatedRecordOptions,\n type UseRelatedRecordResult,\n type RelatedRecord,\n} from './hooks/relation-aggregator.js';\nexport {\n useResourceUrlState,\n DEFAULT_HISTORY_MODE,\n serializeResourceState,\n deserializeResourceState,\n RESOURCE_URL_STATE_LIMITS,\n RESERVED_LIST_SUFFIXES,\n getResourceParams,\n type HistoryMode,\n type SetterOptions,\n type ResourceUrlState,\n type CodecOptions,\n type FieldType,\n type ListState,\n} from './hooks/url-state/index.js';\nexport {\n useSavedViews,\n type SavedViewEntry,\n type UseSavedViewsResult,\n} from './hooks/saved-views/use-saved-views.js';\n// The framework-owned local-user scope id (Task 9): the ONE `UiSettingScope`\n// id the default local-storage adapter ever produces. UI recognizes this\n// EXACT id to swap its data-layer placeholder label for a reactive i18n\n// one — see `local-storage-adapter.ts`'s doc on `LOCAL_USER_SCOPE_ID`.\nexport {\n createLocalStorageUiSettingsAdapter,\n LOCAL_USER_SCOPE_ID,\n type LocalStorageUiSettingsAdapterOptions,\n} from './ui-settings/local-storage-adapter.js';\nexport {\n applyViewToUrlState,\n type ApplyViewToUrlStateOptions,\n type ApplyViewUrlStateSetters,\n} from './hooks/saved-views/apply-view-to-url-state.js';\nexport {\n useCommandPalette,\n type UseCommandPaletteResult,\n type UseCommandPaletteOptions,\n} from './hooks/command-palette/index.js';\nexport {\n useItemActions,\n modeForSurface,\n buildDI,\n RENDER_TIME_DATA,\n type ResolvedItemAction,\n} from './hooks/use-item-actions.js';\nexport {\n useResourceList,\n type UseResourceListOptions,\n useFilterFields,\n type UseFilterFieldsOptions,\n type FilterFieldsResult,\n ResourceListProvider,\n useResourceListContext,\n type ResourceListProviderProps,\n type ResourceListController,\n type FilterFieldSpec,\n type FilterKind,\n type RowRecord,\n} from './hooks/use-resource-list/index.js';\n\n// UI presentation (imperative)\nexport {\n UIActivationSurfaceProvider,\n UIInstanceProvider,\n UIPresentationRuntimeProvider,\n useCurrentUIActivation,\n useOptionalUIActivationSurface,\n useOptionalUIInstance,\n useOptionalUIPresentation,\n useUIInstance,\n useUIPresent,\n useUIPresentationRuntime,\n UIPresentations,\n BuroPresentationOutlet,\n QUICK_COMPONENT,\n PEEK_COMPONENT,\n BLOCK_COMPONENT,\n type BlockScreenProps,\n FLOW_COMPONENT,\n type FlowScreenProps,\n type FlowStart,\n type PeekScreenProps,\n type QuickScreenProps,\n type UIPresentationScreens,\n type UIInstance,\n type UIPresent,\n type UIPresentInput,\n type UIPresentationHost,\n type UIPresentationHostProps,\n type UIPresentationHosts,\n type UIPresentationLifecycle,\n type UIPresentationOptionsSchema,\n type UIPresentationsProps,\n type PresentationsMode,\n} from './ui/index.js';\n\n// Interaction layer — BuroProvider mounts all of it (P0)\nexport {\n DispatcherProvider,\n useDispatcher,\n type DispatcherProviderProps,\n} from './dispatch/dispatcher-context.js';\n/** @internal A nested dispatcher scope's path to its parent's effects. */\nexport { useDispatcherEffects } from './dispatch/dispatcher-context.js';\nexport { type PresentBlockInput, usePresentBlock } from './ui/present-block.js';\nexport { resolveRoute } from './navigation/resolve-route.js';\nexport { type PageAccess, pageAccessFor, usePageAccess } from './navigation/use-page-access.js';\nexport { type PageFlowGate, usePageFlowGate } from './flows/page-flow-gate.js';\nexport {\n conjoinHostPage,\n type HostPage,\n hostPageFor,\n hostPageRef,\n useHostPage,\n} from './flows/page-host.js';\nexport {\n useRouteNavigate,\n type RouteNavigate,\n type RouteNavigateOptions,\n} from './navigation/use-route-navigate.js';\nexport {\n QUICK_ANCHOR_ATTRIBUTE,\n useNavigationBlocker,\n type NavigationBlockerHandle,\n useRegisterNavigationGuardDialog,\n useNavigationGuardText,\n type NavigationGuardPrompt,\n type NavigationGuardText,\n} from './navigation/navigation-guard.js';\n/** @internal A framework quick opener claims its anchor's clicks from the guard. */\nexport { quickAnchorRef } from './navigation/navigation-guard.js';\nexport {\n DismissGuardScope,\n useDismissGuard,\n type DismissGuard,\n type DismissScopeValue,\n} from './navigation/dismiss-scope.js';\n/** @internal The form controller and a flow's host lock their overlay while they submit. */\nexport { useDismissPending } from './navigation/dismiss-scope.js';\n/** @internal A flow's pending lock holds every route change (P4 plan ruling 7). */\nexport { useNavigationHold } from './navigation/navigation-guard.js';\n\n// Flows (P4): what a flow's control needs before it runs — its state without a run, the page's\n// batched read. The run itself (`useAction`, `useFlowRun`) is `@burojs/react/flows`. Internal.\n/** @internal A flow's control without its run; the UI kit draws the button from it. */\nexport {\n usePresentFlow,\n type PresentFlowInput,\n useFlowOpenImplementation,\n useFlowRowBatch,\n useFlowRowResolver,\n resourceFlowsOn,\n type ResourceFlowSurface,\n FlowRowBatchContext,\n type FlowRowBatchValue,\n type FlowRowControl,\n type FlowRowState,\n} from './flows/index.js';\n\n// Quick entries (P3): the entry gate, `useQuick` and the quick overlay's history\nexport { useQuick, type QuickApi, type QuickOpen } from './quick/use-quick.js';\nexport type { QuickEntry, QuickSettledRow, QuickStack } from './quick/quick-stack.js';\nexport { useQuickEntry, type QuickEntryValue } from './quick/quick-entry-context.js';\n/** @internal The one entry gate every opener asks before any request (spec 4.4). */\nexport { useEntryGate, type EntryAnswer, type EntryKind } from './quick/entry-gate.js';\n/** @internal A framework opener's path to `quick.show`. */\nexport { useQuickOpener } from './quick/use-quick.js';\n/** @internal Provided by the UI kit's quick screen. */\nexport { QuickEntryContext, useQuickEntryValue } from './quick/quick-entry-context.js';\nexport {\n useRegisterNotificationSink,\n type NotificationSink,\n type NotificationSinkMessage,\n} from './notifications/notification-sink.js';\n\n// Helpers\nexport { mergeComponents } from './merge-components.js';\n\n// Routes\nexport {\n BuroRoutes,\n generateRouteDescriptors,\n isCustomPageRoute,\n type RouteDescriptor,\n type ResourceRouteDescriptor,\n type CustomPageRouteDescriptor,\n} from './components/buro-routes.js';\n\n// Locales\nexport { en } from './locales/en.js';\nexport { ru } from './locales/ru.js';\n\n// Declarative forms\nexport { useFormController } from './forms/controller/use-form-controller.js';\nexport {\n type ValidationMessageContext,\n resolveValidationMessage,\n} from './forms/validation-message.js';\nexport { useCurrentUserId } from './hooks/use-current-user-id.js';\nexport { useSearchParamsWriter } from './hooks/url-state/use-search-params-writer.js';\nexport type {\n FormController,\n FormControllerFailure,\n FormDraftState,\n FormSteps,\n FormSubmitResult,\n UseFormControllerFormOptions,\n UseFormControllerRecordOptions,\n} from './forms/controller/types.js';\nexport {\n RecordFrameContext,\n type RecordFrameValue,\n useOptionalRecordFrame,\n useRecordFrame,\n} from './record/record-frame-context.js';\nexport {\n type ScreenOpenState,\n ScreenStateProvider,\n type ScreenStateProviderProps,\n type ScreenStateValue,\n useScreenState,\n} from './forms/controller/screen-state.js';\n/** @internal An inline flow placement's lease and the screen's holder of them (P6). */\nexport type { InlineFlowHolder, InlineLease } from './flows/inline-holder.js';\nexport type {\n FieldBinding,\n FormValues,\n ResolvedIssue,\n RelationFilterOpt,\n} from './forms/types.js';\n\n// Export runs store + hooks\nexport {\n ExportRunsStore,\n type ExportRunEntry,\n useDismissExportRun,\n useExportRuns,\n useResourceExport,\n type UseResourceExportOptions,\n type UseResourceExportResult,\n} from './export/index.js';\n"],"mappings":"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"}
|