{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-table-schema",
  "title": "Data Table Schema System",
  "description": "Declarative table definitions with col.* factories, presets, and generators for columns, filters, and sheet fields.",
  "dependencies": [
    "@tanstack/react-table"
  ],
  "registryDependencies": [
    "https://data-table.openstatus.dev/r/data-table.json",
    "https://data-table.openstatus.dev/r/data-table-cell.json",
    "https://data-table.openstatus.dev/r/data-table-sheet.json"
  ],
  "files": [
    {
      "path": "src/lib/table-schema/index.ts",
      "content": "import { col as _col } from \"./col\";\nimport { presets } from \"./presets\";\nimport { deserializeSchema, serializeSchema } from \"./serialize\";\nimport { validateSchema } from \"./validate\";\n\n/**\n * Column builder factories and presets for defining table schemas.\n *\n * **Primitive factories** — choose based on the data type of the column:\n * - `col.string()` — text data (`string`)\n * - `col.number()` — numeric data (`number`)\n * - `col.boolean()` — boolean data (`boolean`)\n * - `col.timestamp()` — date/time data (`Date`)\n * - `col.enum(values)` — string union (`T[number]`)\n * - `col.array(item)` — array of values (`U[]`)\n * - `col.record()` — key-value map (`Record<string, string>`)\n *\n * **Presets** — pre-configured builders for common log table patterns:\n * - `col.presets.logLevel(values)` — severity levels\n * - `col.presets.httpMethod(values)` — HTTP verbs\n * - `col.presets.httpStatus(codes?)` — HTTP status codes\n * - `col.presets.duration(unit?, slider?)` — timing / latency\n * - `col.presets.timestamp()` — sortable timestamp with timerange filter\n * - `col.presets.traceId()` — trace / request ID (code display, not filterable)\n * - `col.presets.pathname()` — URL path with text search\n *\n * @example\n * ```ts\n * import { col, createTableSchema } from \"@/lib/table-schema\";\n *\n * export const tableSchema = createTableSchema({\n *   level:   col.presets.logLevel(LEVELS).description(\"Log severity\"),\n *   date:    col.presets.timestamp().label(\"Date\").size(200).sheet(),\n *   latency: col.presets.duration(\"ms\").label(\"Latency\").sortable().size(110).sheet(),\n *   status:  col.presets.httpStatus().label(\"Status\").size(60),\n *   method:  col.presets.httpMethod(METHODS).size(69),\n *   host:    col.string().label(\"Host\").size(125).sheet(),\n *   headers: col.record().label(\"Headers\").hidden().sheet(),\n * });\n * ```\n */\nexport const col = { ..._col, presets };\nexport type {\n  ColBuilder,\n  ColConfig,\n  ColKind,\n  ColumnDescriptor,\n  DisplayConfig,\n  FilterConfig,\n  FilterDescriptor,\n  FilterType,\n  InferTableType,\n  SchemaJSON,\n  SheetConfig,\n  SheetDescriptor,\n  TableSchemaDefinition,\n} from \"./types\";\nexport { generateColumns } from \"./generators/columns\";\nexport { generateFilterFields } from \"./generators/filter-fields\";\nexport { generateFilterSchema } from \"./generators/filter-schema\";\nexport { generateSheetFields } from \"./generators/sheet-fields\";\nexport { serializeSchema, deserializeSchema } from \"./serialize\";\n\n/**\n * Derive defaultColumnVisibility from the schema.\n * Returns { [key]: false } for every column marked with .hidden().\n */\nexport function getDefaultColumnVisibility(\n  schema: import(\"./types\").TableSchemaDefinition,\n): Record<string, boolean> {\n  const visibility: Record<string, boolean> = {};\n  for (const [key, builder] of Object.entries(schema)) {\n    if (builder._config.hidden) {\n      visibility[key] = false;\n    }\n  }\n  return visibility;\n}\n\n/**\n * Create a table schema from a map of col.* builders.\n *\n * The returned object holds the definition and exposes:\n * - `toJSON()` — serializes the schema to a function-free JSON descriptor,\n *   suitable for AI agents, MCP tools, and `JSON.stringify`.\n *\n * Use `createTableSchema.fromJSON(json)` to reconstruct a schema from a\n * JSON descriptor (e.g. one generated by an AI agent). Custom renderers\n * (display.cell, filter.component, sheet.component) are not serialized and\n * must be applied manually on top of the reconstructed builders.\n *\n * @example\n * ```ts\n * export const tableSchema = createTableSchema({\n *   level: col.enum(LEVELS).label(\"Level\").defaultOpen().sheet(),\n *   date: col.timestamp().label(\"Date\").sortable().size(200).sheet(),\n * });\n *\n * export type ColumnSchema = InferTableType<typeof tableSchema.definition>;\n *\n * // Serialize for an AI agent or MCP tool\n * const json = tableSchema.toJSON();\n * // JSON.stringify(tableSchema) also works — toJSON() is called automatically\n *\n * // Reconstruct from AI-generated JSON\n * const schema = createTableSchema.fromJSON(json);\n * ```\n */\nexport function createTableSchema<\n  T extends import(\"./types\").TableSchemaDefinition,\n>(definition: T): { definition: T; toJSON(): import(\"./types\").SchemaJSON } {\n  validateSchema(definition);\n  return {\n    definition,\n    toJSON() {\n      return serializeSchema(definition);\n    },\n  };\n}\n\ncreateTableSchema.fromJSON = (\n  json: import(\"./types\").SchemaJSON,\n): {\n  definition: import(\"./types\").TableSchemaDefinition;\n  toJSON(): import(\"./types\").SchemaJSON;\n} => {\n  return createTableSchema(deserializeSchema(json));\n};\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/types.ts",
      "content": "import type {\n  DatePreset,\n  Option,\n} from \"@/components/data-table/types\";\nimport type { JSX } from \"react\";\n\nexport type ColKind =\n  | \"string\"\n  | \"number\"\n  | \"boolean\"\n  | \"timestamp\"\n  | \"enum\"\n  | \"array\"\n  | \"record\"\n  | \"select\";\n\n/** The set of filter UI types. Used as the `F` generic on `ColBuilder<T, F>`. */\nexport type FilterType = \"input\" | \"checkbox\" | \"slider\" | \"timerange\";\n\nexport type DisplayConfig =\n  | { type: \"text\"; colorMap?: Record<string, string> }\n  | { type: \"code\"; colorMap?: Record<string, string> }\n  | { type: \"boolean\"; colorMap?: Record<string, string> }\n  | { type: \"star\"; colorMap?: Record<string, string> }\n  | { type: \"badge\"; colorMap?: Record<string, string> }\n  | { type: \"timestamp\"; colorMap?: Record<string, string> }\n  | { type: \"number\"; unit?: string; colorMap?: Record<string, string> }\n  | {\n      type: \"bar\";\n      min?: number;\n      max?: number;\n      unit?: string;\n      color?: string;\n      colorMap?: Record<string, string>;\n    }\n  | {\n      type: \"heatmap\";\n      min?: number;\n      max?: number;\n      unit?: string;\n      color?: string;\n      colorMap?: Record<string, string>;\n    }\n  | {\n      type: \"gauge\";\n      min?: number;\n      max?: number;\n      unit?: string;\n      color?: string;\n      colorMap?: Record<string, string>;\n    }\n  | { type: \"status-code\"; colorMap?: Record<string, string> }\n  | { type: \"level-indicator\"; colorMap?: Record<string, string> }\n  | {\n      type: \"custom\";\n      cell: (value: unknown, row: unknown) => JSX.Element | null;\n      colorMap?: Record<string, string>;\n    };\n\nexport type FilterConfig = {\n  type: FilterType;\n  defaultOpen: boolean;\n  commandDisabled: boolean;\n  options?: Option[];\n  component?: (props: Option) => JSX.Element | null;\n  min?: number;\n  max?: number;\n  unit?: string;\n  presets?: DatePreset[];\n};\n\nexport type SheetConfig = {\n  label?: string;\n  component?: (row: unknown) => JSX.Element | null | string;\n  condition?: (row: unknown) => boolean;\n  className?: string;\n  skeletonClassName?: string;\n};\n\nexport type ColConfig = {\n  kind: ColKind;\n  enumValues?: readonly string[];\n  arrayItem?: ColConfig;\n  optional: boolean;\n  label: string;\n  description?: string;\n  display: DisplayConfig;\n  size?: number;\n  hidden: boolean;\n  enableHiding: boolean;\n  hideHeader: boolean;\n  resizable: boolean;\n  sortable: boolean;\n  filter: FilterConfig | null;\n  sheet: SheetConfig | null;\n};\n\n/**\n * A fluent builder for a single table column.\n *\n * `T` — TypeScript type of the column's data value (inferred by `InferTableType`).\n * `F` — union of filter UI types valid for this col kind (compile-time constraint):\n *\n * | Factory            | Allowed filter types                    |\n * |--------------------|-----------------------------------------|\n * | `col.string()`     | `\"input\"`                               |\n * | `col.number()`     | `\"input\" \\| \"slider\" \\| \"checkbox\"`     |\n * | `col.boolean()`    | `\"checkbox\"`                            |\n * | `col.timestamp()`  | `\"timerange\"`                           |\n * | `col.enum()`       | `\"checkbox\"`                            |\n * | `col.array()`      | `\"checkbox\"`                            |\n * | `col.record()`     | `never` — `filterable()` is an error    |\n *\n * Calling `filterable(type)` with a type not in `F` is a **compile-time error**.\n */\nexport interface ColBuilder<T, F extends FilterType = FilterType> {\n  /** @internal Raw column configuration. Used by generators — do not access directly. */\n  readonly _config: ColConfig;\n\n  /**\n   * Sets the column header label shown in the table and filter sidebar.\n   *\n   * @example\n   * col.string().label(\"Host\")\n   * col.enum(LEVELS).label(\"Severity\")\n   */\n  label(text: string): ColBuilder<T, F>;\n\n  /**\n   * Attaches a human-readable description of the column's domain meaning.\n   *\n   * Not shown in the UI. Used by AI agents and MCP tools (via `toJSON()`) to\n   * understand what the column represents.\n   *\n   * @example\n   * col.number().label(\"Latency\").description(\"Round-trip time from request to response, in ms\")\n   * col.enum(LEVELS).label(\"Level\").description(\"Log severity: error > warn > info > debug\")\n   */\n  description(text: string): ColBuilder<T, F>;\n\n  /**\n   * Sets how the column value is rendered in table cells.\n   *\n   * Built-in display types:\n   * - `\"text\"` — plain text, truncated with tooltip on overflow\n   * - `\"code\"` — monospace font (IDs, hashes, paths, hostnames)\n   * - `\"boolean\"` — checkmark / dash icon\n   * - `\"badge\"` — colored chip (enums, categories, tags)\n   * - `\"timestamp\"` — relative time (\"3m ago\"), absolute datetime on hover\n   * - `\"number\"` — formatted number with optional `unit` suffix\n   * - `\"bar\"` — horizontal bar with `min`/`max` range and optional `unit`\n   * - `\"heatmap\"` — background color intensity based on `min`/`max` range\n   * - `\"custom\"` — developer-supplied JSX renderer (not serializable)\n   *\n   * @example\n   * col.string().display(\"code\")\n   * col.number().display(\"number\", { unit: \"ms\" })\n   * col.number().display(\"bar\", { min: 0, max: 5000, unit: \"ms\" })\n   * col.number().display(\"heatmap\", { min: 0, max: 100 })\n   * col.enum(LEVELS).display(\"custom\", { cell: (value) => <LevelBadge value={value} /> })\n   */\n  display(\n    type:\n      | \"text\"\n      | \"code\"\n      | \"boolean\"\n      | \"star\"\n      | \"badge\"\n      | \"timestamp\"\n      | \"status-code\"\n      | \"level-indicator\",\n    options?: { colorMap?: Record<string, string> },\n  ): ColBuilder<T, F>;\n  display(\n    type: \"number\",\n    options?: { unit?: string; colorMap?: Record<string, string> },\n  ): ColBuilder<T, F>;\n  display(\n    type: \"bar\",\n    options: {\n      min: number;\n      max: number;\n      unit?: string;\n      colorMap?: Record<string, string>;\n    },\n  ): ColBuilder<T, F>;\n  display(\n    type: \"heatmap\",\n    options: {\n      min: number;\n      max: number;\n      color?: string;\n      colorMap?: Record<string, string>;\n    },\n  ): ColBuilder<T, F>;\n  display(\n    type: \"custom\",\n    options: {\n      cell: (value: unknown, row: unknown) => JSX.Element | null;\n      colorMap?: Record<string, string>;\n    },\n  ): ColBuilder<T, F>;\n  display(\n    type: \"heatmap\" | \"bar\" | \"gauge\",\n    options?: {\n      min?: number;\n      max?: number;\n      unit?: string;\n      color?: string;\n    },\n  ): ColBuilder<T, F>;\n\n  /**\n   * Enables filtering for this column using its default filter type.\n   *\n   * For `col.record()` (`F = never`) this is a **compile-time error**.\n   * Use `.notFilterable()` on record columns instead (it is already the default).\n   */\n  filterable(...args: [F] extends [never] ? [never] : []): ColBuilder<T, F>;\n\n  /**\n   * Enables filtering with an explicit filter type and optional configuration.\n   *\n   * Only types in `F` are accepted — passing an invalid type is a **compile-time error**:\n   * - `\"input\"` — free-text or number search field\n   * - `\"timerange\"` — date range picker (with optional `presets`)\n   * - `\"checkbox\"` — multi-select from a list of `options`\n   * - `\"slider\"` — numeric range with required `min` / `max` bounds\n   *\n   * @example\n   * col.string().filterable(\"input\")\n   * col.timestamp().filterable(\"timerange\")\n   * col.enum(LEVELS).filterable(\"checkbox\", { options: LEVELS.map(v => ({ label: v, value: v })) })\n   * col.number().filterable(\"slider\", { min: 0, max: 5000 })\n   */\n  filterable(type: F & \"input\"): ColBuilder<T, \"input\">;\n  filterable(\n    type: F & \"timerange\",\n    options?: { presets?: DatePreset[] },\n  ): ColBuilder<T, \"timerange\">;\n  filterable(\n    type: F & \"checkbox\",\n    options?: {\n      options?: Option[];\n      component?: (props: Option) => JSX.Element | null;\n    },\n  ): ColBuilder<T, \"checkbox\">;\n  filterable(\n    type: F & \"slider\",\n    options: { min: number; max: number; unit?: string },\n  ): ColBuilder<T, \"slider\">;\n\n  /**\n   * Removes filtering from this column.\n   *\n   * After calling `.notFilterable()`, subsequent `.filterable()` calls are\n   * **compile-time errors** (`F` becomes `never`).\n   *\n   * @example\n   * col.string().label(\"Request ID\").notFilterable().hidden()\n   */\n  notFilterable(): ColBuilder<T, never>;\n\n  /**\n   * Opens the filter accordion for this column by default in the filter sidebar.\n   *\n   * Only applies to filterable columns. Use for high-priority filters that\n   * users should see immediately without expanding the sidebar manually.\n   *\n   * @example\n   * col.enum(LEVELS).label(\"Level\").filterable(\"checkbox\").defaultOpen()\n   */\n  defaultOpen(): ColBuilder<T, F>;\n\n  /**\n   * Excludes this column from the command palette filter search.\n   *\n   * Useful for columns whose filter state is managed elsewhere (e.g. a date\n   * picker in the toolbar) or for UI-only state fields like `cursor`.\n   *\n   * @example\n   * col.timestamp().label(\"Date\").filterable(\"timerange\").commandDisabled()\n   */\n  commandDisabled(): ColBuilder<T, F>;\n\n  /**\n   * Hides the column by default (not shown on first render).\n   *\n   * Hidden columns appear in the column visibility menu and can be toggled on.\n   * Use `getDefaultColumnVisibility(schema)` to derive the initial visibility map.\n   *\n   * @example\n   * col.number().label(\"DNS\").filterable(\"slider\", { min: 0, max: 5000 }).hidden()\n   */\n  hidden(): ColBuilder<T, F>;\n\n  /**\n   * Hides the column header label in the table while keeping the column visible.\n   *\n   * The label is still used in the filter sidebar and other UI elements.\n   *\n   * @example\n   * col.enum(LEVELS).label(\"Level\").hideHeader()\n   */\n  hideHeader(): ColBuilder<T, F>;\n\n  /**\n   * Enables column resizing via a drag handle in the header.\n   *\n   * Without this, `size` locks the column to a fixed width (`minSize === size`).\n   * With this, the column can be freely resized; `size` becomes the initial width only.\n   *\n   * @example\n   * col.string().label(\"Host\").size(125).resizable()\n   */\n  resizable(): ColBuilder<T, F>;\n\n  /**\n   * Sets a fixed column width in pixels.\n   *\n   * Without `.resizable()`, both `size` and `minSize` are set to this value.\n   * With `.resizable()`, only `size` is set (initial width), allowing free resizing.\n   *\n   * @example\n   * col.enum(LEVELS).label(\"Level\").size(27)\n   * col.timestamp().label(\"Date\").size(200)\n   */\n  size(px: number): ColBuilder<T, F>;\n\n  /**\n   * Enables click-to-sort on the column header.\n   *\n   * Renders a `DataTableColumnHeader` with ascending/descending/none sort controls.\n   *\n   * @example\n   * col.timestamp().label(\"Date\").sortable()\n   * col.number().label(\"Latency\").filterable(\"slider\", { min: 0, max: 5000 }).sortable()\n   */\n  sortable(): ColBuilder<T, F>;\n\n  /**\n   * Marks the data field as potentially `undefined` in the row type.\n   *\n   * Changes `T` to `T | undefined` in the inferred schema type (`InferTableType`).\n   * Use when the column field may be absent from some rows.\n   *\n   * @example\n   * col.number().optional().label(\"Percentile\").notFilterable().hidden()\n   * col.string().optional().label(\"Message\").notFilterable()\n   */\n  optional(): ColBuilder<T | undefined, F>;\n\n  /**\n   * Includes this column in the row detail drawer (`DataTableSheet`).\n   *\n   * Pass a `SheetConfig` to customize label, renderer, visibility condition,\n   * and layout class. Calling `.sheet()` with no arguments uses defaults\n   * (label from `.label()`, no custom renderer).\n   *\n   * @example\n   * col.timestamp().label(\"Date\").sheet()\n   * col.string().label(\"Host\").sheet({ skeletonClassName: \"w-24\" })\n   * col.number().label(\"Latency\").sheet({\n   *   component: (row) => <>{row.latency}ms</>,\n   *   skeletonClassName: \"w-16\",\n   * })\n   */\n  sheet(config?: SheetConfig): ColBuilder<T, F>;\n\n  /**\n   * Marks the column as sheet-only: hidden, not filterable, and excluded\n   * from the column visibility dropdown (`enableHiding: false`).\n   *\n   * Convenience for `.hidden().notFilterable()` + `enableHiding: false`.\n   *\n   * @example\n   * col.record().label(\"Headers\").sheetOnly().sheet({ ... })\n   * col.string().optional().label(\"Message\").sheetOnly().sheet({ ... })\n   */\n  sheetOnly(): ColBuilder<T, never>;\n}\n\nexport type TableSchemaDefinition = Record<string, ColBuilder<unknown, any>>;\n\n// Infer the data row type from a table schema definition\nexport type InferTableType<T extends TableSchemaDefinition> = {\n  [K in keyof T]: T[K] extends ColBuilder<infer U, any> ? U : never;\n};\n\n// ── Serializable descriptors (function-free) ────────────────────────────────\n\nexport type FilterDescriptor = {\n  type: FilterType;\n  defaultOpen: boolean;\n  commandDisabled: boolean;\n  options?: Array<{ label: string; value: string | number | boolean }>;\n  min?: number;\n  max?: number;\n};\n\nexport type SheetDescriptor = {\n  label?: string;\n  className?: string;\n  skeletonClassName?: string;\n};\n\n/** Serializable display config — excludes the `custom` variant (contains JSX). */\nexport type SerializableDisplayConfig = Exclude<\n  DisplayConfig,\n  { type: \"custom\" }\n>;\n\nexport type ColumnDescriptor = {\n  key: string;\n  label: string;\n  description?: string;\n  dataType: ColKind;\n  enumValues?: readonly string[];\n  arrayItemType?: { dataType: ColKind; enumValues?: readonly string[] };\n  optional: boolean;\n  hidden: boolean;\n  hideHeader?: boolean;\n  enableHiding?: boolean;\n  sortable: boolean;\n  size?: number;\n  display: SerializableDisplayConfig;\n  filter: FilterDescriptor | null;\n  sheet: SheetDescriptor | null;\n};\n\nexport type SchemaJSON = {\n  columns: ColumnDescriptor[];\n};\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/col.ts",
      "content": "import type {\n  ColBuilder,\n  ColConfig,\n  DisplayConfig,\n  FilterConfig,\n  FilterType,\n  SheetConfig,\n} from \"./types\";\n\nfunction createColBuilder<T, F extends FilterType = FilterType>(\n  config: ColConfig,\n): ColBuilder<T, F> {\n  // The implementation uses loose parameter types to satisfy all overload\n  // signatures at once. TypeScript enforces the constraints at call sites\n  // via the ColBuilder<T, F> interface overloads, not here.\n  const builder = {\n    get _config() {\n      return config;\n    },\n\n    label(text: string): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, label: text });\n    },\n\n    description(text: string): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, description: text });\n    },\n\n    display(type: string, options?: Record<string, unknown>): ColBuilder<T, F> {\n      const displayConfig = options\n        ? ({ type, ...options } as DisplayConfig)\n        : ({ type } as DisplayConfig);\n      return createColBuilder<T, F>({ ...config, display: displayConfig });\n    },\n\n    filterable(\n      type?: string,\n      options?: Record<string, unknown>,\n    ): ColBuilder<T, F> {\n      const filterType = (type ||\n        config.filter?.type ||\n        \"input\") as FilterConfig[\"type\"];\n      const existing = config.filter;\n      const sameType = filterType === existing?.type;\n      const newFilter: FilterConfig = {\n        type: filterType,\n        defaultOpen: existing?.defaultOpen ?? false,\n        commandDisabled: existing?.commandDisabled ?? false,\n        // Preserve auto-derived options when filter type stays the same\n        // and no explicit options are provided by the caller.\n        ...(sameType && existing?.options ? { options: existing.options } : {}),\n        ...(options ?? {}),\n      };\n      return createColBuilder<T, F>({ ...config, filter: newFilter });\n    },\n\n    notFilterable(): ColBuilder<T, never> {\n      return createColBuilder<T, never>({ ...config, filter: null });\n    },\n\n    defaultOpen(): ColBuilder<T, F> {\n      if (!config.filter) return createColBuilder<T, F>(config);\n      return createColBuilder<T, F>({\n        ...config,\n        filter: { ...config.filter, defaultOpen: true },\n      });\n    },\n\n    commandDisabled(): ColBuilder<T, F> {\n      if (!config.filter) return createColBuilder<T, F>(config);\n      return createColBuilder<T, F>({\n        ...config,\n        filter: { ...config.filter, commandDisabled: true },\n      });\n    },\n\n    hidden(): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, hidden: true });\n    },\n\n    hideHeader(): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, hideHeader: true });\n    },\n\n    resizable(): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, resizable: true });\n    },\n\n    size(px: number): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, size: px });\n    },\n\n    sortable(): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, sortable: true });\n    },\n\n    optional(): ColBuilder<T | undefined, F> {\n      return createColBuilder<T | undefined, F>({ ...config, optional: true });\n    },\n\n    sheet(sheetConfig?: SheetConfig): ColBuilder<T, F> {\n      return createColBuilder<T, F>({ ...config, sheet: sheetConfig ?? {} });\n    },\n\n    sheetOnly(): ColBuilder<T, never> {\n      return createColBuilder<T, never>({\n        ...config,\n        hidden: true,\n        filter: null,\n        enableHiding: false,\n      });\n    },\n  } as ColBuilder<T, F>;\n\n  return builder;\n}\n\n/**\n * A string column.\n *\n * - Data type: `string`\n * - Default display: `\"text\"` (plain text with overflow tooltip)\n * - Default filter: `\"input\"` (text search)\n * - Allowed filters: `\"input\"`\n *\n * @example\n * col.string().label(\"Host\").size(125).sheet()\n * col.string().label(\"Message\").notFilterable().optional().hidden()\n */\nfunction string(): ColBuilder<string, \"input\"> {\n  return createColBuilder<string, \"input\">({\n    kind: \"string\",\n    optional: false,\n    label: \"\",\n    display: { type: \"text\" },\n    hidden: false,\n    enableHiding: true,\n    hideHeader: false,\n    resizable: false,\n    sortable: false,\n    filter: { type: \"input\", defaultOpen: false, commandDisabled: false },\n    sheet: null,\n  });\n}\n\n/**\n * A numeric column.\n *\n * - Data type: `number`\n * - Default display: `\"number\"` (formatted, with optional unit)\n * - Default filter: `\"input\"` (exact match)\n * - Allowed filters: `\"input\"` | `\"slider\"` | `\"checkbox\"`\n *   - Use `\"slider\"` for continuous values (latency, file size)\n *   - Use `\"checkbox\"` for discrete values (HTTP status codes, port numbers)\n *\n * @example\n * col.number().label(\"Latency\").display(\"number\", { unit: \"ms\" }).filterable(\"slider\", { min: 0, max: 5000 }).sortable()\n * col.number().label(\"Status\").filterable(\"checkbox\", { options: [{ label: \"200\", value: 200 }] })\n */\nfunction number(): ColBuilder<number, \"input\" | \"slider\" | \"checkbox\"> {\n  return createColBuilder<number, \"input\" | \"slider\" | \"checkbox\">({\n    kind: \"number\",\n    optional: false,\n    label: \"\",\n    display: { type: \"number\" },\n    hidden: false,\n    enableHiding: true,\n    hideHeader: false,\n    resizable: false,\n    sortable: false,\n    filter: { type: \"input\", defaultOpen: false, commandDisabled: false },\n    sheet: null,\n  });\n}\n\n/**\n * A boolean column.\n *\n * - Data type: `boolean`\n * - Default display: `\"boolean\"` (checkmark / dash icon)\n * - Default filter: `\"checkbox\"` with `true` / `false` options pre-wired\n * - Allowed filters: `\"checkbox\"`\n *\n * @example\n * col.boolean().label(\"Cache Hit\").defaultOpen()\n */\nfunction boolean(): ColBuilder<boolean, \"checkbox\"> {\n  return createColBuilder<boolean, \"checkbox\">({\n    kind: \"boolean\",\n    optional: false,\n    label: \"\",\n    display: { type: \"boolean\" },\n    hidden: false,\n    enableHiding: true,\n    hideHeader: false,\n    resizable: false,\n    sortable: false,\n    filter: {\n      type: \"checkbox\",\n      defaultOpen: false,\n      commandDisabled: false,\n      options: [\n        { label: \"true\", value: true },\n        { label: \"false\", value: false },\n      ],\n    },\n    sheet: null,\n  });\n}\n\n/**\n * A timestamp column.\n *\n * - Data type: `Date`\n * - Default display: `\"timestamp\"` (relative time, absolute datetime on hover)\n * - Default filter: `\"timerange\"` (date range picker)\n * - Allowed filters: `\"timerange\"`\n *\n * @example\n * col.timestamp().label(\"Date\").sortable().commandDisabled().size(200).sheet()\n */\nfunction timestamp(): ColBuilder<Date, \"timerange\"> {\n  return createColBuilder<Date, \"timerange\">({\n    kind: \"timestamp\",\n    optional: false,\n    label: \"\",\n    display: { type: \"timestamp\" },\n    hidden: false,\n    enableHiding: true,\n    hideHeader: false,\n    resizable: false,\n    sortable: false,\n    filter: { type: \"timerange\", defaultOpen: false, commandDisabled: true },\n    sheet: null,\n  });\n}\n\n/**\n * An enum column from a `readonly string[]` union.\n *\n * - Data type: `T[number]` (union of the provided string literals)\n * - Default display: `\"badge\"` (colored chip)\n * - Default filter: `\"checkbox\"` with options auto-derived from `values`\n * - Allowed filters: `\"checkbox\"`\n *\n * Checkbox options are auto-derived from `values` by default. Override them via\n * `.filterable(\"checkbox\", { options: [...] })` when you need custom labels,\n * icons, or a subset of values.\n *\n * @param values - `as const` array of allowed string values\n *\n * @example\n * col.enum(LEVELS).label(\"Level\").defaultOpen()\n * col.enum(LEVELS).label(\"Level\").filterable(\"checkbox\", {\n *   options: LEVELS.map(v => ({ label: v, value: v })), // override labels\n * })\n */\nfunction colEnum<T extends readonly string[]>(\n  values: T,\n): ColBuilder<T[number], \"checkbox\"> {\n  return createColBuilder<T[number], \"checkbox\">({\n    kind: \"enum\",\n    enumValues: values,\n    optional: false,\n    label: \"\",\n    display: { type: \"badge\" },\n    hidden: false,\n    enableHiding: true,\n    hideHeader: false,\n    resizable: false,\n    sortable: false,\n    filter: {\n      type: \"checkbox\",\n      defaultOpen: false,\n      commandDisabled: false,\n      options: Array.from(values).map((v) => ({ label: v, value: v })),\n    },\n    sheet: null,\n  });\n}\n\n/**\n * An array column, typically used for multi-value enum fields.\n *\n * - Data type: `U[]` where `U` is the item builder's type\n * - Default display: `\"badge\"` (colored chip per value)\n * - Default filter: `\"checkbox\"`\n * - Allowed filters: `\"checkbox\"`\n *\n * Most commonly used as `col.array(col.enum(values))` for tags / regions / labels.\n *\n * @param itemBuilder - A `ColBuilder` describing the array item type\n *\n * @example\n * col.array(col.enum(REGIONS)).label(\"Regions\").filterable(\"checkbox\", {\n *   options: REGIONS.map(r => ({ label: r, value: r })),\n * })\n */\n\nfunction array<U>(\n  itemBuilder: ColBuilder<U, any>,\n): ColBuilder<U[], \"checkbox\"> {\n  return createColBuilder<U[], \"checkbox\">({\n    kind: \"array\",\n    arrayItem: itemBuilder._config,\n    optional: false,\n    label: \"\",\n    display: { type: \"badge\" },\n    hidden: false,\n    enableHiding: true,\n    hideHeader: false,\n    resizable: false,\n    sortable: false,\n    filter: { type: \"checkbox\", defaultOpen: false, commandDisabled: false },\n    sheet: null,\n  });\n}\n\n/**\n * A key-value record column.\n *\n * - Data type: `Record<string, string>`\n * - Default display: `\"text\"`\n * - Not filterable (`F = never`)\n *\n * Use for metadata maps, HTTP headers, environment variables, etc.\n * Typically rendered with a custom sheet component (key-value table / tabs).\n *\n * @example\n * col.record().label(\"Headers\").hidden().sheet({\n *   component: (row) => <KVTabs data={row.headers} />,\n *   className: \"flex-col items-start w-full gap-1\",\n * })\n */\nfunction record(): ColBuilder<Record<string, string>, never> {\n  return createColBuilder<Record<string, string>, never>({\n    kind: \"record\",\n    optional: false,\n    label: \"\",\n    display: { type: \"text\" },\n    hidden: false,\n    enableHiding: true,\n    hideHeader: false,\n    resizable: false,\n    sortable: false,\n    filter: null,\n    sheet: null,\n  });\n}\n\n/**\n * A row-selection checkbox column.\n *\n * - Data type: `boolean` (selected state)\n * - Not filterable (`F = never`)\n * - Not shown in sheet or filters\n * - Renders a checkbox in both the header (select all) and each row\n *\n * @example\n * col.select().label(\"Select\")\n */\nfunction select(): ColBuilder<boolean, never> {\n  return createColBuilder<boolean, never>({\n    kind: \"select\",\n    optional: false,\n    label: \"Select\",\n    display: { type: \"boolean\" },\n    hidden: false,\n    enableHiding: false,\n    hideHeader: false,\n    resizable: false,\n    size: 40,\n    sortable: false,\n    filter: null,\n    sheet: null,\n  });\n}\n\nexport const col = {\n  string,\n  number,\n  boolean,\n  timestamp,\n  enum: colEnum,\n  array,\n  record,\n  select,\n};\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/presets.ts",
      "content": "import { col } from \"./col\";\nimport type { ColBuilder } from \"./types\";\n\nconst DEFAULT_HTTP_STATUS_CODES = [\n  200, 201, 204, 301, 302, 400, 401, 403, 404, 422, 429, 500, 502, 503, 504,\n];\n\n/**\n * Pre-configured column builders for patterns common in log and observability tables.\n *\n * Every preset returns a `ColBuilder` with sensible defaults already applied.\n * All builders remain fully customizable — chain additional methods to override\n * any default (label, size, display, sheet, etc.).\n *\n * @example\n * ```ts\n * const tableSchema = createTableSchema({\n *   level:   col.presets.logLevel(LEVELS).description(\"Log severity\"),\n *   date:    col.presets.timestamp().label(\"Date\").size(200).sheet(),\n *   latency: col.presets.duration(\"ms\").label(\"Latency\").sortable().size(110).sheet(),\n *   status:  col.presets.httpStatus().label(\"Status\").size(60),\n *   method:  col.presets.httpMethod(METHODS).size(69),\n *   path:    col.presets.pathname().label(\"Path\").size(130).sheet(),\n *   traceId: col.presets.traceId().label(\"Request ID\").hidden().sheet(),\n * });\n * ```\n */\nexport const presets = {\n  /**\n   * A log severity level column.\n   *\n   * Defaults: enum + badge display + checkbox filter + `defaultOpen`.\n   * Checkbox options are auto-derived from `values` — no need to map them manually.\n   *\n   * @param values - The allowed severity levels, e.g. `[\"error\", \"warn\", \"info\", \"debug\"] as const`\n   *\n   * @example\n   * ```ts\n   * col.presets.logLevel(LEVELS)\n   *   .label(\"Level\")\n   *   .description(\"Log severity: error > warn > info > debug\")\n   *   .size(27)\n   * ```\n   */\n  logLevel<T extends readonly string[]>(\n    values: T,\n  ): ColBuilder<T[number], \"checkbox\"> {\n    return col\n      .enum(values)\n      .label(\"Level\")\n      .filterable(\"checkbox\", {\n        options: values.map((v) => ({ label: v, value: v })),\n      })\n      .defaultOpen();\n  },\n\n  /**\n   * An HTTP method column.\n   *\n   * Defaults: enum + plain text display + checkbox filter.\n   * Options are auto-derived from `values`.\n   *\n   * @param values - The allowed HTTP methods, e.g. `[\"GET\", \"POST\", \"PUT\", \"DELETE\"] as const`\n   *\n   * @example\n   * ```ts\n   * col.presets.httpMethod(METHODS).size(69)\n   * ```\n   */\n  httpMethod<T extends readonly string[]>(\n    values: T,\n  ): ColBuilder<T[number], \"checkbox\"> {\n    return col\n      .enum(values)\n      .label(\"Method\")\n      .display(\"text\")\n      .filterable(\"checkbox\", {\n        options: values.map((v) => ({ label: v, value: v })),\n      });\n  },\n\n  /**\n   * An HTTP status code column.\n   *\n   * Defaults: number + checkbox filter with a standard set of common status codes.\n   * Pass a custom `codes` array to override the defaults.\n   *\n   * Default codes: 200, 201, 204, 301, 302, 400, 401, 403, 404, 422, 429, 500, 502, 503, 504\n   *\n   * @param codes - Override the default status code options\n   *\n   * @example\n   * ```ts\n   * col.presets.httpStatus().label(\"Status\").size(60)\n   * col.presets.httpStatus([200, 400, 500]).label(\"Status\") // custom codes\n   * ```\n   */\n  httpStatus(\n    codes?: number[],\n  ): ColBuilder<number, \"input\" | \"slider\" | \"checkbox\"> {\n    return col\n      .number()\n      .label(\"Status\")\n      .filterable(\"checkbox\", {\n        options: (codes ?? DEFAULT_HTTP_STATUS_CODES).map((code) => ({\n          label: String(code),\n          value: code,\n        })),\n      });\n  },\n\n  /**\n   * A duration / latency / timing column.\n   *\n   * Defaults: number + formatted number display with unit + slider filter\n   * with bounds `{ min: 0, max: 5000 }`.\n   *\n   * @param unit   - Unit label shown after the value, e.g. `\"ms\"`, `\"s\"`, `\"µs\"`\n   * @param slider - Override the slider bounds (default: `{ min: 0, max: 5000 }`)\n   *\n   * @example\n   * ```ts\n   * col.presets.duration(\"ms\").label(\"Latency\").sortable().size(110).sheet()\n   * col.presets.duration(\"s\", { min: 0, max: 60 }).label(\"Response time\")\n   * ```\n   */\n  duration(\n    unit?: string,\n    slider?: { min: number; max: number },\n  ): ColBuilder<number, \"input\" | \"slider\" | \"checkbox\"> {\n    return col\n      .number()\n      .label(\"Duration\")\n      .display(\"number\", { unit })\n      .filterable(\"slider\", slider ?? { min: 0, max: 5000 });\n  },\n\n  /**\n   * A timestamp column.\n   *\n   * Defaults: Date + relative timestamp display (absolute on hover) +\n   * timerange filter + sortable.\n   *\n   * @example\n   * ```ts\n   * col.presets.timestamp().label(\"Date\").commandDisabled().size(200).sheet()\n   * ```\n   */\n  timestamp(): ColBuilder<Date, \"timerange\"> {\n    return col.timestamp().label(\"Timestamp\").display(\"timestamp\").sortable();\n  },\n\n  /**\n   * A trace / span / request ID column.\n   *\n   * Defaults: string + monospace code display + not filterable.\n   * Typically hidden in the table and shown only in the row detail drawer.\n   *\n   * @example\n   * ```ts\n   * col.presets.traceId().label(\"Request ID\").hidden().sheet({ skeletonClassName: \"w-64\" })\n   * ```\n   */\n  traceId(): ColBuilder<string, never> {\n    return col.string().label(\"Trace ID\").display(\"code\").notFilterable();\n  },\n\n  /**\n   * A URL pathname column.\n   *\n   * Defaults: string + plain text display + input (text search) filter.\n   *\n   * @example\n   * ```ts\n   * col.presets.pathname().size(130).sheet()\n   * ```\n   */\n  pathname(): ColBuilder<string, \"input\"> {\n    return col.string().label(\"Pathname\").filterable(\"input\");\n  },\n\n  /**\n   * A latency column with heatmap visualization.\n   *\n   * Defaults: number + heatmap display with unit + slider filter\n   * with bounds `{ min: 0, max: 5000 }` + sortable.\n   *\n   * @param unit   - Unit label shown after the value, e.g. `\"ms\"`, `\"s\"`, `\"µs\"`\n   * @param slider - Override the slider bounds (default: `{ min: 0, max: 5000 }`)\n   *\n   * @example\n   * ```ts\n   * col.presets.latency(\"ms\").label(\"Latency\").size(110).sheet()\n   * col.presets.latency(\"s\", { min: 0, max: 60 }).label(\"Response time\")\n   * ```\n   */\n  latency(\n    unit?: string,\n    slider?: { min: number; max: number },\n  ): ColBuilder<number, \"input\" | \"slider\" | \"checkbox\"> {\n    const bounds = slider ?? { min: 0, max: 5000 };\n    return col\n      .number()\n      .label(\"Latency\")\n      .display(\"heatmap\", { unit, min: bounds.min, max: bounds.max })\n      .filterable(\"slider\", bounds)\n      .sortable();\n  },\n\n  /**\n   * A health/score column with gauge visualization.\n   *\n   * Defaults: number + gauge display (0–100) + sortable.\n   *\n   * @param range - Override the min/max range (default: `{ min: 0, max: 100 }`)\n   *\n   * @example\n   * ```ts\n   * col.presets.health().label(\"Health\")\n   * col.presets.health({ min: 0, max: 1000 }).label(\"Score\")\n   * ```\n   */\n  health(range?: {\n    min: number;\n    max: number;\n  }): ColBuilder<number, \"input\" | \"slider\" | \"checkbox\"> {\n    const { min = 0, max = 100 } = range ?? {};\n    return col\n      .number()\n      .label(\"Health\")\n      .display(\"gauge\", { min, max })\n      .sortable();\n  },\n\n  /**\n   * A progress column with bar visualization.\n   *\n   * Defaults: number + bar display (0–100) + sortable.\n   *\n   * @param range - Override the min/max range (default: `{ min: 0, max: 100 }`)\n   *\n   * @example\n   * ```ts\n   * col.presets.progress().label(\"Progress\")\n   * col.presets.progress({ min: 0, max: 1000 }).label(\"Completion\")\n   * ```\n   */\n  progress(range?: {\n    min: number;\n    max: number;\n  }): ColBuilder<number, \"input\" | \"slider\" | \"checkbox\"> {\n    const { min = 0, max = 100 } = range ?? {};\n    return col\n      .number()\n      .label(\"Progress\")\n      .display(\"bar\", { min, max })\n      .sortable();\n  },\n};\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/validate.ts",
      "content": "import type { TableSchemaDefinition } from \"./types\";\n\n/**\n * Validates a table schema definition and throws a descriptive error on the\n * first violation found.\n *\n * Called automatically by `createTableSchema()` — no need to call manually.\n *\n * Catches errors that the TypeScript type system cannot prevent:\n * - Missing label (`.label()` was never called)\n * - Slider `min` greater than `max`\n *\n * These checks run for both the TypeScript-authored path (`createTableSchema({...})`)\n * and the AI-generated path (`createTableSchema.fromJSON(json)`).\n */\nexport function validateSchema(definition: TableSchemaDefinition): void {\n  for (const [key, builder] of Object.entries(definition)) {\n    const c = builder._config;\n\n    // 1. Label is required — col.* factories default to label: \"\"\n    if (!c.label) {\n      throw new Error(\n        `[createTableSchema] Column \"${key}\" is missing a label.\\n` +\n          `  Fix: .label(\"${key[0]!.toUpperCase()}${key.slice(1)}\")`,\n      );\n    }\n\n    // 2. Number checkbox filter requires explicit options — the number factory\n    //    has no value list to auto-derive from, so an empty options list would\n    //    render a filter with no checkboxes (a silent no-op in the UI).\n    if (\n      c.kind === \"number\" &&\n      c.filter?.type === \"checkbox\" &&\n      (!c.filter.options || c.filter.options.length === 0)\n    ) {\n      throw new Error(\n        `[createTableSchema] Column \"${key}\": checkbox filter on a number column requires explicit options.\\n` +\n          `  Fix: .filterable(\"checkbox\", { options: [{ label: \"200\", value: 200 }, ...] })`,\n      );\n    }\n\n    // 3. Slider bounds must be valid — type system requires { min, max } to be\n    //    passed but cannot enforce min < max\n    if (c.filter?.type === \"slider\") {\n      const { min, max } = c.filter;\n      if (min === undefined || max === undefined) {\n        throw new Error(\n          `[createTableSchema] Column \"${key}\": slider filter is missing min/max bounds.\\n` +\n            `  Fix: .filterable(\"slider\", { min: 0, max: 100 })`,\n        );\n      }\n      if (min > max) {\n        throw new Error(\n          `[createTableSchema] Column \"${key}\": slider min (${min}) must be less than max (${max}).\\n` +\n            `  Fix: swap the values — .filterable(\"slider\", { min: ${max}, max: ${min} })`,\n        );\n      }\n    }\n  }\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/serialize.ts",
      "content": "import { col } from \"./col\";\nimport type {\n  ColBuilder,\n  ColConfig,\n  ColumnDescriptor,\n  DisplayConfig,\n  FilterDescriptor,\n  SchemaJSON,\n  SerializableDisplayConfig,\n  SheetDescriptor,\n  TableSchemaDefinition,\n} from \"./types\";\n\n// ── Serialization (schema → JSON) ────────────────────────────────────────────\n\nfunction serializeFilter(filter: ColConfig[\"filter\"]): FilterDescriptor | null {\n  if (!filter) return null;\n  const descriptor: FilterDescriptor = {\n    type: filter.type,\n    defaultOpen: filter.defaultOpen,\n    commandDisabled: filter.commandDisabled,\n  };\n  if (filter.options) {\n    descriptor.options = filter.options.map((o) => ({\n      label: o.label,\n      value: o.value as string | number | boolean,\n    }));\n  }\n  if (filter.min !== undefined) descriptor.min = filter.min;\n  if (filter.max !== undefined) descriptor.max = filter.max;\n  // filter.component and filter.presets are functions/complex objects — stripped\n  return descriptor;\n}\n\nfunction serializeSheet(sheet: ColConfig[\"sheet\"]): SheetDescriptor | null {\n  if (!sheet) return null;\n  const descriptor: SheetDescriptor = {};\n  if (sheet.label) descriptor.label = sheet.label;\n  if (sheet.className) descriptor.className = sheet.className;\n  if (sheet.skeletonClassName)\n    descriptor.skeletonClassName = sheet.skeletonClassName;\n  // sheet.component and sheet.condition are functions — stripped\n  return descriptor;\n}\n\nfunction serializeDisplay(display: DisplayConfig): SerializableDisplayConfig {\n  switch (display.type) {\n    case \"custom\":\n      // Custom renderers are not serializable — fall back to text\n      return { type: \"text\" };\n    case \"number\": {\n      const d: SerializableDisplayConfig = { type: \"number\" };\n      if (display.unit)\n        (d as { type: \"number\"; unit?: string }).unit = display.unit;\n      if (display.colorMap)\n        (d as { colorMap?: Record<string, string> }).colorMap =\n          display.colorMap;\n      return d;\n    }\n    case \"bar\": {\n      const d = { type: \"bar\" as const, min: display.min, max: display.max };\n      return {\n        ...d,\n        ...(display.unit ? { unit: display.unit } : {}),\n        ...(display.colorMap ? { colorMap: display.colorMap } : {}),\n      };\n    }\n    case \"heatmap\": {\n      const d: SerializableDisplayConfig = {\n        type: \"heatmap\" as const,\n        min: display.min,\n        max: display.max,\n      };\n      if (display.unit) (d as { unit?: string }).unit = display.unit;\n      if (display.color) (d as { color?: string }).color = display.color;\n      if (display.colorMap)\n        (d as { colorMap?: Record<string, string> }).colorMap =\n          display.colorMap;\n      return d;\n    }\n    case \"gauge\": {\n      const d: SerializableDisplayConfig = {\n        type: \"gauge\" as const,\n        min: display.min,\n        max: display.max,\n      };\n      if (display.unit) (d as { unit?: string }).unit = display.unit;\n      if (display.color) (d as { color?: string }).color = display.color;\n      return d;\n    }\n    default: {\n      const d: SerializableDisplayConfig = { type: display.type };\n      if (display.colorMap)\n        (d as { colorMap?: Record<string, string> }).colorMap =\n          display.colorMap;\n      return d;\n    }\n  }\n}\n\nexport function serializeSchema(definition: TableSchemaDefinition): SchemaJSON {\n  const columns: ColumnDescriptor[] = Object.entries(definition).map(\n    ([key, builder]) => {\n      const c = builder._config;\n      const descriptor: ColumnDescriptor = {\n        key,\n        label: c.label,\n        dataType: c.kind,\n        optional: c.optional,\n        hidden: c.hidden,\n        sortable: c.sortable,\n        display: serializeDisplay(c.display),\n        filter: serializeFilter(c.filter),\n        sheet: serializeSheet(c.sheet),\n      };\n      if (c.description) descriptor.description = c.description;\n      if (c.enumValues) descriptor.enumValues = c.enumValues;\n      if (c.arrayItem) {\n        descriptor.arrayItemType = {\n          dataType: c.arrayItem.kind,\n          ...(c.arrayItem.enumValues\n            ? { enumValues: c.arrayItem.enumValues }\n            : {}),\n        };\n      }\n      if (c.size !== undefined) descriptor.size = c.size;\n      if (c.hideHeader) descriptor.hideHeader = true;\n      if (c.enableHiding === false) descriptor.enableHiding = false;\n      return descriptor;\n    },\n  );\n  return { columns };\n}\n\n// ── Deserialization (JSON → schema) ─────────────────────────────────────────\n//\n// Reconstructs col.* builders from a SchemaJSON descriptor.\n// Limitation: custom renderers (display.cell, filter.component, sheet.component,\n// sheet.condition) are not serialized and therefore cannot be reconstructed.\n// Columns with display.type === \"custom\" fall back to the col kind's default\n// display. Developers can override renderers on the returned builders.\n\nexport function deserializeSchema(json: SchemaJSON): TableSchemaDefinition {\n  const definition: TableSchemaDefinition = {};\n\n  for (const col_ of json.columns) {\n    // 1. Pick the right col.* factory.\n    // F is typed as `any` on the variable so we can call filterable() dynamically\n    // without knowing the col kind at compile time — this is intentional since\n    // deserializeSchema is a runtime operation reading from JSON.\n\n    let builder: ColBuilder<unknown, any> =\n      col_.dataType === \"select\"\n        ? col.select()\n        : col_.dataType === \"enum\" && col_.enumValues\n          ? col.enum(col_.enumValues as readonly string[])\n          : col_.dataType === \"array\" &&\n              col_.arrayItemType?.dataType === \"enum\" &&\n              col_.arrayItemType.enumValues\n            ? col.array(\n                col.enum(col_.arrayItemType.enumValues as readonly string[]),\n              )\n            : col_.dataType === \"boolean\"\n              ? col.boolean()\n              : col_.dataType === \"timestamp\"\n                ? col.timestamp()\n                : col_.dataType === \"number\"\n                  ? col.number()\n                  : col_.dataType === \"record\"\n                    ? col.record()\n                    : col.string();\n\n    // 2. Label + description\n    builder = builder.label(col_.label);\n    if (col_.description) builder = builder.description(col_.description);\n\n    // 3. Display\n    const display = col_.display;\n    if (display.type === \"number\") {\n      const opts: { unit?: string; colorMap?: Record<string, string> } = {};\n      if (display.unit) opts.unit = display.unit;\n      if (display.colorMap) opts.colorMap = display.colorMap;\n      builder = builder.display(\n        \"number\",\n        Object.keys(opts).length > 0 ? opts : undefined,\n      );\n    } else if (\n      display.type === \"bar\" ||\n      display.type === \"heatmap\" ||\n      display.type === \"gauge\"\n    ) {\n      const opts: {\n        min?: number;\n        max?: number;\n        unit?: string;\n        color?: string;\n      } = {};\n      if (display.min !== undefined) opts.min = display.min;\n      if (display.max !== undefined) opts.max = display.max;\n      if (display.unit) opts.unit = display.unit;\n      if (display.color) opts.color = display.color;\n      builder = builder.display(\n        display.type,\n        Object.keys(opts).length > 0 ? opts : undefined,\n      );\n    } else if (\n      display.type === \"text\" ||\n      display.type === \"code\" ||\n      display.type === \"boolean\" ||\n      display.type === \"star\" ||\n      display.type === \"badge\" ||\n      display.type === \"timestamp\" ||\n      display.type === \"status-code\" ||\n      display.type === \"level-indicator\"\n    ) {\n      builder = builder.display(\n        display.type,\n        display.colorMap ? { colorMap: display.colorMap } : undefined,\n      );\n    }\n\n    // 4. Filter\n    if (col_.filter === null) {\n      builder = builder.notFilterable();\n    } else {\n      const f = col_.filter;\n      if (f.type === \"slider\" && f.min !== undefined && f.max !== undefined) {\n        builder = builder.filterable(\"slider\", { min: f.min, max: f.max });\n      } else if (f.type === \"checkbox\") {\n        builder = builder.filterable(\"checkbox\", {\n          ...(f.options ? { options: f.options } : {}),\n        });\n      } else if (f.type === \"timerange\") {\n        builder = builder.filterable(\"timerange\");\n      } else {\n        builder = builder.filterable(\"input\");\n      }\n      if (f.defaultOpen) builder = builder.defaultOpen();\n      if (f.commandDisabled) builder = builder.commandDisabled();\n    }\n\n    // 5. Structural modifiers\n    // sheetOnly() sets both enableHiding: false AND hidden: true.\n    // enableHiding: false alone (e.g. col.select()) should NOT trigger sheetOnly().\n    if (col_.enableHiding === false && col_.hidden) {\n      builder = builder.sheetOnly();\n    } else if (col_.hidden) {\n      builder = builder.hidden();\n    }\n    if (col_.hideHeader) builder = builder.hideHeader();\n    if (col_.sortable) builder = builder.sortable();\n    if (col_.optional) builder = builder.optional();\n    if (col_.size !== undefined) builder = builder.size(col_.size);\n\n    // 6. Sheet\n    if (col_.sheet !== null) {\n      builder = builder.sheet({\n        ...(col_.sheet.label ? { label: col_.sheet.label } : {}),\n        ...(col_.sheet.className ? { className: col_.sheet.className } : {}),\n        ...(col_.sheet.skeletonClassName\n          ? { skeletonClassName: col_.sheet.skeletonClassName }\n          : {}),\n      });\n    }\n\n    definition[col_.key] = builder;\n  }\n\n  return definition;\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/infer.ts",
      "content": "import type {\n  ColumnDescriptor,\n  FilterDescriptor,\n  SchemaJSON,\n  SerializableDisplayConfig,\n} from \"./types\";\n\n// Unix ms timestamps are 13-digit numbers (> Sep 2001, < Nov 2286)\nconst UNIX_MS_MIN = 1_000_000_000_000;\nconst UNIX_MS_MAX = 9_999_999_999_999;\n\nfunction isIso8601(value: string): boolean {\n  return (\n    /^\\d{4}-\\d{2}-\\d{2}(T[\\d:.Z+\\-]+)?$/.test(value) &&\n    !isNaN(Date.parse(value))\n  );\n}\n\nfunction isUnixMs(value: number): boolean {\n  return (\n    Number.isInteger(value) && value >= UNIX_MS_MIN && value <= UNIX_MS_MAX\n  );\n}\n\n/** Convert camelCase, snake_case, or kebab-case key to a human-readable label. */\nfunction keyToLabel(key: string): string {\n  let label = key.replace(/[-_]/g, \" \");\n  label = label.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n  return label.replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction displayForDataType(\n  dataType: ColumnDescriptor[\"dataType\"],\n): SerializableDisplayConfig {\n  switch (dataType) {\n    case \"number\":\n      return { type: \"number\" };\n    case \"boolean\":\n      return { type: \"boolean\" };\n    case \"timestamp\":\n      return { type: \"timestamp\" };\n    case \"enum\":\n    case \"array\":\n      return { type: \"badge\" };\n    case \"string\":\n    case \"record\":\n    case \"select\":\n    default:\n      return { type: \"text\" };\n  }\n}\n\nfunction makeDescriptor(\n  key: string,\n  label: string,\n  dataType: ColumnDescriptor[\"dataType\"],\n  filter: FilterDescriptor | null,\n): ColumnDescriptor {\n  return {\n    key,\n    label,\n    dataType,\n    optional: false,\n    hidden: false,\n    sortable: false,\n    display: displayForDataType(dataType),\n    filter,\n    sheet: {},\n  };\n}\n\n/** Split a key into lowercase words, handling camelCase, snake_case, and kebab-case. */\nfunction keyToWords(key: string): string[] {\n  return key\n    .replace(/([a-z])([A-Z])/g, \"$1_$2\")\n    .split(/[-_]/)\n    .map((w) => w.toLowerCase())\n    .filter(Boolean);\n}\n\nconst ID_WORDS = new Set([\"id\", \"uuid\", \"hash\", \"token\", \"key\"]);\nconst CODE_WORDS = new Set([\n  \"path\",\n  \"url\",\n  \"uri\",\n  \"endpoint\",\n  \"route\",\n  \"host\",\n  \"link\",\n  \"href\",\n  \"website\",\n]);\nconst LATENCY_WORDS = new Set([\n  \"latency\",\n  \"duration\",\n  \"elapsed\",\n  \"delay\",\n  \"wait\",\n  \"ttfb\",\n  \"rtt\",\n  \"ping\",\n]);\nconst SIZE_WORDS = new Set([\"size\", \"bytes\", \"length\"]);\nconst LEVEL_WORDS = new Set([\"level\", \"severity\"]);\nconst TRACE_ID_WORDS = new Set([\"trace\", \"span\", \"request\"]);\nconst FAVORITE_WORDS = new Set([\"favorite\", \"starred\", \"bookmarked\", \"pinned\"]);\nconst EMAIL_WORDS = new Set([\"email\", \"mail\"]);\nconst STATUS_WORDS = new Set([\"status\", \"state\"]);\nconst HEALTH_WORDS = new Set([\n  \"health\",\n  \"score\",\n  \"rating\",\n  \"accuracy\",\n  \"uptime\",\n]);\nconst PROGRESS_WORDS = new Set([\"progress\", \"completion\", \"percentage\"]);\nconst HP_WORDS = new Set([\"hp\", \"hitpoints\"]);\n\n/** Semantic color mapping for status-like enum values. */\nconst STATUS_COLORS: Record<string, string> = {\n  active: \"#22c55e\",\n  completed: \"#22c55e\",\n  success: \"#22c55e\",\n  published: \"#22c55e\",\n  approved: \"#22c55e\",\n  pending: \"#f59e0b\",\n  draft: \"#f59e0b\",\n  inactive: \"#f59e0b\",\n  paused: \"#f59e0b\",\n  error: \"#ef4444\",\n  failed: \"#ef4444\",\n  rejected: \"#ef4444\",\n  cancelled: \"#ef4444\",\n  archived: \"#6b7280\",\n  deleted: \"#6b7280\",\n  disabled: \"#6b7280\",\n};\n\n/** Neutral palette for enum values without semantic meaning. */\nconst NEUTRAL_PALETTE = [\n  \"#6366f1\",\n  \"#8b5cf6\",\n  \"#ec4899\",\n  \"#14b8a6\",\n  \"#f97316\",\n  \"#06b6d4\",\n  \"#84cc16\",\n  \"#eab308\",\n  \"#ef4444\",\n  \"#64748b\",\n];\n\n/** Generate a colorMap for enum values, using semantic colors where possible. */\nfunction generateColorMap(values: readonly string[]): Record<string, string> {\n  const colorMap: Record<string, string> = {};\n  let neutralIdx = 0;\n  for (const value of values) {\n    const lower = value.toLowerCase();\n    if (STATUS_COLORS[lower]) {\n      colorMap[value] = STATUS_COLORS[lower];\n    } else {\n      colorMap[value] = NEUTRAL_PALETTE[neutralIdx % NEUTRAL_PALETTE.length]!;\n      neutralIdx++;\n    }\n  }\n  return colorMap;\n}\n\n/** Post-process an inferred descriptor with smart display/config heuristics. */\nfunction enhanceDescriptor(descriptor: ColumnDescriptor): ColumnDescriptor {\n  const words = keyToWords(descriptor.key);\n  const joined = words.join(\"\");\n  const d = { ...descriptor };\n\n  const hasIdWord = words.some((w) => ID_WORDS.has(w));\n  const hasCodeWord = words.some((w) => CODE_WORDS.has(w));\n  const hasLatencyWord =\n    words.some((w) => LATENCY_WORDS.has(w)) || joined.includes(\"responsetime\");\n  const hasSizeWord = words.some((w) => SIZE_WORDS.has(w));\n  const hasLevelWord = words.some((w) => LEVEL_WORDS.has(w));\n  const isTraceId = hasIdWord && words.some((w) => TRACE_ID_WORDS.has(w));\n  const hasFavoriteWord = words.some((w) => FAVORITE_WORDS.has(w));\n  const hasEmailWord = words.some((w) => EMAIL_WORDS.has(w));\n  const hasStatusWord = words.some((w) => STATUS_WORDS.has(w));\n  const hasHealthWord = words.some((w) => HEALTH_WORDS.has(w));\n  const hasProgressWord = words.some((w) => PROGRESS_WORDS.has(w));\n  const hasHpWord = words.some((w) => HP_WORDS.has(w));\n\n  // ID-like columns → code display, not sortable\n  if (hasIdWord) {\n    d.display = { type: \"code\" };\n    d.sortable = false;\n    // Trace/span/request IDs → hidden, not filterable (matches col.presets.traceId())\n    if (isTraceId) {\n      d.hidden = true;\n      d.filter = null;\n    }\n  }\n  // Favorite/starred booleans → star display, hide column header\n  else if (hasFavoriteWord && d.dataType === \"boolean\") {\n    d.display = { type: \"star\" };\n    d.hideHeader = true;\n  }\n  // Email columns → code display\n  else if (hasEmailWord && d.dataType === \"string\") {\n    d.display = { type: \"code\" };\n  }\n  // Path/URL-like columns → code display\n  else if (hasCodeWord) {\n    d.display = { type: \"code\" };\n  }\n  // Latency-like number columns → heatmap with ms unit, sortable\n  else if (hasLatencyWord && d.dataType === \"number\") {\n    d.display = {\n      type: \"heatmap\",\n      unit: \"ms\",\n      min: d.filter?.min,\n      max: d.filter?.max,\n    };\n    d.sortable = true;\n  }\n  // Size-like number columns → number with B unit, sortable\n  else if (hasSizeWord && d.dataType === \"number\") {\n    d.display = { type: \"number\", unit: \"B\" };\n    d.sortable = true;\n  }\n  // Health/score/rating → gauge display (min always 0 for visual baseline)\n  else if (hasHealthWord && d.dataType === \"number\") {\n    d.display = { type: \"gauge\", min: 0, max: d.filter?.max };\n    d.sortable = true;\n  }\n  // HP/hitpoints → bar display (min always 0 for visual baseline)\n  else if (hasHpWord && d.dataType === \"number\") {\n    d.display = { type: \"bar\", min: 0, max: d.filter?.max };\n    d.sortable = true;\n  }\n  // Progress/completion → bar display (min always 0 for visual baseline)\n  else if (hasProgressWord && d.dataType === \"number\") {\n    d.display = { type: \"bar\", min: 0, max: d.filter?.max };\n    d.sortable = true;\n  }\n\n  // Sortable defaults by type (unless ID-like)\n  if (!hasIdWord) {\n    if (d.dataType === \"timestamp\" || d.dataType === \"number\") {\n      d.sortable = true;\n    }\n  }\n\n  // Log level / severity enums: expand filter by default (matches col.presets.logLevel())\n  if (hasLevelWord && d.dataType === \"enum\" && d.filter) {\n    d.filter = { ...d.filter, defaultOpen: true };\n  }\n\n  // Status/state enums → semantic colorMap on badge display\n  if (hasStatusWord && d.dataType === \"enum\" && d.enumValues) {\n    d.display = { type: \"badge\", colorMap: generateColorMap(d.enumValues) };\n  }\n\n  // Column sizing defaults\n  const sizeDefaults: Record<string, number> = {\n    boolean: 100,\n    timestamp: 220,\n    number: 120,\n    enum: 130,\n  };\n  if (sizeDefaults[d.dataType] !== undefined) {\n    d.size = sizeDefaults[d.dataType];\n  }\n\n  return d;\n}\n\nfunction inferColDescriptor(key: string, values: unknown[]): ColumnDescriptor {\n  const label = keyToLabel(key);\n  const nonNull = values.filter((v) => v !== null && v !== undefined);\n\n  if (nonNull.length === 0) {\n    return makeDescriptor(key, label, \"string\", {\n      type: \"input\",\n      defaultOpen: false,\n      commandDisabled: false,\n    });\n  }\n\n  // Timestamp: ISO 8601 strings\n  if (nonNull.every((v) => typeof v === \"string\" && isIso8601(v as string))) {\n    return makeDescriptor(key, label, \"timestamp\", {\n      type: \"timerange\",\n      defaultOpen: false,\n      commandDisabled: true,\n    });\n  }\n\n  // Timestamp: Unix ms numbers\n  if (nonNull.every((v) => typeof v === \"number\" && isUnixMs(v as number))) {\n    return makeDescriptor(key, label, \"timestamp\", {\n      type: \"timerange\",\n      defaultOpen: false,\n      commandDisabled: true,\n    });\n  }\n\n  // Boolean\n  if (nonNull.every((v) => v === true || v === false)) {\n    return makeDescriptor(key, label, \"boolean\", {\n      type: \"checkbox\",\n      defaultOpen: false,\n      commandDisabled: false,\n    });\n  }\n\n  // Number\n  if (nonNull.every((v) => typeof v === \"number\")) {\n    const nums = nonNull as number[];\n    const min = Math.min(...nums);\n    const max = Math.max(...nums);\n    const filter: FilterDescriptor =\n      min !== max\n        ? {\n            type: \"slider\",\n            defaultOpen: false,\n            commandDisabled: false,\n            min,\n            max,\n          }\n        : { type: \"input\", defaultOpen: false, commandDisabled: false };\n    return {\n      ...makeDescriptor(key, label, \"number\", filter),\n      display: { type: \"number\" },\n    };\n  }\n\n  // Array\n  if (nonNull.every((v) => Array.isArray(v))) {\n    const allItems = (nonNull as unknown[][])\n      .flat()\n      .filter((v) => v !== null && v !== undefined);\n    const allStrings =\n      allItems.length > 0 && allItems.every((v) => typeof v === \"string\");\n    if (allStrings) {\n      const distinct = new Set(allItems as string[]);\n      if (distinct.size <= 10) {\n        const enumValues = Array.from(distinct);\n        return {\n          key,\n          label,\n          dataType: \"array\",\n          arrayItemType: { dataType: \"enum\", enumValues },\n          optional: false,\n          hidden: false,\n          sortable: false,\n          display: { type: \"badge\" },\n          filter: {\n            type: \"checkbox\",\n            defaultOpen: false,\n            commandDisabled: false,\n            options: enumValues.map((v) => ({ label: v, value: v })),\n          },\n          sheet: {},\n        };\n      }\n    }\n    // Non-enum array: not filterable\n    return makeDescriptor(key, label, \"array\", null);\n  }\n\n  // Record (plain object, non-array)\n  if (nonNull.every((v) => typeof v === \"object\" && !Array.isArray(v))) {\n    return makeDescriptor(key, label, \"record\", null);\n  }\n\n  // String: check if enum (≤ 10 distinct values)\n  if (nonNull.every((v) => typeof v === \"string\")) {\n    const distinct = new Set(nonNull as string[]);\n    if (distinct.size <= 10) {\n      const enumValues = Array.from(distinct);\n      return {\n        key,\n        label,\n        dataType: \"enum\",\n        enumValues,\n        optional: false,\n        hidden: false,\n        sortable: false,\n        display: { type: \"badge\" },\n        filter: {\n          type: \"checkbox\",\n          defaultOpen: false,\n          commandDisabled: false,\n          options: enumValues.map((v) => ({ label: v, value: v })),\n        },\n        sheet: {},\n      };\n    }\n    return makeDescriptor(key, label, \"string\", {\n      type: \"input\",\n      defaultOpen: false,\n      commandDisabled: false,\n    });\n  }\n\n  // Fallback: mixed or unrecognised types — warn and treat as string\n  const types = [\n    ...new Set(nonNull.map((v) => (Array.isArray(v) ? \"array\" : typeof v))),\n  ];\n  console.warn(\n    `[inferSchemaFromJSON] Column \"${key}\" has mixed or ambiguous types (${types.join(\", \")}). ` +\n      `Falling back to string input filter.`,\n  );\n  return makeDescriptor(key, label, \"string\", {\n    type: \"input\",\n    defaultOpen: false,\n    commandDisabled: false,\n  });\n}\n\n/**\n * Infer a SchemaJSON from an array of plain data objects.\n *\n * Walks all rows, collects per-key values, and infers the best ColKind and\n * FilterType for each column using these heuristics:\n * - `timestamp`: ISO 8601 strings or Unix-ms numbers\n * - `boolean`: all values strictly true/false\n * - `number`: all non-null values are typeof \"number\"\n * - `enum`: strings with ≤ 10 distinct values across the sample\n * - `array`: values are arrays (item type inferred recursively)\n * - `record`: values are plain objects (non-array)\n * - `string`: fallback\n *\n * Number columns with min ≠ max get a \"slider\" filter; otherwise \"input\".\n */\nexport function inferSchemaFromJSON(data: unknown[]): SchemaJSON {\n  if (!Array.isArray(data) || data.length === 0) {\n    return { columns: [] };\n  }\n\n  // Collect all keys and their values across rows (preserving insertion order)\n  const keyValues = new Map<string, unknown[]>();\n\n  for (const row of data) {\n    if (typeof row !== \"object\" || row === null || Array.isArray(row)) continue;\n    for (const [key, value] of Object.entries(row as Record<string, unknown>)) {\n      if (!keyValues.has(key)) keyValues.set(key, []);\n      keyValues.get(key)!.push(value);\n    }\n  }\n\n  const columns = Array.from(keyValues.entries()).map(([key, values]) =>\n    enhanceDescriptor(inferColDescriptor(key, values)),\n  );\n\n  return { columns };\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/to-typescript.ts",
      "content": "import type { ColumnDescriptor, SchemaJSON } from \"./types\";\n\ninterface PresetMatch {\n  factory: string;\n  skipDisplay: boolean;\n  skipFilter: boolean;\n  skipSortable: boolean;\n}\n\n/**\n * Detect whether a descriptor matches a known `col.presets.*` pattern.\n * Returns the preset factory call and which method chain steps it already covers.\n */\nfunction detectPreset(c: ColumnDescriptor): PresetMatch | null {\n  // traceId: string + code display + not filterable\n  if (\n    c.dataType === \"string\" &&\n    c.display.type === \"code\" &&\n    c.filter === null\n  ) {\n    return {\n      factory: \"col.presets.traceId()\",\n      skipDisplay: true,\n      skipFilter: true,\n      skipSortable: false,\n    };\n  }\n\n  // timestamp + sortable → col.presets.timestamp()\n  if (c.dataType === \"timestamp\" && c.sortable) {\n    return {\n      factory: \"col.presets.timestamp()\",\n      skipDisplay: true,\n      skipFilter: true,\n      skipSortable: true,\n    };\n  }\n\n  // duration: number + slider + number display → col.presets.duration(unit?, bounds?)\n  if (\n    c.dataType === \"number\" &&\n    c.filter?.type === \"slider\" &&\n    c.display.type === \"number\"\n  ) {\n    const unit = c.display.unit;\n    const min = c.filter.min ?? 0;\n    const max = c.filter.max ?? 100;\n    const defaultBounds = min === 0 && max === 5000;\n    const args: string[] = [];\n    if (unit) {\n      args.push(JSON.stringify(unit));\n      if (!defaultBounds) args.push(`{ min: ${min}, max: ${max} }`);\n    } else if (!defaultBounds) {\n      args.push(`undefined, { min: ${min}, max: ${max} }`);\n    }\n    return {\n      factory: `col.presets.duration(${args.join(\", \")})`,\n      skipDisplay: true,\n      skipFilter: true,\n      skipSortable: false,\n    };\n  }\n\n  // logLevel: enum + badge + checkbox + defaultOpen\n  if (\n    c.dataType === \"enum\" &&\n    c.enumValues &&\n    c.filter?.type === \"checkbox\" &&\n    c.filter?.defaultOpen &&\n    c.display.type === \"badge\"\n  ) {\n    const vals = c.enumValues.map((v) => JSON.stringify(v)).join(\", \");\n    return {\n      factory: `col.presets.logLevel([${vals}])`,\n      skipDisplay: true,\n      skipFilter: true,\n      skipSortable: false,\n    };\n  }\n\n  // httpStatus: number + number display + checkbox with all-numeric options\n  if (\n    c.dataType === \"number\" &&\n    c.display.type === \"number\" &&\n    c.filter?.type === \"checkbox\" &&\n    c.filter?.options?.every((o) => typeof o.value === \"number\")\n  ) {\n    const codes = c.filter.options!.map((o) => o.value);\n    return {\n      factory: `col.presets.httpStatus([${codes.join(\", \")}])`,\n      skipDisplay: true,\n      skipFilter: true,\n      skipSortable: false,\n    };\n  }\n\n  // httpMethod: enum + text + checkbox + !defaultOpen\n  if (\n    c.dataType === \"enum\" &&\n    c.enumValues &&\n    c.filter?.type === \"checkbox\" &&\n    !c.filter?.defaultOpen &&\n    c.display.type === \"text\"\n  ) {\n    const vals = c.enumValues.map((v) => JSON.stringify(v)).join(\", \");\n    return {\n      factory: `col.presets.httpMethod([${vals}])`,\n      skipDisplay: true,\n      skipFilter: true,\n      skipSortable: false,\n    };\n  }\n\n  return null;\n}\n\n/**\n * Build the `col.*` factory call and method chain for one column descriptor.\n */\nfunction buildChain(c: ColumnDescriptor): string {\n  const parts: string[] = [];\n  let skipDisplay = false;\n  let skipFilter = false;\n  let skipSortable = false;\n\n  // 1. Factory (with preset detection)\n  const preset = detectPreset(c);\n  if (preset) {\n    parts.push(preset.factory);\n    skipDisplay = preset.skipDisplay;\n    skipFilter = preset.skipFilter;\n    skipSortable = preset.skipSortable;\n  } else if (c.dataType === \"enum\" && c.enumValues) {\n    const vals = c.enumValues.map((v) => JSON.stringify(v)).join(\", \");\n    parts.push(`col.enum([${vals}])`);\n  } else if (\n    c.dataType === \"array\" &&\n    c.arrayItemType?.dataType === \"enum\" &&\n    c.arrayItemType.enumValues\n  ) {\n    const vals = c.arrayItemType.enumValues\n      .map((v) => JSON.stringify(v))\n      .join(\", \");\n    parts.push(`col.array(col.enum([${vals}]))`);\n  } else {\n    parts.push(`col.${c.dataType}()`);\n  }\n\n  // 2. .label()\n  parts.push(`.label(${JSON.stringify(c.label)})`);\n\n  // 3. .description()\n  if (c.description) {\n    parts.push(`.description(${JSON.stringify(c.description)})`);\n  }\n\n  // 4. .display() — skip if covered by preset (unless colorMap needs emitting)\n  if (!skipDisplay) {\n    const display = c.display;\n    const hasColorMap = !!display.colorMap;\n    if (\n      display.type === \"heatmap\" ||\n      display.type === \"bar\" ||\n      display.type === \"gauge\"\n    ) {\n      const opts: Record<string, unknown> = {};\n      if (display.min !== undefined) opts.min = display.min;\n      if (display.max !== undefined) opts.max = display.max;\n      if (display.unit) opts.unit = display.unit;\n      if (display.color) opts.color = display.color;\n      parts.push(\n        Object.keys(opts).length > 0\n          ? `.display(${JSON.stringify(display.type)}, ${JSON.stringify(opts)})`\n          : `.display(${JSON.stringify(display.type)})`,\n      );\n    } else if (display.type === \"number\" && (display.unit || hasColorMap)) {\n      const opts: Record<string, unknown> = {};\n      if (display.unit) opts.unit = display.unit;\n      if (hasColorMap) opts.colorMap = display.colorMap;\n      parts.push(`.display(\"number\", ${JSON.stringify(opts)})`);\n    } else if (hasColorMap) {\n      parts.push(\n        `.display(${JSON.stringify(display.type)}, ${JSON.stringify({ colorMap: display.colorMap })})`,\n      );\n    } else if (\n      display.type !== \"text\" // \"text\" is the default for string/record, skip it\n    ) {\n      parts.push(`.display(${JSON.stringify(display.type)})`);\n    }\n  } else if (c.display.colorMap) {\n    // Preset covers display type, but colorMap still needs to be emitted\n    parts.push(\n      `.display(${JSON.stringify(c.display.type)}, ${JSON.stringify({ colorMap: c.display.colorMap })})`,\n    );\n  }\n\n  // 5. .filterable() / .notFilterable() — skip if covered by preset\n  if (!skipFilter) {\n    if (c.filter === null) {\n      parts.push(`.notFilterable()`);\n    } else {\n      const f = c.filter;\n      if (f.type === \"slider\" && f.min !== undefined && f.max !== undefined) {\n        parts.push(`.filterable(\"slider\", { min: ${f.min}, max: ${f.max} })`);\n      } else if (f.type === \"checkbox\") {\n        if (f.options && f.options.length > 0) {\n          const opts = f.options\n            .map(\n              (o) =>\n                `{ label: ${JSON.stringify(o.label)}, value: ${JSON.stringify(o.value)} }`,\n            )\n            .join(\", \");\n          parts.push(`.filterable(\"checkbox\", { options: [${opts}] })`);\n        } else {\n          parts.push(`.filterable(\"checkbox\")`);\n        }\n      } else if (f.type === \"timerange\") {\n        parts.push(`.filterable(\"timerange\")`);\n      } else {\n        parts.push(`.filterable(\"input\")`);\n      }\n\n      if (f.defaultOpen) parts.push(`.defaultOpen()`);\n      if (f.commandDisabled) parts.push(`.commandDisabled()`);\n    }\n  } else if (c.filter) {\n    // Preset covers the filter, but still emit behavioral flags if set\n    if (c.filter.defaultOpen) parts.push(`.defaultOpen()`);\n    if (c.filter.commandDisabled) parts.push(`.commandDisabled()`);\n  }\n\n  // 6. Structural modifiers\n  if (!skipSortable && c.sortable) parts.push(`.sortable()`);\n  if (c.hidden) parts.push(`.hidden()`);\n  if (c.optional) parts.push(`.optional()`);\n  if (c.size !== undefined) parts.push(`.size(${c.size})`);\n\n  // 7. .sheet()\n  if (c.sheet !== null) {\n    const sheetArgs: string[] = [];\n    if (c.sheet.label)\n      sheetArgs.push(`label: ${JSON.stringify(c.sheet.label)}`);\n    if (c.sheet.className)\n      sheetArgs.push(`className: ${JSON.stringify(c.sheet.className)}`);\n    if (c.sheet.skeletonClassName)\n      sheetArgs.push(\n        `skeletonClassName: ${JSON.stringify(c.sheet.skeletonClassName)}`,\n      );\n    parts.push(\n      sheetArgs.length > 0 ? `.sheet({ ${sheetArgs.join(\", \")} })` : `.sheet()`,\n    );\n  }\n\n  return parts.join(\"\\n    \");\n}\n\n/**\n * Convert a `SchemaJSON` descriptor to a `createTableSchema(...)` TypeScript\n * source code string.\n *\n * The output is ready to copy-paste into a project that imports from\n * `@/lib/table-schema`.\n *\n * @example\n * ```ts\n * const ts = schemaToTypeScript(tableSchema.toJSON());\n * // → 'import { createTableSchema, col } from \"@/lib/table-schema\"; ...'\n * ```\n */\nexport function schemaToTypeScript(json: SchemaJSON): string {\n  const lines: string[] = [\n    'import { createTableSchema, col } from \"@/lib/table-schema\";',\n    \"\",\n    \"export const schema = createTableSchema({\",\n  ];\n\n  for (const descriptor of json.columns) {\n    const chain = buildChain(descriptor);\n    lines.push(`  ${descriptor.key}: ${chain},`);\n  }\n\n  lines.push(\"});\");\n  return lines.join(\"\\n\");\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/generators/columns.tsx",
      "content": "\"use client\";\n\nimport {\n  DataTableCellBadge,\n  DataTableCellBar,\n  DataTableCellBoolean,\n  DataTableCellCode,\n  DataTableCellGauge,\n  DataTableCellHeatmap,\n  DataTableCellLevelIndicator,\n  DataTableCellNumber,\n  DataTableCellStar,\n  DataTableCellStatusCode,\n  DataTableCellText,\n  DataTableCellTimestamp,\n} from \"@/components/data-table/data-table-cell\";\nimport { DataTableColumnHeader } from \"@/components/data-table/data-table-column-header\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport type { ColumnDef } from \"@tanstack/react-table\";\nimport type { JSX } from \"react\";\nimport type { ColConfig, DisplayConfig, TableSchemaDefinition } from \"../types\";\n\n/**\n * Derive the TanStack Table filterFn name from a column config.\n *\n * Custom filterFns (arrSome, inDateRange) must be registered on the table:\n *   filterFns: { inDateRange, arrSome }  // from src/lib/table/filterfns.ts\n */\nfunction getFilterFn(config: ColConfig): string | undefined {\n  if (!config.filter) return undefined;\n\n  const { kind, filter, arrayItem } = config;\n\n  switch (filter.type) {\n    case \"timerange\":\n      return \"inDateRange\"; // custom — must be registered\n    case \"slider\":\n      return \"inNumberRange\"; // TanStack built-in\n    case \"input\":\n      return \"includesString\"; // TanStack built-in; works for strings and numbers (via toString)\n    case \"checkbox\":\n      // Array columns use arrIncludesSome (checks row's array for filter values)\n      if (kind === \"array\") return \"arrIncludesSome\"; // TanStack built-in\n      // Single-value columns use arrSome (checks if row value is in filter array)\n      return \"arrSome\"; // custom — must be registered\n  }\n}\n\n/**\n * Render the cell based on the display config.\n */\nfunction renderCell(\n  display: DisplayConfig,\n  value: unknown,\n  row: unknown,\n  context?: { min: number; max: number },\n): JSX.Element | null {\n  const fallback = <DataTableCellText value={String(value ?? \"\")} />;\n  const colorMap = \"colorMap\" in display ? display.colorMap : undefined;\n  switch (display.type) {\n    case \"text\": {\n      const hex = colorMap?.[String(value)];\n      return typeof value === \"string\" || typeof value === \"number\" ? (\n        <DataTableCellText value={value} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"code\": {\n      const hex = colorMap?.[String(value)];\n      return typeof value === \"string\" || typeof value === \"number\" ? (\n        <DataTableCellCode value={value} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"number\": {\n      const hex = colorMap?.[String(value)];\n      return typeof value === \"number\" ? (\n        <DataTableCellNumber value={value} unit={display.unit} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"timestamp\": {\n      const hex = colorMap?.[String(value)];\n      return value instanceof Date ||\n        typeof value === \"string\" ||\n        typeof value === \"number\" ? (\n        <DataTableCellTimestamp date={value} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"badge\": {\n      if (Array.isArray(value)) {\n        return (\n          <div className=\"flex-no-wrap flex gap-1\">\n            {value.map((item, i) => (\n              <DataTableCellBadge\n                key={i}\n                value={item}\n                color={colorMap?.[String(item)]}\n              />\n            ))}\n          </div>\n        );\n      }\n      const hex = colorMap?.[String(value)];\n      return typeof value === \"string\" || typeof value === \"number\" ? (\n        <DataTableCellBadge value={value} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"boolean\": {\n      const hex = colorMap?.[String(value)];\n      return typeof value === \"boolean\" ? (\n        <DataTableCellBoolean value={value} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"star\": {\n      return typeof value === \"boolean\" ? (\n        <DataTableCellStar value={value} />\n      ) : (\n        fallback\n      );\n    }\n    case \"status-code\": {\n      const hex = colorMap?.[String(value)];\n      return typeof value === \"number\" ? (\n        <DataTableCellStatusCode value={value} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"level-indicator\": {\n      const hex = colorMap?.[String(value)];\n      return typeof value === \"string\" ? (\n        <DataTableCellLevelIndicator value={value} color={hex} />\n      ) : (\n        fallback\n      );\n    }\n    case \"custom\":\n      return display.cell(value, row);\n    case \"heatmap\": {\n      const { min = 0, max = 100 } = context ?? {};\n      return typeof value === \"number\" ? (\n        <DataTableCellHeatmap\n          value={value}\n          min={min}\n          max={max}\n          unit={display.unit}\n          color={display.color}\n        />\n      ) : (\n        fallback\n      );\n    }\n    case \"bar\": {\n      const { min = 0, max = 100 } = context ?? {};\n      return typeof value === \"number\" ? (\n        <DataTableCellBar\n          value={value}\n          min={min}\n          max={max}\n          unit={display.unit}\n          color={display.color}\n        />\n      ) : (\n        fallback\n      );\n    }\n    case \"gauge\": {\n      const { min = 0, max = 100 } = context ?? {};\n      return typeof value === \"number\" ? (\n        <DataTableCellGauge\n          value={value}\n          min={min}\n          max={max}\n          unit={display.unit}\n          color={display.color}\n        />\n      ) : (\n        fallback\n      );\n    }\n  }\n}\n\n/**\n * Generate ColumnDef[] from a table schema definition.\n *\n * Rules:\n * - Dotted keys (e.g. \"timing.dns\") → id + accessorFn\n * - Non-dotted keys → accessorKey\n * - Sortable columns get DataTableColumnHeader; others get a plain string header\n * - filterFn is derived from col kind + filter type\n * - Cell renders via built-in display components or the \"custom\" cell function\n * - meta.label is always set; meta.hidden reflects .hidden() calls\n *\n * The consuming component must register custom filterFns:\n *   filterFns: { inDateRange, arrSome }\n *\n * Composite/virtual columns that span multiple fields must be appended manually:\n * @example\n * ```ts\n * const columns = [\n *   ...generateColumns(tableSchema),\n *   { id: \"timing\", header: ..., cell: ..., size: 130 },\n * ];\n * ```\n */\nexport function generateColumns<TData>(\n  schema: TableSchemaDefinition,\n): ColumnDef<TData>[] {\n  return Object.entries(schema).map(([key, builder]) => {\n    const config = builder._config;\n\n    // Select column — checkbox header + cell\n    if (config.kind === \"select\") {\n      return {\n        id: key,\n        header: ({ table }) => (\n          <div className=\"flex items-center justify-center\">\n            <Checkbox\n              checked={\n                table.getIsAllPageRowsSelected() ||\n                (table.getIsSomePageRowsSelected() && \"indeterminate\")\n              }\n              onCheckedChange={(value) =>\n                table.toggleAllPageRowsSelected(!!value)\n              }\n              aria-label=\"Select all\"\n              className=\"shadow-none\"\n            />\n          </div>\n        ),\n        cell: ({ row }) => (\n          <div\n            className=\"flex items-center justify-center\"\n            onClick={(e) => e.stopPropagation()}\n          >\n            <Checkbox\n              checked={row.getIsSelected()}\n              onCheckedChange={(value) => row.toggleSelected(!!value)}\n              aria-label=\"Select row\"\n              className=\"shadow-none\"\n            />\n          </div>\n        ),\n        enableSorting: false,\n        enableHiding: false,\n        enableResizing: false,\n        ...(config.size !== undefined\n          ? { size: config.size, minSize: config.size, maxSize: config.size }\n          : {}),\n        meta: { label: config.label, kind: \"select\", hidden: false },\n      } as ColumnDef<TData>;\n    }\n\n    const isDotted = key.includes(\".\");\n    const filterFn = getFilterFn(config);\n\n    const header = config.hideHeader\n      ? () => <span className=\"sr-only\">{config.label}</span>\n      : config.sortable\n        ? ({\n            column,\n          }: {\n            column: Parameters<typeof DataTableColumnHeader>[0][\"column\"];\n          }) => <DataTableColumnHeader column={column} title={config.label} />\n        : config.label;\n\n    const needsMinMax =\n      config.display.type === \"heatmap\" ||\n      config.display.type === \"bar\" ||\n      config.display.type === \"gauge\";\n\n    const cell = ({\n      getValue,\n      row,\n      column,\n    }: {\n      getValue: () => unknown;\n      row: { original: TData };\n      column: { getFacetedMinMaxValues?: () => [number, number] | undefined };\n    }) => {\n      if (needsMinMax) {\n        const display = config.display as {\n          min?: number;\n          max?: number;\n        };\n        const faceted = column.getFacetedMinMaxValues?.();\n        const min = faceted?.[0] ?? display.min ?? 0;\n        const max = faceted?.[1] ?? display.max ?? 100;\n        return renderCell(config.display, getValue(), row.original, {\n          min,\n          max,\n        });\n      }\n      return renderCell(config.display, getValue(), row.original);\n    };\n\n    const meta = {\n      label: config.label,\n      hidden: config.hidden,\n      kind: config.kind,\n    };\n\n    const base = {\n      header,\n      cell,\n      enableResizing: config.resizable,\n      ...(config.enableHiding === false ? { enableHiding: false } : {}),\n      ...(filterFn ? { filterFn } : {}),\n      ...(config.size !== undefined\n        ? {\n            size: config.size,\n            ...(config.resizable ? {} : { minSize: config.size }),\n          }\n        : {}),\n      meta,\n    };\n\n    if (isDotted) {\n      return {\n        ...base,\n        id: key,\n        accessorFn: (row: TData) => (row as Record<string, unknown>)[key],\n      } as ColumnDef<TData>;\n    }\n\n    return {\n      ...base,\n      accessorKey: key,\n    } as ColumnDef<TData>;\n  });\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/generators/filter-fields.ts",
      "content": "import type { DataTableFilterField } from \"@/components/data-table/types\";\nimport type { TableSchemaDefinition } from \"../types\";\n\n/**\n * Generate DataTableFilterField[] from a table schema definition.\n *\n * Only includes fields where filter !== null.\n * Order follows schema definition order (JS object key insertion order).\n *\n * Options for checkbox fields are auto-derived from col.enum(values) or\n * col.boolean() if not explicitly provided via filterable(\"checkbox\", { options }).\n */\nexport function generateFilterFields<TData>(\n  schema: TableSchemaDefinition,\n): DataTableFilterField<TData>[] {\n  const result: DataTableFilterField<TData>[] = [];\n\n  for (const [key, builder] of Object.entries(schema)) {\n    const config = builder._config;\n    if (!config.filter) continue;\n\n    const { filter, label, kind, enumValues, arrayItem } = config;\n\n    const base = {\n      label,\n      value: key as keyof TData,\n      defaultOpen: filter.defaultOpen || undefined,\n      commandDisabled: filter.commandDisabled || undefined,\n    };\n\n    switch (filter.type) {\n      case \"input\": {\n        result.push({ ...base, type: \"input\" });\n        break;\n      }\n      case \"timerange\": {\n        result.push({\n          ...base,\n          type: \"timerange\",\n          presets: filter.presets,\n        });\n        break;\n      }\n      case \"checkbox\": {\n        // Derive options if not explicitly provided\n        let options = filter.options;\n        if (!options) {\n          if (kind === \"enum\" && enumValues) {\n            options = enumValues.map((v) => ({ label: v, value: v }));\n          } else if (kind === \"boolean\") {\n            options = [\n              { label: \"Yes\", value: true },\n              { label: \"No\", value: false },\n            ];\n          } else if (\n            kind === \"array\" &&\n            arrayItem?.kind === \"enum\" &&\n            arrayItem.enumValues\n          ) {\n            options = arrayItem.enumValues.map((v) => ({ label: v, value: v }));\n          }\n        }\n        result.push({\n          ...base,\n          type: \"checkbox\",\n          options,\n          component: filter.component,\n        });\n        break;\n      }\n      case \"slider\": {\n        const displayUnit =\n          config.display.type === \"number\" && \"unit\" in config.display\n            ? config.display.unit\n            : undefined;\n        result.push({\n          ...base,\n          type: \"slider\",\n          min: filter.min ?? 0,\n          max: filter.max ?? 100,\n          unit: filter.unit ?? displayUnit,\n        });\n        break;\n      }\n    }\n  }\n\n  return result;\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/generators/filter-schema.ts",
      "content": "import {\n  ARRAY_DELIMITER,\n  RANGE_DELIMITER,\n  SLIDER_DELIMITER,\n} from \"@/lib/delimiters\";\nimport { createSchema, field } from \"@/lib/store/schema\";\nimport type {\n  FieldBuilder,\n  Schema,\n  SchemaDefinition,\n} from \"@/lib/store/schema\";\nimport type { ColBuilder, TableSchemaDefinition } from \"../types\";\n\n/**\n * Extract keys from a TableSchemaDefinition where the column is filterable.\n * A column is filterable when its filter type `F` is not `never`.\n * Uses `[F] extends [never]` to avoid distribution issues with `any`.\n */\ntype FilterableKeys<T extends TableSchemaDefinition> = {\n  [K in keyof T]: T[K] extends ColBuilder<infer _T, infer F>\n    ? [F] extends [never]\n      ? never\n      : K\n    : never;\n}[keyof T];\n\n// Extract T and F separately — TS struggles to infer both at once from ColBuilder\ntype GetColValue<B> = B extends ColBuilder<infer T, any> ? T : never;\ntype GetColFilter<B> = B extends ColBuilder<any, infer F> ? F : never;\n\n/**\n * Map a single ColBuilder to the correct FieldBuilder type based on its\n * value type `T` and filter type `F`.\n */\ntype InferFilterFieldType<B> = [GetColFilter<B>] extends [never]\n  ? never\n  : GetColFilter<B> extends \"input\"\n    ? GetColValue<B> extends string\n      ? FieldBuilder<string | null>\n      : GetColValue<B> extends number\n        ? FieldBuilder<number | null>\n        : FieldBuilder<unknown>\n    : GetColFilter<B> extends \"slider\"\n      ? FieldBuilder<(number | null)[]>\n      : GetColFilter<B> extends \"timerange\"\n        ? FieldBuilder<(Date | null)[]>\n        : GetColFilter<B> extends \"checkbox\"\n          ? GetColValue<B> extends (infer U)[]\n            ? FieldBuilder<(U | null)[]>\n            : FieldBuilder<(GetColValue<B> | null)[]>\n          : FieldBuilder<unknown>;\n\n/** The generated filter definition — preserves the filterable keys from `T`. */\ntype GeneratedFilterDef<T extends TableSchemaDefinition> = {\n  [K in FilterableKeys<T>]: InferFilterFieldType<T[K]>;\n};\n\nfunction buildFilterDefinition(\n  schema: TableSchemaDefinition,\n): SchemaDefinition {\n  const definition: SchemaDefinition = {};\n\n  for (const [key, builder] of Object.entries(schema)) {\n    const config = builder._config;\n    if (!config.filter) continue;\n\n    const { kind, filter, enumValues, arrayItem } = config;\n\n    switch (filter.type) {\n      case \"input\": {\n        if (kind === \"string\") {\n          definition[key] = field.string();\n        } else if (kind === \"number\") {\n          definition[key] = field.number();\n        }\n        break;\n      }\n      case \"checkbox\": {\n        if (kind === \"enum\" && enumValues) {\n          definition[key] = field.array(\n            field.stringLiteral(enumValues as readonly string[]),\n          );\n        } else if (kind === \"number\") {\n          definition[key] = field\n            .array(field.number())\n            .delimiter(ARRAY_DELIMITER);\n        } else if (kind === \"boolean\") {\n          definition[key] = field\n            .array(field.boolean())\n            .delimiter(ARRAY_DELIMITER);\n        } else if (\n          kind === \"array\" &&\n          arrayItem?.kind === \"enum\" &&\n          arrayItem.enumValues\n        ) {\n          definition[key] = field.array(\n            field.stringLiteral(arrayItem.enumValues as readonly string[]),\n          );\n        }\n        break;\n      }\n      case \"slider\": {\n        definition[key] = field\n          .array(field.number())\n          .delimiter(SLIDER_DELIMITER);\n        break;\n      }\n      case \"timerange\": {\n        definition[key] = field\n          .array(field.timestamp())\n          .delimiter(RANGE_DELIMITER);\n        break;\n      }\n    }\n  }\n\n  return definition;\n}\n\n/**\n * Generate a BYOS filter schema from a table schema definition.\n *\n * Each filterable column maps to the appropriate field.* builder:\n * - col.string()  + input    → field.string()\n * - col.number()  + input    → field.number()\n * - col.number()  + slider   → field.array(field.number()).delimiter(SLIDER_DELIMITER)\n * - col.number()  + checkbox → field.array(field.number()).delimiter(ARRAY_DELIMITER)\n * - col.boolean() + checkbox → field.array(field.boolean()).delimiter(ARRAY_DELIMITER)\n * - col.timestamp()+ timerange→ field.array(field.timestamp()).delimiter(RANGE_DELIMITER)\n * - col.enum(v)   + checkbox → field.array(field.stringLiteral(v))\n * - col.array(col.enum(v)) + checkbox → field.array(field.stringLiteral(v))\n *\n * Non-filterable fields are excluded. Pass `extraFields` for pagination,\n * sorting, and other non-filter state.\n *\n * @example\n * ```ts\n * // Without extra fields (filter fields only)\n * const filterSchema = generateFilterSchema(tableSchema.definition);\n *\n * // With extra fields (recommended)\n * const filterSchema = generateFilterSchema(tableSchema.definition, {\n *   sort: field.sort(),\n *   uuid: field.string(),\n *   live: field.boolean().default(false),\n *   size: field.number().default(40),\n * });\n * ```\n */\nexport function generateFilterSchema<T extends TableSchemaDefinition>(\n  schema: T,\n): Schema<GeneratedFilterDef<T>>;\nexport function generateFilterSchema<\n  T extends TableSchemaDefinition,\n  E extends SchemaDefinition,\n>(schema: T, extraFields: E): Schema<GeneratedFilterDef<T> & E>;\nexport function generateFilterSchema<\n  T extends TableSchemaDefinition,\n  E extends SchemaDefinition,\n>(schema: T, extraFields?: E) {\n  const generated = buildFilterDefinition(schema);\n  const merged = extraFields ? { ...generated, ...extraFields } : generated;\n  return createSchema(merged);\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/lib/table-schema/generators/sheet-fields.ts",
      "content": "import type { SheetField } from \"@/components/data-table/types\";\nimport type {\n  ColConfig,\n  SerializableDisplayConfig,\n  TableSchemaDefinition,\n} from \"../types\";\n\nfunction defaultDisplayForKind(\n  kind: ColConfig[\"kind\"],\n): SerializableDisplayConfig {\n  switch (kind) {\n    case \"enum\":\n    case \"array\":\n      return { type: \"badge\" };\n    case \"boolean\":\n      return { type: \"boolean\" };\n    case \"timestamp\":\n      return { type: \"timestamp\" };\n    case \"number\":\n      return { type: \"number\" };\n    case \"string\":\n    case \"record\":\n    case \"select\":\n    default:\n      return { type: \"text\" };\n  }\n}\n\nfunction getDisplayDescriptor(config: ColConfig): SerializableDisplayConfig {\n  if (config.display.type === \"custom\") {\n    return defaultDisplayForKind(config.kind);\n  }\n  return config.display as SerializableDisplayConfig;\n}\n\n/**\n * Generate SheetField[] from a table schema definition.\n *\n * Only includes fields where sheet !== null (.sheet() was called).\n * Sheet type is derived from the filter type, or \"readonly\" if not filterable.\n * Sheet label falls back to the column label if not overridden in .sheet({ label }).\n */\nexport function generateSheetFields<TData>(\n  schema: TableSchemaDefinition,\n): SheetField<TData>[] {\n  const result: SheetField<TData>[] = [];\n\n  for (const [key, builder] of Object.entries(schema)) {\n    const config = builder._config;\n    if (config.sheet === null) continue;\n\n    const sheetConfig = config.sheet;\n    const filterConfig = config.filter;\n\n    // Derive sheet type from filter type, or \"readonly\" if not filterable\n    const sheetType: SheetField<TData>[\"type\"] =\n      filterConfig?.type ?? \"readonly\";\n\n    result.push({\n      id: key as keyof TData,\n      label: sheetConfig.label ?? config.label,\n      type: sheetType,\n      display: getDisplayDescriptor(config),\n      component: sheetConfig.component as SheetField<TData>[\"component\"],\n      condition: sheetConfig.condition as SheetField<TData>[\"condition\"],\n      className: sheetConfig.className,\n      skeletonClassName: sheetConfig.skeletonClassName,\n    });\n  }\n\n  return result;\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "src/components/data-table/data-table-auto.tsx",
      "content": "\"use client\";\n\n// REMINDER: React Compiler is not compatible with Tanstack Table v8 https://github.com/TanStack/table/issues/5567\n\"use no memo\";\n\nimport { DataTableFilterCommand } from \"@/components/data-table/data-table-filter-command\";\nimport { DataTableInfinite } from \"@/components/data-table/data-table-infinite\";\nimport { useDataTable } from \"@/components/data-table/data-table-provider\";\nimport { MemoizedDataTableSheetContent } from \"@/components/data-table/data-table-sheet/data-table-sheet-content\";\nimport { DataTableSheetDetails } from \"@/components/data-table/data-table-sheet/data-table-sheet-details\";\nimport type { SheetField } from \"@/components/data-table/types\";\nimport { useMemoryAdapter } from \"@/lib/store/adapters/memory\";\nimport { DataTableStoreProvider } from \"@/lib/store/provider/DataTableStoreProvider\";\nimport { field } from \"@/lib/store/schema\";\nimport type { SchemaDefinition } from \"@/lib/store/schema/types\";\nimport {\n  createTableSchema,\n  generateColumns,\n  generateFilterFields,\n  generateFilterSchema,\n  generateSheetFields,\n  getDefaultColumnVisibility,\n} from \"@/lib/table-schema\";\nimport { inferSchemaFromJSON } from \"@/lib/table-schema/infer\";\nimport * as React from \"react\";\n\ntype AutoRow = Record<string, unknown>;\n\nexport interface DataTableAutoProps {\n  data: AutoRow[];\n}\n\nexport function DataTableAuto({ data }: DataTableAutoProps) {\n  const schemaJson = React.useMemo(() => inferSchemaFromJSON(data), [data]);\n\n  const { definition } = React.useMemo(\n    () => createTableSchema.fromJSON(schemaJson),\n    [schemaJson],\n  );\n\n  const columns = React.useMemo(\n    () => generateColumns<AutoRow>(definition),\n    [definition],\n  );\n\n  const filterFields = React.useMemo(\n    () => generateFilterFields<AutoRow>(definition),\n    [definition],\n  );\n\n  const sheetFields = React.useMemo(\n    () => generateSheetFields<AutoRow>(definition),\n    [definition],\n  );\n\n  const defaultColumnVisibility = React.useMemo(\n    () => getDefaultColumnVisibility(definition),\n    [definition],\n  );\n\n  const filterSchema = React.useMemo(() => {\n    const generated = generateFilterSchema(definition);\n    return {\n      ...generated,\n      definition: {\n        ...generated.definition,\n        sort: field.sort(),\n      },\n    };\n  }, [definition]);\n\n  const adapter = useMemoryAdapter(filterSchema.definition, { id: \"auto\" });\n\n  return (\n    <DataTableStoreProvider adapter={adapter}>\n      <DataTableAutoInner\n        data={data}\n        columns={columns}\n        filterFields={filterFields}\n        sheetFields={sheetFields}\n        defaultColumnVisibility={defaultColumnVisibility}\n        schema={filterSchema.definition}\n      />\n    </DataTableStoreProvider>\n  );\n}\n\nconst noop = () => Promise.resolve();\nconst noopRefetch = () => {};\n\nfunction DataTableAutoInner({\n  data,\n  columns,\n  filterFields,\n  sheetFields,\n  defaultColumnVisibility,\n  schema,\n}: {\n  data: AutoRow[];\n  columns: React.ComponentProps<\n    typeof DataTableInfinite<AutoRow, unknown>\n  >[\"columns\"];\n  filterFields: React.ComponentProps<\n    typeof DataTableInfinite<AutoRow, unknown>\n  >[\"filterFields\"];\n  sheetFields: SheetField<AutoRow>[];\n  defaultColumnVisibility: Record<string, boolean>;\n  schema: SchemaDefinition;\n}) {\n  return (\n    <DataTableInfinite\n      columns={columns}\n      data={data}\n      filterFields={filterFields}\n      defaultColumnVisibility={defaultColumnVisibility}\n      totalRowsFetched={data.length}\n      hasNextPage={false}\n      fetchNextPage={noop}\n      refetch={noopRefetch}\n      isFetching={false}\n      isLoading={false}\n      tableId=\"auto\"\n      commandSlot={<DataTableFilterCommand schema={schema} tableId=\"auto\" />}\n      sheetSlot={\n        <AutoSheetSlot sheetFields={sheetFields} totalRows={data.length} />\n      }\n      footerSlot={\n        <div className=\"text-muted-foreground text-sm\">\n          powered by{\" \"}\n          <a\n            href=\"https://openstatus.dev\"\n            target=\"_blank\"\n            rel=\"noreferrer\"\n            className=\"text-foreground hover:text-primary\"\n          >\n            openstatus.dev\n          </a>\n        </div>\n      }\n    />\n  );\n}\n\nfunction AutoSheetSlot({\n  sheetFields: fields,\n  totalRows,\n}: {\n  sheetFields: SheetField<AutoRow>[];\n  totalRows: number;\n}) {\n  const { table, rowSelection, isLoading, filterFields } = useDataTable<\n    AutoRow,\n    unknown\n  >();\n  const selectedRowKey = Object.keys(rowSelection)?.[0];\n  const selectedRow = React.useMemo(() => {\n    if (isLoading && !selectedRowKey) return undefined;\n    return table\n      .getCoreRowModel()\n      .flatRows.find((row) => row.id === selectedRowKey);\n  }, [selectedRowKey, isLoading, table]);\n\n  return (\n    <DataTableSheetDetails\n      title={\n        selectedRow ? String(Object.values(selectedRow.original)[0] ?? \"\") : \"\"\n      }\n      titleClassName=\"font-mono\"\n    >\n      <MemoizedDataTableSheetContent\n        table={table}\n        data={selectedRow?.original}\n        filterFields={filterFields}\n        fields={fields}\n        metadata={{\n          totalRows,\n          filterRows: totalRows,\n          totalRowsFetched: totalRows,\n        }}\n      />\n    </DataTableSheetDetails>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}