{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "core",
  "title": "Fable UI Core",
  "description": "Shared tool rendering, data-source types, schemas, registry, local querying, and provider utilities.",
  "dependencies": [
    "ai",
    "zod"
  ],
  "files": [
    {
      "path": "lib/fable-ui/core/definitions.ts",
      "content": "import type { ComponentType, LazyExoticComponent } from \"react\"\nimport type { Tool } from \"ai\"\nimport type { z } from \"zod\"\n\nexport class ToolPayloadError extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = \"ToolPayloadError\"\n  }\n}\n\nexport type ToolRenderHandlers = {\n  onSuggestedAction?: (action: { label: string; prompt: string; description?: string }) => void\n  onConfirm?: (confirmation: { id: string; label: string }) => void\n  onCancel?: (confirmation: { id: string; label: string }) => void\n  onFormSubmit?: (values: Record<string, string | number | boolean>) => void\n  onRowAction?: (action: { id: string; rowId: string }) => void\n}\n\nexport type ToolPartLike = {\n  type: string\n  toolName?: string\n  toolCallId?: string\n  state?: string\n  input?: unknown\n  output?: unknown\n  errorText?: string\n  toolMetadata?: {\n    fableState?: \"loading\" | \"empty\" | \"error\" | \"disabled\"\n  }\n}\n\nexport type FableRenderableComponent<TProps extends object> =\n  | ComponentType<TProps>\n  | LazyExoticComponent<ComponentType<TProps>>\n\nexport interface FableComponent<TSchema extends z.ZodType = z.ZodType, TProps extends object = Record<string, unknown>> {\n  name: string\n  schema: TSchema\n  tool: Tool\n  renderer: {\n    Component: FableRenderableComponent<TProps>\n    loadingProps: TProps\n    emptyProps: TProps\n    errorProps: (description: string) => TProps\n    toProps: (data: z.infer<TSchema>, handlers: ToolRenderHandlers) => TProps\n  }\n}\n\nexport type FableToolRegistry = Record<string, FableComponent<z.ZodType, any>>\n\nexport function defineFableComponent<TSchema extends z.ZodType, TProps extends object>(\n  def: FableComponent<TSchema, TProps>,\n) {\n  return def\n}\n\nexport function getToolNameFromPart(part: ToolPartLike) {\n  if (part.toolName) {\n    return part.toolName\n  }\n\n  if (part.type.startsWith(\"tool-\")) {\n    return part.type.slice(\"tool-\".length)\n  }\n\n  return null\n}\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/definitions.ts"
    },
    {
      "path": "lib/fable-ui/core/tool-renderer.tsx",
      "content": "import * as React from \"react\"\nimport type { ReactNode } from \"react\"\n\nimport {\n  getToolNameFromPart,\n  ToolPayloadError,\n  type FableToolRegistry,\n  type ToolPartLike,\n  type ToolRenderHandlers,\n} from \"./definitions\"\n\nfunction UnknownToolPart({ name }: { name: string }) {\n  return (\n    <div className=\"rounded-md border bg-muted/40 p-4 text-sm text-muted-foreground\">\n      Unknown Fable tool part: <code>{name}</code>\n    </div>\n  )\n}\n\nfunction renderComponent(\n  Component: FableToolRegistry[string][\"renderer\"][\"Component\"],\n  props: Record<string, unknown>,\n) {\n  return (\n    <React.Suspense fallback={null}>\n      <Component {...props} />\n    </React.Suspense>\n  )\n}\n\nexport function renderFableToolPart({\n  part,\n  registry,\n  handlers = {},\n}: {\n  part: ToolPartLike\n  registry: FableToolRegistry\n  handlers?: ToolRenderHandlers\n}): ReactNode {\n  const toolName = getToolNameFromPart(part)\n  const def = toolName ? registry[toolName] : undefined\n\n  if (!def) {\n    return <UnknownToolPart name={toolName ?? part.type} />\n  }\n\n  const fableState = part.toolMetadata?.fableState\n  const isDisabled = fableState === \"disabled\"\n\n  if (part.state === \"input-streaming\" || fableState === \"loading\") {\n    return renderComponent(def.renderer.Component, def.renderer.loadingProps)\n  }\n\n  if (part.state === \"output-error\" || fableState === \"error\") {\n    return renderComponent(\n      def.renderer.Component,\n      def.renderer.errorProps(part.errorText || \"The tool result could not be rendered.\"),\n    )\n  }\n\n  if (fableState === \"empty\") {\n    return renderComponent(def.renderer.Component, def.renderer.emptyProps)\n  }\n\n  const parsed = def.schema.safeParse(part.output ?? part.input)\n\n  if (!parsed.success) {\n    return renderComponent(\n      def.renderer.Component,\n      def.renderer.errorProps(\"The tool result did not match the expected data contract.\"),\n    )\n  }\n\n  try {\n    return renderComponent(\n      def.renderer.Component,\n      {\n        ...def.renderer.toProps(parsed.data, handlers),\n        isDisabled,\n      },\n    )\n  } catch (error) {\n    const description =\n      error instanceof ToolPayloadError ? error.message : \"Unexpected error rendering component.\"\n\n    return renderComponent(def.renderer.Component, def.renderer.errorProps(description))\n  }\n}\n\nexport function FableToolPart({\n  part,\n  registry,\n  handlers,\n}: {\n  part: ToolPartLike\n  registry: FableToolRegistry\n  handlers?: ToolRenderHandlers\n}) {\n  return <>{renderFableToolPart({ part, registry, handlers })}</>\n}\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/tool-renderer.tsx"
    },
    {
      "path": "lib/fable-ui/core/types.ts",
      "content": "export type DataCell = string | number | boolean | null\n\nexport type DataRow = {\n  id?: string\n  _id?: string\n  uid?: string\n  [key: string]: unknown\n}\n\nexport type DataColumn = {\n  key: string\n  label: string\n  description?: string\n  type?:\n    \"text\" | \"number\" | \"currency\" | \"date\" | \"datetime\" | \"boolean\" | \"badge\"\n  align?: \"left\" | \"center\" | \"right\"\n  width?: number | string\n  sortable?: boolean\n  filterable?: boolean\n  hidden?: boolean\n}\n\nexport type DataFilterOption = {\n  label: string\n  value: string | number | boolean\n}\n\nexport type DataFilter = {\n  key: string\n  label: string\n  type:\n    | \"text\"\n    | \"select\"\n    | \"multi-select\"\n    | \"date\"\n    | \"date-preset\"\n    | \"number\"\n    | \"boolean\"\n  options?: Array<DataFilterOption | string>\n}\n\nexport type DataSortDirection = \"asc\" | \"desc\"\n\nexport type DataSort = {\n  key: string\n  label: string\n  directions?: DataSortDirection[]\n}\n\nexport type SortState = {\n  key: string\n  direction: DataSortDirection\n}\n\nexport type DataQuery = {\n  search?: string\n  filters?: Record<string, unknown>\n  sort?: SortState\n  cursor?: string\n  page?: number\n  pageSize?: number\n}\n\nexport type DataQueryResult<Row extends DataRow = DataRow> = {\n  rows: Row[]\n  columns?: DataColumn[]\n  totalRows?: number\n  page?: number\n  pageSize?: number\n  nextCursor?: string\n  previousCursor?: string\n}\n\nexport type DataSourceContext = {\n  orgId?: string\n  tenantId?: string\n  locale?: string\n  signal?: AbortSignal\n  auth?: {\n    userId?: string\n    getAccessToken?: () =>\n      Promise<string | null | undefined> | string | null | undefined\n  }\n  [key: string]: unknown\n}\n\nexport type DataActionField = {\n  name: string\n  label: string\n  type: \"text\" | \"number\" | \"textarea\" | \"select\" | \"date\" | \"toggle\"\n  required?: boolean\n  options?: DataFilterOption[]\n}\n\nexport type DataActionInput = {\n  actionId: string\n  resourceId: string\n  rowId?: string\n  values?: Record<string, unknown>\n}\n\nexport type DataActionResult = {\n  ok: boolean\n  message?: string\n  data?: unknown\n  invalidate?: boolean\n}\n\nexport type DataActionConfig = {\n  id: string\n  label: string\n  description?: string\n  variant?: \"default\" | \"warning\" | \"destructive\"\n  requiresConfirmation?: boolean\n  fields?: DataActionField[]\n}\n\nexport type ResourceConfig<TSource = unknown, Row extends DataRow = DataRow> = {\n  id: string\n  label: string\n  entityLabel: string\n  driver: string\n  source: TSource\n  columns: DataColumn[]\n  filters?: DataFilter[]\n  sort?: DataSort[]\n  actions?: DataActionConfig[]\n  search?: {\n    mode?: \"client\" | \"exact\" | \"prefix\"\n    fields?: string[]\n  }\n  agent?: {\n    description?: string\n    aliases?: string[]\n    useWhen?: string[]\n    avoidWhen?: string[]\n  }\n  transformRows?: (rows: Row[]) => Row[]\n}\n\nexport type ResourceRuntime<\n  Row extends DataRow = DataRow,\n  TSource = unknown,\n> = {\n  list?: (\n    resource: ResourceConfig<TSource, Row>,\n    query: DataQuery,\n    ctx: DataSourceContext\n  ) => Promise<DataQueryResult<Row>> | DataQueryResult<Row>\n  get?: (\n    resource: ResourceConfig<TSource, Row>,\n    rowId: string,\n    ctx: DataSourceContext\n  ) => Promise<Row | null> | Row | null\n  executeAction?: (\n    input: DataActionInput,\n    resource: ResourceConfig<TSource, Row>,\n    ctx: DataSourceContext\n  ) => Promise<DataActionResult> | DataActionResult\n}\n\nexport type DataSourceDriver<\n  TSource = unknown,\n  Row extends DataRow = DataRow,\n> = {\n  list: (\n    resource: ResourceConfig<TSource, Row>,\n    query: DataQuery,\n    ctx: DataSourceContext,\n    runtime?: ResourceRuntime<Row, TSource>\n  ) => Promise<DataQueryResult<Row>> | DataQueryResult<Row>\n  get?: (\n    resource: ResourceConfig<TSource, Row>,\n    rowId: string,\n    ctx: DataSourceContext,\n    runtime?: ResourceRuntime<Row, TSource>\n  ) => Promise<Row | null> | Row | null\n  executeAction?: (\n    input: DataActionInput,\n    resource: ResourceConfig<TSource, Row>,\n    ctx: DataSourceContext,\n    runtime?: ResourceRuntime<Row, TSource>\n  ) => Promise<DataActionResult> | DataActionResult\n}\n\nexport type AgentResourceManifest = {\n  resources: Array<{\n    id: string\n    label: string\n    entityLabel: string\n    description?: string\n    aliases?: string[]\n    useWhen?: string[]\n    avoidWhen?: string[]\n    columns: Array<Pick<DataColumn, \"key\" | \"label\" | \"type\" | \"description\">>\n    filters?: Array<Pick<DataFilter, \"key\" | \"label\" | \"type\" | \"options\">>\n    sort?: DataSort[]\n    actions?: Array<\n      Pick<\n        DataActionConfig,\n        | \"id\"\n        | \"label\"\n        | \"description\"\n        | \"variant\"\n        | \"requiresConfirmation\"\n        | \"fields\"\n      >\n    >\n  }>\n}\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/types.ts"
    },
    {
      "path": "lib/fable-ui/core/schemas.ts",
      "content": "import { z } from \"zod\"\n\nexport const dataCellSchema = z.union([\n  z.string(),\n  z.number(),\n  z.boolean(),\n  z.null(),\n])\nexport const dataRowSchema = z.record(z.string(), z.unknown())\n\nexport const dataColumnSchema = z.object({\n  key: z.string().min(1),\n  label: z.string().min(1),\n  description: z.string().optional(),\n  type: z\n    .enum([\n      \"text\",\n      \"number\",\n      \"currency\",\n      \"date\",\n      \"datetime\",\n      \"boolean\",\n      \"badge\",\n    ])\n    .optional(),\n  align: z.enum([\"left\", \"center\", \"right\"]).optional(),\n  width: z.union([z.number().positive(), z.string().min(1)]).optional(),\n  sortable: z.boolean().optional(),\n  filterable: z.boolean().optional(),\n  hidden: z.boolean().optional(),\n})\n\nexport const dataFilterOptionSchema = z.union([\n  z.string(),\n  z.object({\n    label: z.string().min(1),\n    value: z.union([z.string(), z.number(), z.boolean()]),\n  }),\n])\n\nexport const dataFilterSchema = z.object({\n  key: z.string().min(1),\n  label: z.string().min(1),\n  type: z.enum([\n    \"text\",\n    \"select\",\n    \"multi-select\",\n    \"date\",\n    \"date-preset\",\n    \"number\",\n    \"boolean\",\n  ]),\n  options: z.array(dataFilterOptionSchema).optional(),\n})\n\nexport const dataSortSchema = z.object({\n  key: z.string().min(1),\n  label: z.string().min(1),\n  directions: z.array(z.enum([\"asc\", \"desc\"])).optional(),\n})\n\nexport const sortStateSchema = z.object({\n  key: z.string().min(1),\n  direction: z.enum([\"asc\", \"desc\"]),\n})\n\nexport const dataQuerySchema = z.object({\n  search: z.string().optional(),\n  filters: z.record(z.string(), z.unknown()).optional(),\n  sort: sortStateSchema.optional(),\n  cursor: z.string().optional(),\n  page: z.number().int().positive().optional(),\n  pageSize: z.number().int().positive().max(100).optional(),\n})\n\nexport const dataActionFieldSchema = z.object({\n  name: z.string().min(1),\n  label: z.string().min(1),\n  type: z.enum([\"text\", \"number\", \"textarea\", \"select\", \"date\", \"toggle\"]),\n  required: z.boolean().optional(),\n  options: z\n    .array(\n      z.object({\n        label: z.string().min(1),\n        value: z.union([z.string(), z.number(), z.boolean()]),\n      })\n    )\n    .optional(),\n})\n\nexport const dataActionInputSchema = z.object({\n  actionId: z.string().min(1),\n  resourceId: z.string().min(1),\n  rowId: z.string().optional(),\n  values: z.record(z.string(), z.unknown()).optional(),\n})\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/schemas.ts"
    },
    {
      "path": "lib/fable-ui/core/format.ts",
      "content": "import type { DataColumn, DataRow } from \"./types\"\n\nexport function getDataValue(row: DataRow, key: string): unknown {\n  const cells = row.cells\n\n  if (cells && typeof cells === \"object\" && key in cells) {\n    return (cells as Record<string, unknown>)[key]\n  }\n\n  return key.split(\".\").reduce<unknown>((value, part) => {\n    if (value && typeof value === \"object\" && part in value) {\n      return (value as Record<string, unknown>)[part]\n    }\n\n    return undefined\n  }, row)\n}\n\nexport function normalizeDataValue(value: unknown) {\n  if (value instanceof Date) {\n    return value.toISOString()\n  }\n\n  if (value == null) {\n    return \"\"\n  }\n\n  return String(value)\n}\n\nexport function formatDataCell(row: DataRow, column: DataColumn) {\n  const value = getDataValue(row, column.key)\n\n  if (value == null) {\n    return \"\"\n  }\n\n  if (column.type === \"date\" || column.type === \"datetime\") {\n    const date = value instanceof Date ? value : new Date(String(value))\n\n    if (!Number.isNaN(date.getTime())) {\n      return column.type === \"date\" ? date.toLocaleDateString() : date.toLocaleString()\n    }\n  }\n\n  return normalizeDataValue(value)\n}\n\nexport function getRowId(row: DataRow) {\n  const id = row.id ?? row._id ?? row.uid ?? row.orderId ?? row.order\n  return id == null ? null : String(id)\n}\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/format.ts"
    },
    {
      "path": "lib/fable-ui/core/local-query.ts",
      "content": "import { getDataValue, normalizeDataValue } from \"./format\"\nimport type { DataColumn, DataQuery, DataQueryResult, DataRow } from \"./types\"\n\nfunction matchesSearch(row: DataRow, query: string, columns?: DataColumn[]) {\n  const keys = columns?.map((column) => column.key) ?? Object.keys(row)\n  const normalizedQuery = query.trim().toLowerCase()\n\n  if (!normalizedQuery) {\n    return true\n  }\n\n  return keys.some((key) => normalizeDataValue(getDataValue(row, key)).toLowerCase().includes(normalizedQuery))\n}\n\nfunction matchesFilters(row: DataRow, filters: Record<string, unknown>) {\n  return Object.entries(filters).every(([key, expected]) => {\n    if (expected == null || expected === \"\" || (Array.isArray(expected) && expected.length === 0)) {\n      return true\n    }\n\n    const value = getDataValue(row, key)\n\n    if (Array.isArray(expected)) {\n      return expected.map(String).includes(String(value))\n    }\n\n    if (typeof expected === \"boolean\") {\n      return Boolean(value) === expected\n    }\n\n    return String(value).toLowerCase() === String(expected).toLowerCase()\n  })\n}\n\nfunction compareValues(a: unknown, b: unknown) {\n  if (typeof a === \"number\" && typeof b === \"number\") {\n    return a - b\n  }\n\n  return normalizeDataValue(a).localeCompare(normalizeDataValue(b), undefined, {\n    numeric: true,\n    sensitivity: \"base\",\n  })\n}\n\nexport function queryLocalRows<Row extends DataRow>(\n  rows: Row[],\n  query: DataQuery = {},\n  columns?: DataColumn[],\n): DataQueryResult<Row> {\n  const page = query.page ?? 1\n  const pageSize = query.pageSize ?? (rows.length || 10)\n\n  let nextRows = rows.filter((row) => matchesSearch(row, query.search ?? \"\", columns))\n  nextRows = nextRows.filter((row) => matchesFilters(row, query.filters ?? {}))\n\n  if (query.sort?.key) {\n    const { key, direction } = query.sort\n    nextRows = [...nextRows].sort((a, b) => {\n      const result = compareValues(getDataValue(a, key), getDataValue(b, key))\n      return direction === \"desc\" ? -result : result\n    })\n  }\n\n  const totalRows = nextRows.length\n  const start = (page - 1) * pageSize\n  const pagedRows = nextRows.slice(start, start + pageSize)\n\n  return {\n    rows: pagedRows,\n    totalRows,\n    page,\n    pageSize,\n    nextCursor: start + pageSize < totalRows ? String(page + 1) : undefined,\n    previousCursor: page > 1 ? String(page - 1) : undefined,\n  }\n}\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/local-query.ts"
    },
    {
      "path": "lib/fable-ui/core/registry.ts",
      "content": "import type {\n  AgentResourceManifest,\n  DataActionInput,\n  DataActionResult,\n  DataQuery,\n  DataQueryResult,\n  DataRow,\n  DataSourceContext,\n  DataSourceDriver,\n  ResourceConfig,\n  ResourceRuntime,\n} from \"./types\"\n\nfunction warnOnce(message: string) {\n  if (process.env.NODE_ENV === \"development\") {\n    console.warn(message)\n  }\n}\n\nexport function defineResource<TSource, Row extends DataRow = DataRow>(\n  resource: ResourceConfig<TSource, Row>,\n) {\n  return resource\n}\n\nexport function defineResourceRuntime<Row extends DataRow = DataRow>(runtime: ResourceRuntime<Row>) {\n  return runtime\n}\n\nexport class DataSourceRegistry {\n  private drivers = new Map<string, DataSourceDriver<any, any>>()\n  private resources = new Map<string, ResourceConfig<any, any>>()\n  private runtimes = new Map<string, ResourceRuntime<any>>()\n\n  registerDriver(id: string, driver: DataSourceDriver<any, any>) {\n    const existing = this.drivers.get(id)\n\n    if (existing) {\n      if (existing !== driver) {\n        warnOnce(`[fable-ui] Driver \"${id}\" is already registered. Keeping the latest registration.`)\n      }\n    }\n\n    this.drivers.set(id, driver)\n    return this\n  }\n\n  registerResource<TSource, Row extends DataRow = DataRow>(resource: ResourceConfig<TSource, Row>) {\n    const existing = this.resources.get(resource.id)\n\n    if (existing) {\n      if (JSON.stringify(existing) !== JSON.stringify(resource)) {\n        warnOnce(`[fable-ui] Resource \"${resource.id}\" is already registered. Keeping the latest registration.`)\n      }\n    }\n\n    this.resources.set(resource.id, resource)\n    return this\n  }\n\n  registerResourceRuntime<Row extends DataRow = DataRow>(resourceId: string, runtime: ResourceRuntime<Row>) {\n    const existing = this.runtimes.get(resourceId)\n\n    if (existing && existing !== runtime) {\n      warnOnce(`[fable-ui] Runtime for resource \"${resourceId}\" is already registered. Keeping the latest registration.`)\n    }\n\n    this.runtimes.set(resourceId, runtime)\n    return this\n  }\n\n  getResource(resourceId: string) {\n    return this.resources.get(resourceId)\n  }\n\n  listResources() {\n    return Array.from(this.resources.values())\n  }\n\n  resolve(resourceId: string) {\n    const resource = this.resources.get(resourceId)\n\n    if (!resource) {\n      throw new Error(`Fable resource \"${resourceId}\" is not registered.`)\n    }\n\n    const driver = this.drivers.get(resource.driver)\n\n    if (!driver) {\n      throw new Error(`Fable driver \"${resource.driver}\" for resource \"${resourceId}\" is not registered.`)\n    }\n\n    return {\n      resource,\n      driver,\n      runtime: this.runtimes.get(resourceId),\n    }\n  }\n\n  async list<Row extends DataRow = DataRow>(\n    resourceId: string,\n    query: DataQuery = {},\n    ctx: DataSourceContext = {},\n  ): Promise<DataQueryResult<Row>> {\n    const { resource, driver, runtime } = this.resolve(resourceId)\n\n    if (runtime?.list) {\n      return runtime.list(resource, query, ctx) as Promise<DataQueryResult<Row>> | DataQueryResult<Row>\n    }\n\n    return driver.list(resource, query, ctx, runtime)\n  }\n\n  async get<Row extends DataRow = DataRow>(\n    resourceId: string,\n    rowId: string,\n    ctx: DataSourceContext = {},\n  ): Promise<Row | null> {\n    const { resource, driver, runtime } = this.resolve(resourceId)\n\n    if (runtime?.get) {\n      return runtime.get(resource, rowId, ctx) as Promise<Row | null> | Row | null\n    }\n\n    return driver.get ? driver.get(resource, rowId, ctx, runtime) : null\n  }\n\n  async executeAction(\n    input: DataActionInput,\n    ctx: DataSourceContext = {},\n  ): Promise<DataActionResult> {\n    const { resource, driver, runtime } = this.resolve(input.resourceId)\n\n    if (runtime?.executeAction) {\n      return runtime.executeAction(input, resource, ctx)\n    }\n\n    if (!driver.executeAction) {\n      throw new Error(`Fable resource \"${input.resourceId}\" does not support actions.`)\n    }\n\n    return driver.executeAction(input, resource, ctx, runtime)\n  }\n\n  getAgentResourceManifest(): AgentResourceManifest {\n    return {\n      resources: this.listResources().map((resource) => ({\n        id: resource.id,\n        label: resource.label,\n        entityLabel: resource.entityLabel,\n        description: resource.agent?.description,\n        aliases: resource.agent?.aliases,\n        useWhen: resource.agent?.useWhen,\n        avoidWhen: resource.agent?.avoidWhen,\n        columns: resource.columns.map(({ key, label, type, description }) => ({\n          key,\n          label,\n          type,\n          description,\n        })),\n        filters: resource.filters?.map(({ key, label, type, options }) => ({\n          key,\n          label,\n          type,\n          options,\n        })),\n        sort: resource.sort,\n        actions: resource.actions?.map(({ id, label, description, variant, requiresConfirmation, fields }) => ({\n          id,\n          label,\n          description,\n          variant,\n          requiresConfirmation,\n          fields,\n        })),\n      })),\n    }\n  }\n}\n\nexport const fableRegistry = new DataSourceRegistry()\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/registry.ts"
    },
    {
      "path": "lib/fable-ui/core/provider.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { fableRegistry, type DataSourceRegistry } from \"./registry\"\nimport type { DataActionInput, DataQuery, DataSourceContext } from \"./types\"\n\ntype FableDataContextValue = {\n  registry: DataSourceRegistry\n  context: DataSourceContext\n}\n\nconst FableDataContext = React.createContext<FableDataContextValue | null>(null)\n\nexport function FableDataProvider({\n  registry = fableRegistry,\n  context = {},\n  children,\n}: {\n  registry?: DataSourceRegistry\n  context?: DataSourceContext\n  children: React.ReactNode\n}) {\n  const value = React.useMemo(() => ({ registry, context }), [context, registry])\n\n  return <FableDataContext.Provider value={value}>{children}</FableDataContext.Provider>\n}\n\nexport function useFableDataContext() {\n  const value = React.useContext(FableDataContext)\n\n  if (!value) {\n    throw new Error(\"useFableDataContext must be used within FableDataProvider.\")\n  }\n\n  return value\n}\n\nexport function useOptionalFableDataContext() {\n  return React.useContext(FableDataContext)\n}\n\nexport function useFableResource(resourceId: string) {\n  const { registry, context } = useFableDataContext()\n  const resource = registry.getResource(resourceId)\n\n  const list = React.useCallback(\n    (query: DataQuery = {}) => registry.list(resourceId, query, context),\n    [context, registry, resourceId],\n  )\n\n  const runAction = React.useCallback(\n    (input: Omit<DataActionInput, \"resourceId\">) =>\n      registry.executeAction({ ...input, resourceId }, context),\n    [context, registry, resourceId],\n  )\n\n  return {\n    resource,\n    list,\n    runAction,\n  }\n}\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/provider.tsx"
    },
    {
      "path": "lib/fable-ui/core/index.ts",
      "content": "export * from \"./definitions\"\nexport * from \"./format\"\nexport * from \"./local-query\"\nexport * from \"./provider\"\nexport * from \"./registry\"\nexport * from \"./schemas\"\nexport * from \"./tool-renderer\"\nexport * from \"./types\"\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/core/index.ts"
    }
  ],
  "type": "registry:lib"
}