@open-mercato/core 0.6.6-develop.6253.1.a8c2b49d90 → 0.6.6-develop.6255.1.a6ee4a57c1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -124,14 +124,15 @@ function TimeGrid({
124
124
  const scrollRef = React.useRef(null);
125
125
  const nowMs = Date.now();
126
126
  const today = startOfDay(/* @__PURE__ */ new Date());
127
+ const todayMs = today.getTime();
127
128
  const anchorMs = anchor.getTime();
128
129
  const [selectedId, setSelectedId] = React.useState(null);
129
130
  const [drag, setDrag] = React.useState(null);
130
131
  const dayStarts = React.useMemo(() => {
131
132
  const rangeStart = getVisibleRange(days === 7 ? "week" : "day", new Date(anchorMs), 0).from;
132
133
  const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index));
133
- return days === 7 ? applyWeekendVisibility(all, showWeekends) : all;
134
- }, [days, anchorMs, showWeekends]);
134
+ return days === 7 ? applyWeekendVisibility(all, showWeekends, new Date(todayMs)) : all;
135
+ }, [days, anchorMs, showWeekends, todayMs]);
135
136
  const dayColumns = React.useMemo(
136
137
  () => dayStarts.map((dayStart) => buildDayColumn(dayStart, items)),
137
138
  [dayStarts, items]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/calendar/TimeGrid.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CalendarDays, ChevronLeft, ChevronRight } from 'lucide-react'\nimport { addDays } from 'date-fns/addDays'\nimport { isSameDay } from 'date-fns/isSameDay'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { EmptyState } from '@open-mercato/ui/primitives/empty-state'\nimport { packOverlaps } from '../../lib/calendar/layout'\nimport { getVisibleRange } from '../../lib/calendar/range'\nimport {\n applyWeekendVisibility,\n buildDragRange,\n DRAG_SNAP_MINUTES,\n isWeekendDay,\n offsetYToMinutes,\n} from '../../lib/calendar/grid'\nimport { EventBlock, formatTimeRange, resolveEventTone } from './EventBlock'\nimport { EventPeekPopover } from './EventPeekPopover'\nimport type { CalendarItem, TimeGridProps } from './types'\n\nconst HOUR_HEIGHT_PX = 120\nconst HOURS_PER_DAY = 24\nconst GRID_BODY_MAX_HEIGHT_PX = 654\nconst INITIAL_SCROLL_HOUR = 8\nconst BLOCK_VERTICAL_GAP_PX = 1\nconst MIN_BLOCK_HEIGHT_PX = 32\nconst PACKED_COLUMN_GAP_PX = 2\n\nconst NON_WORKING_HATCH_BACKGROUND =\n 'repeating-linear-gradient(45deg, transparent 0px, transparent 8px, var(--border) 8px, var(--border) 9px)'\n\ntype PositionedBlock = {\n item: CalendarItem\n top: number\n height: number\n insetInlineStart: string\n width: string\n}\n\ntype DayColumnData = {\n dayStart: Date\n allDayItems: CalendarItem[]\n blocks: PositionedBlock[]\n}\n\ntype DragState = { dayMs: number; startMin: number; endMin: number; moved: boolean }\n\nfunction buildDayColumn(dayStart: Date, items: CalendarItem[]): DayColumnData {\n const dayEnd = addDays(dayStart, 1)\n const dayStartMs = dayStart.getTime()\n const dayEndMs = dayEnd.getTime()\n const allDayItems: CalendarItem[] = []\n const segments: Array<{ original: CalendarItem; start: Date; end: Date }> = []\n\n for (const item of items) {\n const startMs = item.start.getTime()\n const endMs = item.end.getTime()\n if (startMs >= dayEndMs || endMs <= dayStartMs) continue\n if (item.allDay) {\n allDayItems.push(item)\n continue\n }\n segments.push({\n original: item,\n start: startMs < dayStartMs ? dayStart : item.start,\n end: endMs > dayEndMs ? dayEnd : item.end,\n })\n }\n\n allDayItems.sort((first, second) => first.start.getTime() - second.start.getTime())\n\n const clones = segments.map((segment) => ({ ...segment.original, start: segment.start, end: segment.end }))\n const originalByClone = new Map<CalendarItem, CalendarItem>()\n clones.forEach((clone, index) => originalByClone.set(clone, segments[index].original))\n\n const blocks: PositionedBlock[] = packOverlaps(clones).map(({ item: clone, column, columns }) => {\n const startMinutes = (clone.start.getTime() - dayStartMs) / 60000\n const durationMinutes = (clone.end.getTime() - clone.start.getTime()) / 60000\n const rawTop = (startMinutes / 60) * HOUR_HEIGHT_PX\n const rawHeight = (durationMinutes / 60) * HOUR_HEIGHT_PX\n const widthPct = 100 / columns\n return {\n item: originalByClone.get(clone) ?? clone,\n top: rawTop + BLOCK_VERTICAL_GAP_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, rawHeight - BLOCK_VERTICAL_GAP_PX * 2),\n insetInlineStart: `calc(${column * widthPct}% + ${column * PACKED_COLUMN_GAP_PX}px)`,\n width: `calc(${widthPct}% - ${((columns - 1) * PACKED_COLUMN_GAP_PX) / columns}px)`,\n }\n })\n\n return { dayStart, allDayItems, blocks }\n}\n\ntype ConflictBadgeProps = { count: number }\n\nfunction ConflictBadge({ count }: ConflictBadgeProps) {\n const t = useT()\n const label =\n count === 1\n ? t('customers.calendar.grid.conflictCount', '1 conflict')\n : t('customers.calendar.grid.conflictsCount', '{count} conflicts', { count })\n return (\n <span className=\"pointer-events-none absolute left-2 top-1 z-40 inline-flex items-center gap-1 rounded-full bg-status-error-bg px-2 py-0.5 text-overline font-medium uppercase tracking-wide text-status-error-text\">\n <span aria-hidden className=\"size-1.5 rounded-full bg-status-error-icon\" />\n {label}\n </span>\n )\n}\n\ntype AllDayChipProps = {\n item: CalendarItem\n conflicted: boolean\n highlighted: boolean\n selected: boolean\n nowMs: number\n} & Omit<React.ComponentProps<typeof Button>, 'style' | 'children'>\n\nconst AllDayChip = React.forwardRef<HTMLButtonElement, AllDayChipProps>(function AllDayChip(\n { item, conflicted, highlighted, selected, nowMs, className, ...buttonProps },\n ref,\n) {\n const t = useT()\n const tone = resolveEventTone(item, nowMs)\n const title = item.title || t('customers.calendar.grid.untitled', 'Untitled')\n return (\n <Button\n ref={ref}\n type=\"button\"\n variant=\"ghost\"\n aria-label={`${title}, ${t('customers.calendar.grid.allDay', 'All day')}`}\n className={cn(\n 'h-auto w-full min-w-0 justify-start rounded-sm px-2 py-0.5 text-start hover:bg-muted/70',\n tone.surfaceClassName,\n conflicted && 'ring-1 ring-status-warning-icon',\n selected && 'shadow-md ring-2 ring-foreground',\n highlighted && 'motion-safe:animate-pulse',\n 'focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n style={tone.style}\n {...buttonProps}\n >\n <span className={cn('truncate text-xs font-medium', tone.titleClassName)}>{title}</span>\n </Button>\n )\n})\n\nAllDayChip.displayName = 'AllDayChip'\n\nexport function TimeGrid({\n days,\n anchor,\n items,\n conflictIds,\n showWeekends,\n showConflicts,\n aiSummaries,\n highlightItemId,\n onItemClick,\n onJoin,\n onNavigate,\n onCreate,\n onCreateRange,\n}: TimeGridProps) {\n const t = useT()\n const locale = useLocale()\n const scrollRef = React.useRef<HTMLDivElement | null>(null)\n const nowMs = Date.now()\n const today = startOfDay(new Date())\n const anchorMs = anchor.getTime()\n const [selectedId, setSelectedId] = React.useState<string | null>(null)\n const [drag, setDrag] = React.useState<DragState | null>(null)\n\n const dayStarts = React.useMemo(() => {\n const rangeStart = getVisibleRange(days === 7 ? 'week' : 'day', new Date(anchorMs), 0).from\n const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index))\n return days === 7 ? applyWeekendVisibility(all, showWeekends) : all\n }, [days, anchorMs, showWeekends])\n\n const dayColumns = React.useMemo(\n () => dayStarts.map((dayStart) => buildDayColumn(dayStart, items)),\n [dayStarts, items],\n )\n\n const resolveJoinUrl = React.useCallback((location: string | null): string | null => {\n const trimmed = location?.trim() ?? ''\n if (!trimmed) return null\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed\n if (/^www\\./i.test(trimmed)) return `https://${trimmed}`\n return null\n }, [])\n\n const hasAllDayLane = dayColumns.some((column) => column.allDayItems.length > 0)\n\n const formatters = React.useMemo(\n () => ({\n dayNumber: new Intl.DateTimeFormat(locale, { day: '2-digit' }),\n weekdayShort: new Intl.DateTimeFormat(locale, { weekday: 'short' }),\n weekdayLong: new Intl.DateTimeFormat(locale, { weekday: 'long' }),\n }),\n [locale],\n )\n\n const hourLabels = React.useMemo(() => {\n const formatter = new Intl.DateTimeFormat(locale, { hour: 'numeric' })\n return Array.from({ length: HOURS_PER_DAY }, (_, hour) => formatter.format(new Date(2024, 0, 1, hour)))\n }, [locale])\n\n React.useEffect(() => {\n const node = scrollRef.current\n if (!node) return\n node.scrollTop = INITIAL_SCROLL_HOUR * HOUR_HEIGHT_PX\n }, [])\n\n React.useEffect(() => {\n if (!highlightItemId) return\n const node = scrollRef.current\n if (!node) return\n const target = items.find((item) => item.id === highlightItemId && !item.allDay)\n if (!target) return\n const minutes = (target.start.getTime() - startOfDay(target.start).getTime()) / 60000\n const top = (minutes / 60) * HOUR_HEIGHT_PX\n const reduceMotion =\n typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n node.scrollTo({ top: Math.max(0, top - HOUR_HEIGHT_PX), behavior: reduceMotion ? 'auto' : 'smooth' })\n }, [highlightItemId, items])\n\n const nonWorkingLabel = t('customers.calendar.grid.nonWorking', 'Non-working day')\n const previousLabel =\n days === 7\n ? t('customers.calendar.previousWeek', 'Previous week')\n : t('customers.calendar.grid.previousDay', 'Previous day')\n const nextLabel =\n days === 7 ? t('customers.calendar.nextWeek', 'Next week') : t('customers.calendar.grid.nextDay', 'Next day')\n\n const headerLabelFor = (dayStart: Date): string => {\n const dayNumber = formatters.dayNumber.format(dayStart)\n if (days === 1) return `${formatters.weekdayLong.format(dayStart).toUpperCase()} \u00B7 ${dayNumber}`\n return `${dayNumber} ${formatters.weekdayShort.format(dayStart).toUpperCase()}`\n }\n\n const canCreateRange = Boolean(onCreateRange)\n\n const beginDrag = (event: React.PointerEvent<HTMLDivElement>, dayStart: Date) => {\n if (!canCreateRange || event.button !== 0) return\n const layer = event.currentTarget\n const rect = layer.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n try {\n layer.setPointerCapture(event.pointerId)\n } catch {\n // Pointer capture is best-effort; ignore environments that reject it.\n }\n setSelectedId(null)\n setDrag({ dayMs: dayStart.getTime(), startMin: minute, endMin: minute, moved: false })\n }\n\n const moveDrag = (event: React.PointerEvent<HTMLDivElement>) => {\n // Read the layer rect synchronously: `event.currentTarget` is only valid during\n // event dispatch, but the setDrag updater below runs later during re-render.\n const rect = event.currentTarget.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n setDrag((previous) => {\n if (!previous) return previous\n return {\n ...previous,\n endMin: minute,\n moved: previous.moved || Math.abs(minute - previous.startMin) >= DRAG_SNAP_MINUTES,\n }\n })\n }\n\n const endDrag = (dayStart: Date) => {\n setDrag((previous) => {\n if (previous && previous.moved && onCreateRange) {\n const range = buildDragRange(dayStart, previous.startMin, previous.endMin)\n onCreateRange(range.start, range.end)\n }\n return null\n })\n }\n\n return (\n <div className=\"relative flex flex-col overflow-hidden rounded-lg border border-border bg-card\">\n <div\n ref={scrollRef}\n className=\"overflow-auto overscroll-contain\"\n style={{ maxHeight: GRID_BODY_MAX_HEIGHT_PX }}\n >\n <div className=\"sticky top-0 z-30 min-w-full bg-card max-md:w-max\">\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 bg-card md:w-26\">\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={previousLabel} onClick={() => onNavigate(-days)}>\n <ChevronLeft aria-hidden />\n </IconButton>\n </span>\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={nextLabel} onClick={() => onNavigate(days)}>\n <ChevronRight aria-hidden />\n </IconButton>\n </span>\n </div>\n {dayColumns.map(({ dayStart }) => {\n const isToday = isSameDay(dayStart, today)\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'flex min-w-0 flex-1 items-center justify-center border-e border-border bg-muted px-1 py-2 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n <span\n className={cn(\n 'truncate text-xs uppercase tracking-wide',\n isToday ? 'font-semibold text-foreground' : 'font-medium text-muted-foreground',\n )}\n >\n {headerLabelFor(dayStart)}\n </span>\n </div>\n )\n })}\n </div>\n {hasAllDayLane ? (\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 items-center justify-center border-e border-border bg-card py-1 md:w-26\">\n <span className=\"truncate text-overline uppercase tracking-wide text-muted-foreground\">\n {t('customers.calendar.grid.allDay', 'All day')}\n </span>\n </div>\n {dayColumns.map(({ dayStart, allDayItems }) => (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'min-w-0 flex-1 space-y-1 border-e border-border p-1 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n {allDayItems.map((item) => (\n <EventPeekPopover\n key={item.id}\n item={item}\n open={selectedId === item.id}\n joinUrl={resolveJoinUrl(item.location)}\n aiSummaries={aiSummaries}\n onOpenChange={(open) => setSelectedId(open ? item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <AllDayChip\n item={item}\n conflicted={showConflicts && conflictIds.has(item.id)}\n highlighted={highlightItemId === item.id}\n selected={selectedId === item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n ))}\n </div>\n ) : null}\n </div>\n <div className=\"flex min-w-full max-md:w-max\" style={{ height: HOURS_PER_DAY * HOUR_HEIGHT_PX }}>\n <div className=\"sticky start-0 z-10 w-14 shrink-0 border-e border-border bg-card md:w-26\">\n <div className=\"relative h-full\">\n {hourLabels.map((label, hour) =>\n hour === 0 ? null : (\n <span\n key={hour}\n className=\"absolute w-full -translate-y-1/2 px-1 text-center text-xs font-medium text-muted-foreground md:px-3 md:text-sm\"\n style={{ top: hour * HOUR_HEIGHT_PX }}\n >\n {label}\n </span>\n ),\n )}\n </div>\n </div>\n {dayColumns.map(({ dayStart, blocks }) => {\n const nonWorking = isWeekendDay(dayStart)\n const conflictCount = showConflicts\n ? blocks.filter((block) => conflictIds.has(block.item.id)).length\n : 0\n const dragActive = drag && drag.moved && drag.dayMs === dayStart.getTime()\n const dragRange = dragActive ? buildDragRange(dayStart, drag.startMin, drag.endMin) : null\n const dragStartMinutes = dragRange\n ? (dragRange.start.getTime() - startOfDay(dragRange.start).getTime()) / 60000\n : 0\n const dragDurationMinutes = dragRange\n ? (dragRange.end.getTime() - dragRange.start.getTime()) / 60000\n : 0\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'relative min-w-0 flex-1 border-e border-border last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n title={nonWorking ? nonWorkingLabel : undefined}\n >\n {nonWorking ? <span className=\"sr-only\">{nonWorkingLabel}</span> : null}\n <div aria-hidden className=\"absolute inset-0\">\n {Array.from({ length: HOURS_PER_DAY }, (_, hour) => (\n <div key={hour} className=\"relative h-30 border-b border-border\">\n <span className=\"absolute inset-x-0 top-1/2 h-px bg-border/50\" />\n </div>\n ))}\n </div>\n {nonWorking ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0\"\n style={{ backgroundImage: NON_WORKING_HATCH_BACKGROUND }}\n />\n ) : null}\n {canCreateRange ? (\n <div\n className=\"absolute inset-0 cursor-cell\"\n onPointerDown={(event) => beginDrag(event, dayStart)}\n onPointerMove={moveDrag}\n onPointerUp={() => endDrag(dayStart)}\n onPointerCancel={() => setDrag(null)}\n aria-hidden\n />\n ) : null}\n {dragRange ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute z-30 flex flex-col gap-0.5 overflow-hidden rounded-md border-2 border-dashed border-foreground bg-accent-indigo/10 px-2 pt-1.5\"\n style={{\n top: (dragStartMinutes / 60) * HOUR_HEIGHT_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, (dragDurationMinutes / 60) * HOUR_HEIGHT_PX),\n insetInlineStart: 8,\n insetInlineEnd: 8,\n }}\n >\n <span className=\"text-overline font-semibold text-foreground\">\n {t('customers.calendar.actions.newEvent', 'New event')}\n </span>\n <span className=\"text-overline text-muted-foreground\">\n {formatTimeRange(locale, dragRange.start, dragRange.end)}\n </span>\n </div>\n ) : null}\n {conflictCount > 0 ? <ConflictBadge count={conflictCount} /> : null}\n {/* Click-through container so empty space reaches the drag-to-create layer\n below; each block re-enables pointer events for its own click/peek. */}\n <div className=\"pointer-events-none absolute inset-y-0\" style={{ insetInlineStart: 8, insetInlineEnd: 8 }}>\n {blocks.map((block) => (\n <EventPeekPopover\n key={`${block.item.id}-${block.top}`}\n item={block.item}\n open={selectedId === block.item.id}\n joinUrl={resolveJoinUrl(block.item.location)}\n aiSummaries={aiSummaries}\n onOpenChange={(open) => setSelectedId(open ? block.item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <EventBlock\n item={block.item}\n top={block.top}\n height={block.height}\n insetInlineStart={block.insetInlineStart}\n width={block.width}\n conflicted={showConflicts && conflictIds.has(block.item.id)}\n highlighted={highlightItemId === block.item.id}\n selected={selectedId === block.item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n {items.length === 0 ? (\n <div className=\"pointer-events-none absolute inset-0 z-40 flex items-center justify-center p-6\">\n <EmptyState\n className=\"pointer-events-auto bg-card/95 shadow-sm\"\n icon={<CalendarDays className=\"h-6 w-6\" aria-hidden />}\n title={\n days === 7\n ? t('customers.calendar.empty.week', 'Nothing scheduled this week')\n : t('customers.calendar.empty.day', 'Nothing scheduled this day')\n }\n description={t('customers.calendar.empty.description', 'Plan a meeting, event or task to fill your week.')}\n actions={\n onCreate ? (\n <Button type=\"button\" size=\"sm\" onClick={onCreate}>\n {t('customers.calendar.actions.newEvent', 'New event')}\n </Button>\n ) : undefined\n }\n />\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CalendarDays, ChevronLeft, ChevronRight } from 'lucide-react'\nimport { addDays } from 'date-fns/addDays'\nimport { isSameDay } from 'date-fns/isSameDay'\nimport { startOfDay } from 'date-fns/startOfDay'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { EmptyState } from '@open-mercato/ui/primitives/empty-state'\nimport { packOverlaps } from '../../lib/calendar/layout'\nimport { getVisibleRange } from '../../lib/calendar/range'\nimport {\n applyWeekendVisibility,\n buildDragRange,\n DRAG_SNAP_MINUTES,\n isWeekendDay,\n offsetYToMinutes,\n} from '../../lib/calendar/grid'\nimport { EventBlock, formatTimeRange, resolveEventTone } from './EventBlock'\nimport { EventPeekPopover } from './EventPeekPopover'\nimport type { CalendarItem, TimeGridProps } from './types'\n\nconst HOUR_HEIGHT_PX = 120\nconst HOURS_PER_DAY = 24\nconst GRID_BODY_MAX_HEIGHT_PX = 654\nconst INITIAL_SCROLL_HOUR = 8\nconst BLOCK_VERTICAL_GAP_PX = 1\nconst MIN_BLOCK_HEIGHT_PX = 32\nconst PACKED_COLUMN_GAP_PX = 2\n\nconst NON_WORKING_HATCH_BACKGROUND =\n 'repeating-linear-gradient(45deg, transparent 0px, transparent 8px, var(--border) 8px, var(--border) 9px)'\n\ntype PositionedBlock = {\n item: CalendarItem\n top: number\n height: number\n insetInlineStart: string\n width: string\n}\n\ntype DayColumnData = {\n dayStart: Date\n allDayItems: CalendarItem[]\n blocks: PositionedBlock[]\n}\n\ntype DragState = { dayMs: number; startMin: number; endMin: number; moved: boolean }\n\nfunction buildDayColumn(dayStart: Date, items: CalendarItem[]): DayColumnData {\n const dayEnd = addDays(dayStart, 1)\n const dayStartMs = dayStart.getTime()\n const dayEndMs = dayEnd.getTime()\n const allDayItems: CalendarItem[] = []\n const segments: Array<{ original: CalendarItem; start: Date; end: Date }> = []\n\n for (const item of items) {\n const startMs = item.start.getTime()\n const endMs = item.end.getTime()\n if (startMs >= dayEndMs || endMs <= dayStartMs) continue\n if (item.allDay) {\n allDayItems.push(item)\n continue\n }\n segments.push({\n original: item,\n start: startMs < dayStartMs ? dayStart : item.start,\n end: endMs > dayEndMs ? dayEnd : item.end,\n })\n }\n\n allDayItems.sort((first, second) => first.start.getTime() - second.start.getTime())\n\n const clones = segments.map((segment) => ({ ...segment.original, start: segment.start, end: segment.end }))\n const originalByClone = new Map<CalendarItem, CalendarItem>()\n clones.forEach((clone, index) => originalByClone.set(clone, segments[index].original))\n\n const blocks: PositionedBlock[] = packOverlaps(clones).map(({ item: clone, column, columns }) => {\n const startMinutes = (clone.start.getTime() - dayStartMs) / 60000\n const durationMinutes = (clone.end.getTime() - clone.start.getTime()) / 60000\n const rawTop = (startMinutes / 60) * HOUR_HEIGHT_PX\n const rawHeight = (durationMinutes / 60) * HOUR_HEIGHT_PX\n const widthPct = 100 / columns\n return {\n item: originalByClone.get(clone) ?? clone,\n top: rawTop + BLOCK_VERTICAL_GAP_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, rawHeight - BLOCK_VERTICAL_GAP_PX * 2),\n insetInlineStart: `calc(${column * widthPct}% + ${column * PACKED_COLUMN_GAP_PX}px)`,\n width: `calc(${widthPct}% - ${((columns - 1) * PACKED_COLUMN_GAP_PX) / columns}px)`,\n }\n })\n\n return { dayStart, allDayItems, blocks }\n}\n\ntype ConflictBadgeProps = { count: number }\n\nfunction ConflictBadge({ count }: ConflictBadgeProps) {\n const t = useT()\n const label =\n count === 1\n ? t('customers.calendar.grid.conflictCount', '1 conflict')\n : t('customers.calendar.grid.conflictsCount', '{count} conflicts', { count })\n return (\n <span className=\"pointer-events-none absolute left-2 top-1 z-40 inline-flex items-center gap-1 rounded-full bg-status-error-bg px-2 py-0.5 text-overline font-medium uppercase tracking-wide text-status-error-text\">\n <span aria-hidden className=\"size-1.5 rounded-full bg-status-error-icon\" />\n {label}\n </span>\n )\n}\n\ntype AllDayChipProps = {\n item: CalendarItem\n conflicted: boolean\n highlighted: boolean\n selected: boolean\n nowMs: number\n} & Omit<React.ComponentProps<typeof Button>, 'style' | 'children'>\n\nconst AllDayChip = React.forwardRef<HTMLButtonElement, AllDayChipProps>(function AllDayChip(\n { item, conflicted, highlighted, selected, nowMs, className, ...buttonProps },\n ref,\n) {\n const t = useT()\n const tone = resolveEventTone(item, nowMs)\n const title = item.title || t('customers.calendar.grid.untitled', 'Untitled')\n return (\n <Button\n ref={ref}\n type=\"button\"\n variant=\"ghost\"\n aria-label={`${title}, ${t('customers.calendar.grid.allDay', 'All day')}`}\n className={cn(\n 'h-auto w-full min-w-0 justify-start rounded-sm px-2 py-0.5 text-start hover:bg-muted/70',\n tone.surfaceClassName,\n conflicted && 'ring-1 ring-status-warning-icon',\n selected && 'shadow-md ring-2 ring-foreground',\n highlighted && 'motion-safe:animate-pulse',\n 'focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n style={tone.style}\n {...buttonProps}\n >\n <span className={cn('truncate text-xs font-medium', tone.titleClassName)}>{title}</span>\n </Button>\n )\n})\n\nAllDayChip.displayName = 'AllDayChip'\n\nexport function TimeGrid({\n days,\n anchor,\n items,\n conflictIds,\n showWeekends,\n showConflicts,\n aiSummaries,\n highlightItemId,\n onItemClick,\n onJoin,\n onNavigate,\n onCreate,\n onCreateRange,\n}: TimeGridProps) {\n const t = useT()\n const locale = useLocale()\n const scrollRef = React.useRef<HTMLDivElement | null>(null)\n const nowMs = Date.now()\n const today = startOfDay(new Date())\n const todayMs = today.getTime()\n const anchorMs = anchor.getTime()\n const [selectedId, setSelectedId] = React.useState<string | null>(null)\n const [drag, setDrag] = React.useState<DragState | null>(null)\n\n const dayStarts = React.useMemo(() => {\n const rangeStart = getVisibleRange(days === 7 ? 'week' : 'day', new Date(anchorMs), 0).from\n const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index))\n return days === 7 ? applyWeekendVisibility(all, showWeekends, new Date(todayMs)) : all\n }, [days, anchorMs, showWeekends, todayMs])\n\n const dayColumns = React.useMemo(\n () => dayStarts.map((dayStart) => buildDayColumn(dayStart, items)),\n [dayStarts, items],\n )\n\n const resolveJoinUrl = React.useCallback((location: string | null): string | null => {\n const trimmed = location?.trim() ?? ''\n if (!trimmed) return null\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed\n if (/^www\\./i.test(trimmed)) return `https://${trimmed}`\n return null\n }, [])\n\n const hasAllDayLane = dayColumns.some((column) => column.allDayItems.length > 0)\n\n const formatters = React.useMemo(\n () => ({\n dayNumber: new Intl.DateTimeFormat(locale, { day: '2-digit' }),\n weekdayShort: new Intl.DateTimeFormat(locale, { weekday: 'short' }),\n weekdayLong: new Intl.DateTimeFormat(locale, { weekday: 'long' }),\n }),\n [locale],\n )\n\n const hourLabels = React.useMemo(() => {\n const formatter = new Intl.DateTimeFormat(locale, { hour: 'numeric' })\n return Array.from({ length: HOURS_PER_DAY }, (_, hour) => formatter.format(new Date(2024, 0, 1, hour)))\n }, [locale])\n\n React.useEffect(() => {\n const node = scrollRef.current\n if (!node) return\n node.scrollTop = INITIAL_SCROLL_HOUR * HOUR_HEIGHT_PX\n }, [])\n\n React.useEffect(() => {\n if (!highlightItemId) return\n const node = scrollRef.current\n if (!node) return\n const target = items.find((item) => item.id === highlightItemId && !item.allDay)\n if (!target) return\n const minutes = (target.start.getTime() - startOfDay(target.start).getTime()) / 60000\n const top = (minutes / 60) * HOUR_HEIGHT_PX\n const reduceMotion =\n typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n node.scrollTo({ top: Math.max(0, top - HOUR_HEIGHT_PX), behavior: reduceMotion ? 'auto' : 'smooth' })\n }, [highlightItemId, items])\n\n const nonWorkingLabel = t('customers.calendar.grid.nonWorking', 'Non-working day')\n const previousLabel =\n days === 7\n ? t('customers.calendar.previousWeek', 'Previous week')\n : t('customers.calendar.grid.previousDay', 'Previous day')\n const nextLabel =\n days === 7 ? t('customers.calendar.nextWeek', 'Next week') : t('customers.calendar.grid.nextDay', 'Next day')\n\n const headerLabelFor = (dayStart: Date): string => {\n const dayNumber = formatters.dayNumber.format(dayStart)\n if (days === 1) return `${formatters.weekdayLong.format(dayStart).toUpperCase()} \u00B7 ${dayNumber}`\n return `${dayNumber} ${formatters.weekdayShort.format(dayStart).toUpperCase()}`\n }\n\n const canCreateRange = Boolean(onCreateRange)\n\n const beginDrag = (event: React.PointerEvent<HTMLDivElement>, dayStart: Date) => {\n if (!canCreateRange || event.button !== 0) return\n const layer = event.currentTarget\n const rect = layer.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n try {\n layer.setPointerCapture(event.pointerId)\n } catch {\n // Pointer capture is best-effort; ignore environments that reject it.\n }\n setSelectedId(null)\n setDrag({ dayMs: dayStart.getTime(), startMin: minute, endMin: minute, moved: false })\n }\n\n const moveDrag = (event: React.PointerEvent<HTMLDivElement>) => {\n // Read the layer rect synchronously: `event.currentTarget` is only valid during\n // event dispatch, but the setDrag updater below runs later during re-render.\n const rect = event.currentTarget.getBoundingClientRect()\n const minute = offsetYToMinutes(event.clientY - rect.top, HOUR_HEIGHT_PX)\n setDrag((previous) => {\n if (!previous) return previous\n return {\n ...previous,\n endMin: minute,\n moved: previous.moved || Math.abs(minute - previous.startMin) >= DRAG_SNAP_MINUTES,\n }\n })\n }\n\n const endDrag = (dayStart: Date) => {\n setDrag((previous) => {\n if (previous && previous.moved && onCreateRange) {\n const range = buildDragRange(dayStart, previous.startMin, previous.endMin)\n onCreateRange(range.start, range.end)\n }\n return null\n })\n }\n\n return (\n <div className=\"relative flex flex-col overflow-hidden rounded-lg border border-border bg-card\">\n <div\n ref={scrollRef}\n className=\"overflow-auto overscroll-contain\"\n style={{ maxHeight: GRID_BODY_MAX_HEIGHT_PX }}\n >\n <div className=\"sticky top-0 z-30 min-w-full bg-card max-md:w-max\">\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 bg-card md:w-26\">\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={previousLabel} onClick={() => onNavigate(-days)}>\n <ChevronLeft aria-hidden />\n </IconButton>\n </span>\n <span className=\"flex flex-1 items-center justify-center border-e border-border\">\n <IconButton type=\"button\" variant=\"ghost\" size=\"xs\" aria-label={nextLabel} onClick={() => onNavigate(days)}>\n <ChevronRight aria-hidden />\n </IconButton>\n </span>\n </div>\n {dayColumns.map(({ dayStart }) => {\n const isToday = isSameDay(dayStart, today)\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'flex min-w-0 flex-1 items-center justify-center border-e border-border bg-muted px-1 py-2 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n <span\n className={cn(\n 'truncate text-xs uppercase tracking-wide',\n isToday ? 'font-semibold text-foreground' : 'font-medium text-muted-foreground',\n )}\n >\n {headerLabelFor(dayStart)}\n </span>\n </div>\n )\n })}\n </div>\n {hasAllDayLane ? (\n <div className=\"flex border-b border-border\">\n <div className=\"sticky start-0 z-10 flex w-14 shrink-0 items-center justify-center border-e border-border bg-card py-1 md:w-26\">\n <span className=\"truncate text-overline uppercase tracking-wide text-muted-foreground\">\n {t('customers.calendar.grid.allDay', 'All day')}\n </span>\n </div>\n {dayColumns.map(({ dayStart, allDayItems }) => (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'min-w-0 flex-1 space-y-1 border-e border-border p-1 last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n >\n {allDayItems.map((item) => (\n <EventPeekPopover\n key={item.id}\n item={item}\n open={selectedId === item.id}\n joinUrl={resolveJoinUrl(item.location)}\n aiSummaries={aiSummaries}\n onOpenChange={(open) => setSelectedId(open ? item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <AllDayChip\n item={item}\n conflicted={showConflicts && conflictIds.has(item.id)}\n highlighted={highlightItemId === item.id}\n selected={selectedId === item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n ))}\n </div>\n ) : null}\n </div>\n <div className=\"flex min-w-full max-md:w-max\" style={{ height: HOURS_PER_DAY * HOUR_HEIGHT_PX }}>\n <div className=\"sticky start-0 z-10 w-14 shrink-0 border-e border-border bg-card md:w-26\">\n <div className=\"relative h-full\">\n {hourLabels.map((label, hour) =>\n hour === 0 ? null : (\n <span\n key={hour}\n className=\"absolute w-full -translate-y-1/2 px-1 text-center text-xs font-medium text-muted-foreground md:px-3 md:text-sm\"\n style={{ top: hour * HOUR_HEIGHT_PX }}\n >\n {label}\n </span>\n ),\n )}\n </div>\n </div>\n {dayColumns.map(({ dayStart, blocks }) => {\n const nonWorking = isWeekendDay(dayStart)\n const conflictCount = showConflicts\n ? blocks.filter((block) => conflictIds.has(block.item.id)).length\n : 0\n const dragActive = drag && drag.moved && drag.dayMs === dayStart.getTime()\n const dragRange = dragActive ? buildDragRange(dayStart, drag.startMin, drag.endMin) : null\n const dragStartMinutes = dragRange\n ? (dragRange.start.getTime() - startOfDay(dragRange.start).getTime()) / 60000\n : 0\n const dragDurationMinutes = dragRange\n ? (dragRange.end.getTime() - dragRange.start.getTime()) / 60000\n : 0\n return (\n <div\n key={dayStart.getTime()}\n className={cn(\n 'relative min-w-0 flex-1 border-e border-border last:border-e-0',\n days === 7 && 'min-w-[120px] max-md:max-w-[120px] md:min-w-0',\n )}\n title={nonWorking ? nonWorkingLabel : undefined}\n >\n {nonWorking ? <span className=\"sr-only\">{nonWorkingLabel}</span> : null}\n <div aria-hidden className=\"absolute inset-0\">\n {Array.from({ length: HOURS_PER_DAY }, (_, hour) => (\n <div key={hour} className=\"relative h-30 border-b border-border\">\n <span className=\"absolute inset-x-0 top-1/2 h-px bg-border/50\" />\n </div>\n ))}\n </div>\n {nonWorking ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0\"\n style={{ backgroundImage: NON_WORKING_HATCH_BACKGROUND }}\n />\n ) : null}\n {canCreateRange ? (\n <div\n className=\"absolute inset-0 cursor-cell\"\n onPointerDown={(event) => beginDrag(event, dayStart)}\n onPointerMove={moveDrag}\n onPointerUp={() => endDrag(dayStart)}\n onPointerCancel={() => setDrag(null)}\n aria-hidden\n />\n ) : null}\n {dragRange ? (\n <div\n aria-hidden\n className=\"pointer-events-none absolute z-30 flex flex-col gap-0.5 overflow-hidden rounded-md border-2 border-dashed border-foreground bg-accent-indigo/10 px-2 pt-1.5\"\n style={{\n top: (dragStartMinutes / 60) * HOUR_HEIGHT_PX,\n height: Math.max(MIN_BLOCK_HEIGHT_PX, (dragDurationMinutes / 60) * HOUR_HEIGHT_PX),\n insetInlineStart: 8,\n insetInlineEnd: 8,\n }}\n >\n <span className=\"text-overline font-semibold text-foreground\">\n {t('customers.calendar.actions.newEvent', 'New event')}\n </span>\n <span className=\"text-overline text-muted-foreground\">\n {formatTimeRange(locale, dragRange.start, dragRange.end)}\n </span>\n </div>\n ) : null}\n {conflictCount > 0 ? <ConflictBadge count={conflictCount} /> : null}\n {/* Click-through container so empty space reaches the drag-to-create layer\n below; each block re-enables pointer events for its own click/peek. */}\n <div className=\"pointer-events-none absolute inset-y-0\" style={{ insetInlineStart: 8, insetInlineEnd: 8 }}>\n {blocks.map((block) => (\n <EventPeekPopover\n key={`${block.item.id}-${block.top}`}\n item={block.item}\n open={selectedId === block.item.id}\n joinUrl={resolveJoinUrl(block.item.location)}\n aiSummaries={aiSummaries}\n onOpenChange={(open) => setSelectedId(open ? block.item.id : null)}\n onJoin={onJoin}\n onEdit={onItemClick}\n >\n <EventBlock\n item={block.item}\n top={block.top}\n height={block.height}\n insetInlineStart={block.insetInlineStart}\n width={block.width}\n conflicted={showConflicts && conflictIds.has(block.item.id)}\n highlighted={highlightItemId === block.item.id}\n selected={selectedId === block.item.id}\n nowMs={nowMs}\n />\n </EventPeekPopover>\n ))}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n {items.length === 0 ? (\n <div className=\"pointer-events-none absolute inset-0 z-40 flex items-center justify-center p-6\">\n <EmptyState\n className=\"pointer-events-auto bg-card/95 shadow-sm\"\n icon={<CalendarDays className=\"h-6 w-6\" aria-hidden />}\n title={\n days === 7\n ? t('customers.calendar.empty.week', 'Nothing scheduled this week')\n : t('customers.calendar.empty.day', 'Nothing scheduled this day')\n }\n description={t('customers.calendar.empty.description', 'Plan a meeting, event or task to fill your week.')}\n actions={\n onCreate ? (\n <Button type=\"button\" size=\"sm\" onClick={onCreate}>\n {t('customers.calendar.actions.newEvent', 'New event')}\n </Button>\n ) : undefined\n }\n />\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["AllDayChip"]
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { isSameDay } from "date-fns/isSameDay";
1
2
  const DRAG_SNAP_MINUTES = 15;
2
3
  const MIN_DRAG_DURATION_MINUTES = 30;
3
4
  const MINUTES_PER_DAY = 24 * 60;
@@ -5,9 +6,11 @@ function isWeekendDay(date) {
5
6
  const weekday = date.getDay();
6
7
  return weekday === 0 || weekday === 6;
7
8
  }
8
- function applyWeekendVisibility(days, showWeekends) {
9
+ function applyWeekendVisibility(days, showWeekends, keepWeekendDate) {
9
10
  if (showWeekends) return days;
10
- const workingDays = days.filter((day) => !isWeekendDay(day));
11
+ const workingDays = days.filter(
12
+ (day) => !isWeekendDay(day) || keepWeekendDate != null && isSameDay(day, keepWeekendDate)
13
+ );
11
14
  return workingDays.length > 0 ? workingDays : days;
12
15
  }
13
16
  function clampMinutes(value) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/lib/calendar/grid.ts"],
4
- "sourcesContent": ["export const DRAG_SNAP_MINUTES = 15\nexport const MIN_DRAG_DURATION_MINUTES = 30\nconst MINUTES_PER_DAY = 24 * 60\n\nexport function isWeekendDay(date: Date): boolean {\n const weekday = date.getDay()\n return weekday === 0 || weekday === 6\n}\n\nexport function applyWeekendVisibility(days: Date[], showWeekends: boolean): Date[] {\n if (showWeekends) return days\n const workingDays = days.filter((day) => !isWeekendDay(day))\n return workingDays.length > 0 ? workingDays : days\n}\n\nfunction clampMinutes(value: number): number {\n if (value < 0) return 0\n if (value > MINUTES_PER_DAY) return MINUTES_PER_DAY\n return value\n}\n\nexport function offsetYToMinutes(\n offsetY: number,\n hourHeightPx: number,\n snapMinutes: number = DRAG_SNAP_MINUTES,\n): number {\n if (hourHeightPx <= 0) return 0\n const rawMinutes = (offsetY / hourHeightPx) * 60\n const snapped = Math.round(rawMinutes / snapMinutes) * snapMinutes\n return clampMinutes(snapped)\n}\n\nexport type DragRange = { start: Date; end: Date }\n\nexport function buildDragRange(dayStart: Date, startMinutes: number, endMinutes: number): DragRange {\n let lower = clampMinutes(Math.min(startMinutes, endMinutes))\n let upper = clampMinutes(Math.max(startMinutes, endMinutes))\n if (upper - lower < MIN_DRAG_DURATION_MINUTES) upper = lower + MIN_DRAG_DURATION_MINUTES\n if (upper > MINUTES_PER_DAY) {\n upper = MINUTES_PER_DAY\n lower = Math.max(0, upper - MIN_DRAG_DURATION_MINUTES)\n }\n const start = new Date(dayStart)\n start.setHours(0, 0, 0, 0)\n start.setMinutes(lower)\n const end = new Date(dayStart)\n end.setHours(0, 0, 0, 0)\n end.setMinutes(upper)\n return { start, end }\n}\n"],
5
- "mappings": "AAAO,MAAM,oBAAoB;AAC1B,MAAM,4BAA4B;AACzC,MAAM,kBAAkB,KAAK;AAEtB,SAAS,aAAa,MAAqB;AAChD,QAAM,UAAU,KAAK,OAAO;AAC5B,SAAO,YAAY,KAAK,YAAY;AACtC;AAEO,SAAS,uBAAuB,MAAc,cAA+B;AAClF,MAAI,aAAc,QAAO;AACzB,QAAM,cAAc,KAAK,OAAO,CAAC,QAAQ,CAAC,aAAa,GAAG,CAAC;AAC3D,SAAO,YAAY,SAAS,IAAI,cAAc;AAChD;AAEA,SAAS,aAAa,OAAuB;AAC3C,MAAI,QAAQ,EAAG,QAAO;AACtB,MAAI,QAAQ,gBAAiB,QAAO;AACpC,SAAO;AACT;AAEO,SAAS,iBACd,SACA,cACA,cAAsB,mBACd;AACR,MAAI,gBAAgB,EAAG,QAAO;AAC9B,QAAM,aAAc,UAAU,eAAgB;AAC9C,QAAM,UAAU,KAAK,MAAM,aAAa,WAAW,IAAI;AACvD,SAAO,aAAa,OAAO;AAC7B;AAIO,SAAS,eAAe,UAAgB,cAAsB,YAA+B;AAClG,MAAI,QAAQ,aAAa,KAAK,IAAI,cAAc,UAAU,CAAC;AAC3D,MAAI,QAAQ,aAAa,KAAK,IAAI,cAAc,UAAU,CAAC;AAC3D,MAAI,QAAQ,QAAQ,0BAA2B,SAAQ,QAAQ;AAC/D,MAAI,QAAQ,iBAAiB;AAC3B,YAAQ;AACR,YAAQ,KAAK,IAAI,GAAG,QAAQ,yBAAyB;AAAA,EACvD;AACA,QAAM,QAAQ,IAAI,KAAK,QAAQ;AAC/B,QAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AACzB,QAAM,WAAW,KAAK;AACtB,QAAM,MAAM,IAAI,KAAK,QAAQ;AAC7B,MAAI,SAAS,GAAG,GAAG,GAAG,CAAC;AACvB,MAAI,WAAW,KAAK;AACpB,SAAO,EAAE,OAAO,IAAI;AACtB;",
4
+ "sourcesContent": ["import { isSameDay } from 'date-fns/isSameDay'\n\nexport const DRAG_SNAP_MINUTES = 15\nexport const MIN_DRAG_DURATION_MINUTES = 30\nconst MINUTES_PER_DAY = 24 * 60\n\nexport function isWeekendDay(date: Date): boolean {\n const weekday = date.getDay()\n return weekday === 0 || weekday === 6\n}\n\nexport function applyWeekendVisibility(\n days: Date[],\n showWeekends: boolean,\n keepWeekendDate?: Date | null,\n): Date[] {\n if (showWeekends) return days\n const workingDays = days.filter(\n (day) => !isWeekendDay(day) || (keepWeekendDate != null && isSameDay(day, keepWeekendDate)),\n )\n return workingDays.length > 0 ? workingDays : days\n}\n\nfunction clampMinutes(value: number): number {\n if (value < 0) return 0\n if (value > MINUTES_PER_DAY) return MINUTES_PER_DAY\n return value\n}\n\nexport function offsetYToMinutes(\n offsetY: number,\n hourHeightPx: number,\n snapMinutes: number = DRAG_SNAP_MINUTES,\n): number {\n if (hourHeightPx <= 0) return 0\n const rawMinutes = (offsetY / hourHeightPx) * 60\n const snapped = Math.round(rawMinutes / snapMinutes) * snapMinutes\n return clampMinutes(snapped)\n}\n\nexport type DragRange = { start: Date; end: Date }\n\nexport function buildDragRange(dayStart: Date, startMinutes: number, endMinutes: number): DragRange {\n let lower = clampMinutes(Math.min(startMinutes, endMinutes))\n let upper = clampMinutes(Math.max(startMinutes, endMinutes))\n if (upper - lower < MIN_DRAG_DURATION_MINUTES) upper = lower + MIN_DRAG_DURATION_MINUTES\n if (upper > MINUTES_PER_DAY) {\n upper = MINUTES_PER_DAY\n lower = Math.max(0, upper - MIN_DRAG_DURATION_MINUTES)\n }\n const start = new Date(dayStart)\n start.setHours(0, 0, 0, 0)\n start.setMinutes(lower)\n const end = new Date(dayStart)\n end.setHours(0, 0, 0, 0)\n end.setMinutes(upper)\n return { start, end }\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,oBAAoB;AAC1B,MAAM,4BAA4B;AACzC,MAAM,kBAAkB,KAAK;AAEtB,SAAS,aAAa,MAAqB;AAChD,QAAM,UAAU,KAAK,OAAO;AAC5B,SAAO,YAAY,KAAK,YAAY;AACtC;AAEO,SAAS,uBACd,MACA,cACA,iBACQ;AACR,MAAI,aAAc,QAAO;AACzB,QAAM,cAAc,KAAK;AAAA,IACvB,CAAC,QAAQ,CAAC,aAAa,GAAG,KAAM,mBAAmB,QAAQ,UAAU,KAAK,eAAe;AAAA,EAC3F;AACA,SAAO,YAAY,SAAS,IAAI,cAAc;AAChD;AAEA,SAAS,aAAa,OAAuB;AAC3C,MAAI,QAAQ,EAAG,QAAO;AACtB,MAAI,QAAQ,gBAAiB,QAAO;AACpC,SAAO;AACT;AAEO,SAAS,iBACd,SACA,cACA,cAAsB,mBACd;AACR,MAAI,gBAAgB,EAAG,QAAO;AAC9B,QAAM,aAAc,UAAU,eAAgB;AAC9C,QAAM,UAAU,KAAK,MAAM,aAAa,WAAW,IAAI;AACvD,SAAO,aAAa,OAAO;AAC7B;AAIO,SAAS,eAAe,UAAgB,cAAsB,YAA+B;AAClG,MAAI,QAAQ,aAAa,KAAK,IAAI,cAAc,UAAU,CAAC;AAC3D,MAAI,QAAQ,aAAa,KAAK,IAAI,cAAc,UAAU,CAAC;AAC3D,MAAI,QAAQ,QAAQ,0BAA2B,SAAQ,QAAQ;AAC/D,MAAI,QAAQ,iBAAiB;AAC3B,YAAQ;AACR,YAAQ,KAAK,IAAI,GAAG,QAAQ,yBAAyB;AAAA,EACvD;AACA,QAAM,QAAQ,IAAI,KAAK,QAAQ;AAC/B,QAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AACzB,QAAM,WAAW,KAAK;AACtB,QAAM,MAAM,IAAI,KAAK,QAAQ;AAC7B,MAAI,SAAS,GAAG,GAAG,GAAG,CAAC;AACvB,MAAI,WAAW,KAAK;AACpB,SAAO,EAAE,OAAO,IAAI;AACtB;",
6
6
  "names": []
7
7
  }
@@ -793,7 +793,11 @@ class HybridQueryEngine {
793
793
  const cap = resolveEncryptedSortMaxRows();
794
794
  const phase1Root = db.selectFrom(`${baseTable} as b`);
795
795
  let phase1 = await applyQueryShape(phase1Root);
796
- const sortFieldNames = Array.from(/* @__PURE__ */ new Set(["id", ...resolvedSorts.map((s) => String(s.field))]));
796
+ const scopeFieldNames = [
797
+ hasTenantColumn ? "tenant_id" : null,
798
+ hasOrganizationColumn ? "organization_id" : null
799
+ ].filter((field) => field !== null);
800
+ const sortFieldNames = Array.from(/* @__PURE__ */ new Set(["id", ...scopeFieldNames, ...resolvedSorts.map((s) => String(s.field))]));
797
801
  phase1 = applySelection(phase1, sortFieldNames);
798
802
  if (cap !== null) {
799
803
  phase1 = phase1.limit(cap).orderBy(qualify("id"), "asc");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/query_index/lib/engine.ts"],
4
- "sourcesContent": ["import type { QueryEngine, QueryOptions, QueryResult, QueryResultMeta, EncryptedSortRowCapWarning, FilterOp, Filter, QueryCustomFieldSource, PartialIndexWarning, QueryExtensionsConfig, Sort } from '@open-mercato/shared/lib/query/types'\nimport { SortDir } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { BasicQueryEngine, resolveEntityTableName, resolveRegisteredEntityTableName } from '@open-mercato/shared/lib/query/engine'\nimport { type Kysely, sql, type RawBuilder } from 'kysely'\nimport type { EventBus } from '@open-mercato/events'\nimport { readCoverageSnapshot, refreshCoverageSnapshot } from './coverage'\nimport { createProfiler, shouldEnableProfiler, type Profiler } from '@open-mercato/shared/lib/profiler'\nimport type { VectorIndexService } from '@open-mercato/search/vector'\nimport { decryptIndexDocCustomFields } from '@open-mercato/shared/lib/encryption/indexDoc'\nimport { parseBooleanToken, parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport {\n applyJoinFilters,\n normalizeFilters,\n partitionFilters,\n resolveJoins,\n type BaseFilter,\n type ResolvedJoin,\n} from '@open-mercato/shared/lib/query/join-utils'\nimport { resolveSearchConfig, type SearchConfig } from '@open-mercato/shared/lib/search/config'\nimport { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'\nimport { runBeforeQueryPipeline, runAfterQueryPipeline, type QueryExtensionContext } from '@open-mercato/shared/lib/query/query-extension-runner'\nimport { resolveEncryptedSortFields, resolveEncryptedSortMaxRows, sortRowsInMemory } from '@open-mercato/shared/lib/query/encrypted-sort'\nimport { mapWithConcurrency } from '@open-mercato/shared/lib/query/bounded-decrypt'\n\nconst DECRYPT_CONCURRENCY = 8\n\nfunction buildFilterableCustomFieldJoins(\n sources: QueryCustomFieldSource[] | undefined,\n): Array<{\n alias: string\n table?: string\n entityId: EntityId\n from: { field: string }\n to: { field: string }\n type: 'left' | 'inner'\n}> {\n if (!sources || sources.length === 0) return []\n return sources.flatMap((source, index) => {\n if (!source.join) return []\n const alias = typeof source.alias === 'string' && source.alias.trim().length > 0\n ? source.alias.trim()\n : `cfs_${index}`\n return [{\n alias,\n table: source.table,\n entityId: source.entityId,\n from: { field: source.join.fromField },\n to: { field: source.join.toField },\n type: source.join.type === 'inner' ? 'inner' : 'left',\n }]\n })\n}\n\nfunction resolveBooleanEnv(names: readonly string[], defaultValue: boolean): boolean {\n for (const name of names) {\n const raw = process.env[name]\n if (raw !== undefined) return parseBooleanWithDefault(raw, defaultValue)\n }\n return defaultValue\n}\n\nexport function coerceSortDirection(dir: unknown): SortDir {\n return String(dir ?? SortDir.Asc).toLowerCase() === SortDir.Desc ? SortDir.Desc : SortDir.Asc\n}\n\nfunction resolveDebugVerbosity(): boolean {\n const queryIndexDebug = process.env.OM_QUERY_INDEX_DEBUG\n if (queryIndexDebug !== undefined) {\n return parseBooleanToken(queryIndexDebug) ?? false\n }\n const level = (process.env.LOG_VERBOSITY ?? process.env.LOG_LEVEL ?? '').toLowerCase()\n if (['debug', 'trace', 'silly'].includes(level)) return true\n return false\n}\n\ntype AnyDb = Kysely<any>\ntype AnyBuilder = any\ntype NormalizedFilter = { field: string; op: FilterOp; value?: unknown }\ntype IndexDocSource = { alias: string; entityId: EntityId; recordIdColumn: string }\ntype PreparedCustomFieldSource = {\n alias: string\n indexAlias: string\n entityId: EntityId\n recordIdColumn: string\n organizationField?: string\n tenantField?: string\n table: string\n}\ntype SearchRuntime = {\n enabled: boolean\n config: SearchConfig\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n tenantId?: string | null\n searchSources?: SearchTokenSource[]\n /** Per-`query()` alias minter for `search_tokens` subqueries (see #2738). */\n mintAlias: () => string\n}\n\ntype EncryptionResolver = () => {\n decryptEntityPayload?: (entityId: EntityId, payload: Record<string, unknown>, tenantId?: string | null, organizationId?: string | null) => Promise<Record<string, unknown>>\n getEncryptedFieldNames?: (entityId: EntityId, tenantId?: string | null, organizationId?: string | null) => Promise<readonly string[]>\n isEnabled?: () => boolean\n} | null\n\ntype SearchTokenSource = { entity: string; recordIdColumn: string }\n\n/**\n * Mints `search_tokens` subquery aliases (`st_0`, `st_1`, \u2026). Aliases only need\n * to be unique within a single SQL statement, so every `query()` invocation owns\n * a fresh minter. Keeping the counter call-local (rather than on the shared\n * engine instance) means concurrent queries can never reset or collide on each\n * other's sequence (#2738).\n */\nfunction createSearchAliasMinter(): () => string {\n let seq = 0\n return () => `st_${seq++}`\n}\n\nfunction createQueryProfiler(entity: string): Profiler {\n const enabled = shouldEnableProfiler(entity)\n return createProfiler({\n scope: 'query_engine',\n target: entity,\n label: `query_engine:${entity}`,\n loggerLabel: '[qe:profile]',\n enabled,\n })\n}\n\nexport class HybridQueryEngine implements QueryEngine {\n private coverageStatsTtlMs: number\n private customFieldKeysCache = new Map<string, { expiresAt: number; value: string[] }>()\n private customFieldKeysTtlMs: number\n private columnCache = new Map<string, boolean>()\n private customEntityCache = new Map<string, boolean>()\n private debugVerbosity: boolean | null = null\n private sqlDebugEnabled: boolean | null = null\n private forcePartialIndexEnabled: boolean | null = null\n private autoReindexEnabled: boolean | null = null\n private coverageOptimizationEnabled: boolean | null = null\n private pendingCoverageRefreshKeys = new Set<string>()\n\n constructor(\n private em: EntityManager,\n private fallback: BasicQueryEngine,\n private eventBusResolver?: () => Pick<EventBus, 'emitEvent'> | null | undefined,\n private vectorServiceResolver?: () => VectorIndexService | null | undefined,\n private encryptionResolver?: EncryptionResolver,\n ) {\n const coverageTtl = Number.parseInt(process.env.QUERY_INDEX_COVERAGE_CACHE_MS ?? '', 10)\n this.coverageStatsTtlMs = Number.isFinite(coverageTtl) && coverageTtl >= 0 ? coverageTtl : 5 * 60 * 1000\n const cfTtl = Number.parseInt(process.env.QUERY_INDEX_CF_KEYS_CACHE_MS ?? '', 10)\n this.customFieldKeysTtlMs = Number.isFinite(cfTtl) && cfTtl >= 0 ? cfTtl : 5 * 60 * 1000\n }\n\n private getEncryptionService() {\n try {\n return this.encryptionResolver?.() ?? null\n } catch {\n return null\n }\n }\n\n private getDb(): AnyDb {\n const emAny = this.em as any\n if (typeof emAny.getKysely === 'function') return emAny.getKysely() as AnyDb\n throw new Error('HybridQueryEngine requires an EntityManager exposing getKysely() (MikroORM v7)')\n }\n\n async query<T = unknown>(entity: EntityId, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const ext: QueryExtensionsConfig | undefined = opts.extensions\n let hybridExtCtx: QueryExtensionContext | null = null\n const noopDi = { resolve: <R = unknown>(_name: string): R => { throw new Error('No DI context') } }\n\n if (ext) {\n hybridExtCtx = {\n entity: String(entity),\n engine: 'hybrid',\n tenantId: opts.tenantId ?? '',\n organizationId: opts.organizationId,\n userId: ext.userId,\n em: this.em,\n container: ext.container,\n userFeatures: ext.userFeatures,\n }\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n const beforeResult = await runBeforeQueryPipeline(opts, hybridExtCtx, diCtx)\n if (beforeResult.blocked) {\n throw new Error(beforeResult.errorMessage ?? 'Query blocked by extension subscriber')\n }\n opts = beforeResult.query\n }\n const { extensions: _stripExt, ...coreOpts } = opts\n opts = coreOpts\n\n const providedProfiler = opts.profiler\n const profiler = providedProfiler && providedProfiler.enabled\n ? providedProfiler\n : createQueryProfiler(String(entity))\n profiler.mark('query:init')\n let profileClosed = false\n const finishProfile = (meta?: Record<string, unknown>) => {\n if (!profiler.enabled || profileClosed) return\n profileClosed = true\n profiler.end(meta)\n }\n\n const applyAfterExtensions = async <R>(queryResult: QueryResult<R>): Promise<QueryResult<R>> => {\n if (!ext || !hybridExtCtx) return queryResult\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n return await runAfterQueryPipeline(\n queryResult as QueryResult<Record<string, unknown>>,\n opts,\n hybridExtCtx,\n diCtx,\n ) as QueryResult<R>\n }\n\n try {\n const debugEnabled = this.isDebugVerbosity()\n if (debugEnabled) this.debug('query:start', { entity })\n\n const isCustom = opts.forceCustomEntityStorage === true || await this.isCustomEntity(entity)\n if (isCustom) {\n if (debugEnabled) this.debug('query:custom-entity', { entity })\n const section = profiler.section('custom_entity')\n try {\n const result = await this.queryCustomEntity<T>(entity, opts)\n section.end({ mode: 'custom_entity' })\n finishProfile({\n result: 'custom_entity',\n total: Array.isArray(result.items) ? result.items.length : undefined,\n })\n return await applyAfterExtensions(result)\n } catch (err) {\n section.end({ error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n const db = this.getDb()\n profiler.mark('query:db_ready')\n const baseTable = resolveEntityTableName(this.em, entity)\n profiler.mark('query:base_table_resolved')\n const searchConfig = resolveSearchConfig()\n const orgScope = this.resolveOrganizationScope(opts)\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n\n const baseExists = await profiler.measure('base_table_exists', () => this.tableExists(baseTable))\n if (!baseExists) {\n if (debugEnabled) this.debug('query:fallback:missing-base', { entity, baseTable })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'missing_base' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n if (opts.omitAutomaticTenantOrgScope === true) {\n if (debugEnabled) this.debug('query:fallback:omit-automatic-scope', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'omit_automatic_tenant_org_scope' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n const cfFilters = normalizedFilters.filter((filter) => filter.field.startsWith('cf:') || filter.field.startsWith('l10n:'))\n const coverageScope = this.resolveCoverageSnapshotScope(opts)\n const wantsCf = (\n (opts.fields || []).some((field) => typeof field === 'string' && (field.startsWith('cf:') || field.startsWith('l10n:'))) ||\n cfFilters.length > 0 ||\n (Array.isArray(opts.includeCustomFields) && opts.includeCustomFields.length > 0)\n )\n\n if (debugEnabled) {\n this.debug('query:config', {\n entity,\n wantsCustomFields: wantsCf,\n customFieldSources: Array.isArray(opts.customFieldSources) ? opts.customFieldSources.map((src) => src?.entityId) : undefined,\n fields: opts.fields,\n })\n }\n\n let partialIndexWarning: PartialIndexWarning | null = null\n let entityHasActiveCustomFields = true\n\n if (wantsCf) {\n entityHasActiveCustomFields = await this.entityHasActiveCustomFields(entity, opts.tenantId ?? null)\n const hasIndexRows = await profiler.measure(\n 'index_any_rows',\n () => this.indexAnyRows(entity),\n (value) => ({ hasIndexRows: value })\n )\n if (!hasIndexRows) {\n if (debugEnabled) this.debug('query:fallback:no-index', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'no_index_rows' })\n return await applyAfterExtensions(fallbackResult)\n }\n if (entityHasActiveCustomFields) {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(entity, opts, coverageScope),\n (value) => (value\n ? {\n scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { scope: null })\n )\n if (gap) {\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(entity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n const force = this.isForcePartialIndexEnabled()\n if (!force) {\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity })\n }\n const fallbackResult = await this.fallback.query(entity, opts)\n const resultWithWarning: QueryResult<T> = {\n ...fallbackResult,\n meta: {\n ...(fallbackResult.meta ?? {}),\n partialIndexWarning: {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n },\n },\n }\n finishProfile({\n result: 'fallback',\n reason: 'partial_index',\n scope: gap.scope,\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n })\n return await applyAfterExtensions(resultWithWarning)\n }\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity })\n }\n partialIndexWarning = {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n }\n } else if (debugEnabled) {\n this.debug('query:coverage:skip-no-custom-fields', { entity })\n }\n }\n\n const qualify = (col: string) => `b.${col}`\n const columns = await this.getBaseColumnsForEntity(entity)\n const hasOrganizationColumn = await this.columnExists(baseTable, 'organization_id')\n const hasTenantColumn = await this.columnExists(baseTable, 'tenant_id')\n const hasDeletedColumn = await this.columnExists(baseTable, 'deleted_at')\n\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const resolvedJoinsConfig = resolveJoins(\n baseTable,\n [...(opts.joins ?? []), ...buildFilterableCustomFieldJoins(opts.customFieldSources)],\n (entityId) => resolveEntityTableName(this.em, entityId as any),\n )\n const joinMap = new Map<string, ResolvedJoin>()\n const aliasTables = new Map<string, string>()\n aliasTables.set('b', baseTable)\n aliasTables.set('base', baseTable)\n aliasTables.set(baseTable, baseTable)\n for (const join of resolvedJoinsConfig) {\n joinMap.set(join.alias, join)\n aliasTables.set(join.alias, join.table)\n }\n const { baseFilters, joinFilters } = partitionFilters(baseTable, normalizedFilters, joinMap)\n\n const searchRuntimeBase = {\n enabled: false,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n mintAlias: createSearchAliasMinter(),\n }\n\n // Prepare index sources for JSONB custom-field access.\n const indexSources: IndexDocSource[] = [{ alias: 'ei', entityId: entity, recordIdColumn: 'b.id' }]\n let preparedCfSources: PreparedCustomFieldSource[] = []\n const shouldAttachCustomSources = Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && (wantsCf || searchEnabled)\n if (shouldAttachCustomSources) {\n preparedCfSources = this.prepareCustomFieldSources(opts.customFieldSources ?? [])\n for (const source of preparedCfSources) {\n indexSources.push({ alias: source.indexAlias, entityId: source.entityId, recordIdColumn: `${source.alias}.${source.recordIdColumn}` })\n }\n }\n\n const searchSources: SearchTokenSource[] = indexSources\n .map((src) => ({ entity: String(src.entityId), recordIdColumn: src.recordIdColumn }))\n .filter((src) => src.recordIdColumn && src.entity)\n const hasSearchTokens = searchEnabled && searchSources.length\n ? await this.searchSourcesHaveTokens(searchSources, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = { ...searchRuntimeBase, searchSources, enabled: searchEnabled && hasSearchTokens }\n const joinSearchAvailability = new Map<string, boolean>()\n const searchFilters = normalizeFilters(opts.filters).filter((filter) => filter.op === 'like' || filter.op === 'ilike')\n if (searchFilters.length) {\n this.logSearchDebug('search:init', {\n entity,\n baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n fields: searchFilters.map((filter) => String(filter.field)),\n searchEnabled,\n hasSearchTokens,\n searchSources,\n searchConfig: {\n enabled: searchConfig.enabled,\n minTokenLength: searchConfig.minTokenLength,\n enablePartials: searchConfig.enablePartials,\n hashAlgorithm: searchConfig.hashAlgorithm,\n blocklistedFields: searchConfig.blocklistedFields,\n },\n })\n if (!searchEnabled) this.logSearchDebug('search:disabled', { entity, baseTable })\n else if (!hasSearchTokens) this.logSearchDebug('search:no-search-tokens', {\n entity, baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n searchSources,\n })\n }\n const hasNonBaseSearchSource = searchSources.some(\n (src) => src.entity !== String(entity) || src.recordIdColumn !== 'b.id'\n )\n\n // Additional partial-coverage checks for customFieldSources\n if (!partialIndexWarning && Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && this.isForcePartialIndexEnabled()) {\n const seen = new Set<string>([entity])\n for (const source of opts.customFieldSources) {\n const targetEntity = source?.entityId ? String(source.entityId) : null\n if (!targetEntity || seen.has(targetEntity)) continue\n seen.add(targetEntity)\n const sourceHasCustomFields = await this.entityHasActiveCustomFields(targetEntity, opts.tenantId ?? null)\n if (!sourceHasCustomFields) {\n if (debugEnabled) this.debug('query:coverage:skip-no-custom-fields', { entity: targetEntity })\n continue\n }\n const sourceTable = source.table ?? resolveEntityTableName(this.em, targetEntity)\n try {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(targetEntity, opts, coverageScope, sourceTable),\n (value) => (value\n ? {\n entity: targetEntity, scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { entity: targetEntity, scope: null })\n )\n if (!gap) continue\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(targetEntity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n partialIndexWarning = {\n entity: targetEntity,\n entityLabel: this.resolveEntityLabel(targetEntity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n if (debugEnabled) {\n if (gap.stats) this.debug('query:partial-coverage:forced', { entity: targetEntity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n else this.debug('query:partial-coverage:forced', { entity: targetEntity })\n }\n break\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:check-failed', { entity: targetEntity, error: err instanceof Error ? err.message : err })\n }\n }\n }\n\n if (\n !partialIndexWarning &&\n wantsCf &&\n entityHasActiveCustomFields &&\n this.isForcePartialIndexEnabled() &&\n opts.tenantId\n ) {\n try {\n await this.indexCoverageStats(entity, opts, coverageScope)\n const globalStats = await this.indexCoverageStats(entity, opts, coverageScope)\n if (globalStats) {\n const globalBase = globalStats.baseCount\n const globalIndexed = globalStats.indexedCount\n const globalGap = (globalBase > 0 && globalIndexed < globalBase) || globalIndexed > globalBase\n if (globalGap) {\n console.warn('[HybridQueryEngine] Partial index coverage detected at global scope; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n partialIndexWarning = {\n entity, entityLabel: this.resolveEntityLabel(entity),\n baseCount: globalBase, indexedCount: globalIndexed, scope: 'global',\n }\n }\n }\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:global-check-failed', { entity, error: err instanceof Error ? err.message : err })\n }\n }\n\n const resolveBaseColumn = (field: string): string | null => {\n if (columns.has(field)) return field\n if (field === 'organization_id' && columns.has('id')) return 'id'\n return null\n }\n const fallbackOrgId =\n opts.organizationId\n ?? (Array.isArray(opts.organizationIds) && opts.organizationIds.length === 1 ? opts.organizationIds[0] : null)\n const encSvc = this.getEncryptionService()\n const resolvedSorts: Sort[] = []\n for (const sort of opts.sort || []) {\n const field = String(sort.field)\n if (field.startsWith('cf:')) {\n resolvedSorts.push({ ...sort, field })\n } else {\n const baseField = resolveBaseColumn(field)\n if (baseField) resolvedSorts.push({ ...sort, field: baseField })\n }\n }\n const encryptedSortFields = await resolveEncryptedSortFields(\n encSvc,\n entity,\n resolvedSorts.filter((sort) => !sort.field.startsWith('cf:')).map((sort) => sort.field),\n opts.tenantId ?? null,\n fallbackOrgId,\n )\n const requiresPlaintextSort = encryptedSortFields.size > 0\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Build a reusable \"applyQueryShape\" function that applies every\n // WHERE/JOIN/scope to a fresh SelectQueryBuilder. We use this in\n // place of knex's `.clone()` for producing count + data queries.\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const applyBaseScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (orgScope && hasOrganizationColumn) {\n next = this.applyOrganizationScope(next, qualify('organization_id'), orgScope)\n }\n if (hasTenantColumn) {\n next = next.where(qualify('tenant_id'), '=', opts.tenantId)\n }\n if (!opts.withDeleted && hasDeletedColumn) {\n next = next.where(qualify('deleted_at'), 'is', null)\n }\n return next\n }\n\n const applyEntityIndexesJoin = (q: AnyBuilder): AnyBuilder => {\n return q.leftJoin('entity_indexes as ei', (jb: any) => {\n let jc = jb\n .on('ei.entity_type', '=', String(entity))\n .onRef('ei.entity_id', '=', sql<string>`(${sql.ref(qualify('id'))}::text)`)\n if (hasOrganizationColumn) {\n jc = jc\n .onRef('ei.organization_id', '=', qualify('organization_id'))\n .on('ei.organization_id', 'is not', null)\n }\n if (hasTenantColumn) {\n jc = jc\n .onRef('ei.tenant_id', '=', qualify('tenant_id'))\n .on('ei.tenant_id', 'is not', null)\n }\n if (!opts.withDeleted) {\n jc = jc.on('ei.deleted_at', 'is', null)\n }\n return jc\n })\n }\n\n const applyCustomFieldSourceJoins = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const source of preparedCfSources) {\n const join = (opts.customFieldSources ?? []).find((s) => s && (s.alias ?? undefined) === source.alias)?.join\n if (!join) continue\n const joinType = (join.type ?? 'left') === 'inner' ? 'innerJoin' : 'leftJoin'\n next = (next as any)[joinType](`${source.table} as ${source.alias}`, (jb: any) =>\n jb.onRef(`${source.alias}.${join.toField}`, '=', qualify(join.fromField)))\n // Index join for source\n next = next.leftJoin(`entity_indexes as ${source.indexAlias}`, (jb: any) => {\n let jc = jb\n .on(`${source.indexAlias}.entity_type`, '=', String(source.entityId))\n .onRef(`${source.indexAlias}.entity_id`, '=', sql<string>`(${sql.ref(`${source.alias}.${source.recordIdColumn}`)}::text)`)\n const orgRef = source.organizationField\n ? `${source.alias}.${source.organizationField}`\n : (columns.has('organization_id') ? qualify('organization_id') : null)\n if (orgRef) {\n jc = jc\n .onRef(`${source.indexAlias}.organization_id`, '=', orgRef)\n .on(`${source.indexAlias}.organization_id`, 'is not', null)\n }\n const tenantRef = source.tenantField\n ? `${source.alias}.${source.tenantField}`\n : (columns.has('tenant_id') ? qualify('tenant_id') : null)\n if (tenantRef) {\n jc = jc\n .onRef(`${source.indexAlias}.tenant_id`, '=', tenantRef)\n .on(`${source.indexAlias}.tenant_id`, 'is not', null)\n }\n if (!opts.withDeleted) jc = jc.on(`${source.indexAlias}.deleted_at`, 'is', null)\n return jc\n })\n }\n return next\n }\n\n const applyCfFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of cfFilters) {\n next = this.applyCfFilterAcrossSources(\n next, filter.field, filter.op, filter.value, indexSources, searchRuntime,\n )\n }\n return next\n }\n\n const regularBaseFilters = baseFilters.filter((filter) => !filter.orGroup)\n const orGroupFilters = baseFilters.filter((filter) => filter.orGroup)\n\n const applyRegularBaseFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of regularBaseFilters) {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n next = this.applyIndexDocFilterFromAlias(\n next, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime,\n )\n continue\n }\n const column = qualify(baseField)\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime,\n entity, field: fieldName, recordIdColumn: 'b.id',\n })\n }\n return next\n }\n\n const applyOrGroupedBaseFilters = (q: AnyBuilder): AnyBuilder => {\n if (orGroupFilters.length === 0) return q\n const groups = new Map<string, BaseFilter[]>()\n for (const filter of orGroupFilters) {\n if (!filter.orGroup) continue\n const existing = groups.get(filter.orGroup) ?? []\n existing.push(filter)\n groups.set(filter.orGroup, existing)\n }\n const groupList = Array.from(groups.values()).filter((g) => g.length > 0)\n if (groupList.length === 0) return q\n // Combine all groups in a single WHERE: disjuncts are OR'd together; within\n // each disjunct, fields are AND'd. Building this as separate `.where()` calls\n // would AND the disjuncts (wrong semantics).\n return q.where((eb: any) => eb.or(\n groupList.map((groupFilters) => {\n const parts = groupFilters.map((filter) =>\n this.buildBaseFilterExpression(eb, filter, resolveBaseColumn, qualify, entity, searchRuntime),\n )\n return parts.length === 1 ? parts[0] : eb.and(parts)\n }),\n ))\n }\n\n const applyAliasScopes = async (target: AnyBuilder, aliasName: string): Promise<AnyBuilder> => {\n let next = target\n const tableName = aliasTables.get(aliasName)\n if (!tableName) return next\n if (orgScope && await this.columnExists(tableName, 'organization_id')) {\n next = this.applyOrganizationScope(next, `${aliasName}.organization_id`, orgScope)\n }\n if (opts.tenantId && await this.columnExists(tableName, 'tenant_id')) {\n next = next.where(`${aliasName}.tenant_id`, '=', opts.tenantId)\n }\n if (!opts.withDeleted && await this.columnExists(tableName, 'deleted_at')) {\n next = next.where(`${aliasName}.deleted_at`, 'is', null)\n }\n return next\n }\n\n const applyJoinFilterOpFn = (target: AnyBuilder, column: string, op: FilterOp, value?: unknown): AnyBuilder => {\n switch (op) {\n case 'eq': return target.where(column, '=', value as any)\n case 'ne': return target.where(column, '!=', value as any)\n case 'gt': return target.where(column, '>', value as any)\n case 'gte': return target.where(column, '>=', value as any)\n case 'lt': return target.where(column, '<', value as any)\n case 'lte': return target.where(column, '<=', value as any)\n case 'in': return target.where(column, 'in', this.toArray(value))\n case 'nin': return target.where(column, 'not in', this.toArray(value))\n case 'like': return target.where(column, 'like', value as any)\n case 'ilike': return target.where(column, 'ilike', value as any)\n case 'exists': return value ? target.where(column, 'is not', null) : target.where(column, 'is', null)\n default: return target\n }\n }\n\n const applyJoinSearchFilterOp = async (\n target: AnyBuilder,\n filter: { column: string; op: FilterOp; value?: unknown },\n _qualified: string,\n join: ResolvedJoin,\n ): Promise<boolean> => {\n if (!searchEnabled || !join.entityId) return false\n if (!['like', 'ilike'].includes(filter.op)) return false\n if (typeof filter.value !== 'string' || filter.value.trim().length === 0) return false\n\n let searchAvailable = joinSearchAvailability.get(join.entityId)\n if (searchAvailable === undefined) {\n searchAvailable = await this.hasSearchTokens(String(join.entityId), opts.tenantId ?? null, orgScope)\n joinSearchAvailability.set(join.entityId, searchAvailable)\n }\n if (!searchAvailable) return false\n\n const tokens = tokenizeText(String(filter.value), searchConfig)\n if (!tokens.hashes.length) return false\n\n return this.applySearchTokens(target, {\n entity: String(join.entityId),\n field: filter.column,\n hashes: tokens.hashes,\n recordIdColumn: `${join.alias}.id`,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n mintAlias: searchRuntime.mintAlias,\n })\n }\n\n const applyQueryShape = async (q: AnyBuilder): Promise<AnyBuilder> => {\n let next = applyBaseScope(q)\n next = applyEntityIndexesJoin(next)\n next = applyCustomFieldSourceJoins(next)\n next = applyCfFilters(next)\n next = applyRegularBaseFilters(next)\n next = applyOrGroupedBaseFilters(next)\n // applyJoinFilters is the shared helper that handles `joinFilters` (ALIAS:col -> value).\n next = await applyJoinFilters({\n db,\n baseTable,\n builder: next,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n return next\n }\n\n const hasCustomFieldFilters = cfFilters.length > 0\n const canOptimizeCount = !hasCustomFieldFilters && !hasNonBaseSearchSource\n\n // Selection (for data query)\n const selectFieldSet = new Set<string>((opts.fields && opts.fields.length) ? opts.fields.map(String) : Array.from(columns.keys()))\n if (requiresPlaintextSort) {\n for (const field of encryptedSortFields) selectFieldSet.add(field)\n }\n if (opts.includeCustomFields === true) {\n const entityIds = Array.from(new Set(indexSources.map((src) => String(src.entityId))))\n try {\n const resolvedKeys = await this.resolveAvailableCustomFieldKeys(entityIds, opts.tenantId ?? null)\n resolvedKeys.forEach((key) => selectFieldSet.add(`cf:${key}`))\n if (this.isDebugVerbosity()) this.debug('query:cf:resolved-keys', { entity, keys: resolvedKeys })\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to resolve custom field keys for', entity, err)\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n opts.includeCustomFields.map((key) => String(key)).forEach((key) => selectFieldSet.add(`cf:${key}`))\n }\n const selectFields = Array.from(selectFieldSet)\n\n const applySelection = (q: AnyBuilder, fieldsOverride?: string[]): AnyBuilder => {\n let next = q\n const fields = fieldsOverride ?? selectFields\n for (const field of fields) {\n const fieldName = String(field)\n if (fieldName.startsWith('cf:')) {\n const alias = this.sanitize(fieldName)\n const jsonExpr = this.buildCfJsonExprSql(fieldName, indexSources)\n const exprRaw = jsonExpr ?? sql`NULL::jsonb`\n next = next.select(exprRaw.as(alias))\n } else if (columns.has(fieldName)) {\n next = next.select(`${qualify(fieldName)} as ${fieldName}`)\n }\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (requiresPlaintextSort) return next\n for (const s of resolvedSorts) {\n const fieldName = String(s.field)\n if (fieldName.startsWith('cf:')) {\n const textExpr = this.buildCfTextExprSql(fieldName, indexSources)\n if (textExpr) {\n const direction = sql.raw(coerceSortDirection(s.dir))\n next = next.orderBy(sql`${textExpr} ${direction}`)\n }\n } else {\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) continue\n next = next.orderBy(qualify(baseField), s.dir ?? SortDir.Asc)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n const sqlDebugEnabled = this.isSqlDebugEnabled()\n\n let total: number\n\n if (canOptimizeCount) {\n // Optimized count: apply only base-scope + regular filters + or-group filters (no index joins).\n const optimizedRoot = db.selectFrom(`${baseTable} as b` as any)\n let countCore = applyBaseScope(optimizedRoot)\n countCore = applyRegularBaseFilters(countCore)\n countCore = applyOrGroupedBaseFilters(countCore)\n // joinFilters still need to be re-applied in the optimized path\n countCore = await applyJoinFilters({\n db,\n baseTable,\n builder: countCore,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n const sub = countCore.select(sql.ref(qualify('id')).as('id')).groupBy(qualify('id')).as('sq')\n const countQuery = db.selectFrom(sub as any).select(sql<string>`count(*)`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countQuery.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countQuery.executeTakeFirst(),\n { optimized: true }, profiler,\n )\n total = this.parseCount(countRow)\n } else {\n const countRoot = db.selectFrom(`${baseTable} as b` as any)\n const countBuilder = (await applyQueryShape(countRoot))\n .select(sql<string>`count(distinct ${sql.ref(qualify('id'))})`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countBuilder.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countBuilder.executeTakeFirst(),\n { optimized: false }, profiler,\n )\n total = this.parseCount(countRow)\n }\n\n const dekKeyCache = new Map<string | null, string | null>()\n\n const decryptRow = async (item: Record<string, unknown>): Promise<Record<string, unknown>> => {\n let next = item\n if (encSvc?.decryptEntityPayload) {\n const decrypt = encSvc.decryptEntityPayload.bind(encSvc) as (\n entityId: EntityId, payload: Record<string, unknown>, tenantId: string | null, organizationId: string | null,\n ) => Promise<Record<string, unknown>>\n try {\n const decrypted = await decrypt(\n entity, next,\n (next?.tenant_id ?? next?.tenantId ?? opts.tenantId ?? null) as string | null,\n (next?.organization_id ?? next?.organizationId ?? fallbackOrgId ?? null) as string | null,\n )\n next = { ...next, ...decrypted }\n } catch (err) {\n console.error('Error decrypting entity payload', err)\n }\n }\n if (encSvc) {\n try {\n next = await decryptIndexDocCustomFields(\n next,\n {\n tenantId: (next?.tenant_id ?? next?.tenantId ?? opts.tenantId ?? null) as string | null,\n organizationId: (next?.organization_id ?? next?.organizationId ?? null) as string | null,\n },\n encSvc as any, dekKeyCache,\n )\n } catch { /* keep next as-is */ }\n }\n return next\n }\n\n let items: Record<string, unknown>[]\n let encryptedSortRowCapWarning: EncryptedSortRowCapWarning | undefined\n\n if (requiresPlaintextSort) {\n // Phase 1: slim id+sort-columns candidate scan, bounded-concurrency decrypt,\n // in-memory sort over the full candidate set, then slice to the page's ids.\n const cap = resolveEncryptedSortMaxRows()\n const phase1Root = db.selectFrom(`${baseTable} as b` as any)\n let phase1 = await applyQueryShape(phase1Root)\n const sortFieldNames = Array.from(new Set(['id', ...resolvedSorts.map((s) => String(s.field))]))\n phase1 = applySelection(phase1, sortFieldNames)\n if (cap !== null) {\n phase1 = phase1.limit(cap).orderBy(qualify('id'), 'asc' as any)\n }\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = phase1.compile()\n this.debug('query:sql:data:phase1', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const candidateRows = await this.captureSqlTiming(\n 'query:sql:data:phase1', entity,\n () => phase1.execute(),\n { phase: 1 }, profiler,\n ) as Record<string, unknown>[]\n const decryptedCandidates = await mapWithConcurrency(candidateRows, DECRYPT_CONCURRENCY, decryptRow)\n const orderedCandidates = sortRowsInMemory(decryptedCandidates, resolvedSorts)\n const pageIds = orderedCandidates\n .slice((page - 1) * pageSize, page * pageSize)\n .map((row) => row.id)\n\n if (cap !== null && total > cap) {\n encryptedSortRowCapWarning = {\n entity,\n sortFields: resolvedSorts.map((s) => String(s.field)),\n maxRows: cap,\n totalMatched: total,\n }\n }\n\n // Phase 2: fetch + decrypt full rows for just the page's ids, then reassemble\n // in phase-1's order (SQL `WHERE id IN (...)` order is unspecified \u2014 never\n // trust it for ordering).\n if (pageIds.length === 0) {\n items = []\n } else {\n const phase2Root = db.selectFrom(`${baseTable} as b` as any)\n let phase2 = await applyQueryShape(phase2Root)\n phase2 = applySelection(phase2)\n phase2 = phase2.where(qualify('id'), 'in', pageIds)\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = phase2.compile()\n this.debug('query:sql:data:phase2', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const pageRowsRaw = await this.captureSqlTiming(\n 'query:sql:data:phase2', entity,\n () => phase2.execute(),\n { phase: 2 }, profiler,\n ) as Record<string, unknown>[]\n const decryptedPageRows = await mapWithConcurrency(pageRowsRaw, DECRYPT_CONCURRENCY, decryptRow)\n const byId = new Map(decryptedPageRows.map((row) => [String(row.id), row]))\n items = pageIds\n .map((id) => byId.get(String(id)))\n .filter((row): row is Record<string, unknown> => row != null)\n }\n } else {\n const dataRoot = db.selectFrom(`${baseTable} as b` as any)\n let dataBuilder = await applyQueryShape(dataRoot)\n dataBuilder = applySelection(dataBuilder)\n dataBuilder = applySort(dataBuilder)\n dataBuilder = dataBuilder.limit(pageSize).offset((page - 1) * pageSize)\n\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = dataBuilder.compile()\n this.debug('query:sql:data', { entity, sql: compiled.sql, bindings: compiled.parameters, page, pageSize })\n }\n const itemsRaw = await this.captureSqlTiming(\n 'query:sql:data', entity,\n () => dataBuilder.execute(),\n { page, pageSize }, profiler,\n ) as Record<string, unknown>[]\n items = await mapWithConcurrency(itemsRaw, DECRYPT_CONCURRENCY, decryptRow)\n }\n if (debugEnabled) this.debug('query:complete', { entity, total, items: items.length })\n\n const typedItems = items as unknown as T[]\n let result: QueryResult<T> = { items: typedItems, page, pageSize, total }\n if (partialIndexWarning || encryptedSortRowCapWarning) {\n const meta: QueryResultMeta = {}\n if (partialIndexWarning) meta.partialIndexWarning = partialIndexWarning\n if (encryptedSortRowCapWarning) meta.encryptedSortRowCapWarning = encryptedSortRowCapWarning\n result.meta = meta\n }\n\n result = await applyAfterExtensions(result)\n finishProfile({\n result: 'ok', total, page, pageSize,\n itemCount: Array.isArray(items) ? items.length : undefined,\n partialIndexWarning: partialIndexWarning ? true : false,\n })\n return result\n } catch (err) {\n finishProfile({ result: 'error', error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n private prepareCustomFieldSources(\n sources: QueryCustomFieldSource[],\n ): PreparedCustomFieldSource[] {\n const prepared: PreparedCustomFieldSource[] = []\n sources.forEach((source, index) => {\n if (!source) return\n const joinTable = source.table ?? resolveEntityTableName(this.em, source.entityId)\n const alias = source.alias ?? `cfs_${index}`\n if (!source.join) {\n throw new Error(`QueryEngine: customFieldSources entry for ${String(source.entityId)} requires a join configuration`)\n }\n prepared.push({\n alias,\n indexAlias: `ei_${alias}`,\n entityId: source.entityId,\n recordIdColumn: source.recordIdColumn ?? 'id',\n organizationField: source.organizationField,\n tenantField: source.tenantField,\n table: joinTable,\n })\n })\n return prepared\n }\n\n private async isCustomEntity(entity: string): Promise<boolean> {\n const cached = this.customEntityCache.get(entity)\n if (cached !== undefined) return cached\n let result = false\n try {\n const db = this.getDb() as any\n const row = await db\n .selectFrom('custom_entities')\n .select('id')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .executeTakeFirst()\n if (row) {\n result = true\n } else if (resolveRegisteredEntityTableName(this.em, entity) !== null) {\n // An id backed by a registered ORM table is never doc-storage-backed by\n // inference: stray `custom_entities_storage` rows for such an id (e.g. written\n // through the generic entities data engine) must not hijack every list/detail\n // read for the whole entity type away from its base table (#2939). Surfaces\n // that intentionally read doc records for a dual-declared id pass\n // `forceCustomEntityStorage` in QueryOptions instead.\n result = false\n } else {\n // Read/write symmetry. Records written through the entities data engine\n // (`de.createCustomEntityRecord`) always land in `custom_entities_storage`,\n // even for module-declared custom entities whose id is also a frozen system\n // id \u2014 those are NEVER registered in `custom_entities` (install treats a\n // system id as non-registrable). Without this fallback the query routes to\n // the empty ORM/index path and those records are write-only (created with\n // 200 but unreadable on the edit form).\n result = await this.hasCustomEntityStorageRows(entity)\n }\n } catch {\n result = false\n }\n this.customEntityCache.set(entity, result)\n return result\n }\n\n private async hasCustomEntityStorageRows(entity: string): Promise<boolean> {\n try {\n const db = this.getDb() as any\n const row = await db\n .selectFrom('custom_entities_storage')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n .limit(1)\n .executeTakeFirst()\n return !!row\n } catch {\n return false\n }\n }\n\n /**\n * Adds a WHERE EXISTS / OR WHERE EXISTS subquery that matches\n * `search_tokens` for the supplied (entity, field) against the\n * provided record id column.\n *\n * Returns true when the sub-query was applied (i.e. tokens were\n * non-empty). Caller is responsible for the calling context\n * (direct where vs. inside `eb.or([...])`).\n */\n private applySearchTokens(\n q: AnyBuilder,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n combineWith?: 'and' | 'or'\n mintAlias: () => string\n }\n ): boolean {\n if (!opts.hashes.length) {\n this.logSearchDebug('search:skip-no-hashes', {\n entity: opts.entity, field: opts.field,\n tenantId: opts.tenantId ?? null, organizationScope: opts.organizationScope,\n })\n return false\n }\n const alias = opts.mintAlias()\n this.logSearchDebug('search:apply-search-tokens', {\n entity: opts.entity, field: opts.field, alias,\n tokenCount: opts.hashes.length,\n tenantId: opts.tenantId ?? null,\n organizationScope: opts.organizationScope,\n combineWith: opts.combineWith ?? 'and',\n })\n\n const engine = this\n const buildSub = (eb: any) => {\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = engine.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n if (opts.combineWith === 'or') {\n // When called inside an .or([...]) array the caller supplied `eb`.\n // `q` is the ExpressionBuilder callable (eb) itself in that case.\n // We return the expression node rather than mutating q.\n ;(q as any).__pendingOrExists = buildSub(q)\n return true\n }\n\n // Default: append WHERE EXISTS (...) to the outer builder.\n ;(q as any).__applied = true\n const built = buildSub(q)\n // If q is a Kysely builder (has .where), use eb => eb.exists(sub)\n if (typeof q.where === 'function') {\n ;(q as any) = q.where((eb: any) => eb.exists(built))\n }\n return true\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as JSON across a single alias. */\n private jsonbSqlAlias(alias: string, key: string): RawBuilder<unknown> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql`coalesce(${sql.ref(alias + '.doc')} -> ${key}, ${sql.ref(alias + '.doc')} -> ${bare})`\n }\n return sql`${sql.ref(alias + '.doc')} -> ${key}`\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as text across a single alias. */\n private cfTextExprAlias(alias: string, key: string): RawBuilder<string | null> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql<string | null>`coalesce((${sql.ref(alias + '.doc')} ->> ${key}), (${sql.ref(alias + '.doc')} ->> ${bare}))`\n }\n return sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n }\n\n /** Build JSON/text SQL expressions across multiple index alias sources (coalesce over them). */\n private buildCfJsonExprSql(key: string, sources: IndexDocSource[]): RawBuilder<unknown> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.jsonbSqlAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private buildCfTextExprSql(key: string, sources: IndexDocSource[]): RawBuilder<string | null> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.cfTextExprAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql<string | null>`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private applyCfFilterAcrossSources(\n builder: AnyBuilder,\n key: string,\n op: FilterOp,\n value: unknown,\n sources: IndexDocSource[],\n search?: SearchRuntime\n ): AnyBuilder {\n if (!sources.length) return builder\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = this.applyMultiSourceSearchExists(builder, sources, key, hashes, search)\n this.logSearchDebug('search:cf-filter-across', {\n entity: sources.map((src) => src.entityId),\n field: key, tokens: tokens.tokens, hashes, applied,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n if (applied.builder !== builder) return applied.builder\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', {\n entity: sources.map((src) => src.entityId), field: key, value,\n })\n }\n return builder\n }\n\n const textExpr = this.buildCfTextExprSql(key, sources)\n const jsonExpr = this.buildCfJsonExprSql(key, sources)\n if (!textExpr || !jsonExpr) return builder\n\n const arrContains = (val: unknown) => sql<boolean>`${jsonExpr} @> ${JSON.stringify([val])}::jsonb`\n\n switch (op) {\n case 'eq':\n return builder.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return builder.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const values = this.toArray(value)\n return builder.where((eb: any) => eb.or(\n values.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const values = this.toArray(value)\n return builder.where(sql<boolean>`${textExpr} not in (${sql.join(values.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return builder.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return builder.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? builder.where(sql<boolean>`${textExpr} is not null`)\n : builder.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return builder.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return builder\n }\n }\n\n /** Apply a search-token EXISTS subquery across multiple sources (OR-joined). */\n private applyMultiSourceSearchExists(\n builder: AnyBuilder,\n sources: IndexDocSource[],\n key: string,\n hashes: string[],\n search: SearchRuntime,\n ): { builder: AnyBuilder; applied: boolean } {\n if (!sources.length || !hashes.length) return { builder, applied: false }\n const next = builder.where((eb: any) => eb.or(\n sources.map((source) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: String(source.entityId),\n field: key, hashes,\n recordIdColumn: `${source.alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n }))\n )\n ))\n return { builder: next, applied: true }\n }\n\n /** Construct a search-token EXISTS subquery using the given ExpressionBuilder. */\n private buildSearchTokensSub(\n eb: any,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n mintAlias: () => string\n }\n ): any {\n const alias = opts.mintAlias()\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = this.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n private applyCfFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n search?: SearchRuntime\n ): AnyBuilder {\n const textExpr = this.cfTextExprAlias(alias, key)\n const arrExpr = sql<unknown>`(${sql.ref(alias + '.doc')} -> ${key})`\n const arrContains = (val: unknown) => sql<boolean>`${arrExpr} @> ${JSON.stringify([val])}::jsonb`\n\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes,\n recordIdColumn: `${alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n })))\n this.logSearchDebug('search:cf-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where((eb: any) => eb.or(\n vals.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n private applyIndexDocFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n recordIdColumn: string,\n search?: SearchRuntime,\n ): AnyBuilder {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes, recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n })))\n this.logSearchDebug('search:index-doc-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:index-doc-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where(sql<boolean>`${textExpr} = ${value}`)\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n /**\n * Build a single OR-group base filter expression as a Kysely predicate\n * (no side effects on the outer builder).\n */\n private buildBaseFilterExpression(\n eb: any,\n filter: BaseFilter,\n resolveBaseColumn: (field: string) => string | null,\n qualify: (col: string) => string,\n entity: EntityId,\n searchRuntime: SearchRuntime,\n ): any {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n // Doc-based filter via `ei` alias \u2014 returned as EXISTS where possible\n return this.buildIndexDocFilterExpression(eb, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime)\n }\n // For like/ilike with active search-tokens, route through hashed-token EXISTS subquery\n // so encrypted-at-rest columns can still be searched.\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n searchRuntime?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), searchRuntime.config)\n if (tokens.hashes.length) {\n const sources: SearchTokenSource[] = (searchRuntime.searchSources && searchRuntime.searchSources.length\n ? searchRuntime.searchSources\n : [{ entity: String(entity), recordIdColumn: 'b.id' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n return eb.or(\n sources.map((src) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: src.entity,\n field: fieldName,\n hashes: tokens.hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: searchRuntime.tenantId ?? null,\n organizationScope: searchRuntime.organizationScope ?? null,\n mintAlias: searchRuntime.mintAlias,\n })),\n ),\n )\n }\n }\n // Tokenizer produced no hashes (e.g. value too short). Match the regular-base-filter\n // path's behavior of skipping the predicate (no filter), which is preferable to\n // silently turning into a plain `ilike` against an encrypted column.\n return sql<boolean>`true`\n }\n return this.buildColumnFilterExpression(eb, qualify(baseField), filter.op, filter.value)\n }\n\n private buildColumnFilterExpression(\n eb: any,\n column: string,\n op: FilterOp,\n value: unknown,\n ): any {\n switch (op) {\n case 'eq': return eb(column, '=', value)\n case 'ne': return eb(column, '!=', value)\n case 'gt': return eb(column, '>', value)\n case 'gte': return eb(column, '>=', value)\n case 'lt': return eb(column, '<', value)\n case 'lte': return eb(column, '<=', value)\n case 'in': return eb(column, 'in', this.toArray(value))\n case 'nin': return eb(column, 'not in', this.toArray(value))\n case 'like': return eb(column, 'like', value)\n case 'ilike': return eb(column, 'ilike', value)\n case 'exists': return eb(column, value ? 'is not' : 'is', null)\n default: return sql<boolean>`true`\n }\n }\n\n private buildIndexDocFilterExpression(\n eb: any,\n alias: string,\n _entity: EntityId,\n key: string,\n op: FilterOp,\n value: unknown,\n _recordIdColumn: string,\n _search?: SearchRuntime,\n ): any {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n switch (op) {\n case 'eq': return sql<boolean>`${textExpr} = ${value}`\n case 'ne': return sql<boolean>`${textExpr} <> ${value}`\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return sql<boolean>`${textExpr} ${operator} ${value}`\n }\n case 'like': return sql<boolean>`${textExpr} like ${value}`\n case 'ilike': return sql<boolean>`${textExpr} ilike ${value}`\n case 'in': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'nin': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'exists':\n return value ? sql<boolean>`${textExpr} is not null` : sql<boolean>`${textExpr} is null`\n default:\n return sql<boolean>`true`\n }\n }\n\n private async queryCustomEntity<T = unknown>(entity: string, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const db = this.getDb() as any\n const alias = 'ce'\n\n const orgScope = this.resolveOrganizationScope(opts)\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const searchConfig = resolveSearchConfig()\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n const hasSearchTokens = searchEnabled\n ? await this.hasSearchTokens(entity, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = {\n enabled: searchEnabled && hasSearchTokens,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n mintAlias: createSearchAliasMinter(),\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n\n const applyScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n .where(`${alias}.entity_type`, '=', entity)\n .where(`${alias}.tenant_id`, '=', opts.tenantId)\n if (orgScope) {\n next = this.applyOrganizationScope(next, `${alias}.organization_id`, orgScope)\n }\n if (!opts.withDeleted) next = next.where(`${alias}.deleted_at`, 'is', null)\n for (const filter of normalizedFilters) {\n if (filter.field.startsWith('cf:')) {\n next = this.applyCfFilterFromAlias(next, alias, entity, filter.field, filter.op, filter.value, searchRuntime)\n continue\n }\n const column = this.resolveCustomEntityColumn(alias, String(filter.field))\n if (column) {\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n continue\n }\n // Unknown field \u2192 filter on doc JSON text\n const docExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${String(filter.field)})`\n next = this.applyColumnFilter(next, docExpr, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n }\n return next\n }\n\n // Determine CFs and l10n keys to include\n const cfKeys = new Set<string>()\n for (const f of (opts.fields || [])) {\n if (typeof f === 'string' && f.startsWith('cf:')) cfKeys.add(f.slice(3))\n else if (typeof f === 'string' && f.startsWith('l10n:')) cfKeys.add(f)\n }\n for (const filter of normalizedFilters) {\n if (typeof filter.field === 'string' && filter.field.startsWith('cf:')) cfKeys.add(filter.field.slice(3))\n else if (typeof filter.field === 'string' && filter.field.startsWith('l10n:')) cfKeys.add(filter.field)\n }\n if (opts.includeCustomFields === true) {\n try {\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .where('tenant_id', '=', opts.tenantId)\n .execute() as Array<{ key: unknown }>\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string') cfKeys.add(key)\n else if (key != null) cfKeys.add(String(key))\n }\n } catch {\n // ignore\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n for (const k of opts.includeCustomFields) cfKeys.add(k)\n }\n\n const applySelection = (q: AnyBuilder): AnyBuilder => {\n let next = q\n const requested = (opts.fields && opts.fields.length) ? opts.fields : ['id']\n for (const field of requested) {\n const f = String(field)\n if (f.startsWith('cf:')) {\n const aliasName = this.sanitize(f)\n next = next.select(this.jsonbSqlAlias(alias, f).as(aliasName))\n } else if (f === 'id') {\n next = next.select(`${alias}.entity_id as id`)\n } else if (f === 'created_at' || f === 'updated_at' || f === 'deleted_at') {\n next = next.select(`${alias}.${f} as ${f}`)\n } else {\n const expr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${f})`\n next = next.select(expr.as(f))\n }\n }\n // Ensure CF fields for sort / includeCustomFields are selected\n for (const key of cfKeys) {\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.select(this.jsonbSqlAlias(alias, `cf:${key}`).as(aliasName))\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const s of opts.sort || []) {\n if (s.field.startsWith('cf:')) {\n const key = s.field.slice(3)\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.orderBy(aliasName, s.dir ?? SortDir.Asc)\n } else if (s.field === 'id') {\n next = next.orderBy(`${alias}.entity_id`, s.dir ?? SortDir.Asc)\n } else if (s.field === 'created_at' || s.field === 'updated_at' || s.field === 'deleted_at') {\n next = next.orderBy(`${alias}.${s.field}`, s.dir ?? SortDir.Asc)\n } else {\n const direction = sql.raw(coerceSortDirection(s.dir))\n next = next.orderBy(sql`(${sql.ref(alias + '.doc')} ->> ${s.field}) ${direction}`)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n\n const root = db.selectFrom(`custom_entities_storage as ${alias}`)\n const countQuery = applyScope(root).select(sql<string>`count(distinct ${sql.ref(`${alias}.entity_id`)})`.as('count'))\n const countRow = await countQuery.executeTakeFirst()\n const total = this.parseCount(countRow)\n\n let dataQuery = applyScope(db.selectFrom(`custom_entities_storage as ${alias}`))\n dataQuery = applySelection(dataQuery)\n dataQuery = applySort(dataQuery)\n dataQuery = dataQuery.limit(pageSize).offset((page - 1) * pageSize)\n const items = await dataQuery.execute()\n return { items, page, pageSize, total }\n }\n\n private async tableExists(table: string): Promise<boolean> {\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.tables')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .executeTakeFirst()\n return !!exists\n }\n\n private async hasSearchTokens(\n entity: string,\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n try {\n const db = this.getDb() as any\n let query = db\n .selectFrom('search_tokens')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n if (tenantId !== undefined) {\n query = query.where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n }\n if (orgScope) {\n query = this.applyOrganizationScope(query, 'search_tokens.organization_id', orgScope)\n }\n const row = await query.limit(1).executeTakeFirst()\n return !!row\n } catch (err) {\n this.logSearchDebug('search:has-tokens-error', {\n entity, tenantId, organizationScope: orgScope,\n error: err instanceof Error ? err.message : String(err),\n })\n return false\n }\n }\n\n private async searchSourcesHaveTokens(\n sources: SearchTokenSource[],\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n for (const source of sources) {\n const ok = await this.hasSearchTokens(source.entity, tenantId, orgScope)\n this.logSearchDebug('search:source-has-tokens', {\n entity: source.entity, recordIdColumn: source.recordIdColumn,\n tenantId, organizationScope: orgScope, hasTokens: ok,\n })\n if (ok) return true\n }\n return false\n }\n\n private async resolveAvailableCustomFieldKeys(entityIds: string[], tenantId: string | null): Promise<string[]> {\n if (!entityIds.length) return []\n const cacheKey = this.customFieldKeysCacheKey(entityIds, tenantId)\n const now = Date.now()\n const cached = this.customFieldKeysCache.get(cacheKey)\n if (cached && cached.expiresAt > now) return cached.value.slice()\n\n const db = this.getDb() as any\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', 'in', entityIds)\n .where('is_active', '=', true)\n .where((eb: any) => eb.or([\n eb('tenant_id', '=', tenantId),\n eb('tenant_id', 'is', null),\n ]))\n .execute() as Array<{ key: unknown }>\n const keys = new Set<string>()\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string' && key.trim().length) keys.add(key.trim())\n else if (key != null) keys.add(String(key))\n }\n const result = Array.from(keys)\n if (this.customFieldKeysTtlMs > 0) {\n this.customFieldKeysCache.set(cacheKey, { expiresAt: now + this.customFieldKeysTtlMs, value: result })\n }\n return result.slice()\n }\n\n private async entityHasActiveCustomFields(entityId: string, tenantId: string | null): Promise<boolean> {\n try {\n const keys = await this.resolveAvailableCustomFieldKeys([entityId], tenantId)\n return keys.length > 0\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('query:cf:check-error', {\n entity: entityId, tenantId: tenantId ?? null,\n error: err instanceof Error ? err.message : err,\n })\n }\n return true\n }\n }\n\n private customFieldKeysCacheKey(entityIds: string[], tenantId: string | null): string {\n const sorted = entityIds.slice().sort((a, b) => a.localeCompare(b)).join(',')\n return `${tenantId ?? '__none__'}|${sorted}`\n }\n\n private resolveVectorService(): VectorIndexService | null {\n if (!this.vectorServiceResolver) return null\n try {\n return this.vectorServiceResolver() ?? null\n } catch {\n return null\n }\n }\n\n private resolveEntityLabel(entity: string): string {\n return entity\n }\n\n private async indexAnyRows(entity: string): Promise<boolean> {\n const db = this.getDb() as any\n const coverage = await db\n .selectFrom('entity_index_coverage')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n .where('indexed_count', '>', 0)\n .executeTakeFirst()\n if (coverage) return true\n const exists = await db\n .selectFrom('entity_indexes')\n .select('entity_id')\n .where('entity_type', '=', entity)\n .executeTakeFirst()\n return !!exists\n }\n\n private async getStoredCoverageSnapshot(\n entity: string,\n tenantId: string | null,\n organizationId: string | null,\n withDeleted: boolean\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n try {\n const db = this.getDb()\n const scope = {\n entityType: entity, tenantId, organizationId, withDeleted,\n }\n const row = await readCoverageSnapshot(db as any, scope)\n if (row && this.isCoverageSnapshotFresh(row)) {\n return { baseCount: row.baseCount, indexedCount: row.indexedCount }\n }\n\n if (this.isCoverageOptimizationEnabled()) {\n this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)\n if (!row) return null\n return { baseCount: row.baseCount, indexedCount: row.indexedCount }\n }\n\n await refreshCoverageSnapshot(this.em, scope)\n const refreshed = await readCoverageSnapshot(db as any, scope)\n if (!refreshed) return null\n return { baseCount: refreshed.baseCount, indexedCount: refreshed.indexedCount }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:snapshot:read-error', {\n entity, tenantId, organizationId, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n return null\n }\n }\n\n private isCoverageSnapshotFresh(\n row: Awaited<ReturnType<typeof readCoverageSnapshot>>\n ): boolean {\n if (this.coverageStatsTtlMs <= 0) return false\n if (!row) return false\n const refreshedAt = row.refreshed_at instanceof Date\n ? row.refreshed_at\n : row.refreshed_at\n ? new Date(row.refreshed_at)\n : null\n const refreshedAtMs = refreshedAt?.getTime()\n if (!refreshedAtMs || !Number.isFinite(refreshedAtMs)) return false\n return Date.now() - refreshedAtMs <= this.coverageStatsTtlMs\n }\n\n private scheduleAutoReindex(\n entity: string,\n opts: QueryOptions,\n stats?: { baseCount: number; indexedCount: number },\n organizationIdOverride?: string | null\n ) {\n if (!this.isAutoReindexEnabled()) return\n const bus = this.resolveEventBus()\n if (!bus) return\n const payload = {\n entityType: entity,\n tenantId: opts.tenantId ?? null,\n organizationId: organizationIdOverride ?? opts.organizationId ?? null,\n force: false,\n }\n const context = stats\n ? { entity, tenantId: payload.tenantId, organizationId: payload.organizationId, baseCount: stats.baseCount, indexedCount: stats.indexedCount }\n : { entity, tenantId: payload.tenantId, organizationId: payload.organizationId }\n\n void Promise.resolve().then(async () => {\n try {\n await bus.emitEvent('query_index.reindex', payload, { persistent: true })\n if (this.isDebugVerbosity()) this.debug('query:auto-reindex:scheduled', context)\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to schedule auto reindex:', {\n ...context, error: err instanceof Error ? err.message : err,\n })\n }\n })\n }\n\n private scheduleCoverageRefresh(\n entity: string,\n tenantId: string | null | undefined,\n organizationId: string | null | undefined,\n withDeleted: boolean\n ): void {\n const bus = this.resolveEventBus()\n if (!bus) return\n const key = [entity, tenantId ?? '__tenant__', organizationId ?? '__org__', withDeleted ? '1' : '0'].join('|')\n if (this.pendingCoverageRefreshKeys.has(key)) return\n this.pendingCoverageRefreshKeys.add(key)\n void Promise.resolve()\n .then(async () => {\n try {\n await bus.emitEvent('query_index.coverage.refresh', {\n entityType: entity,\n tenantId: tenantId ?? null, organizationId: organizationId ?? null,\n withDeleted, delayMs: 0,\n })\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:scheduled', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n })\n }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:failed', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n }\n })\n .finally(() => { this.pendingCoverageRefreshKeys.delete(key) })\n }\n\n private resolveEventBus(): Pick<EventBus, 'emitEvent'> | null {\n if (!this.eventBusResolver) return null\n try {\n const bus = this.eventBusResolver()\n return bus ?? null\n } catch {\n return null\n }\n }\n\n private isAutoReindexEnabled(): boolean {\n if (this.autoReindexEnabled != null) return this.autoReindexEnabled\n const raw = (process.env.SCHEDULE_AUTO_REINDEX ?? process.env.QUERY_INDEX_AUTO_REINDEX ?? '').trim().toLowerCase()\n if (!raw) { this.autoReindexEnabled = true; return true }\n const parsed = parseBooleanToken(raw)\n this.autoReindexEnabled = parsed === null ? true : parsed\n return this.autoReindexEnabled\n }\n\n private isCoverageOptimizationEnabled(): boolean {\n if (this.coverageOptimizationEnabled != null) return this.coverageOptimizationEnabled\n const raw = (process.env.OPTIMIZE_INDEX_COVERAGE_STATS ?? '').trim().toLowerCase()\n if (!raw) { this.coverageOptimizationEnabled = false; return false }\n this.coverageOptimizationEnabled = parseBooleanToken(raw) === true\n return this.coverageOptimizationEnabled\n }\n\n private async columnExists(table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (this.columnCache.has(key)) {\n const cached = this.columnCache.get(key)\n if (cached === true) return true\n this.columnCache.delete(key)\n }\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.columns')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .where('column_name', '=', column)\n .executeTakeFirst()\n const present = !!exists\n if (present) this.columnCache.set(key, true)\n else this.columnCache.delete(key)\n return present\n }\n\n private async getBaseColumnsForEntity(entity: string): Promise<Map<string, string>> {\n const db = this.getDb() as any\n const table = resolveEntityTableName(this.em, entity)\n const rows = await db\n .selectFrom('information_schema.columns')\n .select(['column_name', 'data_type'])\n .where('table_name', '=', table)\n .execute() as Array<{ column_name: string; data_type: string }>\n const map = new Map<string, string>()\n for (const r of rows) map.set(r.column_name, r.data_type)\n return map\n }\n\n private resolveOrganizationScope(opts: QueryOptions): { ids: string[]; includeNull: boolean } | null {\n if (opts.organizationIds !== undefined) {\n const raw = (opts.organizationIds ?? []).map((id) => (typeof id === 'string' ? id.trim() : id))\n const includeNull = raw.some((id) => id == null || id === '')\n const ids = raw.filter((id): id is string => typeof id === 'string' && id.length > 0)\n const unique = Array.from(new Set(ids))\n return { ids: unique, includeNull }\n }\n if (typeof opts.organizationId === 'string' && opts.organizationId.trim().length > 0) {\n return { ids: [opts.organizationId], includeNull: false }\n }\n return null\n }\n\n private resolveCoverageSnapshotScope(\n opts: QueryOptions\n ): { tenantId: string | null; organizationId: string | null } | null {\n const tenantId = opts.tenantId ?? null\n const orgScope = this.resolveOrganizationScope(opts)\n if (!orgScope) return { tenantId, organizationId: null }\n if (orgScope.includeNull) {\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n if (orgScope.ids.length === 1) return { tenantId, organizationId: orgScope.ids[0] }\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n\n private applyOrganizationScope(\n q: AnyBuilder,\n column: string,\n scope: { ids: string[]; includeNull: boolean }\n ): AnyBuilder {\n if (scope.ids.length === 0 && !scope.includeNull) {\n return q.where(sql<boolean>`1 = 0`)\n }\n return q.where((eb: any) => {\n const parts: any[] = []\n if (scope.ids.length > 0) parts.push(eb(column, 'in', scope.ids))\n if (scope.includeNull) parts.push(eb(column, 'is', null))\n if (parts.length === 1) return parts[0]\n return eb.or(parts)\n })\n }\n\n private normalizeFilters(filters?: QueryOptions['filters']): NormalizedFilter[] {\n if (!filters) return []\n const normalizeField = (k: string) => k.startsWith('cf_') ? `cf:${k.slice(3)}` : k\n if (Array.isArray(filters)) {\n return (filters as Filter[]).map((filter) => ({\n field: normalizeField(String(filter.field)),\n op: filter.op, value: filter.value,\n }))\n }\n const out: NormalizedFilter[] = []\n const obj = filters as Record<string, unknown>\n const add = (field: string, op: FilterOp, value?: unknown) => out.push({ field, op, value })\n for (const [rawKey, rawVal] of Object.entries(obj)) {\n const field = normalizeField(rawKey)\n if (rawVal !== null && typeof rawVal === 'object' && !Array.isArray(rawVal)) {\n for (const [opKey, opVal] of Object.entries(rawVal as Record<string, unknown>)) {\n switch (opKey) {\n case '$eq': add(field, 'eq', opVal); break\n case '$ne': add(field, 'ne', opVal); break\n case '$gt': add(field, 'gt', opVal); break\n case '$gte': add(field, 'gte', opVal); break\n case '$lt': add(field, 'lt', opVal); break\n case '$lte': add(field, 'lte', opVal); break\n case '$in': add(field, 'in', opVal); break\n case '$nin': add(field, 'nin', opVal); break\n case '$like': add(field, 'like', opVal); break\n case '$ilike': add(field, 'ilike', opVal); break\n case '$exists': add(field, 'exists', opVal); break\n }\n }\n } else {\n add(field, 'eq', rawVal)\n }\n }\n return out\n }\n\n private sanitize(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_')\n }\n\n private toArray(value: unknown): readonly unknown[] {\n if (Array.isArray(value)) return value\n if (value === undefined) return []\n return [value]\n }\n\n private parseCount(row: unknown): number {\n if (row && typeof row === 'object' && 'count' in row) {\n const value = (row as { count: unknown }).count\n if (typeof value === 'number') return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? 0 : parsed\n }\n if (typeof value === 'bigint') return Number(value)\n }\n return 0\n }\n\n private logSearchDebug(event: string, payload: Record<string, unknown>) {\n if (!this.isDebugVerbosity()) return\n try {\n console.info('[query-index:search]', event, JSON.stringify(payload))\n } catch {\n console.info('[query-index:search]', event, payload)\n }\n }\n\n private applyColumnFilter(\n q: AnyBuilder,\n column: string | RawBuilder<unknown>,\n filter: NormalizedFilter,\n search?: SearchRuntime & { entity: string; field: string; recordIdColumn?: string },\n ): AnyBuilder {\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n search?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const sources: SearchTokenSource[] = (search.searchSources && search.searchSources.length\n ? search.searchSources\n : [{ entity: search.entity, recordIdColumn: search.recordIdColumn ?? '' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n const engine = this\n q = q.where((eb: any) => eb.or(\n sources.map((src) =>\n eb.exists(engine.buildSearchTokensSub(eb, {\n entity: src.entity, field: search.field, hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n })))\n ))\n this.logSearchDebug('search:filter', {\n entity: search.entity, field: search.field, tokens: tokens.tokens, hashes,\n applied: true, tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope,\n sources: sources.map((src) => ({ entity: src.entity, recordIdColumn: src.recordIdColumn })),\n })\n return q\n }\n } else {\n this.logSearchDebug('search:skip-empty-hashes', {\n entity: search.entity, field: search.field, value: filter.value,\n })\n }\n return q\n }\n const col: any = column\n switch (filter.op) {\n case 'eq': return q.where(col, '=', filter.value as any)\n case 'ne': return q.where(col, '!=', filter.value as any)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = filter.op === 'gt' ? '>' : filter.op === 'gte' ? '>=' : filter.op === 'lt' ? '<' : '<='\n return q.where(col, operator, filter.value as any)\n }\n case 'in':\n return q.where(col, 'in', this.toArray(filter.value))\n case 'nin':\n return q.where(col, 'not in', this.toArray(filter.value))\n case 'like':\n return q.where(col, 'like', filter.value as any)\n case 'ilike':\n return q.where(col, 'ilike', filter.value as any)\n case 'exists':\n return filter.value ? q.where(col, 'is not', null) : q.where(col, 'is', null)\n default:\n return q\n }\n }\n\n private resolveCustomEntityColumn(alias: string, field: string): string | null {\n if (field === 'id') return `${alias}.entity_id`\n if (field === 'organization_id' || field === 'organizationId') return `${alias}.organization_id`\n if (field === 'tenant_id' || field === 'tenantId') return `${alias}.tenant_id`\n if (field === 'created_at' || field === 'updated_at' || field === 'deleted_at') return `${alias}.${field}`\n return null\n }\n\n private isDebugVerbosity(): boolean {\n if (this.debugVerbosity != null) return this.debugVerbosity\n this.debugVerbosity = resolveDebugVerbosity()\n return this.debugVerbosity\n }\n\n private isSqlDebugEnabled(): boolean {\n if (this.sqlDebugEnabled != null) return this.sqlDebugEnabled\n this.sqlDebugEnabled = resolveBooleanEnv(['QUERY_ENGINE_DEBUG_SQL'], false)\n return this.sqlDebugEnabled\n }\n\n private isForcePartialIndexEnabled(): boolean {\n if (this.forcePartialIndexEnabled != null) return this.forcePartialIndexEnabled\n this.forcePartialIndexEnabled = resolveBooleanEnv(['FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES'], false)\n return this.forcePartialIndexEnabled\n }\n\n private async resolveCoverageGap(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n _sourceTable?: string\n ): Promise<{ stats?: { baseCount: number; indexedCount: number }; scope: 'scoped' | 'global' } | null> {\n const scope = coverageScope ?? this.resolveCoverageSnapshotScope(opts)\n if (!scope) return null\n const tenantId = scope.tenantId\n const organizationId = scope.organizationId\n const withDeleted = !!opts.withDeleted\n\n const snapshot = await this.getStoredCoverageSnapshot(entity, tenantId, organizationId, withDeleted)\n if (!snapshot) {\n this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)\n return { stats: undefined, scope: 'scoped' }\n }\n\n const baseCount = snapshot.baseCount\n const indexCount = snapshot.indexedCount\n const hasGap = baseCount > 0 && indexCount < baseCount\n if (hasGap || indexCount > baseCount) return { stats: snapshot, scope: 'scoped' }\n return null\n }\n\n // Backward-compatible hook for tests that mock coverage stats\n private async indexCoverageStats(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n const gap = await this.resolveCoverageGap(entity, opts, coverageScope)\n return gap?.stats ?? null\n }\n\n private async captureSqlTiming<TResult>(\n label: string,\n entity: EntityId,\n execute: () => Promise<TResult> | TResult,\n extra?: Record<string, unknown>,\n profiler?: Profiler\n ): Promise<TResult> {\n const shouldDebug = this.isSqlDebugEnabled() && this.isDebugVerbosity()\n const shouldProfile = profiler?.enabled === true\n if (!shouldDebug && !shouldProfile) return Promise.resolve(execute())\n const startedAt = process.hrtime.bigint()\n try {\n return await Promise.resolve(execute())\n } finally {\n const elapsedMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000\n const context: Record<string, unknown> = { entity, durationMs: Math.round(elapsedMs * 1000) / 1000 }\n if (extra) Object.assign(context, extra)\n if (shouldProfile) profiler!.record(label, context.durationMs as number, extra)\n if (shouldDebug) this.debug(`${label}:timing`, context)\n }\n }\n\n private debug(message: string, context?: Record<string, unknown>): void {\n if (!this.isDebugVerbosity()) return\n if (!this.isSqlDebugEnabled()) return\n if (context) console.debug('[HybridQueryEngine]', message, context)\n else console.debug('[HybridQueryEngine]', message)\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { QueryEngine, QueryOptions, QueryResult, QueryResultMeta, EncryptedSortRowCapWarning, FilterOp, Filter, QueryCustomFieldSource, PartialIndexWarning, QueryExtensionsConfig, Sort } from '@open-mercato/shared/lib/query/types'\nimport { SortDir } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { BasicQueryEngine, resolveEntityTableName, resolveRegisteredEntityTableName } from '@open-mercato/shared/lib/query/engine'\nimport { type Kysely, sql, type RawBuilder } from 'kysely'\nimport type { EventBus } from '@open-mercato/events'\nimport { readCoverageSnapshot, refreshCoverageSnapshot } from './coverage'\nimport { createProfiler, shouldEnableProfiler, type Profiler } from '@open-mercato/shared/lib/profiler'\nimport type { VectorIndexService } from '@open-mercato/search/vector'\nimport { decryptIndexDocCustomFields } from '@open-mercato/shared/lib/encryption/indexDoc'\nimport { parseBooleanToken, parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport {\n applyJoinFilters,\n normalizeFilters,\n partitionFilters,\n resolveJoins,\n type BaseFilter,\n type ResolvedJoin,\n} from '@open-mercato/shared/lib/query/join-utils'\nimport { resolveSearchConfig, type SearchConfig } from '@open-mercato/shared/lib/search/config'\nimport { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'\nimport { runBeforeQueryPipeline, runAfterQueryPipeline, type QueryExtensionContext } from '@open-mercato/shared/lib/query/query-extension-runner'\nimport { resolveEncryptedSortFields, resolveEncryptedSortMaxRows, sortRowsInMemory } from '@open-mercato/shared/lib/query/encrypted-sort'\nimport { mapWithConcurrency } from '@open-mercato/shared/lib/query/bounded-decrypt'\n\nconst DECRYPT_CONCURRENCY = 8\n\nfunction buildFilterableCustomFieldJoins(\n sources: QueryCustomFieldSource[] | undefined,\n): Array<{\n alias: string\n table?: string\n entityId: EntityId\n from: { field: string }\n to: { field: string }\n type: 'left' | 'inner'\n}> {\n if (!sources || sources.length === 0) return []\n return sources.flatMap((source, index) => {\n if (!source.join) return []\n const alias = typeof source.alias === 'string' && source.alias.trim().length > 0\n ? source.alias.trim()\n : `cfs_${index}`\n return [{\n alias,\n table: source.table,\n entityId: source.entityId,\n from: { field: source.join.fromField },\n to: { field: source.join.toField },\n type: source.join.type === 'inner' ? 'inner' : 'left',\n }]\n })\n}\n\nfunction resolveBooleanEnv(names: readonly string[], defaultValue: boolean): boolean {\n for (const name of names) {\n const raw = process.env[name]\n if (raw !== undefined) return parseBooleanWithDefault(raw, defaultValue)\n }\n return defaultValue\n}\n\nexport function coerceSortDirection(dir: unknown): SortDir {\n return String(dir ?? SortDir.Asc).toLowerCase() === SortDir.Desc ? SortDir.Desc : SortDir.Asc\n}\n\nfunction resolveDebugVerbosity(): boolean {\n const queryIndexDebug = process.env.OM_QUERY_INDEX_DEBUG\n if (queryIndexDebug !== undefined) {\n return parseBooleanToken(queryIndexDebug) ?? false\n }\n const level = (process.env.LOG_VERBOSITY ?? process.env.LOG_LEVEL ?? '').toLowerCase()\n if (['debug', 'trace', 'silly'].includes(level)) return true\n return false\n}\n\ntype AnyDb = Kysely<any>\ntype AnyBuilder = any\ntype NormalizedFilter = { field: string; op: FilterOp; value?: unknown }\ntype IndexDocSource = { alias: string; entityId: EntityId; recordIdColumn: string }\ntype PreparedCustomFieldSource = {\n alias: string\n indexAlias: string\n entityId: EntityId\n recordIdColumn: string\n organizationField?: string\n tenantField?: string\n table: string\n}\ntype SearchRuntime = {\n enabled: boolean\n config: SearchConfig\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n tenantId?: string | null\n searchSources?: SearchTokenSource[]\n /** Per-`query()` alias minter for `search_tokens` subqueries (see #2738). */\n mintAlias: () => string\n}\n\ntype EncryptionResolver = () => {\n decryptEntityPayload?: (entityId: EntityId, payload: Record<string, unknown>, tenantId?: string | null, organizationId?: string | null) => Promise<Record<string, unknown>>\n getEncryptedFieldNames?: (entityId: EntityId, tenantId?: string | null, organizationId?: string | null) => Promise<readonly string[]>\n isEnabled?: () => boolean\n} | null\n\ntype SearchTokenSource = { entity: string; recordIdColumn: string }\n\n/**\n * Mints `search_tokens` subquery aliases (`st_0`, `st_1`, \u2026). Aliases only need\n * to be unique within a single SQL statement, so every `query()` invocation owns\n * a fresh minter. Keeping the counter call-local (rather than on the shared\n * engine instance) means concurrent queries can never reset or collide on each\n * other's sequence (#2738).\n */\nfunction createSearchAliasMinter(): () => string {\n let seq = 0\n return () => `st_${seq++}`\n}\n\nfunction createQueryProfiler(entity: string): Profiler {\n const enabled = shouldEnableProfiler(entity)\n return createProfiler({\n scope: 'query_engine',\n target: entity,\n label: `query_engine:${entity}`,\n loggerLabel: '[qe:profile]',\n enabled,\n })\n}\n\nexport class HybridQueryEngine implements QueryEngine {\n private coverageStatsTtlMs: number\n private customFieldKeysCache = new Map<string, { expiresAt: number; value: string[] }>()\n private customFieldKeysTtlMs: number\n private columnCache = new Map<string, boolean>()\n private customEntityCache = new Map<string, boolean>()\n private debugVerbosity: boolean | null = null\n private sqlDebugEnabled: boolean | null = null\n private forcePartialIndexEnabled: boolean | null = null\n private autoReindexEnabled: boolean | null = null\n private coverageOptimizationEnabled: boolean | null = null\n private pendingCoverageRefreshKeys = new Set<string>()\n\n constructor(\n private em: EntityManager,\n private fallback: BasicQueryEngine,\n private eventBusResolver?: () => Pick<EventBus, 'emitEvent'> | null | undefined,\n private vectorServiceResolver?: () => VectorIndexService | null | undefined,\n private encryptionResolver?: EncryptionResolver,\n ) {\n const coverageTtl = Number.parseInt(process.env.QUERY_INDEX_COVERAGE_CACHE_MS ?? '', 10)\n this.coverageStatsTtlMs = Number.isFinite(coverageTtl) && coverageTtl >= 0 ? coverageTtl : 5 * 60 * 1000\n const cfTtl = Number.parseInt(process.env.QUERY_INDEX_CF_KEYS_CACHE_MS ?? '', 10)\n this.customFieldKeysTtlMs = Number.isFinite(cfTtl) && cfTtl >= 0 ? cfTtl : 5 * 60 * 1000\n }\n\n private getEncryptionService() {\n try {\n return this.encryptionResolver?.() ?? null\n } catch {\n return null\n }\n }\n\n private getDb(): AnyDb {\n const emAny = this.em as any\n if (typeof emAny.getKysely === 'function') return emAny.getKysely() as AnyDb\n throw new Error('HybridQueryEngine requires an EntityManager exposing getKysely() (MikroORM v7)')\n }\n\n async query<T = unknown>(entity: EntityId, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const ext: QueryExtensionsConfig | undefined = opts.extensions\n let hybridExtCtx: QueryExtensionContext | null = null\n const noopDi = { resolve: <R = unknown>(_name: string): R => { throw new Error('No DI context') } }\n\n if (ext) {\n hybridExtCtx = {\n entity: String(entity),\n engine: 'hybrid',\n tenantId: opts.tenantId ?? '',\n organizationId: opts.organizationId,\n userId: ext.userId,\n em: this.em,\n container: ext.container,\n userFeatures: ext.userFeatures,\n }\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n const beforeResult = await runBeforeQueryPipeline(opts, hybridExtCtx, diCtx)\n if (beforeResult.blocked) {\n throw new Error(beforeResult.errorMessage ?? 'Query blocked by extension subscriber')\n }\n opts = beforeResult.query\n }\n const { extensions: _stripExt, ...coreOpts } = opts\n opts = coreOpts\n\n const providedProfiler = opts.profiler\n const profiler = providedProfiler && providedProfiler.enabled\n ? providedProfiler\n : createQueryProfiler(String(entity))\n profiler.mark('query:init')\n let profileClosed = false\n const finishProfile = (meta?: Record<string, unknown>) => {\n if (!profiler.enabled || profileClosed) return\n profileClosed = true\n profiler.end(meta)\n }\n\n const applyAfterExtensions = async <R>(queryResult: QueryResult<R>): Promise<QueryResult<R>> => {\n if (!ext || !hybridExtCtx) return queryResult\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n return await runAfterQueryPipeline(\n queryResult as QueryResult<Record<string, unknown>>,\n opts,\n hybridExtCtx,\n diCtx,\n ) as QueryResult<R>\n }\n\n try {\n const debugEnabled = this.isDebugVerbosity()\n if (debugEnabled) this.debug('query:start', { entity })\n\n const isCustom = opts.forceCustomEntityStorage === true || await this.isCustomEntity(entity)\n if (isCustom) {\n if (debugEnabled) this.debug('query:custom-entity', { entity })\n const section = profiler.section('custom_entity')\n try {\n const result = await this.queryCustomEntity<T>(entity, opts)\n section.end({ mode: 'custom_entity' })\n finishProfile({\n result: 'custom_entity',\n total: Array.isArray(result.items) ? result.items.length : undefined,\n })\n return await applyAfterExtensions(result)\n } catch (err) {\n section.end({ error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n const db = this.getDb()\n profiler.mark('query:db_ready')\n const baseTable = resolveEntityTableName(this.em, entity)\n profiler.mark('query:base_table_resolved')\n const searchConfig = resolveSearchConfig()\n const orgScope = this.resolveOrganizationScope(opts)\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n\n const baseExists = await profiler.measure('base_table_exists', () => this.tableExists(baseTable))\n if (!baseExists) {\n if (debugEnabled) this.debug('query:fallback:missing-base', { entity, baseTable })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'missing_base' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n if (opts.omitAutomaticTenantOrgScope === true) {\n if (debugEnabled) this.debug('query:fallback:omit-automatic-scope', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'omit_automatic_tenant_org_scope' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n const cfFilters = normalizedFilters.filter((filter) => filter.field.startsWith('cf:') || filter.field.startsWith('l10n:'))\n const coverageScope = this.resolveCoverageSnapshotScope(opts)\n const wantsCf = (\n (opts.fields || []).some((field) => typeof field === 'string' && (field.startsWith('cf:') || field.startsWith('l10n:'))) ||\n cfFilters.length > 0 ||\n (Array.isArray(opts.includeCustomFields) && opts.includeCustomFields.length > 0)\n )\n\n if (debugEnabled) {\n this.debug('query:config', {\n entity,\n wantsCustomFields: wantsCf,\n customFieldSources: Array.isArray(opts.customFieldSources) ? opts.customFieldSources.map((src) => src?.entityId) : undefined,\n fields: opts.fields,\n })\n }\n\n let partialIndexWarning: PartialIndexWarning | null = null\n let entityHasActiveCustomFields = true\n\n if (wantsCf) {\n entityHasActiveCustomFields = await this.entityHasActiveCustomFields(entity, opts.tenantId ?? null)\n const hasIndexRows = await profiler.measure(\n 'index_any_rows',\n () => this.indexAnyRows(entity),\n (value) => ({ hasIndexRows: value })\n )\n if (!hasIndexRows) {\n if (debugEnabled) this.debug('query:fallback:no-index', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'no_index_rows' })\n return await applyAfterExtensions(fallbackResult)\n }\n if (entityHasActiveCustomFields) {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(entity, opts, coverageScope),\n (value) => (value\n ? {\n scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { scope: null })\n )\n if (gap) {\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(entity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n const force = this.isForcePartialIndexEnabled()\n if (!force) {\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity })\n }\n const fallbackResult = await this.fallback.query(entity, opts)\n const resultWithWarning: QueryResult<T> = {\n ...fallbackResult,\n meta: {\n ...(fallbackResult.meta ?? {}),\n partialIndexWarning: {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n },\n },\n }\n finishProfile({\n result: 'fallback',\n reason: 'partial_index',\n scope: gap.scope,\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n })\n return await applyAfterExtensions(resultWithWarning)\n }\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity })\n }\n partialIndexWarning = {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n }\n } else if (debugEnabled) {\n this.debug('query:coverage:skip-no-custom-fields', { entity })\n }\n }\n\n const qualify = (col: string) => `b.${col}`\n const columns = await this.getBaseColumnsForEntity(entity)\n const hasOrganizationColumn = await this.columnExists(baseTable, 'organization_id')\n const hasTenantColumn = await this.columnExists(baseTable, 'tenant_id')\n const hasDeletedColumn = await this.columnExists(baseTable, 'deleted_at')\n\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const resolvedJoinsConfig = resolveJoins(\n baseTable,\n [...(opts.joins ?? []), ...buildFilterableCustomFieldJoins(opts.customFieldSources)],\n (entityId) => resolveEntityTableName(this.em, entityId as any),\n )\n const joinMap = new Map<string, ResolvedJoin>()\n const aliasTables = new Map<string, string>()\n aliasTables.set('b', baseTable)\n aliasTables.set('base', baseTable)\n aliasTables.set(baseTable, baseTable)\n for (const join of resolvedJoinsConfig) {\n joinMap.set(join.alias, join)\n aliasTables.set(join.alias, join.table)\n }\n const { baseFilters, joinFilters } = partitionFilters(baseTable, normalizedFilters, joinMap)\n\n const searchRuntimeBase = {\n enabled: false,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n mintAlias: createSearchAliasMinter(),\n }\n\n // Prepare index sources for JSONB custom-field access.\n const indexSources: IndexDocSource[] = [{ alias: 'ei', entityId: entity, recordIdColumn: 'b.id' }]\n let preparedCfSources: PreparedCustomFieldSource[] = []\n const shouldAttachCustomSources = Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && (wantsCf || searchEnabled)\n if (shouldAttachCustomSources) {\n preparedCfSources = this.prepareCustomFieldSources(opts.customFieldSources ?? [])\n for (const source of preparedCfSources) {\n indexSources.push({ alias: source.indexAlias, entityId: source.entityId, recordIdColumn: `${source.alias}.${source.recordIdColumn}` })\n }\n }\n\n const searchSources: SearchTokenSource[] = indexSources\n .map((src) => ({ entity: String(src.entityId), recordIdColumn: src.recordIdColumn }))\n .filter((src) => src.recordIdColumn && src.entity)\n const hasSearchTokens = searchEnabled && searchSources.length\n ? await this.searchSourcesHaveTokens(searchSources, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = { ...searchRuntimeBase, searchSources, enabled: searchEnabled && hasSearchTokens }\n const joinSearchAvailability = new Map<string, boolean>()\n const searchFilters = normalizeFilters(opts.filters).filter((filter) => filter.op === 'like' || filter.op === 'ilike')\n if (searchFilters.length) {\n this.logSearchDebug('search:init', {\n entity,\n baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n fields: searchFilters.map((filter) => String(filter.field)),\n searchEnabled,\n hasSearchTokens,\n searchSources,\n searchConfig: {\n enabled: searchConfig.enabled,\n minTokenLength: searchConfig.minTokenLength,\n enablePartials: searchConfig.enablePartials,\n hashAlgorithm: searchConfig.hashAlgorithm,\n blocklistedFields: searchConfig.blocklistedFields,\n },\n })\n if (!searchEnabled) this.logSearchDebug('search:disabled', { entity, baseTable })\n else if (!hasSearchTokens) this.logSearchDebug('search:no-search-tokens', {\n entity, baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n searchSources,\n })\n }\n const hasNonBaseSearchSource = searchSources.some(\n (src) => src.entity !== String(entity) || src.recordIdColumn !== 'b.id'\n )\n\n // Additional partial-coverage checks for customFieldSources\n if (!partialIndexWarning && Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && this.isForcePartialIndexEnabled()) {\n const seen = new Set<string>([entity])\n for (const source of opts.customFieldSources) {\n const targetEntity = source?.entityId ? String(source.entityId) : null\n if (!targetEntity || seen.has(targetEntity)) continue\n seen.add(targetEntity)\n const sourceHasCustomFields = await this.entityHasActiveCustomFields(targetEntity, opts.tenantId ?? null)\n if (!sourceHasCustomFields) {\n if (debugEnabled) this.debug('query:coverage:skip-no-custom-fields', { entity: targetEntity })\n continue\n }\n const sourceTable = source.table ?? resolveEntityTableName(this.em, targetEntity)\n try {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(targetEntity, opts, coverageScope, sourceTable),\n (value) => (value\n ? {\n entity: targetEntity, scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { entity: targetEntity, scope: null })\n )\n if (!gap) continue\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(targetEntity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n partialIndexWarning = {\n entity: targetEntity,\n entityLabel: this.resolveEntityLabel(targetEntity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n if (debugEnabled) {\n if (gap.stats) this.debug('query:partial-coverage:forced', { entity: targetEntity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n else this.debug('query:partial-coverage:forced', { entity: targetEntity })\n }\n break\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:check-failed', { entity: targetEntity, error: err instanceof Error ? err.message : err })\n }\n }\n }\n\n if (\n !partialIndexWarning &&\n wantsCf &&\n entityHasActiveCustomFields &&\n this.isForcePartialIndexEnabled() &&\n opts.tenantId\n ) {\n try {\n await this.indexCoverageStats(entity, opts, coverageScope)\n const globalStats = await this.indexCoverageStats(entity, opts, coverageScope)\n if (globalStats) {\n const globalBase = globalStats.baseCount\n const globalIndexed = globalStats.indexedCount\n const globalGap = (globalBase > 0 && globalIndexed < globalBase) || globalIndexed > globalBase\n if (globalGap) {\n console.warn('[HybridQueryEngine] Partial index coverage detected at global scope; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n partialIndexWarning = {\n entity, entityLabel: this.resolveEntityLabel(entity),\n baseCount: globalBase, indexedCount: globalIndexed, scope: 'global',\n }\n }\n }\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:global-check-failed', { entity, error: err instanceof Error ? err.message : err })\n }\n }\n\n const resolveBaseColumn = (field: string): string | null => {\n if (columns.has(field)) return field\n if (field === 'organization_id' && columns.has('id')) return 'id'\n return null\n }\n const fallbackOrgId =\n opts.organizationId\n ?? (Array.isArray(opts.organizationIds) && opts.organizationIds.length === 1 ? opts.organizationIds[0] : null)\n const encSvc = this.getEncryptionService()\n const resolvedSorts: Sort[] = []\n for (const sort of opts.sort || []) {\n const field = String(sort.field)\n if (field.startsWith('cf:')) {\n resolvedSorts.push({ ...sort, field })\n } else {\n const baseField = resolveBaseColumn(field)\n if (baseField) resolvedSorts.push({ ...sort, field: baseField })\n }\n }\n const encryptedSortFields = await resolveEncryptedSortFields(\n encSvc,\n entity,\n resolvedSorts.filter((sort) => !sort.field.startsWith('cf:')).map((sort) => sort.field),\n opts.tenantId ?? null,\n fallbackOrgId,\n )\n const requiresPlaintextSort = encryptedSortFields.size > 0\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Build a reusable \"applyQueryShape\" function that applies every\n // WHERE/JOIN/scope to a fresh SelectQueryBuilder. We use this in\n // place of knex's `.clone()` for producing count + data queries.\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const applyBaseScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (orgScope && hasOrganizationColumn) {\n next = this.applyOrganizationScope(next, qualify('organization_id'), orgScope)\n }\n if (hasTenantColumn) {\n next = next.where(qualify('tenant_id'), '=', opts.tenantId)\n }\n if (!opts.withDeleted && hasDeletedColumn) {\n next = next.where(qualify('deleted_at'), 'is', null)\n }\n return next\n }\n\n const applyEntityIndexesJoin = (q: AnyBuilder): AnyBuilder => {\n return q.leftJoin('entity_indexes as ei', (jb: any) => {\n let jc = jb\n .on('ei.entity_type', '=', String(entity))\n .onRef('ei.entity_id', '=', sql<string>`(${sql.ref(qualify('id'))}::text)`)\n if (hasOrganizationColumn) {\n jc = jc\n .onRef('ei.organization_id', '=', qualify('organization_id'))\n .on('ei.organization_id', 'is not', null)\n }\n if (hasTenantColumn) {\n jc = jc\n .onRef('ei.tenant_id', '=', qualify('tenant_id'))\n .on('ei.tenant_id', 'is not', null)\n }\n if (!opts.withDeleted) {\n jc = jc.on('ei.deleted_at', 'is', null)\n }\n return jc\n })\n }\n\n const applyCustomFieldSourceJoins = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const source of preparedCfSources) {\n const join = (opts.customFieldSources ?? []).find((s) => s && (s.alias ?? undefined) === source.alias)?.join\n if (!join) continue\n const joinType = (join.type ?? 'left') === 'inner' ? 'innerJoin' : 'leftJoin'\n next = (next as any)[joinType](`${source.table} as ${source.alias}`, (jb: any) =>\n jb.onRef(`${source.alias}.${join.toField}`, '=', qualify(join.fromField)))\n // Index join for source\n next = next.leftJoin(`entity_indexes as ${source.indexAlias}`, (jb: any) => {\n let jc = jb\n .on(`${source.indexAlias}.entity_type`, '=', String(source.entityId))\n .onRef(`${source.indexAlias}.entity_id`, '=', sql<string>`(${sql.ref(`${source.alias}.${source.recordIdColumn}`)}::text)`)\n const orgRef = source.organizationField\n ? `${source.alias}.${source.organizationField}`\n : (columns.has('organization_id') ? qualify('organization_id') : null)\n if (orgRef) {\n jc = jc\n .onRef(`${source.indexAlias}.organization_id`, '=', orgRef)\n .on(`${source.indexAlias}.organization_id`, 'is not', null)\n }\n const tenantRef = source.tenantField\n ? `${source.alias}.${source.tenantField}`\n : (columns.has('tenant_id') ? qualify('tenant_id') : null)\n if (tenantRef) {\n jc = jc\n .onRef(`${source.indexAlias}.tenant_id`, '=', tenantRef)\n .on(`${source.indexAlias}.tenant_id`, 'is not', null)\n }\n if (!opts.withDeleted) jc = jc.on(`${source.indexAlias}.deleted_at`, 'is', null)\n return jc\n })\n }\n return next\n }\n\n const applyCfFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of cfFilters) {\n next = this.applyCfFilterAcrossSources(\n next, filter.field, filter.op, filter.value, indexSources, searchRuntime,\n )\n }\n return next\n }\n\n const regularBaseFilters = baseFilters.filter((filter) => !filter.orGroup)\n const orGroupFilters = baseFilters.filter((filter) => filter.orGroup)\n\n const applyRegularBaseFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of regularBaseFilters) {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n next = this.applyIndexDocFilterFromAlias(\n next, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime,\n )\n continue\n }\n const column = qualify(baseField)\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime,\n entity, field: fieldName, recordIdColumn: 'b.id',\n })\n }\n return next\n }\n\n const applyOrGroupedBaseFilters = (q: AnyBuilder): AnyBuilder => {\n if (orGroupFilters.length === 0) return q\n const groups = new Map<string, BaseFilter[]>()\n for (const filter of orGroupFilters) {\n if (!filter.orGroup) continue\n const existing = groups.get(filter.orGroup) ?? []\n existing.push(filter)\n groups.set(filter.orGroup, existing)\n }\n const groupList = Array.from(groups.values()).filter((g) => g.length > 0)\n if (groupList.length === 0) return q\n // Combine all groups in a single WHERE: disjuncts are OR'd together; within\n // each disjunct, fields are AND'd. Building this as separate `.where()` calls\n // would AND the disjuncts (wrong semantics).\n return q.where((eb: any) => eb.or(\n groupList.map((groupFilters) => {\n const parts = groupFilters.map((filter) =>\n this.buildBaseFilterExpression(eb, filter, resolveBaseColumn, qualify, entity, searchRuntime),\n )\n return parts.length === 1 ? parts[0] : eb.and(parts)\n }),\n ))\n }\n\n const applyAliasScopes = async (target: AnyBuilder, aliasName: string): Promise<AnyBuilder> => {\n let next = target\n const tableName = aliasTables.get(aliasName)\n if (!tableName) return next\n if (orgScope && await this.columnExists(tableName, 'organization_id')) {\n next = this.applyOrganizationScope(next, `${aliasName}.organization_id`, orgScope)\n }\n if (opts.tenantId && await this.columnExists(tableName, 'tenant_id')) {\n next = next.where(`${aliasName}.tenant_id`, '=', opts.tenantId)\n }\n if (!opts.withDeleted && await this.columnExists(tableName, 'deleted_at')) {\n next = next.where(`${aliasName}.deleted_at`, 'is', null)\n }\n return next\n }\n\n const applyJoinFilterOpFn = (target: AnyBuilder, column: string, op: FilterOp, value?: unknown): AnyBuilder => {\n switch (op) {\n case 'eq': return target.where(column, '=', value as any)\n case 'ne': return target.where(column, '!=', value as any)\n case 'gt': return target.where(column, '>', value as any)\n case 'gte': return target.where(column, '>=', value as any)\n case 'lt': return target.where(column, '<', value as any)\n case 'lte': return target.where(column, '<=', value as any)\n case 'in': return target.where(column, 'in', this.toArray(value))\n case 'nin': return target.where(column, 'not in', this.toArray(value))\n case 'like': return target.where(column, 'like', value as any)\n case 'ilike': return target.where(column, 'ilike', value as any)\n case 'exists': return value ? target.where(column, 'is not', null) : target.where(column, 'is', null)\n default: return target\n }\n }\n\n const applyJoinSearchFilterOp = async (\n target: AnyBuilder,\n filter: { column: string; op: FilterOp; value?: unknown },\n _qualified: string,\n join: ResolvedJoin,\n ): Promise<boolean> => {\n if (!searchEnabled || !join.entityId) return false\n if (!['like', 'ilike'].includes(filter.op)) return false\n if (typeof filter.value !== 'string' || filter.value.trim().length === 0) return false\n\n let searchAvailable = joinSearchAvailability.get(join.entityId)\n if (searchAvailable === undefined) {\n searchAvailable = await this.hasSearchTokens(String(join.entityId), opts.tenantId ?? null, orgScope)\n joinSearchAvailability.set(join.entityId, searchAvailable)\n }\n if (!searchAvailable) return false\n\n const tokens = tokenizeText(String(filter.value), searchConfig)\n if (!tokens.hashes.length) return false\n\n return this.applySearchTokens(target, {\n entity: String(join.entityId),\n field: filter.column,\n hashes: tokens.hashes,\n recordIdColumn: `${join.alias}.id`,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n mintAlias: searchRuntime.mintAlias,\n })\n }\n\n const applyQueryShape = async (q: AnyBuilder): Promise<AnyBuilder> => {\n let next = applyBaseScope(q)\n next = applyEntityIndexesJoin(next)\n next = applyCustomFieldSourceJoins(next)\n next = applyCfFilters(next)\n next = applyRegularBaseFilters(next)\n next = applyOrGroupedBaseFilters(next)\n // applyJoinFilters is the shared helper that handles `joinFilters` (ALIAS:col -> value).\n next = await applyJoinFilters({\n db,\n baseTable,\n builder: next,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n return next\n }\n\n const hasCustomFieldFilters = cfFilters.length > 0\n const canOptimizeCount = !hasCustomFieldFilters && !hasNonBaseSearchSource\n\n // Selection (for data query)\n const selectFieldSet = new Set<string>((opts.fields && opts.fields.length) ? opts.fields.map(String) : Array.from(columns.keys()))\n if (requiresPlaintextSort) {\n for (const field of encryptedSortFields) selectFieldSet.add(field)\n }\n if (opts.includeCustomFields === true) {\n const entityIds = Array.from(new Set(indexSources.map((src) => String(src.entityId))))\n try {\n const resolvedKeys = await this.resolveAvailableCustomFieldKeys(entityIds, opts.tenantId ?? null)\n resolvedKeys.forEach((key) => selectFieldSet.add(`cf:${key}`))\n if (this.isDebugVerbosity()) this.debug('query:cf:resolved-keys', { entity, keys: resolvedKeys })\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to resolve custom field keys for', entity, err)\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n opts.includeCustomFields.map((key) => String(key)).forEach((key) => selectFieldSet.add(`cf:${key}`))\n }\n const selectFields = Array.from(selectFieldSet)\n\n const applySelection = (q: AnyBuilder, fieldsOverride?: string[]): AnyBuilder => {\n let next = q\n const fields = fieldsOverride ?? selectFields\n for (const field of fields) {\n const fieldName = String(field)\n if (fieldName.startsWith('cf:')) {\n const alias = this.sanitize(fieldName)\n const jsonExpr = this.buildCfJsonExprSql(fieldName, indexSources)\n const exprRaw = jsonExpr ?? sql`NULL::jsonb`\n next = next.select(exprRaw.as(alias))\n } else if (columns.has(fieldName)) {\n next = next.select(`${qualify(fieldName)} as ${fieldName}`)\n }\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (requiresPlaintextSort) return next\n for (const s of resolvedSorts) {\n const fieldName = String(s.field)\n if (fieldName.startsWith('cf:')) {\n const textExpr = this.buildCfTextExprSql(fieldName, indexSources)\n if (textExpr) {\n const direction = sql.raw(coerceSortDirection(s.dir))\n next = next.orderBy(sql`${textExpr} ${direction}`)\n }\n } else {\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) continue\n next = next.orderBy(qualify(baseField), s.dir ?? SortDir.Asc)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n const sqlDebugEnabled = this.isSqlDebugEnabled()\n\n let total: number\n\n if (canOptimizeCount) {\n // Optimized count: apply only base-scope + regular filters + or-group filters (no index joins).\n const optimizedRoot = db.selectFrom(`${baseTable} as b` as any)\n let countCore = applyBaseScope(optimizedRoot)\n countCore = applyRegularBaseFilters(countCore)\n countCore = applyOrGroupedBaseFilters(countCore)\n // joinFilters still need to be re-applied in the optimized path\n countCore = await applyJoinFilters({\n db,\n baseTable,\n builder: countCore,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n const sub = countCore.select(sql.ref(qualify('id')).as('id')).groupBy(qualify('id')).as('sq')\n const countQuery = db.selectFrom(sub as any).select(sql<string>`count(*)`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countQuery.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countQuery.executeTakeFirst(),\n { optimized: true }, profiler,\n )\n total = this.parseCount(countRow)\n } else {\n const countRoot = db.selectFrom(`${baseTable} as b` as any)\n const countBuilder = (await applyQueryShape(countRoot))\n .select(sql<string>`count(distinct ${sql.ref(qualify('id'))})`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countBuilder.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countBuilder.executeTakeFirst(),\n { optimized: false }, profiler,\n )\n total = this.parseCount(countRow)\n }\n\n const dekKeyCache = new Map<string | null, string | null>()\n\n const decryptRow = async (item: Record<string, unknown>): Promise<Record<string, unknown>> => {\n let next = item\n if (encSvc?.decryptEntityPayload) {\n const decrypt = encSvc.decryptEntityPayload.bind(encSvc) as (\n entityId: EntityId, payload: Record<string, unknown>, tenantId: string | null, organizationId: string | null,\n ) => Promise<Record<string, unknown>>\n try {\n const decrypted = await decrypt(\n entity, next,\n (next?.tenant_id ?? next?.tenantId ?? opts.tenantId ?? null) as string | null,\n (next?.organization_id ?? next?.organizationId ?? fallbackOrgId ?? null) as string | null,\n )\n next = { ...next, ...decrypted }\n } catch (err) {\n console.error('Error decrypting entity payload', err)\n }\n }\n if (encSvc) {\n try {\n next = await decryptIndexDocCustomFields(\n next,\n {\n tenantId: (next?.tenant_id ?? next?.tenantId ?? opts.tenantId ?? null) as string | null,\n organizationId: (next?.organization_id ?? next?.organizationId ?? null) as string | null,\n },\n encSvc as any, dekKeyCache,\n )\n } catch { /* keep next as-is */ }\n }\n return next\n }\n\n let items: Record<string, unknown>[]\n let encryptedSortRowCapWarning: EncryptedSortRowCapWarning | undefined\n\n if (requiresPlaintextSort) {\n // Phase 1: slim id+sort-columns candidate scan, bounded-concurrency decrypt,\n // in-memory sort over the full candidate set, then slice to the page's ids.\n const cap = resolveEncryptedSortMaxRows()\n const phase1Root = db.selectFrom(`${baseTable} as b` as any)\n let phase1 = await applyQueryShape(phase1Root)\n const scopeFieldNames = [\n hasTenantColumn ? 'tenant_id' : null,\n hasOrganizationColumn ? 'organization_id' : null,\n ].filter((field): field is string => field !== null)\n const sortFieldNames = Array.from(new Set(['id', ...scopeFieldNames, ...resolvedSorts.map((s) => String(s.field))]))\n phase1 = applySelection(phase1, sortFieldNames)\n if (cap !== null) {\n phase1 = phase1.limit(cap).orderBy(qualify('id'), 'asc' as any)\n }\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = phase1.compile()\n this.debug('query:sql:data:phase1', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const candidateRows = await this.captureSqlTiming(\n 'query:sql:data:phase1', entity,\n () => phase1.execute(),\n { phase: 1 }, profiler,\n ) as Record<string, unknown>[]\n const decryptedCandidates = await mapWithConcurrency(candidateRows, DECRYPT_CONCURRENCY, decryptRow)\n const orderedCandidates = sortRowsInMemory(decryptedCandidates, resolvedSorts)\n const pageIds = orderedCandidates\n .slice((page - 1) * pageSize, page * pageSize)\n .map((row) => row.id)\n\n if (cap !== null && total > cap) {\n encryptedSortRowCapWarning = {\n entity,\n sortFields: resolvedSorts.map((s) => String(s.field)),\n maxRows: cap,\n totalMatched: total,\n }\n }\n\n // Phase 2: fetch + decrypt full rows for just the page's ids, then reassemble\n // in phase-1's order (SQL `WHERE id IN (...)` order is unspecified \u2014 never\n // trust it for ordering).\n if (pageIds.length === 0) {\n items = []\n } else {\n const phase2Root = db.selectFrom(`${baseTable} as b` as any)\n let phase2 = await applyQueryShape(phase2Root)\n phase2 = applySelection(phase2)\n phase2 = phase2.where(qualify('id'), 'in', pageIds)\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = phase2.compile()\n this.debug('query:sql:data:phase2', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const pageRowsRaw = await this.captureSqlTiming(\n 'query:sql:data:phase2', entity,\n () => phase2.execute(),\n { phase: 2 }, profiler,\n ) as Record<string, unknown>[]\n const decryptedPageRows = await mapWithConcurrency(pageRowsRaw, DECRYPT_CONCURRENCY, decryptRow)\n const byId = new Map(decryptedPageRows.map((row) => [String(row.id), row]))\n items = pageIds\n .map((id) => byId.get(String(id)))\n .filter((row): row is Record<string, unknown> => row != null)\n }\n } else {\n const dataRoot = db.selectFrom(`${baseTable} as b` as any)\n let dataBuilder = await applyQueryShape(dataRoot)\n dataBuilder = applySelection(dataBuilder)\n dataBuilder = applySort(dataBuilder)\n dataBuilder = dataBuilder.limit(pageSize).offset((page - 1) * pageSize)\n\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = dataBuilder.compile()\n this.debug('query:sql:data', { entity, sql: compiled.sql, bindings: compiled.parameters, page, pageSize })\n }\n const itemsRaw = await this.captureSqlTiming(\n 'query:sql:data', entity,\n () => dataBuilder.execute(),\n { page, pageSize }, profiler,\n ) as Record<string, unknown>[]\n items = await mapWithConcurrency(itemsRaw, DECRYPT_CONCURRENCY, decryptRow)\n }\n if (debugEnabled) this.debug('query:complete', { entity, total, items: items.length })\n\n const typedItems = items as unknown as T[]\n let result: QueryResult<T> = { items: typedItems, page, pageSize, total }\n if (partialIndexWarning || encryptedSortRowCapWarning) {\n const meta: QueryResultMeta = {}\n if (partialIndexWarning) meta.partialIndexWarning = partialIndexWarning\n if (encryptedSortRowCapWarning) meta.encryptedSortRowCapWarning = encryptedSortRowCapWarning\n result.meta = meta\n }\n\n result = await applyAfterExtensions(result)\n finishProfile({\n result: 'ok', total, page, pageSize,\n itemCount: Array.isArray(items) ? items.length : undefined,\n partialIndexWarning: partialIndexWarning ? true : false,\n })\n return result\n } catch (err) {\n finishProfile({ result: 'error', error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n private prepareCustomFieldSources(\n sources: QueryCustomFieldSource[],\n ): PreparedCustomFieldSource[] {\n const prepared: PreparedCustomFieldSource[] = []\n sources.forEach((source, index) => {\n if (!source) return\n const joinTable = source.table ?? resolveEntityTableName(this.em, source.entityId)\n const alias = source.alias ?? `cfs_${index}`\n if (!source.join) {\n throw new Error(`QueryEngine: customFieldSources entry for ${String(source.entityId)} requires a join configuration`)\n }\n prepared.push({\n alias,\n indexAlias: `ei_${alias}`,\n entityId: source.entityId,\n recordIdColumn: source.recordIdColumn ?? 'id',\n organizationField: source.organizationField,\n tenantField: source.tenantField,\n table: joinTable,\n })\n })\n return prepared\n }\n\n private async isCustomEntity(entity: string): Promise<boolean> {\n const cached = this.customEntityCache.get(entity)\n if (cached !== undefined) return cached\n let result = false\n try {\n const db = this.getDb() as any\n const row = await db\n .selectFrom('custom_entities')\n .select('id')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .executeTakeFirst()\n if (row) {\n result = true\n } else if (resolveRegisteredEntityTableName(this.em, entity) !== null) {\n // An id backed by a registered ORM table is never doc-storage-backed by\n // inference: stray `custom_entities_storage` rows for such an id (e.g. written\n // through the generic entities data engine) must not hijack every list/detail\n // read for the whole entity type away from its base table (#2939). Surfaces\n // that intentionally read doc records for a dual-declared id pass\n // `forceCustomEntityStorage` in QueryOptions instead.\n result = false\n } else {\n // Read/write symmetry. Records written through the entities data engine\n // (`de.createCustomEntityRecord`) always land in `custom_entities_storage`,\n // even for module-declared custom entities whose id is also a frozen system\n // id \u2014 those are NEVER registered in `custom_entities` (install treats a\n // system id as non-registrable). Without this fallback the query routes to\n // the empty ORM/index path and those records are write-only (created with\n // 200 but unreadable on the edit form).\n result = await this.hasCustomEntityStorageRows(entity)\n }\n } catch {\n result = false\n }\n this.customEntityCache.set(entity, result)\n return result\n }\n\n private async hasCustomEntityStorageRows(entity: string): Promise<boolean> {\n try {\n const db = this.getDb() as any\n const row = await db\n .selectFrom('custom_entities_storage')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n .limit(1)\n .executeTakeFirst()\n return !!row\n } catch {\n return false\n }\n }\n\n /**\n * Adds a WHERE EXISTS / OR WHERE EXISTS subquery that matches\n * `search_tokens` for the supplied (entity, field) against the\n * provided record id column.\n *\n * Returns true when the sub-query was applied (i.e. tokens were\n * non-empty). Caller is responsible for the calling context\n * (direct where vs. inside `eb.or([...])`).\n */\n private applySearchTokens(\n q: AnyBuilder,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n combineWith?: 'and' | 'or'\n mintAlias: () => string\n }\n ): boolean {\n if (!opts.hashes.length) {\n this.logSearchDebug('search:skip-no-hashes', {\n entity: opts.entity, field: opts.field,\n tenantId: opts.tenantId ?? null, organizationScope: opts.organizationScope,\n })\n return false\n }\n const alias = opts.mintAlias()\n this.logSearchDebug('search:apply-search-tokens', {\n entity: opts.entity, field: opts.field, alias,\n tokenCount: opts.hashes.length,\n tenantId: opts.tenantId ?? null,\n organizationScope: opts.organizationScope,\n combineWith: opts.combineWith ?? 'and',\n })\n\n const engine = this\n const buildSub = (eb: any) => {\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = engine.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n if (opts.combineWith === 'or') {\n // When called inside an .or([...]) array the caller supplied `eb`.\n // `q` is the ExpressionBuilder callable (eb) itself in that case.\n // We return the expression node rather than mutating q.\n ;(q as any).__pendingOrExists = buildSub(q)\n return true\n }\n\n // Default: append WHERE EXISTS (...) to the outer builder.\n ;(q as any).__applied = true\n const built = buildSub(q)\n // If q is a Kysely builder (has .where), use eb => eb.exists(sub)\n if (typeof q.where === 'function') {\n ;(q as any) = q.where((eb: any) => eb.exists(built))\n }\n return true\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as JSON across a single alias. */\n private jsonbSqlAlias(alias: string, key: string): RawBuilder<unknown> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql`coalesce(${sql.ref(alias + '.doc')} -> ${key}, ${sql.ref(alias + '.doc')} -> ${bare})`\n }\n return sql`${sql.ref(alias + '.doc')} -> ${key}`\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as text across a single alias. */\n private cfTextExprAlias(alias: string, key: string): RawBuilder<string | null> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql<string | null>`coalesce((${sql.ref(alias + '.doc')} ->> ${key}), (${sql.ref(alias + '.doc')} ->> ${bare}))`\n }\n return sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n }\n\n /** Build JSON/text SQL expressions across multiple index alias sources (coalesce over them). */\n private buildCfJsonExprSql(key: string, sources: IndexDocSource[]): RawBuilder<unknown> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.jsonbSqlAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private buildCfTextExprSql(key: string, sources: IndexDocSource[]): RawBuilder<string | null> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.cfTextExprAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql<string | null>`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private applyCfFilterAcrossSources(\n builder: AnyBuilder,\n key: string,\n op: FilterOp,\n value: unknown,\n sources: IndexDocSource[],\n search?: SearchRuntime\n ): AnyBuilder {\n if (!sources.length) return builder\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = this.applyMultiSourceSearchExists(builder, sources, key, hashes, search)\n this.logSearchDebug('search:cf-filter-across', {\n entity: sources.map((src) => src.entityId),\n field: key, tokens: tokens.tokens, hashes, applied,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n if (applied.builder !== builder) return applied.builder\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', {\n entity: sources.map((src) => src.entityId), field: key, value,\n })\n }\n return builder\n }\n\n const textExpr = this.buildCfTextExprSql(key, sources)\n const jsonExpr = this.buildCfJsonExprSql(key, sources)\n if (!textExpr || !jsonExpr) return builder\n\n const arrContains = (val: unknown) => sql<boolean>`${jsonExpr} @> ${JSON.stringify([val])}::jsonb`\n\n switch (op) {\n case 'eq':\n return builder.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return builder.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const values = this.toArray(value)\n return builder.where((eb: any) => eb.or(\n values.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const values = this.toArray(value)\n return builder.where(sql<boolean>`${textExpr} not in (${sql.join(values.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return builder.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return builder.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? builder.where(sql<boolean>`${textExpr} is not null`)\n : builder.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return builder.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return builder\n }\n }\n\n /** Apply a search-token EXISTS subquery across multiple sources (OR-joined). */\n private applyMultiSourceSearchExists(\n builder: AnyBuilder,\n sources: IndexDocSource[],\n key: string,\n hashes: string[],\n search: SearchRuntime,\n ): { builder: AnyBuilder; applied: boolean } {\n if (!sources.length || !hashes.length) return { builder, applied: false }\n const next = builder.where((eb: any) => eb.or(\n sources.map((source) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: String(source.entityId),\n field: key, hashes,\n recordIdColumn: `${source.alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n }))\n )\n ))\n return { builder: next, applied: true }\n }\n\n /** Construct a search-token EXISTS subquery using the given ExpressionBuilder. */\n private buildSearchTokensSub(\n eb: any,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n mintAlias: () => string\n }\n ): any {\n const alias = opts.mintAlias()\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = this.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n private applyCfFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n search?: SearchRuntime\n ): AnyBuilder {\n const textExpr = this.cfTextExprAlias(alias, key)\n const arrExpr = sql<unknown>`(${sql.ref(alias + '.doc')} -> ${key})`\n const arrContains = (val: unknown) => sql<boolean>`${arrExpr} @> ${JSON.stringify([val])}::jsonb`\n\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes,\n recordIdColumn: `${alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n })))\n this.logSearchDebug('search:cf-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where((eb: any) => eb.or(\n vals.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n private applyIndexDocFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n recordIdColumn: string,\n search?: SearchRuntime,\n ): AnyBuilder {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes, recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n })))\n this.logSearchDebug('search:index-doc-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:index-doc-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where(sql<boolean>`${textExpr} = ${value}`)\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n /**\n * Build a single OR-group base filter expression as a Kysely predicate\n * (no side effects on the outer builder).\n */\n private buildBaseFilterExpression(\n eb: any,\n filter: BaseFilter,\n resolveBaseColumn: (field: string) => string | null,\n qualify: (col: string) => string,\n entity: EntityId,\n searchRuntime: SearchRuntime,\n ): any {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n // Doc-based filter via `ei` alias \u2014 returned as EXISTS where possible\n return this.buildIndexDocFilterExpression(eb, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime)\n }\n // For like/ilike with active search-tokens, route through hashed-token EXISTS subquery\n // so encrypted-at-rest columns can still be searched.\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n searchRuntime?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), searchRuntime.config)\n if (tokens.hashes.length) {\n const sources: SearchTokenSource[] = (searchRuntime.searchSources && searchRuntime.searchSources.length\n ? searchRuntime.searchSources\n : [{ entity: String(entity), recordIdColumn: 'b.id' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n return eb.or(\n sources.map((src) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: src.entity,\n field: fieldName,\n hashes: tokens.hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: searchRuntime.tenantId ?? null,\n organizationScope: searchRuntime.organizationScope ?? null,\n mintAlias: searchRuntime.mintAlias,\n })),\n ),\n )\n }\n }\n // Tokenizer produced no hashes (e.g. value too short). Match the regular-base-filter\n // path's behavior of skipping the predicate (no filter), which is preferable to\n // silently turning into a plain `ilike` against an encrypted column.\n return sql<boolean>`true`\n }\n return this.buildColumnFilterExpression(eb, qualify(baseField), filter.op, filter.value)\n }\n\n private buildColumnFilterExpression(\n eb: any,\n column: string,\n op: FilterOp,\n value: unknown,\n ): any {\n switch (op) {\n case 'eq': return eb(column, '=', value)\n case 'ne': return eb(column, '!=', value)\n case 'gt': return eb(column, '>', value)\n case 'gte': return eb(column, '>=', value)\n case 'lt': return eb(column, '<', value)\n case 'lte': return eb(column, '<=', value)\n case 'in': return eb(column, 'in', this.toArray(value))\n case 'nin': return eb(column, 'not in', this.toArray(value))\n case 'like': return eb(column, 'like', value)\n case 'ilike': return eb(column, 'ilike', value)\n case 'exists': return eb(column, value ? 'is not' : 'is', null)\n default: return sql<boolean>`true`\n }\n }\n\n private buildIndexDocFilterExpression(\n eb: any,\n alias: string,\n _entity: EntityId,\n key: string,\n op: FilterOp,\n value: unknown,\n _recordIdColumn: string,\n _search?: SearchRuntime,\n ): any {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n switch (op) {\n case 'eq': return sql<boolean>`${textExpr} = ${value}`\n case 'ne': return sql<boolean>`${textExpr} <> ${value}`\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return sql<boolean>`${textExpr} ${operator} ${value}`\n }\n case 'like': return sql<boolean>`${textExpr} like ${value}`\n case 'ilike': return sql<boolean>`${textExpr} ilike ${value}`\n case 'in': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'nin': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'exists':\n return value ? sql<boolean>`${textExpr} is not null` : sql<boolean>`${textExpr} is null`\n default:\n return sql<boolean>`true`\n }\n }\n\n private async queryCustomEntity<T = unknown>(entity: string, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const db = this.getDb() as any\n const alias = 'ce'\n\n const orgScope = this.resolveOrganizationScope(opts)\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const searchConfig = resolveSearchConfig()\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n const hasSearchTokens = searchEnabled\n ? await this.hasSearchTokens(entity, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = {\n enabled: searchEnabled && hasSearchTokens,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n mintAlias: createSearchAliasMinter(),\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n\n const applyScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n .where(`${alias}.entity_type`, '=', entity)\n .where(`${alias}.tenant_id`, '=', opts.tenantId)\n if (orgScope) {\n next = this.applyOrganizationScope(next, `${alias}.organization_id`, orgScope)\n }\n if (!opts.withDeleted) next = next.where(`${alias}.deleted_at`, 'is', null)\n for (const filter of normalizedFilters) {\n if (filter.field.startsWith('cf:')) {\n next = this.applyCfFilterFromAlias(next, alias, entity, filter.field, filter.op, filter.value, searchRuntime)\n continue\n }\n const column = this.resolveCustomEntityColumn(alias, String(filter.field))\n if (column) {\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n continue\n }\n // Unknown field \u2192 filter on doc JSON text\n const docExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${String(filter.field)})`\n next = this.applyColumnFilter(next, docExpr, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n }\n return next\n }\n\n // Determine CFs and l10n keys to include\n const cfKeys = new Set<string>()\n for (const f of (opts.fields || [])) {\n if (typeof f === 'string' && f.startsWith('cf:')) cfKeys.add(f.slice(3))\n else if (typeof f === 'string' && f.startsWith('l10n:')) cfKeys.add(f)\n }\n for (const filter of normalizedFilters) {\n if (typeof filter.field === 'string' && filter.field.startsWith('cf:')) cfKeys.add(filter.field.slice(3))\n else if (typeof filter.field === 'string' && filter.field.startsWith('l10n:')) cfKeys.add(filter.field)\n }\n if (opts.includeCustomFields === true) {\n try {\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .where('tenant_id', '=', opts.tenantId)\n .execute() as Array<{ key: unknown }>\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string') cfKeys.add(key)\n else if (key != null) cfKeys.add(String(key))\n }\n } catch {\n // ignore\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n for (const k of opts.includeCustomFields) cfKeys.add(k)\n }\n\n const applySelection = (q: AnyBuilder): AnyBuilder => {\n let next = q\n const requested = (opts.fields && opts.fields.length) ? opts.fields : ['id']\n for (const field of requested) {\n const f = String(field)\n if (f.startsWith('cf:')) {\n const aliasName = this.sanitize(f)\n next = next.select(this.jsonbSqlAlias(alias, f).as(aliasName))\n } else if (f === 'id') {\n next = next.select(`${alias}.entity_id as id`)\n } else if (f === 'created_at' || f === 'updated_at' || f === 'deleted_at') {\n next = next.select(`${alias}.${f} as ${f}`)\n } else {\n const expr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${f})`\n next = next.select(expr.as(f))\n }\n }\n // Ensure CF fields for sort / includeCustomFields are selected\n for (const key of cfKeys) {\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.select(this.jsonbSqlAlias(alias, `cf:${key}`).as(aliasName))\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const s of opts.sort || []) {\n if (s.field.startsWith('cf:')) {\n const key = s.field.slice(3)\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.orderBy(aliasName, s.dir ?? SortDir.Asc)\n } else if (s.field === 'id') {\n next = next.orderBy(`${alias}.entity_id`, s.dir ?? SortDir.Asc)\n } else if (s.field === 'created_at' || s.field === 'updated_at' || s.field === 'deleted_at') {\n next = next.orderBy(`${alias}.${s.field}`, s.dir ?? SortDir.Asc)\n } else {\n const direction = sql.raw(coerceSortDirection(s.dir))\n next = next.orderBy(sql`(${sql.ref(alias + '.doc')} ->> ${s.field}) ${direction}`)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n\n const root = db.selectFrom(`custom_entities_storage as ${alias}`)\n const countQuery = applyScope(root).select(sql<string>`count(distinct ${sql.ref(`${alias}.entity_id`)})`.as('count'))\n const countRow = await countQuery.executeTakeFirst()\n const total = this.parseCount(countRow)\n\n let dataQuery = applyScope(db.selectFrom(`custom_entities_storage as ${alias}`))\n dataQuery = applySelection(dataQuery)\n dataQuery = applySort(dataQuery)\n dataQuery = dataQuery.limit(pageSize).offset((page - 1) * pageSize)\n const items = await dataQuery.execute()\n return { items, page, pageSize, total }\n }\n\n private async tableExists(table: string): Promise<boolean> {\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.tables')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .executeTakeFirst()\n return !!exists\n }\n\n private async hasSearchTokens(\n entity: string,\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n try {\n const db = this.getDb() as any\n let query = db\n .selectFrom('search_tokens')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n if (tenantId !== undefined) {\n query = query.where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n }\n if (orgScope) {\n query = this.applyOrganizationScope(query, 'search_tokens.organization_id', orgScope)\n }\n const row = await query.limit(1).executeTakeFirst()\n return !!row\n } catch (err) {\n this.logSearchDebug('search:has-tokens-error', {\n entity, tenantId, organizationScope: orgScope,\n error: err instanceof Error ? err.message : String(err),\n })\n return false\n }\n }\n\n private async searchSourcesHaveTokens(\n sources: SearchTokenSource[],\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n for (const source of sources) {\n const ok = await this.hasSearchTokens(source.entity, tenantId, orgScope)\n this.logSearchDebug('search:source-has-tokens', {\n entity: source.entity, recordIdColumn: source.recordIdColumn,\n tenantId, organizationScope: orgScope, hasTokens: ok,\n })\n if (ok) return true\n }\n return false\n }\n\n private async resolveAvailableCustomFieldKeys(entityIds: string[], tenantId: string | null): Promise<string[]> {\n if (!entityIds.length) return []\n const cacheKey = this.customFieldKeysCacheKey(entityIds, tenantId)\n const now = Date.now()\n const cached = this.customFieldKeysCache.get(cacheKey)\n if (cached && cached.expiresAt > now) return cached.value.slice()\n\n const db = this.getDb() as any\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', 'in', entityIds)\n .where('is_active', '=', true)\n .where((eb: any) => eb.or([\n eb('tenant_id', '=', tenantId),\n eb('tenant_id', 'is', null),\n ]))\n .execute() as Array<{ key: unknown }>\n const keys = new Set<string>()\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string' && key.trim().length) keys.add(key.trim())\n else if (key != null) keys.add(String(key))\n }\n const result = Array.from(keys)\n if (this.customFieldKeysTtlMs > 0) {\n this.customFieldKeysCache.set(cacheKey, { expiresAt: now + this.customFieldKeysTtlMs, value: result })\n }\n return result.slice()\n }\n\n private async entityHasActiveCustomFields(entityId: string, tenantId: string | null): Promise<boolean> {\n try {\n const keys = await this.resolveAvailableCustomFieldKeys([entityId], tenantId)\n return keys.length > 0\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('query:cf:check-error', {\n entity: entityId, tenantId: tenantId ?? null,\n error: err instanceof Error ? err.message : err,\n })\n }\n return true\n }\n }\n\n private customFieldKeysCacheKey(entityIds: string[], tenantId: string | null): string {\n const sorted = entityIds.slice().sort((a, b) => a.localeCompare(b)).join(',')\n return `${tenantId ?? '__none__'}|${sorted}`\n }\n\n private resolveVectorService(): VectorIndexService | null {\n if (!this.vectorServiceResolver) return null\n try {\n return this.vectorServiceResolver() ?? null\n } catch {\n return null\n }\n }\n\n private resolveEntityLabel(entity: string): string {\n return entity\n }\n\n private async indexAnyRows(entity: string): Promise<boolean> {\n const db = this.getDb() as any\n const coverage = await db\n .selectFrom('entity_index_coverage')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n .where('indexed_count', '>', 0)\n .executeTakeFirst()\n if (coverage) return true\n const exists = await db\n .selectFrom('entity_indexes')\n .select('entity_id')\n .where('entity_type', '=', entity)\n .executeTakeFirst()\n return !!exists\n }\n\n private async getStoredCoverageSnapshot(\n entity: string,\n tenantId: string | null,\n organizationId: string | null,\n withDeleted: boolean\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n try {\n const db = this.getDb()\n const scope = {\n entityType: entity, tenantId, organizationId, withDeleted,\n }\n const row = await readCoverageSnapshot(db as any, scope)\n if (row && this.isCoverageSnapshotFresh(row)) {\n return { baseCount: row.baseCount, indexedCount: row.indexedCount }\n }\n\n if (this.isCoverageOptimizationEnabled()) {\n this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)\n if (!row) return null\n return { baseCount: row.baseCount, indexedCount: row.indexedCount }\n }\n\n await refreshCoverageSnapshot(this.em, scope)\n const refreshed = await readCoverageSnapshot(db as any, scope)\n if (!refreshed) return null\n return { baseCount: refreshed.baseCount, indexedCount: refreshed.indexedCount }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:snapshot:read-error', {\n entity, tenantId, organizationId, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n return null\n }\n }\n\n private isCoverageSnapshotFresh(\n row: Awaited<ReturnType<typeof readCoverageSnapshot>>\n ): boolean {\n if (this.coverageStatsTtlMs <= 0) return false\n if (!row) return false\n const refreshedAt = row.refreshed_at instanceof Date\n ? row.refreshed_at\n : row.refreshed_at\n ? new Date(row.refreshed_at)\n : null\n const refreshedAtMs = refreshedAt?.getTime()\n if (!refreshedAtMs || !Number.isFinite(refreshedAtMs)) return false\n return Date.now() - refreshedAtMs <= this.coverageStatsTtlMs\n }\n\n private scheduleAutoReindex(\n entity: string,\n opts: QueryOptions,\n stats?: { baseCount: number; indexedCount: number },\n organizationIdOverride?: string | null\n ) {\n if (!this.isAutoReindexEnabled()) return\n const bus = this.resolveEventBus()\n if (!bus) return\n const payload = {\n entityType: entity,\n tenantId: opts.tenantId ?? null,\n organizationId: organizationIdOverride ?? opts.organizationId ?? null,\n force: false,\n }\n const context = stats\n ? { entity, tenantId: payload.tenantId, organizationId: payload.organizationId, baseCount: stats.baseCount, indexedCount: stats.indexedCount }\n : { entity, tenantId: payload.tenantId, organizationId: payload.organizationId }\n\n void Promise.resolve().then(async () => {\n try {\n await bus.emitEvent('query_index.reindex', payload, { persistent: true })\n if (this.isDebugVerbosity()) this.debug('query:auto-reindex:scheduled', context)\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to schedule auto reindex:', {\n ...context, error: err instanceof Error ? err.message : err,\n })\n }\n })\n }\n\n private scheduleCoverageRefresh(\n entity: string,\n tenantId: string | null | undefined,\n organizationId: string | null | undefined,\n withDeleted: boolean\n ): void {\n const bus = this.resolveEventBus()\n if (!bus) return\n const key = [entity, tenantId ?? '__tenant__', organizationId ?? '__org__', withDeleted ? '1' : '0'].join('|')\n if (this.pendingCoverageRefreshKeys.has(key)) return\n this.pendingCoverageRefreshKeys.add(key)\n void Promise.resolve()\n .then(async () => {\n try {\n await bus.emitEvent('query_index.coverage.refresh', {\n entityType: entity,\n tenantId: tenantId ?? null, organizationId: organizationId ?? null,\n withDeleted, delayMs: 0,\n })\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:scheduled', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n })\n }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:failed', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n }\n })\n .finally(() => { this.pendingCoverageRefreshKeys.delete(key) })\n }\n\n private resolveEventBus(): Pick<EventBus, 'emitEvent'> | null {\n if (!this.eventBusResolver) return null\n try {\n const bus = this.eventBusResolver()\n return bus ?? null\n } catch {\n return null\n }\n }\n\n private isAutoReindexEnabled(): boolean {\n if (this.autoReindexEnabled != null) return this.autoReindexEnabled\n const raw = (process.env.SCHEDULE_AUTO_REINDEX ?? process.env.QUERY_INDEX_AUTO_REINDEX ?? '').trim().toLowerCase()\n if (!raw) { this.autoReindexEnabled = true; return true }\n const parsed = parseBooleanToken(raw)\n this.autoReindexEnabled = parsed === null ? true : parsed\n return this.autoReindexEnabled\n }\n\n private isCoverageOptimizationEnabled(): boolean {\n if (this.coverageOptimizationEnabled != null) return this.coverageOptimizationEnabled\n const raw = (process.env.OPTIMIZE_INDEX_COVERAGE_STATS ?? '').trim().toLowerCase()\n if (!raw) { this.coverageOptimizationEnabled = false; return false }\n this.coverageOptimizationEnabled = parseBooleanToken(raw) === true\n return this.coverageOptimizationEnabled\n }\n\n private async columnExists(table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (this.columnCache.has(key)) {\n const cached = this.columnCache.get(key)\n if (cached === true) return true\n this.columnCache.delete(key)\n }\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.columns')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .where('column_name', '=', column)\n .executeTakeFirst()\n const present = !!exists\n if (present) this.columnCache.set(key, true)\n else this.columnCache.delete(key)\n return present\n }\n\n private async getBaseColumnsForEntity(entity: string): Promise<Map<string, string>> {\n const db = this.getDb() as any\n const table = resolveEntityTableName(this.em, entity)\n const rows = await db\n .selectFrom('information_schema.columns')\n .select(['column_name', 'data_type'])\n .where('table_name', '=', table)\n .execute() as Array<{ column_name: string; data_type: string }>\n const map = new Map<string, string>()\n for (const r of rows) map.set(r.column_name, r.data_type)\n return map\n }\n\n private resolveOrganizationScope(opts: QueryOptions): { ids: string[]; includeNull: boolean } | null {\n if (opts.organizationIds !== undefined) {\n const raw = (opts.organizationIds ?? []).map((id) => (typeof id === 'string' ? id.trim() : id))\n const includeNull = raw.some((id) => id == null || id === '')\n const ids = raw.filter((id): id is string => typeof id === 'string' && id.length > 0)\n const unique = Array.from(new Set(ids))\n return { ids: unique, includeNull }\n }\n if (typeof opts.organizationId === 'string' && opts.organizationId.trim().length > 0) {\n return { ids: [opts.organizationId], includeNull: false }\n }\n return null\n }\n\n private resolveCoverageSnapshotScope(\n opts: QueryOptions\n ): { tenantId: string | null; organizationId: string | null } | null {\n const tenantId = opts.tenantId ?? null\n const orgScope = this.resolveOrganizationScope(opts)\n if (!orgScope) return { tenantId, organizationId: null }\n if (orgScope.includeNull) {\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n if (orgScope.ids.length === 1) return { tenantId, organizationId: orgScope.ids[0] }\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n\n private applyOrganizationScope(\n q: AnyBuilder,\n column: string,\n scope: { ids: string[]; includeNull: boolean }\n ): AnyBuilder {\n if (scope.ids.length === 0 && !scope.includeNull) {\n return q.where(sql<boolean>`1 = 0`)\n }\n return q.where((eb: any) => {\n const parts: any[] = []\n if (scope.ids.length > 0) parts.push(eb(column, 'in', scope.ids))\n if (scope.includeNull) parts.push(eb(column, 'is', null))\n if (parts.length === 1) return parts[0]\n return eb.or(parts)\n })\n }\n\n private normalizeFilters(filters?: QueryOptions['filters']): NormalizedFilter[] {\n if (!filters) return []\n const normalizeField = (k: string) => k.startsWith('cf_') ? `cf:${k.slice(3)}` : k\n if (Array.isArray(filters)) {\n return (filters as Filter[]).map((filter) => ({\n field: normalizeField(String(filter.field)),\n op: filter.op, value: filter.value,\n }))\n }\n const out: NormalizedFilter[] = []\n const obj = filters as Record<string, unknown>\n const add = (field: string, op: FilterOp, value?: unknown) => out.push({ field, op, value })\n for (const [rawKey, rawVal] of Object.entries(obj)) {\n const field = normalizeField(rawKey)\n if (rawVal !== null && typeof rawVal === 'object' && !Array.isArray(rawVal)) {\n for (const [opKey, opVal] of Object.entries(rawVal as Record<string, unknown>)) {\n switch (opKey) {\n case '$eq': add(field, 'eq', opVal); break\n case '$ne': add(field, 'ne', opVal); break\n case '$gt': add(field, 'gt', opVal); break\n case '$gte': add(field, 'gte', opVal); break\n case '$lt': add(field, 'lt', opVal); break\n case '$lte': add(field, 'lte', opVal); break\n case '$in': add(field, 'in', opVal); break\n case '$nin': add(field, 'nin', opVal); break\n case '$like': add(field, 'like', opVal); break\n case '$ilike': add(field, 'ilike', opVal); break\n case '$exists': add(field, 'exists', opVal); break\n }\n }\n } else {\n add(field, 'eq', rawVal)\n }\n }\n return out\n }\n\n private sanitize(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_')\n }\n\n private toArray(value: unknown): readonly unknown[] {\n if (Array.isArray(value)) return value\n if (value === undefined) return []\n return [value]\n }\n\n private parseCount(row: unknown): number {\n if (row && typeof row === 'object' && 'count' in row) {\n const value = (row as { count: unknown }).count\n if (typeof value === 'number') return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? 0 : parsed\n }\n if (typeof value === 'bigint') return Number(value)\n }\n return 0\n }\n\n private logSearchDebug(event: string, payload: Record<string, unknown>) {\n if (!this.isDebugVerbosity()) return\n try {\n console.info('[query-index:search]', event, JSON.stringify(payload))\n } catch {\n console.info('[query-index:search]', event, payload)\n }\n }\n\n private applyColumnFilter(\n q: AnyBuilder,\n column: string | RawBuilder<unknown>,\n filter: NormalizedFilter,\n search?: SearchRuntime & { entity: string; field: string; recordIdColumn?: string },\n ): AnyBuilder {\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n search?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const sources: SearchTokenSource[] = (search.searchSources && search.searchSources.length\n ? search.searchSources\n : [{ entity: search.entity, recordIdColumn: search.recordIdColumn ?? '' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n const engine = this\n q = q.where((eb: any) => eb.or(\n sources.map((src) =>\n eb.exists(engine.buildSearchTokensSub(eb, {\n entity: src.entity, field: search.field, hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n mintAlias: search.mintAlias,\n })))\n ))\n this.logSearchDebug('search:filter', {\n entity: search.entity, field: search.field, tokens: tokens.tokens, hashes,\n applied: true, tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope,\n sources: sources.map((src) => ({ entity: src.entity, recordIdColumn: src.recordIdColumn })),\n })\n return q\n }\n } else {\n this.logSearchDebug('search:skip-empty-hashes', {\n entity: search.entity, field: search.field, value: filter.value,\n })\n }\n return q\n }\n const col: any = column\n switch (filter.op) {\n case 'eq': return q.where(col, '=', filter.value as any)\n case 'ne': return q.where(col, '!=', filter.value as any)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = filter.op === 'gt' ? '>' : filter.op === 'gte' ? '>=' : filter.op === 'lt' ? '<' : '<='\n return q.where(col, operator, filter.value as any)\n }\n case 'in':\n return q.where(col, 'in', this.toArray(filter.value))\n case 'nin':\n return q.where(col, 'not in', this.toArray(filter.value))\n case 'like':\n return q.where(col, 'like', filter.value as any)\n case 'ilike':\n return q.where(col, 'ilike', filter.value as any)\n case 'exists':\n return filter.value ? q.where(col, 'is not', null) : q.where(col, 'is', null)\n default:\n return q\n }\n }\n\n private resolveCustomEntityColumn(alias: string, field: string): string | null {\n if (field === 'id') return `${alias}.entity_id`\n if (field === 'organization_id' || field === 'organizationId') return `${alias}.organization_id`\n if (field === 'tenant_id' || field === 'tenantId') return `${alias}.tenant_id`\n if (field === 'created_at' || field === 'updated_at' || field === 'deleted_at') return `${alias}.${field}`\n return null\n }\n\n private isDebugVerbosity(): boolean {\n if (this.debugVerbosity != null) return this.debugVerbosity\n this.debugVerbosity = resolveDebugVerbosity()\n return this.debugVerbosity\n }\n\n private isSqlDebugEnabled(): boolean {\n if (this.sqlDebugEnabled != null) return this.sqlDebugEnabled\n this.sqlDebugEnabled = resolveBooleanEnv(['QUERY_ENGINE_DEBUG_SQL'], false)\n return this.sqlDebugEnabled\n }\n\n private isForcePartialIndexEnabled(): boolean {\n if (this.forcePartialIndexEnabled != null) return this.forcePartialIndexEnabled\n this.forcePartialIndexEnabled = resolveBooleanEnv(['FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES'], false)\n return this.forcePartialIndexEnabled\n }\n\n private async resolveCoverageGap(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n _sourceTable?: string\n ): Promise<{ stats?: { baseCount: number; indexedCount: number }; scope: 'scoped' | 'global' } | null> {\n const scope = coverageScope ?? this.resolveCoverageSnapshotScope(opts)\n if (!scope) return null\n const tenantId = scope.tenantId\n const organizationId = scope.organizationId\n const withDeleted = !!opts.withDeleted\n\n const snapshot = await this.getStoredCoverageSnapshot(entity, tenantId, organizationId, withDeleted)\n if (!snapshot) {\n this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)\n return { stats: undefined, scope: 'scoped' }\n }\n\n const baseCount = snapshot.baseCount\n const indexCount = snapshot.indexedCount\n const hasGap = baseCount > 0 && indexCount < baseCount\n if (hasGap || indexCount > baseCount) return { stats: snapshot, scope: 'scoped' }\n return null\n }\n\n // Backward-compatible hook for tests that mock coverage stats\n private async indexCoverageStats(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n const gap = await this.resolveCoverageGap(entity, opts, coverageScope)\n return gap?.stats ?? null\n }\n\n private async captureSqlTiming<TResult>(\n label: string,\n entity: EntityId,\n execute: () => Promise<TResult> | TResult,\n extra?: Record<string, unknown>,\n profiler?: Profiler\n ): Promise<TResult> {\n const shouldDebug = this.isSqlDebugEnabled() && this.isDebugVerbosity()\n const shouldProfile = profiler?.enabled === true\n if (!shouldDebug && !shouldProfile) return Promise.resolve(execute())\n const startedAt = process.hrtime.bigint()\n try {\n return await Promise.resolve(execute())\n } finally {\n const elapsedMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000\n const context: Record<string, unknown> = { entity, durationMs: Math.round(elapsedMs * 1000) / 1000 }\n if (extra) Object.assign(context, extra)\n if (shouldProfile) profiler!.record(label, context.durationMs as number, extra)\n if (shouldDebug) this.debug(`${label}:timing`, context)\n }\n }\n\n private debug(message: string, context?: Record<string, unknown>): void {\n if (!this.isDebugVerbosity()) return\n if (!this.isSqlDebugEnabled()) return\n if (context) console.debug('[HybridQueryEngine]', message, context)\n else console.debug('[HybridQueryEngine]', message)\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["result"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6253.1.a8c2b49d90",
3
+ "version": "0.6.6-develop.6255.1.a6ee4a57c1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -246,16 +246,16 @@
246
246
  "zod": "^4.4.3"
247
247
  },
248
248
  "peerDependencies": {
249
- "@open-mercato/ai-assistant": "0.6.6-develop.6253.1.a8c2b49d90",
250
- "@open-mercato/shared": "0.6.6-develop.6253.1.a8c2b49d90",
251
- "@open-mercato/ui": "0.6.6-develop.6253.1.a8c2b49d90",
249
+ "@open-mercato/ai-assistant": "0.6.6-develop.6255.1.a6ee4a57c1",
250
+ "@open-mercato/shared": "0.6.6-develop.6255.1.a6ee4a57c1",
251
+ "@open-mercato/ui": "0.6.6-develop.6255.1.a6ee4a57c1",
252
252
  "react": "^19.0.0",
253
253
  "react-dom": "^19.0.0"
254
254
  },
255
255
  "devDependencies": {
256
- "@open-mercato/ai-assistant": "0.6.6-develop.6253.1.a8c2b49d90",
257
- "@open-mercato/shared": "0.6.6-develop.6253.1.a8c2b49d90",
258
- "@open-mercato/ui": "0.6.6-develop.6253.1.a8c2b49d90",
256
+ "@open-mercato/ai-assistant": "0.6.6-develop.6255.1.a6ee4a57c1",
257
+ "@open-mercato/shared": "0.6.6-develop.6255.1.a6ee4a57c1",
258
+ "@open-mercato/ui": "0.6.6-develop.6255.1.a6ee4a57c1",
259
259
  "@testing-library/dom": "^10.4.1",
260
260
  "@testing-library/jest-dom": "^6.9.1",
261
261
  "@testing-library/react": "^16.3.1",
@@ -172,6 +172,7 @@ export function TimeGrid({
172
172
  const scrollRef = React.useRef<HTMLDivElement | null>(null)
173
173
  const nowMs = Date.now()
174
174
  const today = startOfDay(new Date())
175
+ const todayMs = today.getTime()
175
176
  const anchorMs = anchor.getTime()
176
177
  const [selectedId, setSelectedId] = React.useState<string | null>(null)
177
178
  const [drag, setDrag] = React.useState<DragState | null>(null)
@@ -179,8 +180,8 @@ export function TimeGrid({
179
180
  const dayStarts = React.useMemo(() => {
180
181
  const rangeStart = getVisibleRange(days === 7 ? 'week' : 'day', new Date(anchorMs), 0).from
181
182
  const all = Array.from({ length: days }, (_, index) => addDays(rangeStart, index))
182
- return days === 7 ? applyWeekendVisibility(all, showWeekends) : all
183
- }, [days, anchorMs, showWeekends])
183
+ return days === 7 ? applyWeekendVisibility(all, showWeekends, new Date(todayMs)) : all
184
+ }, [days, anchorMs, showWeekends, todayMs])
184
185
 
185
186
  const dayColumns = React.useMemo(
186
187
  () => dayStarts.map((dayStart) => buildDayColumn(dayStart, items)),
@@ -1,3 +1,5 @@
1
+ import { isSameDay } from 'date-fns/isSameDay'
2
+
1
3
  export const DRAG_SNAP_MINUTES = 15
2
4
  export const MIN_DRAG_DURATION_MINUTES = 30
3
5
  const MINUTES_PER_DAY = 24 * 60
@@ -7,9 +9,15 @@ export function isWeekendDay(date: Date): boolean {
7
9
  return weekday === 0 || weekday === 6
8
10
  }
9
11
 
10
- export function applyWeekendVisibility(days: Date[], showWeekends: boolean): Date[] {
12
+ export function applyWeekendVisibility(
13
+ days: Date[],
14
+ showWeekends: boolean,
15
+ keepWeekendDate?: Date | null,
16
+ ): Date[] {
11
17
  if (showWeekends) return days
12
- const workingDays = days.filter((day) => !isWeekendDay(day))
18
+ const workingDays = days.filter(
19
+ (day) => !isWeekendDay(day) || (keepWeekendDate != null && isSameDay(day, keepWeekendDate)),
20
+ )
13
21
  return workingDays.length > 0 ? workingDays : days
14
22
  }
15
23
 
@@ -935,7 +935,11 @@ export class HybridQueryEngine implements QueryEngine {
935
935
  const cap = resolveEncryptedSortMaxRows()
936
936
  const phase1Root = db.selectFrom(`${baseTable} as b` as any)
937
937
  let phase1 = await applyQueryShape(phase1Root)
938
- const sortFieldNames = Array.from(new Set(['id', ...resolvedSorts.map((s) => String(s.field))]))
938
+ const scopeFieldNames = [
939
+ hasTenantColumn ? 'tenant_id' : null,
940
+ hasOrganizationColumn ? 'organization_id' : null,
941
+ ].filter((field): field is string => field !== null)
942
+ const sortFieldNames = Array.from(new Set(['id', ...scopeFieldNames, ...resolvedSorts.map((s) => String(s.field))]))
939
943
  phase1 = applySelection(phase1, sortFieldNames)
940
944
  if (cap !== null) {
941
945
  phase1 = phase1.limit(cap).orderBy(qualify('id'), 'asc' as any)