From c36f80cde0779938201f45cb166a96a1ae01d284 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 8 May 2026 22:11:59 -0700 Subject: [PATCH 01/20] fix(tables): fix bulk ops truncation for tables larger than one page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bulk operations (column-header delete, select-all copy/cut/delete/run) were silently truncated to the first 1000 rows because handlers only iterated the loaded pages from useInfiniteQuery. Fix: - Extract tableRowsInfiniteOptions factory (infiniteQueryOptions) so the hook and imperative drain share the same typed cache key - Add background drain via useEffect watching hasNextPage/isFetchingNextPage — chains fetchNextPage until getNextPageParam returns undefined - Add ensureAllRowsLoaded to use-table: reads cache via getQueryData + calls fetchNextPage in a while loop until the last page is partial - Await ensureAllRowsLoaded at every kind:'all' bulk-op entry point in table-grid (column delete, copy, cut, action-bar delete/run) - Add chunkBatchUpdates to send updates in MAX_BULK_OPERATION_SIZE=1000 chunks so server validation never rejects oversized batches - Fix undo-redo: make executeAction async and chunk clear-cells, update-cells, and delete-column cell-restore with mutateAsync loops Tests: 41 passing across use-table, tables queries, and use-table-undo --- apps/sim/app/api/table/import-csv/route.ts | 6 +- .../cells/expanded-cell-popover.tsx | 10 +- .../table-grid/cells/inline-editors.tsx | 13 +- .../components/table-grid/table-grid.tsx | 316 +++++++++++------- .../tables/[tableId]/hooks/use-table.test.ts | 304 +++++++++++++++++ .../tables/[tableId]/hooks/use-table.ts | 55 ++- .../[workspaceId]/tables/[tableId]/utils.ts | 2 +- .../workspace/[workspaceId]/tables/tables.tsx | 11 - apps/sim/hooks/queries/tables.test.ts | 123 ++++++- apps/sim/hooks/queries/tables.ts | 134 ++++++-- apps/sim/hooks/use-table-undo.test.ts | 230 +++++++++++++ apps/sim/hooks/use-table-undo.ts | 44 ++- apps/sim/lib/table/constants.ts | 2 +- 13 files changed, 1057 insertions(+), 193 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts create mode 100644 apps/sim/hooks/use-table-undo.test.ts diff --git a/apps/sim/app/api/table/import-csv/route.ts b/apps/sim/app/api/table/import-csv/route.ts index 66b0e1f3c0..11951d0cb2 100644 --- a/apps/sim/app/api/table/import-csv/route.ts +++ b/apps/sim/app/api/table/import-csv/route.ts @@ -17,6 +17,7 @@ import { inferSchemaFromCsv, parseCsvBuffer, sanitizeName, + TABLE_LIMITS, type TableSchema, } from '@/lib/table' import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' @@ -67,7 +68,10 @@ export const POST = withRouteHandler(async (request: NextRequest) => { const { headers, rows } = await parseCsvBuffer(buffer, delimiter) const { columns, headerToColumn } = inferSchemaFromCsv(headers, rows) - const tableName = sanitizeName(file.name.replace(/\.[^.]+$/, ''), 'imported_table') + const tableName = sanitizeName(file.name.replace(/\.[^.]+$/, ''), 'imported_table').slice( + 0, + TABLE_LIMITS.MAX_TABLE_NAME_LENGTH + ) const planLimits = await getWorkspaceTableLimits(workspaceId) const normalizedSchema: TableSchema = { diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/expanded-cell-popover.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/expanded-cell-popover.tsx index cc71632069..5430d237dd 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/expanded-cell-popover.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/expanded-cell-popover.tsx @@ -22,13 +22,11 @@ const EXPANDED_CELL_MIN_WIDTH = 420 const EXPANDED_CELL_HEIGHT = 280 /** - * Supabase-style anchored cell expander. Floats over the clicked cell at the cell's - * top-left, minimum width {@link EXPANDED_CELL_MIN_WIDTH}, fixed height, internally - * scrollable. Triggered by cell double-click so long values are readable/editable - * without widening the column. Inline edit via Enter/F2/typing is unaffected. + * Anchored cell editor. Floats over the double-clicked cell, minimum width + * {@link EXPANDED_CELL_MIN_WIDTH}, fixed height, internally scrollable. * - * Workflow and boolean cells are read-only in this view — workflow cells are driven - * by the scheduler, booleans use a checkbox cell inline. + * Workflow and boolean cells are read-only here — workflow cells are driven + * by the scheduler, booleans toggle inline. */ export function ExpandedCellPopover({ expandedCell, diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx index 40dd661e82..742fbbac6f 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx @@ -131,7 +131,7 @@ function InlineDateEditor({ ) } -/** Inline editor for `string`/`number`/`json` columns — single-line text input. */ +/** Inline editor for `string`/`number`/`json` columns — single-line text input. Number columns use `type="number"` so the browser rejects non-numeric input. */ function InlineTextEditor({ value, column, @@ -193,16 +193,21 @@ function InlineTextEditor({ } } + const isNumber = column.type === 'number' + return ( setDraft(e.target.value)} onKeyDown={handleKeyDown} onBlur={() => doSave('blur')} className={cn( - 'w-full min-w-0 select-text border-none bg-transparent p-0 text-[var(--text-primary)] text-small outline-none' + 'w-full min-w-0 select-text border-none bg-transparent p-0 text-[var(--text-primary)] text-small outline-none', + isNumber && + '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none' )} /> ) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index 7e42350e6b..48e256c103 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -10,6 +10,7 @@ import type { RunMode } from '@/lib/api/contracts/tables' import { cn } from '@/lib/core/utils/cn' import { captureEvent } from '@/lib/posthog/client' import type { ColumnDefinition, TableRow as TableRowType, WorkflowGroup } from '@/lib/table' +import { TABLE_LIMITS } from '@/lib/table/constants' import { getUnmetGroupDeps, isExecInFlight } from '@/lib/table/deps' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' import { @@ -234,6 +235,24 @@ interface TableGridProps { > } +/** + * Split updates into chunks that fit within the server's batch-size limit, + * running each chunk sequentially. Throws on first failure so callers see + * an all-or-nothing result and partial success cannot leave the table in an + * ambiguous half-cleared state. + */ +async function chunkBatchUpdates( + updates: Array<{ rowId: string; data: Record }>, + mutateAsync: (args: { + updates: Array<{ rowId: string; data: Record }> + }) => Promise +): Promise { + const size = TABLE_LIMITS.MAX_BULK_OPERATION_SIZE + for (let i = 0; i < updates.length; i += size) { + await mutateAsync({ updates: updates.slice(i, i + size) }) + } +} + export function TableGrid({ workspaceId: propWorkspaceId, tableId: propTableId, @@ -313,6 +332,7 @@ export function TableGrid({ tableWorkflowGroups, workflowStates, columnSourceInfo, + ensureAllRowsLoaded, } = useTable({ workspaceId, tableId, queryOptions }) const fetchNextPageRef = useRef(fetchNextPage) @@ -321,6 +341,8 @@ export function TableGrid({ hasNextPageRef.current = hasNextPage const isFetchingNextPageRef = useRef(isFetchingNextPage) isFetchingNextPageRef.current = isFetchingNextPage + const ensureAllRowsLoadedRef = useRef(ensureAllRowsLoaded) + ensureAllRowsLoadedRef.current = ensureAllRowsLoaded const isAppendingRowRef = useRef(false) const userPermissions = useUserPermissionsContext() @@ -1464,10 +1486,6 @@ export function TableGrid({ [] ) - // The cell has `select-none` which suppresses programmatic selection, so we - // override `user-select` on the inner element until the next click. The popover - // only opens when the leaf's scroll dimensions exceed its client dimensions - // (workflow cells nest text inside a span with its own `overflow-clip`). const handleCellDoubleClick = useCallback( (rowId: string, columnName: string, columnKey: string) => { const column = columnsRef.current.find((c) => c.key === columnKey) @@ -1476,54 +1494,27 @@ export function TableGrid({ setSelectionFocus(null) setIsColumnSelection(false) - const rowArrayIndex = rowsRef.current.findIndex((r) => r.id === rowId) - const row = rowArrayIndex !== -1 ? rowsRef.current[rowArrayIndex] : null - - // Workflow-output cell with no value (status pill showing) → enter edit - // mode with a blank input so the user can write a value over the status. - // Escape cancels without persisting. - if (column?.workflowGroupId && row && canEditRef.current) { - const cellValue = row.data[columnName] - if (cellValue === null || cellValue === undefined || cellValue === '') { - setEditingCell({ rowId, columnName }) - setInitialCharacter('') - return - } + // Date/number: use inline editor (calendar picker / numeric input). + if ((column?.type === 'date' || column?.type === 'number') && canEditRef.current) { + setEditingCell({ rowId, columnName }) + setInitialCharacter(null) + return } - const colIndex = columnsRef.current.findIndex((c) => c.key === columnKey) - let overflows = true - if (row && colIndex !== -1) { - const td = document.querySelector( - `[data-table-scroll] [data-row="${rowArrayIndex}"][data-col="${colIndex}"]` - ) - const inner = td?.querySelector(':scope > div:last-child') - if (inner) { - const candidates: HTMLElement[] = [inner] - const descendants = inner.querySelectorAll('*') - for (const el of descendants) candidates.push(el) - overflows = candidates.some( - (el) => el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1 - ) - - inner.style.userSelect = 'text' - const clear = () => { - inner.style.userSelect = '' - window.removeEventListener('mousedown', clear, true) - } - window.addEventListener('mousedown', clear, true) - - const selection = window.getSelection() - if (selection) { - const range = document.createRange() - range.selectNodeContents(inner) - selection.removeAllRanges() - selection.addRange(range) + // Workflow-output cell with no value → let the user write over the status pill. + if (column?.workflowGroupId && canEditRef.current) { + const row = rowsRef.current.find((r) => r.id === rowId) + if (row) { + const cellValue = row.data[columnName] + if (cellValue === null || cellValue === undefined || cellValue === '') { + setEditingCell({ rowId, columnName }) + setInitialCharacter('') + return } } } - if (overflows) setExpandedCell({ rowId, columnName, columnKey }) + setExpandedCell({ rowId, columnName, columnKey }) }, [] ) @@ -1539,6 +1530,8 @@ export function TableGrid({ const batchUpdateRef = useRef(batchUpdateRowsMutation.mutate) batchUpdateRef.current = batchUpdateRowsMutation.mutate + const batchUpdateAsyncRef = useRef(batchUpdateRowsMutation.mutateAsync) + batchUpdateAsyncRef.current = batchUpdateRowsMutation.mutateAsync const updateMetadataRef = useRef(updateMetadataMutation.mutate) updateMetadataRef.current = updateMetadataMutation.mutate @@ -1640,28 +1633,33 @@ export function TableGrid({ if (editingCellRef.current) return if (!canEditRef.current) return e.preventDefault() - const rowSel = rowSelectionRef.current - const currentRows = rowsRef.current - const currentCols = columnsRef.current - const undoCells: Array<{ rowId: string; data: Record }> = [] - const batchUpdates: Array<{ rowId: string; data: Record }> = [] - for (const row of currentRows) { - if (!rowSelectionIncludes(rowSel, row.id)) continue - const updates: Record = {} - const previousData: Record = {} - for (const col of currentCols) { - previousData[col.name] = row.data[col.name] ?? null - updates[col.name] = null + void (async () => { + const allRows = await ensureAllRowsLoadedRef.current() + const rowSel = rowSelectionRef.current + const currentCols = columnsRef.current + const undoCells: Array<{ rowId: string; data: Record }> = [] + const batchUpdates: Array<{ rowId: string; data: Record }> = [] + for (const row of allRows) { + if (!rowSelectionIncludes(rowSel, row.id)) continue + const updates: Record = {} + const previousData: Record = {} + for (const col of currentCols) { + previousData[col.name] = row.data[col.name] ?? null + updates[col.name] = null + } + undoCells.push({ rowId: row.id, data: previousData }) + batchUpdates.push({ rowId: row.id, data: updates }) } - undoCells.push({ rowId: row.id, data: previousData }) - batchUpdates.push({ rowId: row.id, data: updates }) - } - if (batchUpdates.length > 0) { - batchUpdateRef.current({ updates: batchUpdates }) - } - if (undoCells.length > 0) { - pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) - } + if (batchUpdates.length > 0) { + await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) + } + if (undoCells.length > 0) { + pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) + } + })().catch((error) => { + logger.error('Failed to clear selected cells', { error }) + toast.error('Failed to clear cells — please try again') + }) return } @@ -1863,6 +1861,36 @@ export function TableGrid({ e.preventDefault() const sel = computeNormalizedSelection(anchor, selectionFocusRef.current) if (!sel) return + + if (isColumnSelectionRef.current) { + // Column-header selection spans all rows — selection bounds are capped + // to the loaded page count, so drain first then walk the full set. + void (async () => { + const allRows = await ensureAllRowsLoadedRef.current() + const undoCells: Array<{ rowId: string; data: Record }> = [] + const batchUpdates: Array<{ rowId: string; data: Record }> = [] + for (const row of allRows) { + const updates: Record = {} + const previousData: Record = {} + for (let c = sel.startCol; c <= sel.endCol; c++) { + const colName = cols[c]?.name + if (!colName) continue + previousData[colName] = row.data[colName] ?? null + updates[colName] = null + } + undoCells.push({ rowId: row.id, data: previousData }) + batchUpdates.push({ rowId: row.id, data: updates }) + } + if (batchUpdates.length > 0) + await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) + if (undoCells.length > 0) pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) + })().catch((error) => { + logger.error('Failed to clear column values', { error }) + toast.error('Failed to clear column values — please try again') + }) + return + } + const undoCells: Array<{ rowId: string; data: Record }> = [] const batchUpdates: Array<{ rowId: string; data: Record }> = [] for (let r = sel.startRow; r <= sel.endRow; r++) { @@ -1919,17 +1947,27 @@ export function TableGrid({ if (!rowSelectionIsEmpty(rowSel)) { e.preventDefault() - const lines: string[] = [] - for (const row of currentRows) { - if (!rowSelectionIncludes(rowSel, row.id)) continue - const cells: string[] = cols.map((col) => { - const value: unknown = row.data[col.name] - if (value === null || value === undefined) return '' - return typeof value === 'object' ? JSON.stringify(value) : String(value) - }) - lines.push(cells.join('\t')) - } - e.clipboardData?.setData('text/plain', lines.join('\n')) + void (async () => { + const allRows = await ensureAllRowsLoadedRef.current() + const lines: string[] = [] + for (const row of allRows) { + if (!rowSelectionIncludes(rowSel, row.id)) continue + const cells: string[] = cols.map((col) => { + const value: unknown = row.data[col.name] + if (value === null || value === undefined) return '' + return typeof value === 'object' ? JSON.stringify(value) : String(value) + }) + lines.push(cells.join('\t')) + } + if (!navigator.clipboard) { + toast.error('Clipboard access is unavailable in this context') + return + } + await navigator.clipboard.writeText(lines.join('\n')) + })().catch((error) => { + logger.error('Failed to copy selected rows', { error }) + toast.error('Failed to copy — please try again') + }) return } @@ -1967,65 +2005,83 @@ export function TableGrid({ const rowSel = rowSelectionRef.current const cols = columnsRef.current const currentRows = rowsRef.current - const undoCells: Array<{ rowId: string; data: Record }> = [] - const batchUpdates: Array<{ rowId: string; data: Record }> = [] if (!rowSelectionIsEmpty(rowSel)) { e.preventDefault() - const lines: string[] = [] - for (const row of currentRows) { - if (!rowSelectionIncludes(rowSel, row.id)) continue - const cells: string[] = cols.map((col) => { - const value: unknown = row.data[col.name] - if (value === null || value === undefined) return '' - return typeof value === 'object' ? JSON.stringify(value) : String(value) - }) - lines.push(cells.join('\t')) - const updates: Record = {} - const previousData: Record = {} - for (const col of cols) { - previousData[col.name] = row.data[col.name] ?? null - updates[col.name] = null + void (async () => { + const allRows = await ensureAllRowsLoadedRef.current() + const lines: string[] = [] + const cutUpdates: Array<{ rowId: string; data: Record }> = [] + const cutUndo: Array<{ rowId: string; data: Record }> = [] + for (const row of allRows) { + if (!rowSelectionIncludes(rowSel, row.id)) continue + const cells: string[] = cols.map((col) => { + const value: unknown = row.data[col.name] + if (value === null || value === undefined) return '' + return typeof value === 'object' ? JSON.stringify(value) : String(value) + }) + lines.push(cells.join('\t')) + const updates: Record = {} + const previousData: Record = {} + for (const col of cols) { + previousData[col.name] = row.data[col.name] ?? null + updates[col.name] = null + } + cutUndo.push({ rowId: row.id, data: previousData }) + cutUpdates.push({ rowId: row.id, data: updates }) } - undoCells.push({ rowId: row.id, data: previousData }) - batchUpdates.push({ rowId: row.id, data: updates }) - } - e.clipboardData?.setData('text/plain', lines.join('\n')) - } else { - const anchor = selectionAnchorRef.current - if (!anchor) return + if (!navigator.clipboard) { + toast.error('Clipboard access is unavailable in this context') + return + } + await navigator.clipboard.writeText(lines.join('\n')) + if (cutUpdates.length > 0) { + await chunkBatchUpdates(cutUpdates, batchUpdateAsyncRef.current) + } + if (cutUndo.length > 0) { + pushUndoRef.current({ type: 'clear-cells', cells: cutUndo }) + } + })().catch((error) => { + logger.error('Failed to cut selected rows', { error }) + toast.error('Failed to cut — please try again') + }) + return + } - const sel = computeNormalizedSelection(anchor, selectionFocusRef.current) - if (!sel) return + const anchor = selectionAnchorRef.current + if (!anchor) return - e.preventDefault() - const lines: string[] = [] - for (let r = sel.startRow; r <= sel.endRow; r++) { - const row = currentRows[r] - if (!row) continue - const cells: string[] = [] - const updates: Record = {} - const previousData: Record = {} - for (let c = sel.startCol; c <= sel.endCol; c++) { - if (c < cols.length) { - const colName = cols[c].name - const value: unknown = row.data[colName] - if (value === null || value === undefined) { - cells.push('') - } else { - cells.push(typeof value === 'object' ? JSON.stringify(value) : String(value)) - } - previousData[colName] = row.data[colName] ?? null - updates[colName] = null + const sel = computeNormalizedSelection(anchor, selectionFocusRef.current) + if (!sel) return + + e.preventDefault() + const lines: string[] = [] + const undoCells: Array<{ rowId: string; data: Record }> = [] + const batchUpdates: Array<{ rowId: string; data: Record }> = [] + for (let r = sel.startRow; r <= sel.endRow; r++) { + const row = currentRows[r] + if (!row) continue + const cells: string[] = [] + const updates: Record = {} + const previousData: Record = {} + for (let c = sel.startCol; c <= sel.endCol; c++) { + if (c < cols.length) { + const colName = cols[c].name + const value: unknown = row.data[colName] + if (value === null || value === undefined) { + cells.push('') + } else { + cells.push(typeof value === 'object' ? JSON.stringify(value) : String(value)) } + previousData[colName] = row.data[colName] ?? null + updates[colName] = null } - lines.push(cells.join('\t')) - undoCells.push({ rowId: row.id, data: previousData }) - batchUpdates.push({ rowId: row.id, data: updates }) } - e.clipboardData?.setData('text/plain', lines.join('\n')) + lines.push(cells.join('\t')) + undoCells.push({ rowId: row.id, data: previousData }) + batchUpdates.push({ rowId: row.id, data: updates }) } - + e.clipboardData?.setData('text/plain', lines.join('\n')) if (batchUpdates.length > 0) { batchUpdateRef.current({ updates: batchUpdates }) } @@ -3383,9 +3439,9 @@ const DataRow = React.memo(function DataRow({ onMouseEnter={() => onCellMouseEnter(rowIndex, colIndex)} onClick={(e) => onClick(row.id, column.name, { - toggleBoolean: Boolean( - (e.target as HTMLElement).closest('[data-boolean-cell-toggle]') - ), + toggleBoolean: + !e.shiftKey && + Boolean((e.target as HTMLElement).closest('[data-boolean-cell-toggle]')), }) } onDoubleClick={() => onDoubleClick(row.id, column.name, column.key)} diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts new file mode 100644 index 0000000000..70fe267d8d --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts @@ -0,0 +1,304 @@ +/** + * @vitest-environment node + */ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +// Capture useEffect calls so tests can trigger them manually. +const capturedEffects: Array<() => undefined | (() => void)> = [] + +// Mock React hooks to be passthrough so useTable() can be called without a +// React root. useCallback returns its function arg; useMemo executes +// immediately; useEffect is captured for manual triggering. +vi.mock('react', () => ({ + useCallback: (fn: unknown) => fn, + useMemo: (fn: () => unknown) => fn(), + useEffect: (fn: () => undefined | (() => void)) => { + capturedEffects.push(fn) + }, + useRef: (init: unknown) => ({ current: init }), +})) + +const mockGetQueryData = vi.fn() +const mockFetchNextPage = vi.fn() +const mockQueryClient = { + getQueryData: mockGetQueryData, +} + +vi.mock('@tanstack/react-query', () => ({ + useQueryClient: vi.fn(() => mockQueryClient), +})) + +vi.mock('@/hooks/queries/tables', () => ({ + tableRowsInfiniteOptions: vi.fn(({ tableId, pageSize, filter, sort }) => ({ + queryKey: [ + 'tables', + 'detail', + tableId, + 'rows', + 'infinite', + JSON.stringify({ pageSize, filter, sort }), + ], + queryFn: vi.fn(), + initialPageParam: 0, + staleTime: 30000, + })), + useInfiniteTableRows: vi.fn(() => ({ + data: { pages: [] }, + isLoading: false, + refetch: vi.fn().mockResolvedValue(undefined), + fetchNextPage: mockFetchNextPage, + hasNextPage: false, + isFetchingNextPage: false, + })), + useTable: vi.fn(() => ({ + data: undefined, + isLoading: false, + })), +})) + +vi.mock('@/hooks/queries/workflows', () => ({ + useWorkflows: vi.fn(() => ({ data: undefined })), + useWorkflowStates: vi.fn(() => new Map()), +})) + +vi.mock('@/blocks', () => ({ + getBlock: vi.fn(() => undefined), +})) + +vi.mock('@/lib/table/constants', () => ({ + TABLE_LIMITS: { MAX_QUERY_LIMIT: 1000 }, +})) + +import { useTable } from '@/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table' +import { useInfiniteTableRows } from '@/hooks/queries/tables' + +const WORKSPACE_ID = 'ws-1' +const TABLE_ID = 'tbl-1' +const QUERY_OPTIONS = { filter: null, sort: null } + +function makeRow(id: string, position: number) { + return { id, data: { name: `Row ${id}` }, position, executions: {} } +} + +function makePages(rowsPerPage: number[], totalCount: number) { + return rowsPerPage.map((count, pageIdx) => ({ + rows: Array.from({ length: count }, (_, i) => + makeRow(`r${pageIdx * 1000 + i}`, pageIdx * 1000 + i) + ), + totalCount, + })) +} + +const OK = { status: 'success', hasNextPage: false } as const + +beforeEach(() => { + capturedEffects.length = 0 + vi.clearAllMocks() + mockGetQueryData.mockReturnValue(undefined) + mockFetchNextPage.mockResolvedValue(OK) +}) + +describe('useTable – ensureAllRowsLoaded', () => { + it('returns an empty array when cache is empty', async () => { + mockGetQueryData.mockReturnValue(undefined) + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + queryOptions: QUERY_OPTIONS, + }) + const rows = await ensureAllRowsLoaded() + expect(rows).toEqual([]) + expect(mockFetchNextPage).not.toHaveBeenCalled() + }) + + it('returns rows from cache immediately when last page is partial (< 1 page)', async () => { + const [page] = makePages([3], 3) + mockGetQueryData.mockReturnValue({ pages: [page] }) + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + queryOptions: QUERY_OPTIONS, + }) + const rows = await ensureAllRowsLoaded() + expect(rows).toHaveLength(3) + expect(rows.map((r) => r.id)).toEqual(['r0', 'r1', 'r2']) + // Cache already complete — no HTTP request needed. + expect(mockFetchNextPage).not.toHaveBeenCalled() + }) + + it('returns rows from cache immediately when last page is exactly one full page', async () => { + // A full page means getNextPageParam returns the next offset, so we must + // fetch once to confirm there is no page 2 (which returns 0 rows). After + // that empty page the last page is partial (0 < 1000) and the loop breaks. + const [page0] = makePages([1000], 1000) + const emptyPage = { rows: [], totalCount: 1000 } + mockGetQueryData + .mockReturnValueOnce({ pages: [page0] }) // loop iter 1: full → fetch + .mockReturnValueOnce({ pages: [page0, emptyPage] }) // loop iter 2: empty → break + .mockReturnValue({ pages: [page0, emptyPage] }) // final read + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + queryOptions: QUERY_OPTIONS, + }) + const rows = await ensureAllRowsLoaded() + expect(rows).toHaveLength(1000) + expect(rows[0].id).toBe('r0') + expect(rows[999].id).toBe('r999') + expect(mockFetchNextPage).toHaveBeenCalledTimes(1) + }) + + it('fetches one page when last cached page is full and there is more data', async () => { + const [page0, page1] = makePages([1000, 500], 1500) + mockGetQueryData + .mockReturnValueOnce({ pages: [page0] }) // loop iter 1: full → fetch + .mockReturnValueOnce({ pages: [page0, page1] }) // loop iter 2: partial → break + .mockReturnValue({ pages: [page0, page1] }) // final read + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + queryOptions: QUERY_OPTIONS, + }) + const rows = await ensureAllRowsLoaded() + expect(rows).toHaveLength(1500) + expect(rows[0].id).toBe('r0') + expect(rows[1000].id).toBe('r1000') + expect(mockFetchNextPage).toHaveBeenCalledTimes(1) + }) + + it('fetches multiple pages for a large table until a partial page terminates the drain', async () => { + const [page0, page1, page2] = makePages([1000, 1000, 500], 2500) + mockGetQueryData + .mockReturnValueOnce({ pages: [page0] }) // iter 1: full → fetch + .mockReturnValueOnce({ pages: [page0, page1] }) // iter 2: full → fetch + .mockReturnValueOnce({ pages: [page0, page1, page2] }) // iter 3: partial → break + .mockReturnValue({ pages: [page0, page1, page2] }) // final read + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + queryOptions: QUERY_OPTIONS, + }) + const rows = await ensureAllRowsLoaded() + expect(rows).toHaveLength(2500) + expect(rows[0].id).toBe('r0') + expect(rows[1000].id).toBe('r1000') + expect(rows[2499].id).toBe('r2499') + expect(mockFetchNextPage).toHaveBeenCalledTimes(2) + }) + + it('throws when fetchNextPage returns an error status', async () => { + const [page0] = makePages([1000], 2000) + mockGetQueryData.mockReturnValue({ pages: [page0] }) + const error = new Error('Network failure') + mockFetchNextPage.mockResolvedValueOnce({ status: 'error', error }) + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + queryOptions: QUERY_OPTIONS, + }) + await expect(ensureAllRowsLoaded()).rejects.toThrow('Network failure') + }) + + it('does not call fetchNextPage or getQueryData when workspaceId is empty', async () => { + const { ensureAllRowsLoaded } = useTable({ + workspaceId: '', + tableId: TABLE_ID, + queryOptions: QUERY_OPTIONS, + }) + const rows = await ensureAllRowsLoaded() + expect(rows).toEqual([]) + expect(mockFetchNextPage).not.toHaveBeenCalled() + expect(mockGetQueryData).not.toHaveBeenCalled() + }) + + it('does not call fetchNextPage or getQueryData when tableId is empty', async () => { + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: '', + queryOptions: QUERY_OPTIONS, + }) + const rows = await ensureAllRowsLoaded() + expect(rows).toEqual([]) + expect(mockFetchNextPage).not.toHaveBeenCalled() + expect(mockGetQueryData).not.toHaveBeenCalled() + }) + + it('encodes queryOptions.filter into the queryKey passed to getQueryData', async () => { + const filter = { column: 'name', operator: 'eq', value: 'Alice' } as never + const [page] = makePages([3], 3) + mockGetQueryData.mockReturnValue({ pages: [page] }) + const { ensureAllRowsLoaded } = useTable({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + queryOptions: { filter, sort: null }, + }) + await ensureAllRowsLoaded() + const queryKey = mockGetQueryData.mock.calls[0][0] as unknown[] + expect(JSON.stringify(queryKey)).toContain('Alice') + }) +}) + +describe('useTable – background drain on mount', () => { + it('calls fetchNextPage when hasNextPage is true', () => { + vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ + data: { pages: [] }, + isLoading: false, + refetch: vi.fn().mockResolvedValue(undefined), + fetchNextPage: mockFetchNextPage, + hasNextPage: true, + isFetchingNextPage: false, + }) + useTable({ workspaceId: WORKSPACE_ID, tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) + for (const effect of capturedEffects) effect() + expect(mockFetchNextPage).toHaveBeenCalled() + }) + + it('does not call fetchNextPage when hasNextPage is false', () => { + // Default mock already returns hasNextPage: false. + useTable({ workspaceId: WORKSPACE_ID, tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) + for (const effect of capturedEffects) effect() + expect(mockFetchNextPage).not.toHaveBeenCalled() + }) + + it('does not call fetchNextPage when isFetchingNextPage is true', () => { + vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ + data: { pages: [] }, + isLoading: false, + refetch: vi.fn().mockResolvedValue(undefined), + fetchNextPage: mockFetchNextPage, + hasNextPage: true, + isFetchingNextPage: true, + }) + useTable({ workspaceId: WORKSPACE_ID, tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) + for (const effect of capturedEffects) effect() + expect(mockFetchNextPage).not.toHaveBeenCalled() + }) + + it('does not drain when workspaceId is empty', () => { + vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ + data: { pages: [] }, + isLoading: false, + refetch: vi.fn().mockResolvedValue(undefined), + fetchNextPage: mockFetchNextPage, + hasNextPage: true, + isFetchingNextPage: false, + }) + useTable({ workspaceId: '', tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) + for (const effect of capturedEffects) effect() + expect(mockFetchNextPage).not.toHaveBeenCalled() + }) + + it('does not drain when tableId is empty', () => { + vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ + data: { pages: [] }, + isLoading: false, + refetch: vi.fn().mockResolvedValue(undefined), + fetchNextPage: mockFetchNextPage, + hasNextPage: true, + isFetchingNextPage: false, + }) + useTable({ workspaceId: WORKSPACE_ID, tableId: '', queryOptions: QUERY_OPTIONS }) + for (const effect of capturedEffects) effect() + expect(mockFetchNextPage).not.toHaveBeenCalled() + }) +}) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts index b3d5b311ad..072dc25612 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts @@ -1,11 +1,16 @@ 'use client' -import { useCallback, useMemo } from 'react' +import { useCallback, useEffect, useMemo } from 'react' +import { useQueryClient } from '@tanstack/react-query' import type { ColumnDefinition, TableDefinition, TableRow, WorkflowGroup } from '@/lib/table' import { TABLE_LIMITS } from '@/lib/table/constants' import type { FlattenOutputsBlockInput } from '@/lib/workflows/blocks/flatten-outputs' import { getBlock } from '@/blocks' -import { useInfiniteTableRows, useTable as useTableQuery } from '@/hooks/queries/tables' +import { + tableRowsInfiniteOptions, + useInfiniteTableRows, + useTable as useTableQuery, +} from '@/hooks/queries/tables' import { useWorkflowStates, useWorkflows } from '@/hooks/queries/workflows' import type { WorkflowMetadata } from '@/stores/workflows/registry/types' import type { WorkflowState } from '@/stores/workflows/workflow/types' @@ -52,6 +57,12 @@ export interface UseTableReturn { /** Pre-resolved icon + block-name info per output column name. Headers read * from this map instead of each subscribing to its own workflow-state query. */ columnSourceInfo: Map + /** + * Fetches any missing row pages and returns the full flat row list directly + * from cache — safe to read immediately without waiting for a React re-render. + * Gate bulk ops that must act on the complete row set with this. + */ + ensureAllRowsLoaded: () => Promise } /** @@ -66,6 +77,7 @@ export interface UseTableReturn { * single hook return and re-render the world. */ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams): UseTableReturn { + const queryClient = useQueryClient() const { data: tableData, isLoading: isLoadingTable } = useTableQuery(workspaceId, tableId) const { @@ -84,6 +96,15 @@ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams) enabled: Boolean(workspaceId && tableId), }) + // Background drain: TanStack's prefetchInfiniteQuery is a no-op when the first page is + // already fresh (staleTime not exceeded). Drive the drain through fetchNextPage instead + // — it only fetches the *next* page (not from scratch) and fires whenever a full page + // is sitting in cache, chaining until getNextPageParam returns undefined. + useEffect(() => { + if (!workspaceId || !tableId || !hasNextPage || isFetchingNextPage) return + void fetchNextPage() + }, [workspaceId, tableId, hasNextPage, isFetchingNextPage, fetchNextPage]) + const rows = useMemo( () => rowsData?.pages.flatMap((p) => p.rows) ?? [], [rowsData?.pages] @@ -93,6 +114,35 @@ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams) void refetch() }, [refetch]) + const ensureAllRowsLoaded = useCallback(async (): Promise => { + if (!workspaceId || !tableId) return [] + + const opts = tableRowsInfiniteOptions({ + workspaceId, + tableId, + pageSize: TABLE_LIMITS.MAX_QUERY_LIMIT, + filter: queryOptions.filter, + sort: queryOptions.sort, + }) + + // Drain pages one at a time using the cache as the source of truth. + // fetchNextPage appends exactly one new page without re-fetching existing + // ones. getQueryData reads the live cache synchronously — bypassing React's + // render cycle — so updated pages are visible immediately after each await. + while (true) { + const data = queryClient.getQueryData(opts.queryKey) + const lastPage = data?.pages[data.pages.length - 1] + // A partial (or absent) last page means all available rows are in cache. + if (!lastPage || lastPage.rows.length < TABLE_LIMITS.MAX_QUERY_LIMIT) break + const result = await fetchNextPage() + if (result.status === 'error') { + throw result.error ?? new Error('Failed to load table rows') + } + } + + return queryClient.getQueryData(opts.queryKey)?.pages.flatMap((p) => p.rows) ?? [] + }, [workspaceId, tableId, queryOptions.filter, queryOptions.sort, queryClient, fetchNextPage]) + const fetchNextPageWrapped = useCallback(async () => { const result = await fetchNextPage() if (result.status === 'error') { @@ -149,5 +199,6 @@ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams) tableWorkflowGroups, workflowStates, columnSourceInfo, + ensureAllRowsLoaded, } } diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/utils.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/utils.ts index 75c57b6199..55e310c363 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/utils.ts @@ -45,7 +45,7 @@ export function cleanCellValue(value: unknown, column: ColumnDefinition): unknow if (column.type === 'number') { if (value === '') return null const num = Number(value) - return Number.isNaN(num) ? 0 : num + return Number.isNaN(num) ? null : num } if (column.type === 'json') { if (typeof value === 'string') { diff --git a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx index 3389ab35fc..9070acbc23 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx @@ -399,7 +399,6 @@ export function Tables() { } setUploadProgress({ completed: 0, total: csvFiles.length }) - const failed: string[] = [] for (let i = 0; i < csvFiles.length; i++) { try { @@ -412,23 +411,13 @@ export function Tables() { } } } catch (err) { - failed.push(csvFiles[i].name) logger.error('Error uploading CSV:', err) } finally { setUploadProgress({ completed: i + 1, total: csvFiles.length }) } } - - if (failed.length > 0) { - toast.error( - failed.length === 1 - ? `Failed to import ${failed[0]}` - : `Failed to import ${failed.length} file${failed.length > 1 ? 's' : ''}: ${failed.join(', ')}` - ) - } } catch (err) { logger.error('Error uploading CSV:', err) - toast.error('Failed to import CSV') } finally { setUploading(false) setUploadProgress({ completed: 0, total: 0 }) diff --git a/apps/sim/hooks/queries/tables.test.ts b/apps/sim/hooks/queries/tables.test.ts index c2c8a12724..70e8411df5 100644 --- a/apps/sim/hooks/queries/tables.test.ts +++ b/apps/sim/hooks/queries/tables.test.ts @@ -31,6 +31,7 @@ const { queryClient, cacheStore } = vi.hoisted(() => { vi.mock('@tanstack/react-query', () => ({ keepPreviousData: {}, + infiniteQueryOptions: (opts: unknown) => opts, useQuery: vi.fn(), useInfiniteQuery: vi.fn(), useQueryClient: vi.fn(() => queryClient), @@ -80,7 +81,13 @@ vi.mock('@/components/emcn', () => ({ toast: { error: vi.fn(), success: vi.fn() }, })) -import { tableKeys, useDeleteColumn, useUpdateColumn } from '@/hooks/queries/tables' +import { + tableKeys, + tableRowsInfiniteOptions, + tableRowsParamsKey, + useDeleteColumn, + useUpdateColumn, +} from '@/hooks/queries/tables' const TABLE_ID = 'tbl-1' const WORKSPACE_ID = 'ws-1' @@ -249,3 +256,117 @@ describe('useDeleteColumn case-insensitive row cleanup', () => { expect(rows?.rows[0]?.data).toEqual({ name: 'a' }) }) }) + +describe('tableRowsParamsKey', () => { + it('produces the same key for identical params', () => { + const k1 = tableRowsParamsKey({ pageSize: 1000, filter: null, sort: null }) + const k2 = tableRowsParamsKey({ pageSize: 1000, filter: null, sort: null }) + expect(k1).toBe(k2) + }) + + it('treats undefined filter and sort as null', () => { + const withUndefined = tableRowsParamsKey({ pageSize: 1000, filter: undefined, sort: undefined }) + const withNull = tableRowsParamsKey({ pageSize: 1000, filter: null, sort: null }) + expect(withUndefined).toBe(withNull) + }) + + it('produces different keys for different filters', () => { + const k1 = tableRowsParamsKey({ pageSize: 1000, filter: null, sort: null }) + const k2 = tableRowsParamsKey({ + pageSize: 1000, + filter: { column: 'name', operator: 'eq', value: 'Alice' } as never, + sort: null, + }) + expect(k1).not.toBe(k2) + }) + + it('produces different keys for different page sizes', () => { + const k1 = tableRowsParamsKey({ pageSize: 1000, filter: null, sort: null }) + const k2 = tableRowsParamsKey({ pageSize: 500, filter: null, sort: null }) + expect(k1).not.toBe(k2) + }) + + it('produces different keys for different sorts', () => { + const k1 = tableRowsParamsKey({ pageSize: 1000, filter: null, sort: null }) + const k2 = tableRowsParamsKey({ + pageSize: 1000, + filter: null, + sort: { column: 'name', direction: 'asc' } as never, + }) + expect(k1).not.toBe(k2) + }) +}) + +describe('tableRowsInfiniteOptions', () => { + const PAGE_SIZE = 1000 + + function makeOpts(pageSize = PAGE_SIZE) { + return tableRowsInfiniteOptions({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + pageSize, + filter: null, + sort: null, + }) as { + queryKey: readonly unknown[] + getNextPageParam: ( + lastPage: { rows: unknown[] }, + allPages: unknown[], + lastPageParam: unknown + ) => number | undefined + } + } + + it('getNextPageParam returns undefined for a partial page (drain terminates)', () => { + const opts = makeOpts() + const lastPage = { rows: Array.from({ length: 500 }, (_, i) => ({ id: `r${i}` })) } + expect(opts.getNextPageParam(lastPage, [], 0)).toBeUndefined() + }) + + it('getNextPageParam returns undefined for an empty page', () => { + const opts = makeOpts() + expect(opts.getNextPageParam({ rows: [] }, [], 0)).toBeUndefined() + }) + + it('getNextPageParam returns next offset for a full page', () => { + const opts = makeOpts() + const fullPage = { rows: Array.from({ length: PAGE_SIZE }, (_, i) => ({ id: `r${i}` })) } + expect(opts.getNextPageParam(fullPage, [], 0)).toBe(PAGE_SIZE) + expect(opts.getNextPageParam(fullPage, [], PAGE_SIZE)).toBe(PAGE_SIZE * 2) + }) + + it('getNextPageParam advances correctly across three pages of 1000', () => { + const opts = makeOpts() + const fullPage = { rows: Array.from({ length: PAGE_SIZE }, (_, i) => ({ id: `r${i}` })) } + const lastPartialPage = { rows: Array.from({ length: 200 }, (_, i) => ({ id: `r${i}` })) } + + expect(opts.getNextPageParam(fullPage, [], 0)).toBe(1000) + expect(opts.getNextPageParam(fullPage, [], 1000)).toBe(2000) + expect(opts.getNextPageParam(lastPartialPage, [], 2000)).toBeUndefined() + }) + + it('queryKey includes the result of tableRowsParamsKey', () => { + const paramsKey = tableRowsParamsKey({ pageSize: PAGE_SIZE, filter: null, sort: null }) + const opts = makeOpts(PAGE_SIZE) + // queryKey is a tuple; one element must be exactly the paramsKey string + expect(opts.queryKey).toContain(paramsKey) + }) + + it('queryKey differs when filter changes', () => { + const opts1 = tableRowsInfiniteOptions({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + pageSize: PAGE_SIZE, + filter: null, + sort: null, + }) as { queryKey: readonly unknown[] } + const opts2 = tableRowsInfiniteOptions({ + workspaceId: WORKSPACE_ID, + tableId: TABLE_ID, + pageSize: PAGE_SIZE, + filter: { column: 'name', operator: 'eq', value: 'Alice' } as never, + sort: null, + }) as { queryKey: readonly unknown[] } + expect(JSON.stringify(opts1.queryKey)).not.toBe(JSON.stringify(opts2.queryKey)) + }) +}) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index 6ebd37ce26..89e306b8cc 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -8,6 +8,7 @@ import { useMemo } from 'react' import { createLogger } from '@sim/logger' import { type InfiniteData, + infiniteQueryOptions, keepPreviousData, useInfiniteQuery, useMutation, @@ -243,36 +244,31 @@ export function useTableRows({ }) } -/** - * Paginated row fetching with `useInfiniteQuery`. Each page requests `pageSize` - * rows at the next offset; `getNextPageParam` returns `undefined` once the last - * page comes back short, signalling end-of-list. - * - * Page 0 includes a server `COUNT(*)`; subsequent pages skip it. - */ -export function useInfiniteTableRows({ +export function tableRowsParamsKey({ + pageSize, + filter, + sort, +}: Pick): string { + return JSON.stringify({ pageSize, filter: filter ?? null, sort: sort ?? null }) +} + +/** `infiniteQueryOptions` factory shared by the hook and imperative drain calls to target the same cache key. */ +export function tableRowsInfiniteOptions({ workspaceId, tableId, pageSize, filter, sort, - enabled = true, -}: InfiniteTableRowsParams) { - const paramsKey = JSON.stringify({ - pageSize, - filter: filter ?? null, - sort: sort ?? null, - }) - const queryKey = useMemo(() => tableKeys.infiniteRows(tableId, paramsKey), [tableId, paramsKey]) - - return useInfiniteQuery({ - queryKey, +}: Omit) { + const paramsKey = tableRowsParamsKey({ pageSize, filter, sort }) + return infiniteQueryOptions({ + queryKey: tableKeys.infiniteRows(tableId, paramsKey), queryFn: ({ pageParam, signal }) => fetchTableRows({ workspaceId, tableId, limit: pageSize, - offset: pageParam, + offset: pageParam as number, filter, sort, includeTotal: pageParam === 0, @@ -281,13 +277,105 @@ export function useInfiniteTableRows({ initialPageParam: 0, getNextPageParam: (lastPage, _allPages, lastPageParam) => { if (lastPage.rows.length < pageSize) return undefined - return lastPageParam + pageSize + return (lastPageParam as number) + pageSize }, - enabled: Boolean(workspaceId && tableId) && enabled, staleTime: 30 * 1000, }) } +/** Page 0 fetches a server-side `COUNT(*)`; subsequent pages skip it. */ +export function useInfiniteTableRows({ + workspaceId, + tableId, + pageSize, + filter, + sort, + enabled = true, +}: InfiniteTableRowsParams) { + const queryClient = useQueryClient() + const paramsKey = tableRowsParamsKey({ pageSize, filter, sort }) + // Memoize the key so the polling useEffect below doesn't fire on every render. + const queryKey = useMemo(() => tableKeys.infiniteRows(tableId, paramsKey), [tableId, paramsKey]) + + const query = useInfiniteQuery({ + ...tableRowsInfiniteOptions({ workspaceId, tableId, pageSize, filter, sort }), + queryKey, + enabled: Boolean(workspaceId && tableId) && enabled, + }) + + /** + * Per-page polling. Built-in `refetchInterval` would refetch every loaded + * page on each tick — wasteful when only one page has running cells. + * Instead, walk pages each tick and refetch ONLY the dirty ones, splicing + * results back into the cache. Polling stops when no page has in-flight + * cells, or while a mutation is running (optimistic-update guard). + */ + useEffect(() => { + if (!enabled || !workspaceId || !tableId) return + let cancelled = false + let timeoutId: ReturnType | null = null + const tick = async () => { + if (cancelled) return + if (queryClient.isMutating() === 0) { + const data = queryClient.getQueryData>(queryKey) + const dirty: number[] = [] + if (data) { + for (let i = 0; i < data.pages.length; i++) { + if (hasRunningGroupExecution(data.pages[i].rows)) { + dirty.push(data.pageParams[i] ?? i * pageSize) + } + } + } + if (dirty.length > 0) { + await Promise.all( + dirty.map(async (offset) => { + try { + const fresh = await fetchTableRows({ + workspaceId, + tableId, + limit: pageSize, + offset, + filter, + sort, + includeTotal: offset === 0, + }) + if (cancelled) return + queryClient.setQueryData>( + queryKey, + (prev) => { + if (!prev) return prev + const idx = prev.pageParams.indexOf(offset) + if (idx === -1) return prev + const merged = mergePagePreservingIdentity(prev.pages[idx], fresh) + if (merged === prev.pages[idx]) return prev + const nextPages = prev.pages.slice() + nextPages[idx] = merged + return { ...prev, pages: nextPages } + } + ) + } catch { + // Transient fetch failure — next tick retries. Don't kill the loop. + } + }) + ) + } + } + if (cancelled) return + // Recursive setTimeout instead of setInterval so a slow tick can't + // overlap the next one — out-of-order responses would otherwise let + // stale data overwrite fresh. + timeoutId = setTimeout(() => void tick(), ROWS_POLL_INTERVAL_WHILE_RUNNING_MS) + } + timeoutId = setTimeout(() => void tick(), ROWS_POLL_INTERVAL_WHILE_RUNNING_MS) + return () => { + cancelled = true + if (timeoutId !== null) clearTimeout(timeoutId) + } + }, [enabled, workspaceId, tableId, pageSize, filter, sort, queryClient, queryKey]) + + return query +} + /** * Create a new table in a workspace. */ @@ -923,7 +1011,9 @@ export function useUploadCsvToTable() { return response.json() }, onError: (error) => { + if (isValidationError(error)) return logger.error('Failed to upload CSV:', error) + toast.error(error.message, { duration: 5000 }) }, onSettled: () => { queryClient.invalidateQueries({ queryKey: tableKeys.lists() }) diff --git a/apps/sim/hooks/use-table-undo.test.ts b/apps/sim/hooks/use-table-undo.test.ts new file mode 100644 index 0000000000..e39db3a03a --- /dev/null +++ b/apps/sim/hooks/use-table-undo.test.ts @@ -0,0 +1,230 @@ +/** + * @vitest-environment node + */ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +// Passthrough React hooks so the hook can run outside a React root. +vi.mock('react', () => ({ + useCallback: (fn: unknown) => fn, + useEffect: (fn: () => void) => fn(), + useRef: (init: unknown) => ({ current: init }), +})) + +const mockMutate = vi.fn() +const mockMutateAsync = vi.fn() + +vi.mock('@/hooks/queries/tables', () => ({ + useUpdateTableRow: vi.fn(() => ({ mutate: mockMutate })), + useCreateTableRow: vi.fn(() => ({ mutate: mockMutate })), + useBatchCreateTableRows: vi.fn(() => ({ mutate: mockMutate, mutateAsync: mockMutateAsync })), + useBatchUpdateTableRows: vi.fn(() => ({ mutate: mockMutate, mutateAsync: mockMutateAsync })), + useDeleteTableRow: vi.fn(() => ({ mutate: mockMutate })), + useDeleteTableRows: vi.fn(() => ({ mutate: mockMutate })), + useAddTableColumn: vi.fn(() => ({ mutate: mockMutate })), + useUpdateColumn: vi.fn(() => ({ mutate: mockMutate })), + useDeleteColumn: vi.fn(() => ({ mutate: mockMutate })), + useRenameTable: vi.fn(() => ({ mutate: mockMutate })), + useUpdateTableMetadata: vi.fn(() => ({ mutate: mockMutate })), +})) + +vi.mock('@/lib/table/constants', () => ({ + TABLE_LIMITS: { MAX_BULK_OPERATION_SIZE: 3 }, // small limit so tests don't need 1000 items +})) + +const mockPopUndo = vi.fn() +const mockPopRedo = vi.fn() +const mockPush = vi.fn() +const mockPatchRedoRowId = vi.fn() +const mockPatchUndoRowId = vi.fn() +const mockClear = vi.fn() + +const storeState = { + stacks: {}, + push: mockPush, + popUndo: mockPopUndo, + popRedo: mockPopRedo, + patchRedoRowId: mockPatchRedoRowId, + patchUndoRowId: mockPatchUndoRowId, + clear: mockClear, +} + +vi.mock('@/stores/table/store', () => ({ + useTableUndoStore: vi.fn((selector: (s: typeof storeState) => unknown) => selector(storeState)), + runWithoutRecording: (fn: () => void) => fn(), +})) + +import { useTableUndo } from '@/hooks/use-table-undo' +import type { TableUndoAction } from '@/stores/table/types' + +const WORKSPACE_ID = 'ws-1' +const TABLE_ID = 'tbl-1' + +function makeHook() { + return useTableUndo({ workspaceId: WORKSPACE_ID, tableId: TABLE_ID }) +} + +function makeEntry(action: TableUndoAction) { + return { id: 'e1', action, timestamp: Date.now() } +} + +function makeCellsForClear(count: number) { + return Array.from({ length: count }, (_, i) => ({ + rowId: `row-${i}`, + data: { col: `val-${i}` }, + })) +} + +/** Drain the microtask queue so all async chunks in executeAction finish. */ +async function flush() { + await new Promise((r) => setTimeout(r, 0)) +} + +beforeEach(() => { + vi.clearAllMocks() + mockMutateAsync.mockResolvedValue({}) +}) + +describe('useTableUndo – clear-cells chunking (via undo)', () => { + it('sends a single mutateAsync call when cells fit in one chunk', async () => { + const cells = makeCellsForClear(2) + mockPopUndo.mockReturnValueOnce(makeEntry({ type: 'clear-cells', cells })) + const { undo } = makeHook() + ;(undo as () => void)() + await flush() + expect(mockMutateAsync).toHaveBeenCalledTimes(1) + expect(mockMutateAsync.mock.calls[0][0].updates).toHaveLength(2) + }) + + it('splits into multiple chunks when cells exceed the limit', async () => { + const cells = makeCellsForClear(7) // limit=3 → [3,3,1] + mockPopUndo.mockReturnValueOnce(makeEntry({ type: 'clear-cells', cells })) + const { undo } = makeHook() + ;(undo as () => void)() + await flush() + expect(mockMutateAsync).toHaveBeenCalledTimes(3) + expect(mockMutateAsync.mock.calls[0][0].updates).toHaveLength(3) + expect(mockMutateAsync.mock.calls[1][0].updates).toHaveLength(3) + expect(mockMutateAsync.mock.calls[2][0].updates).toHaveLength(1) + }) + + it('sends original data values for undo direction', async () => { + const cells = makeCellsForClear(1) + mockPopUndo.mockReturnValueOnce(makeEntry({ type: 'clear-cells', cells })) + const { undo } = makeHook() + ;(undo as () => void)() + await flush() + expect(mockMutateAsync.mock.calls[0][0].updates[0].data.col).toBe('val-0') + }) + + it('sends null values for redo direction', async () => { + const cells = makeCellsForClear(1) + mockPopRedo.mockReturnValueOnce(makeEntry({ type: 'clear-cells', cells })) + const { redo } = makeHook() + ;(redo as () => void)() + await flush() + expect(mockMutateAsync.mock.calls[0][0].updates[0].data.col).toBeNull() + }) + + it('does not call mutateAsync when cells is empty', async () => { + mockPopUndo.mockReturnValueOnce(makeEntry({ type: 'clear-cells', cells: [] })) + const { undo } = makeHook() + ;(undo as () => void)() + await flush() + expect(mockMutateAsync).not.toHaveBeenCalled() + }) + + it('stops processing after the first failing chunk', async () => { + mockMutateAsync.mockRejectedValueOnce(new Error('Network error')) + const cells = makeCellsForClear(5) // limit=3 → would be [3,2] but stops at chunk 1 + mockPopUndo.mockReturnValueOnce(makeEntry({ type: 'clear-cells', cells })) + const { undo } = makeHook() + // executeAction catches the error internally via logger — undo itself doesn't re-throw. + ;(undo as () => void)() + await flush() + expect(mockMutateAsync).toHaveBeenCalledTimes(1) + }) +}) + +describe('useTableUndo – update-cells chunking (via undo)', () => { + function makeCellsForUpdate(count: number) { + return Array.from({ length: count }, (_, i) => ({ + rowId: `row-${i}`, + oldData: { col: `old-${i}` }, + newData: { col: `new-${i}` }, + })) + } + + it('sends a single call when cells fit within limit', async () => { + const cells = makeCellsForUpdate(2) + mockPopUndo.mockReturnValueOnce(makeEntry({ type: 'update-cells', cells })) + const { undo } = makeHook() + ;(undo as () => void)() + await flush() + expect(mockMutateAsync).toHaveBeenCalledTimes(1) + expect(mockMutateAsync.mock.calls[0][0].updates[0].data.col).toBe('old-0') + }) + + it('chunks across multiple calls and picks the correct direction data', async () => { + const cells = makeCellsForUpdate(8) // limit=3 → [3,3,2] + mockPopRedo.mockReturnValueOnce(makeEntry({ type: 'update-cells', cells })) + const { redo } = makeHook() + ;(redo as () => void)() + await flush() + expect(mockMutateAsync).toHaveBeenCalledTimes(3) + const lastChunk = mockMutateAsync.mock.calls[2][0].updates + expect(lastChunk).toHaveLength(2) + // redo direction → newData + expect(lastChunk[0].data.col).toBe('new-6') + }) +}) + +describe('useTableUndo – delete-column undo cell restore chunking', () => { + const baseAction: TableUndoAction = { + type: 'delete-column', + columnName: 'col', + columnType: 'string' as const, + columnPosition: 0, + columnUnique: false, + columnRequired: false, + cellData: [], + previousOrder: null, + previousWidth: null, + } + + it('does not call mutateAsync when cellData is empty', async () => { + mockPopUndo.mockReturnValueOnce(makeEntry(baseAction)) + const { undo } = makeHook() + ;(undo as () => void)() + await flush() + // addColumnMutation.mutate fires but the cell-restore block should not. + expect(mockMutateAsync).not.toHaveBeenCalled() + }) + + it('fires chunked mutateAsync calls via the onSuccess IIFE when cellData exceeds limit', async () => { + const cellData = Array.from({ length: 5 }, (_, i) => ({ rowId: `row-${i}`, value: i })) + const action: TableUndoAction = { ...baseAction, cellData } + mockPopUndo.mockReturnValueOnce(makeEntry(action)) + + // addColumnMutation.mutate is the first mockMutate call. + // Capture its onSuccess and invoke it to simulate column creation completing. + let capturedOnSuccess: (() => void) | undefined + mockMutate.mockImplementationOnce((_: unknown, opts: { onSuccess?: () => void }) => { + capturedOnSuccess = opts?.onSuccess + }) + + const { undo } = makeHook() + ;(undo as () => void)() + await flush() + + // At this point executeAction has returned, but the restore happens in the + // addColumn onSuccess callback — fire it now. + capturedOnSuccess?.() + // Allow the void IIFE's microtasks to drain. + await new Promise((r) => setTimeout(r, 0)) + + // limit=3 → [3, 2] + expect(mockMutateAsync).toHaveBeenCalledTimes(2) + expect(mockMutateAsync.mock.calls[0][0].updates).toHaveLength(3) + expect(mockMutateAsync.mock.calls[1][0].updates).toHaveLength(2) + }) +}) diff --git a/apps/sim/hooks/use-table-undo.ts b/apps/sim/hooks/use-table-undo.ts index accdd79b59..9922dcbbf7 100644 --- a/apps/sim/hooks/use-table-undo.ts +++ b/apps/sim/hooks/use-table-undo.ts @@ -4,6 +4,7 @@ import { useCallback, useEffect, useRef } from 'react' import { createLogger } from '@sim/logger' +import { TABLE_LIMITS } from '@/lib/table/constants' import { useAddTableColumn, useBatchCreateTableRows, @@ -90,7 +91,7 @@ export function useTableUndo({ ) const executeAction = useCallback( - (action: TableUndoAction, direction: 'undo' | 'redo') => { + async (action: TableUndoAction, direction: 'undo' | 'redo') => { try { switch (action.type) { case 'update-cell': { @@ -110,7 +111,11 @@ export function useTableUndo({ ? cell.data : Object.fromEntries(Object.keys(cell.data).map((k) => [k, null])), })) - batchUpdateRowsMutation.mutate({ updates }) + for (let i = 0; i < updates.length; i += TABLE_LIMITS.MAX_BULK_OPERATION_SIZE) { + await batchUpdateRowsMutation.mutateAsync({ + updates: updates.slice(i, i + TABLE_LIMITS.MAX_BULK_OPERATION_SIZE), + }) + } break } @@ -119,7 +124,11 @@ export function useTableUndo({ rowId: cell.rowId, data: direction === 'undo' ? cell.oldData : cell.newData, })) - batchUpdateRowsMutation.mutate({ updates }) + for (let i = 0; i < updates.length; i += TABLE_LIMITS.MAX_BULK_OPERATION_SIZE) { + await batchUpdateRowsMutation.mutateAsync({ + updates: updates.slice(i, i + TABLE_LIMITS.MAX_BULK_OPERATION_SIZE), + }) + } break } @@ -239,17 +248,24 @@ export function useTableUndo({ rowId: c.rowId, data: { [action.columnName]: c.value }, })) - batchUpdateRowsMutation.mutate( - { updates }, - { - onError: (error) => { - logger.error('Failed to restore cell data on delete-column undo', { - columnName: action.columnName, - error, + void (async () => { + try { + for ( + let i = 0; + i < updates.length; + i += TABLE_LIMITS.MAX_BULK_OPERATION_SIZE + ) { + await batchUpdateRowsMutation.mutateAsync({ + updates: updates.slice(i, i + TABLE_LIMITS.MAX_BULK_OPERATION_SIZE), }) - }, + } + } catch (error) { + logger.error('Failed to restore cell data on delete-column undo', { + columnName: action.columnName, + error, + }) } - ) + })() } const metadata: Record = {} if (action.previousOrder) { @@ -348,7 +364,7 @@ export function useTableUndo({ if (!entry) return runWithoutRecording(() => { - executeAction(entry.action, 'undo') + void executeAction(entry.action, 'undo') }) }, [popUndo, tableId, executeAction]) @@ -357,7 +373,7 @@ export function useTableUndo({ if (!entry) return runWithoutRecording(() => { - executeAction(entry.action, 'redo') + void executeAction(entry.action, 'redo') }) }, [popRedo, tableId, executeAction]) diff --git a/apps/sim/lib/table/constants.ts b/apps/sim/lib/table/constants.ts index fd165163f2..67f01eb419 100644 --- a/apps/sim/lib/table/constants.ts +++ b/apps/sim/lib/table/constants.ts @@ -9,7 +9,7 @@ export const TABLE_LIMITS = { MAX_ROWS_PER_TABLE: 10000, MAX_ROW_SIZE_BYTES: 100 * 1024, // 100KB MAX_COLUMNS_PER_TABLE: 50, - MAX_TABLE_NAME_LENGTH: 50, + MAX_TABLE_NAME_LENGTH: 128, MAX_COLUMN_NAME_LENGTH: 50, MAX_STRING_VALUE_LENGTH: 10000, MAX_DESCRIPTION_LENGTH: 500, From 9099a98e6011acdf364de1bac7e1999e4e5770ec Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 8 May 2026 22:49:28 -0700 Subject: [PATCH 02/20] chore(tables): remove extraneous comments --- .../tables/[tableId]/hooks/use-table.ts | 47 ++++++------------- apps/sim/hooks/queries/tables.ts | 1 - apps/sim/hooks/use-table-undo.ts | 7 --- 3 files changed, 15 insertions(+), 40 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts index 072dc25612..12e4e7a3da 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts @@ -31,50 +31,38 @@ interface FetchNextPageResult { } export interface UseTableReturn { - /** Table definition (name, schema, metadata, etc.). */ tableData: TableDefinition | undefined isLoadingTable: boolean - /** Flattened rows across every fetched page. */ + /** Flattened across every fetched infinite-query page. */ rows: TableRow[] isLoadingRows: boolean refetchRows: () => void /** - * Fetch the next page of rows. The resolved value's `hasNextPage` reflects - * the post-fetch cache state — read from this rather than the parent's - * `hasNextPage` state, which only updates on the next React render. + * The resolved value's `hasNextPage` reflects the post-fetch cache state — + * read from this rather than the hook's `hasNextPage`, which only updates on + * the next React render. */ fetchNextPage: () => Promise hasNextPage: boolean isFetchingNextPage: boolean - /** Workspace-wide workflow metadata used by header chips and the column sidebar. */ workflows: WorkflowMetadata[] | undefined - /** Stable reference to `tableData?.schema?.columns ?? []`. */ columns: ColumnDefinition[] - /** Stable reference to `tableData?.schema?.workflowGroups ?? []`. */ tableWorkflowGroups: WorkflowGroup[] - /** Pre-fetched live state for every unique workflow id used by the table. */ workflowStates: Map - /** Pre-resolved icon + block-name info per output column name. Headers read - * from this map instead of each subscribing to its own workflow-state query. */ + /** Headers read from this map instead of each subscribing to its own workflow-state query. */ columnSourceInfo: Map /** - * Fetches any missing row pages and returns the full flat row list directly - * from cache — safe to read immediately without waiting for a React re-render. - * Gate bulk ops that must act on the complete row set with this. + * Fetches any missing pages then returns the full flat row list from cache. + * Safe to read immediately — no React re-render required. Gate bulk ops that + * need the complete row set behind this. */ ensureAllRowsLoaded: () => Promise } /** - * Coordinator hook for the table view's data layer. Wraps row/schema/workflow - * fetching and exposes the derived collections every consumer needs (display - * columns, source-info map, workflow-name lookup). Mirrors the shape of - * `use-chat`'s coordinator: one hook returning a typed bundle the surface - * component destructures. - * - * Local interaction state (drag, resize, selection, editing) stays in the - * `Table` component — moving that here would push every keystroke through a - * single hook return and re-render the world. + * Local interaction state (drag, resize, selection, editing) intentionally + * stays in the `Table` component — moving it here would push every keystroke + * through this hook's return value and re-render everything. */ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams): UseTableReturn { const queryClient = useQueryClient() @@ -96,10 +84,8 @@ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams) enabled: Boolean(workspaceId && tableId), }) - // Background drain: TanStack's prefetchInfiniteQuery is a no-op when the first page is - // already fresh (staleTime not exceeded). Drive the drain through fetchNextPage instead - // — it only fetches the *next* page (not from scratch) and fires whenever a full page - // is sitting in cache, chaining until getNextPageParam returns undefined. + // prefetchInfiniteQuery is a no-op when data is fresh (staleTime not exceeded), + // so drive the drain through fetchNextPage — it appends one page at a time. useEffect(() => { if (!workspaceId || !tableId || !hasNextPage || isFetchingNextPage) return void fetchNextPage() @@ -125,14 +111,11 @@ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams) sort: queryOptions.sort, }) - // Drain pages one at a time using the cache as the source of truth. - // fetchNextPage appends exactly one new page without re-fetching existing - // ones. getQueryData reads the live cache synchronously — bypassing React's - // render cycle — so updated pages are visible immediately after each await. + // getQueryData bypasses React's render cycle — pages added by fetchNextPage + // are visible synchronously after each await without waiting for a re-render. while (true) { const data = queryClient.getQueryData(opts.queryKey) const lastPage = data?.pages[data.pages.length - 1] - // A partial (or absent) last page means all available rows are in cache. if (!lastPage || lastPage.rows.length < TABLE_LIMITS.MAX_QUERY_LIMIT) break const result = await fetchNextPage() if (result.status === 'error') { diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index 89e306b8cc..d6f37a06b4 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -252,7 +252,6 @@ export function tableRowsParamsKey({ return JSON.stringify({ pageSize, filter: filter ?? null, sort: sort ?? null }) } -/** `infiniteQueryOptions` factory shared by the hook and imperative drain calls to target the same cache key. */ export function tableRowsInfiniteOptions({ workspaceId, tableId, diff --git a/apps/sim/hooks/use-table-undo.ts b/apps/sim/hooks/use-table-undo.ts index 9922dcbbf7..d27f3826f7 100644 --- a/apps/sim/hooks/use-table-undo.ts +++ b/apps/sim/hooks/use-table-undo.ts @@ -1,7 +1,3 @@ -/** - * Hook that connects the table undo/redo store to React Query mutations. - */ - import { useCallback, useEffect, useRef } from 'react' import { createLogger } from '@sim/logger' import { TABLE_LIMITS } from '@/lib/table/constants' @@ -23,9 +19,6 @@ import type { TableUndoAction } from '@/stores/table/types' const logger = createLogger('useTableUndo') -/** - * Extract the row ID from a create-row API response. - */ export function extractCreatedRowId(response: Record): string | undefined { const data = response?.data as Record | undefined const row = data?.row as Record | undefined From 61752e93c4e6424560d2e6b5bdb15262f8836b64 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 8 May 2026 22:58:26 -0700 Subject: [PATCH 03/20] fix(tables): add missing useEffect import; chunk range-selection delete and cut --- .../[tableId]/components/table-grid/table-grid.tsx | 10 ++++++++-- apps/sim/hooks/queries/tables.ts | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index 48e256c103..15cece49c2 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -1909,7 +1909,10 @@ export function TableGrid({ batchUpdates.push({ rowId: row.id, data: updates }) } if (batchUpdates.length > 0) { - batchUpdateRef.current({ updates: batchUpdates }) + void chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current).catch((error) => { + logger.error('Failed to clear selected cells', { error }) + toast.error('Failed to clear cells — please try again') + }) } if (undoCells.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) @@ -2083,7 +2086,10 @@ export function TableGrid({ } e.clipboardData?.setData('text/plain', lines.join('\n')) if (batchUpdates.length > 0) { - batchUpdateRef.current({ updates: batchUpdates }) + void chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current).catch((error) => { + logger.error('Failed to cut selected cells', { error }) + toast.error('Failed to cut — please try again') + }) } if (undoCells.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index d6f37a06b4..59e473c14c 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -4,7 +4,7 @@ * React Query hooks for managing user-defined tables. */ -import { useMemo } from 'react' +import { useEffect, useMemo } from 'react' import { createLogger } from '@sim/logger' import { type InfiniteData, From 2cb026dfc4d5984b47abb7821814e581b76f9d37 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 8 May 2026 23:05:17 -0700 Subject: [PATCH 04/20] fix(tables): add hasRunningGroupExecution and import it --- apps/sim/hooks/queries/tables.ts | 6 +++++- apps/sim/lib/table/deps.ts | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index 59e473c14c..46f8b99090 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -70,7 +70,11 @@ import type { WorkflowGroupDependencies, WorkflowGroupOutput, } from '@/lib/table' -import { areOutputsFilled, optimisticallyScheduleNewlyEligibleGroups } from '@/lib/table/deps' +import { + areOutputsFilled, + hasRunningGroupExecution, + optimisticallyScheduleNewlyEligibleGroups, +} from '@/lib/table/deps' const logger = createLogger('TableQueries') diff --git a/apps/sim/lib/table/deps.ts b/apps/sim/lib/table/deps.ts index d9b33f59db..fabe8909c9 100644 --- a/apps/sim/lib/table/deps.ts +++ b/apps/sim/lib/table/deps.ts @@ -24,6 +24,15 @@ export function isExecInFlight(exec: RowExecutionMetadata | undefined): boolean return false } +export function hasRunningGroupExecution(rows: TableRow[]): boolean { + for (const row of rows) { + for (const exec of Object.values(row.executions)) { + if (isExecInFlight(exec)) return true + } + } + return false +} + /** * True when every output column the group writes still has a non-empty value * on this row. The "completed" exec status is metadata, but the cells are the From a4e7db244d148846e087579a7c659f23f88e10a4 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 8 May 2026 23:26:02 -0700 Subject: [PATCH 05/20] fix(tables): define mergePagePreservingIdentity helper used in polling cache merge --- apps/sim/hooks/queries/tables.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index 46f8b99090..0e5af4578c 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -248,6 +248,26 @@ export function useTableRows({ }) } +/** Merges a freshly-fetched page into the cached page while preserving row + * object identity for unchanged rows (by `updatedAt`). Returns the original + * `prev` reference unchanged when nothing has actually changed — callers can + * use a `===` check to skip a `setQueryData` write entirely. */ +function mergePagePreservingIdentity( + prev: TableRowsResponse, + fresh: TableRowsResponse +): TableRowsResponse { + if (prev.totalCount !== fresh.totalCount || prev.rows.length !== fresh.rows.length) return fresh + const prevById = new Map(prev.rows.map((r) => [r.id, r])) + let allSame = true + const nextRows = fresh.rows.map((freshRow) => { + const prevRow = prevById.get(freshRow.id) + if (prevRow && String(prevRow.updatedAt) === String(freshRow.updatedAt)) return prevRow + allSame = false + return freshRow + }) + return allSame ? prev : { ...fresh, rows: nextRows } +} + export function tableRowsParamsKey({ pageSize, filter, From 46e3bbffe5288c1464f8a93cee11b6b89219edc7 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 8 May 2026 23:44:09 -0700 Subject: [PATCH 06/20] fix(tables): define ROWS_POLL_INTERVAL_WHILE_RUNNING_MS constant used in polling loop --- apps/sim/hooks/queries/tables.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index 0e5af4578c..486c9aa528 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -78,6 +78,8 @@ import { const logger = createLogger('TableQueries') +const ROWS_POLL_INTERVAL_WHILE_RUNNING_MS = 2_000 + type TableQueryScope = 'active' | 'archived' | 'all' export const tableKeys = { From 6f93d345723fdeaab4de1011dc01294c23c2257d Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 8 May 2026 23:51:02 -0700 Subject: [PATCH 07/20] fix(tables): capture rowSel before await in delete handler; handle clipboard NotAllowedError --- .../components/table-grid/table-grid.tsx | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index 15cece49c2..767ed5216f 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -1633,9 +1633,9 @@ export function TableGrid({ if (editingCellRef.current) return if (!canEditRef.current) return e.preventDefault() + const rowSel = rowSelectionRef.current void (async () => { const allRows = await ensureAllRowsLoadedRef.current() - const rowSel = rowSelectionRef.current const currentCols = columnsRef.current const undoCells: Array<{ rowId: string; data: Record }> = [] const batchUpdates: Array<{ rowId: string; data: Record }> = [] @@ -1966,7 +1966,17 @@ export function TableGrid({ toast.error('Clipboard access is unavailable in this context') return } - await navigator.clipboard.writeText(lines.join('\n')) + try { + await navigator.clipboard.writeText(lines.join('\n')) + } catch (err) { + if (err instanceof DOMException && err.name === 'NotAllowedError') { + toast.error( + 'Clipboard permission expired — press Cmd+C again immediately after selecting' + ) + } else { + throw err + } + } })().catch((error) => { logger.error('Failed to copy selected rows', { error }) toast.error('Failed to copy — please try again') @@ -2037,7 +2047,17 @@ export function TableGrid({ toast.error('Clipboard access is unavailable in this context') return } - await navigator.clipboard.writeText(lines.join('\n')) + try { + await navigator.clipboard.writeText(lines.join('\n')) + } catch (err) { + if (err instanceof DOMException && err.name === 'NotAllowedError') { + toast.error( + 'Clipboard permission expired — press Cmd+X again immediately after selecting' + ) + } else { + throw err + } + } if (cutUpdates.length > 0) { await chunkBatchUpdates(cutUpdates, batchUpdateAsyncRef.current) } From 834260713fae8f650491682b1f58f21d822c846c Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 00:03:33 -0700 Subject: [PATCH 08/20] fix(tables): abort cut on clipboard NotAllowedError to prevent silent cell deletion --- .../tables/[tableId]/components/table-grid/table-grid.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index 767ed5216f..ffb97c524c 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -2054,9 +2054,9 @@ export function TableGrid({ toast.error( 'Clipboard permission expired — press Cmd+X again immediately after selecting' ) - } else { - throw err + return } + throw err } if (cutUpdates.length > 0) { await chunkBatchUpdates(cutUpdates, batchUpdateAsyncRef.current) From 691746d4479744daec2461dbbe22f172d2f6b105 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 00:08:34 -0700 Subject: [PATCH 09/20] fix(tables): push undo before chunkBatchUpdates to survive partial chunk failures --- .../[tableId]/components/table-grid/table-grid.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index ffb97c524c..d1cec05b04 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -1650,12 +1650,12 @@ export function TableGrid({ undoCells.push({ rowId: row.id, data: previousData }) batchUpdates.push({ rowId: row.id, data: updates }) } - if (batchUpdates.length > 0) { - await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) - } if (undoCells.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) } + if (batchUpdates.length > 0) { + await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) + } })().catch((error) => { logger.error('Failed to clear selected cells', { error }) toast.error('Failed to clear cells — please try again') @@ -1881,9 +1881,9 @@ export function TableGrid({ undoCells.push({ rowId: row.id, data: previousData }) batchUpdates.push({ rowId: row.id, data: updates }) } + if (undoCells.length > 0) pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) if (batchUpdates.length > 0) await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) - if (undoCells.length > 0) pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) })().catch((error) => { logger.error('Failed to clear column values', { error }) toast.error('Failed to clear column values — please try again') @@ -2058,12 +2058,12 @@ export function TableGrid({ } throw err } - if (cutUpdates.length > 0) { - await chunkBatchUpdates(cutUpdates, batchUpdateAsyncRef.current) - } if (cutUndo.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: cutUndo }) } + if (cutUpdates.length > 0) { + await chunkBatchUpdates(cutUpdates, batchUpdateAsyncRef.current) + } })().catch((error) => { logger.error('Failed to cut selected rows', { error }) toast.error('Failed to cut — please try again') From fa77b7f14b826949af97c45e7bb420f48123adb2 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 09:52:15 -0700 Subject: [PATCH 10/20] fix(tables): use text input for number cells; idle poll backoff; csv error toast; column-cut drain --- .../table-grid/cells/inline-editors.tsx | 10 +--- .../components/table-grid/table-grid.tsx | 59 +++++++++++++++++++ apps/sim/hooks/queries/tables.ts | 14 +++-- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx index 742fbbac6f..edbe496040 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx @@ -198,17 +198,13 @@ function InlineTextEditor({ return ( setDraft(e.target.value)} onKeyDown={handleKeyDown} onBlur={() => doSave('blur')} - className={cn( - 'w-full min-w-0 select-text border-none bg-transparent p-0 text-[var(--text-primary)] text-small outline-none', - isNumber && - '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none' - )} + className='w-full min-w-0 select-text border-none bg-transparent p-0 text-[var(--text-primary)] text-small outline-none' /> ) } diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index d1cec05b04..bcc32f0606 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -2078,6 +2078,65 @@ export function TableGrid({ if (!sel) return e.preventDefault() + + if (isColumnSelectionRef.current) { + // Column-header cut spans all rows — drain pages first, then use async + // clipboard so we don't block the event before the drain completes. + void (async () => { + const allRows = await ensureAllRowsLoadedRef.current() + const lines: string[] = [] + const undoCells: Array<{ rowId: string; data: Record }> = [] + const batchUpdates: Array<{ rowId: string; data: Record }> = [] + for (const row of allRows) { + const cells: string[] = [] + const updates: Record = {} + const previousData: Record = {} + for (let c = sel.startCol; c <= sel.endCol; c++) { + const colName = cols[c]?.name + if (!colName) continue + const value: unknown = row.data[colName] + cells.push( + value === null || value === undefined + ? '' + : typeof value === 'object' + ? JSON.stringify(value) + : String(value) + ) + previousData[colName] = row.data[colName] ?? null + updates[colName] = null + } + lines.push(cells.join('\t')) + undoCells.push({ rowId: row.id, data: previousData }) + batchUpdates.push({ rowId: row.id, data: updates }) + } + if (!navigator.clipboard) { + toast.error('Clipboard access is unavailable in this context') + return + } + try { + await navigator.clipboard.writeText(lines.join('\n')) + } catch (err) { + if (err instanceof DOMException && err.name === 'NotAllowedError') { + toast.error( + 'Clipboard permission expired — press Cmd+X again immediately after selecting' + ) + return + } + throw err + } + if (undoCells.length > 0) { + pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) + } + if (batchUpdates.length > 0) { + await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) + } + })().catch((error) => { + logger.error('Failed to cut column cells', { error }) + toast.error('Failed to cut — please try again') + }) + return + } + const lines: string[] = [] const undoCells: Array<{ rowId: string; data: Record }> = [] const batchUpdates: Array<{ rowId: string; data: Record }> = [] diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index 486c9aa528..b813038b3f 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -79,6 +79,7 @@ import { const logger = createLogger('TableQueries') const ROWS_POLL_INTERVAL_WHILE_RUNNING_MS = 2_000 +const ROWS_POLL_INTERVAL_IDLE_MS = 30_000 type TableQueryScope = 'active' | 'archived' | 'all' @@ -341,6 +342,7 @@ export function useInfiniteTableRows({ let timeoutId: ReturnType | null = null const tick = async () => { if (cancelled) return + let hasDirty = false if (queryClient.isMutating() === 0) { const data = queryClient.getQueryData>(queryKey) const dirty: number[] = [] @@ -351,7 +353,8 @@ export function useInfiniteTableRows({ } } } - if (dirty.length > 0) { + hasDirty = dirty.length > 0 + if (hasDirty) { await Promise.all( dirty.map(async (offset) => { try { @@ -388,8 +391,12 @@ export function useInfiniteTableRows({ if (cancelled) return // Recursive setTimeout instead of setInterval so a slow tick can't // overlap the next one — out-of-order responses would otherwise let - // stale data overwrite fresh. - timeoutId = setTimeout(() => void tick(), ROWS_POLL_INTERVAL_WHILE_RUNNING_MS) + // stale data overwrite fresh. Use a long interval when idle so tables + // with no running executions don't burn CPU on constant cache reads. + timeoutId = setTimeout( + () => void tick(), + hasDirty ? ROWS_POLL_INTERVAL_WHILE_RUNNING_MS : ROWS_POLL_INTERVAL_IDLE_MS + ) } timeoutId = setTimeout(() => void tick(), ROWS_POLL_INTERVAL_WHILE_RUNNING_MS) return () => { @@ -1036,7 +1043,6 @@ export function useUploadCsvToTable() { return response.json() }, onError: (error) => { - if (isValidationError(error)) return logger.error('Failed to upload CSV:', error) toast.error(error.message, { duration: 5000 }) }, From 4c63d4f2fc2756b36d96216310f19fb147028e27 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 10:12:04 -0700 Subject: [PATCH 11/20] =?UTF-8?q?fix(tables):=20audit=20fixes=20=E2=80=94?= =?UTF-8?q?=20column-copy=20drain,=20polling=20scope,=20merge=20identity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix polling tick: move Promise.all inside else-branch so dirty[] stays in scope; keep hasDirty=true during active mutations so the short interval fires while chunked batch-updates are in flight - Add isColumnSelectionRef branch to handleCopy (mirrors handleCut fix): column-header Cmd+C now drains all pages before building clipboard content - Replace String(updatedAt) comparison in mergePagePreservingIdentity with Date.getTime() equality — handles ISO vs +00:00 timezone variants - Remove redundant batchUpdates.length > 0 guards at chunkBatchUpdates callsites (empty-array case is handled inside the function) - Export _mergePagePreservingIdentity for unit testing - Add 6 unit tests covering mergePagePreservingIdentity edge cases --- .../components/table-grid/table-grid.tsx | 76 ++++++++++++++----- apps/sim/hooks/queries/tables.test.ts | 73 ++++++++++++++++++ apps/sim/hooks/queries/tables.ts | 19 +++-- 3 files changed, 140 insertions(+), 28 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index bcc32f0606..0b6c444e9b 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -1653,9 +1653,7 @@ export function TableGrid({ if (undoCells.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) } - if (batchUpdates.length > 0) { - await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) - } + await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) })().catch((error) => { logger.error('Failed to clear selected cells', { error }) toast.error('Failed to clear cells — please try again') @@ -1882,8 +1880,7 @@ export function TableGrid({ batchUpdates.push({ rowId: row.id, data: updates }) } if (undoCells.length > 0) pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) - if (batchUpdates.length > 0) - await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) + await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) })().catch((error) => { logger.error('Failed to clear column values', { error }) toast.error('Failed to clear column values — please try again') @@ -1908,12 +1905,10 @@ export function TableGrid({ undoCells.push({ rowId: row.id, data: previousData }) batchUpdates.push({ rowId: row.id, data: updates }) } - if (batchUpdates.length > 0) { - void chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current).catch((error) => { - logger.error('Failed to clear selected cells', { error }) - toast.error('Failed to clear cells — please try again') - }) - } + void chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current).catch((error) => { + logger.error('Failed to clear selected cells', { error }) + toast.error('Failed to clear cells — please try again') + }) if (undoCells.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) } @@ -1991,6 +1986,51 @@ export function TableGrid({ if (!sel) return e.preventDefault() + + if (isColumnSelectionRef.current) { + // Column-header copy spans all rows — drain pages first, then use async + // clipboard so we don't block the event before the drain completes. + void (async () => { + const allRows = await ensureAllRowsLoadedRef.current() + const lines: string[] = [] + for (const row of allRows) { + const cells: string[] = [] + for (let c = sel.startCol; c <= sel.endCol; c++) { + const colName = cols[c]?.name + if (!colName) continue + const value: unknown = row.data[colName] + cells.push( + value === null || value === undefined + ? '' + : typeof value === 'object' + ? JSON.stringify(value) + : String(value) + ) + } + lines.push(cells.join('\t')) + } + if (!navigator.clipboard) { + toast.error('Clipboard access is unavailable in this context') + return + } + try { + await navigator.clipboard.writeText(lines.join('\n')) + } catch (err) { + if (err instanceof DOMException && err.name === 'NotAllowedError') { + toast.error( + 'Clipboard permission expired — press Cmd+C again immediately after selecting' + ) + } else { + throw err + } + } + })().catch((error) => { + logger.error('Failed to copy column cells', { error }) + toast.error('Failed to copy — please try again') + }) + return + } + const lines: string[] = [] for (let r = sel.startRow; r <= sel.endRow; r++) { const cells: string[] = [] @@ -2127,9 +2167,7 @@ export function TableGrid({ if (undoCells.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) } - if (batchUpdates.length > 0) { - await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) - } + await chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current) })().catch((error) => { logger.error('Failed to cut column cells', { error }) toast.error('Failed to cut — please try again') @@ -2164,12 +2202,10 @@ export function TableGrid({ batchUpdates.push({ rowId: row.id, data: updates }) } e.clipboardData?.setData('text/plain', lines.join('\n')) - if (batchUpdates.length > 0) { - void chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current).catch((error) => { - logger.error('Failed to cut selected cells', { error }) - toast.error('Failed to cut — please try again') - }) - } + void chunkBatchUpdates(batchUpdates, batchUpdateAsyncRef.current).catch((error) => { + logger.error('Failed to cut selected cells', { error }) + toast.error('Failed to cut — please try again') + }) if (undoCells.length > 0) { pushUndoRef.current({ type: 'clear-cells', cells: undoCells }) } diff --git a/apps/sim/hooks/queries/tables.test.ts b/apps/sim/hooks/queries/tables.test.ts index 70e8411df5..9424b9f027 100644 --- a/apps/sim/hooks/queries/tables.test.ts +++ b/apps/sim/hooks/queries/tables.test.ts @@ -82,6 +82,7 @@ vi.mock('@/components/emcn', () => ({ })) import { + _mergePagePreservingIdentity, tableKeys, tableRowsInfiniteOptions, tableRowsParamsKey, @@ -370,3 +371,75 @@ describe('tableRowsInfiniteOptions', () => { expect(JSON.stringify(opts1.queryKey)).not.toBe(JSON.stringify(opts2.queryKey)) }) }) + +describe('_mergePagePreservingIdentity', () => { + const ts = '2024-01-01T00:00:00.000Z' + const ts2 = '2024-01-02T00:00:00.000Z' + + function makeRow(id: string, updatedAt: string, extra?: Record) { + return { id, updatedAt, data: { value: id, ...extra } } + } + + it('returns fresh when totalCount differs', () => { + const prev = { rows: [makeRow('r1', ts)], totalCount: 1, nextOffset: undefined } + const fresh = { rows: [makeRow('r1', ts)], totalCount: 2, nextOffset: undefined } + const result = _mergePagePreservingIdentity(prev, fresh) + expect(result).toBe(fresh) + }) + + it('returns fresh when row counts differ', () => { + const prev = { rows: [makeRow('r1', ts)], totalCount: 2, nextOffset: undefined } + const fresh = { + rows: [makeRow('r1', ts), makeRow('r2', ts)], + totalCount: 2, + nextOffset: undefined, + } + const result = _mergePagePreservingIdentity(prev, fresh) + expect(result).toBe(fresh) + }) + + it('returns prev (same reference) when all rows are unchanged', () => { + const row1 = makeRow('r1', ts) + const row2 = makeRow('r2', ts) + const prev = { rows: [row1, row2], totalCount: 2, nextOffset: undefined } + const freshRow1 = makeRow('r1', ts) + const fresh = { rows: [freshRow1, makeRow('r2', ts)], totalCount: 2, nextOffset: undefined } + const result = _mergePagePreservingIdentity(prev, fresh) + expect(result).toBe(prev) + }) + + it('preserves identity for unchanged rows, uses fresh for updated rows', () => { + const row1 = makeRow('r1', ts) + const row2 = makeRow('r2', ts) + const prev = { rows: [row1, row2], totalCount: 2, nextOffset: undefined } + const updatedRow2 = makeRow('r2', ts2, { extra: 'new' }) + const fresh = { rows: [makeRow('r1', ts), updatedRow2], totalCount: 2, nextOffset: undefined } + const result = _mergePagePreservingIdentity(prev, fresh) + expect(result).not.toBe(prev) + expect(result.rows[0]).toBe(row1) + expect(result.rows[1]).toBe(updatedRow2) + }) + + it('uses fresh row when ID is not found in prev', () => { + const row1 = makeRow('r1', ts) + const prev = { rows: [row1, makeRow('r2', ts)], totalCount: 2, nextOffset: undefined } + const newRow = makeRow('r3', ts) + const fresh = { rows: [makeRow('r1', ts), newRow], totalCount: 2, nextOffset: undefined } + const result = _mergePagePreservingIdentity(prev, fresh) + expect(result.rows[1]).toBe(newRow) + }) + + it('compares updatedAt as dates, not strings (ISO vs different string forms)', () => { + const row1 = makeRow('r1', ts) + const prev = { rows: [row1], totalCount: 1, nextOffset: undefined } + // Same point in time, different ISO string representation (with trailing Z vs +00:00) + const sameTimeDifferentFormat = '2024-01-01T00:00:00+00:00' + const fresh = { + rows: [makeRow('r1', sameTimeDifferentFormat)], + totalCount: 1, + nextOffset: undefined, + } + const result = _mergePagePreservingIdentity(prev, fresh) + expect(result).toBe(prev) + }) +}) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index b813038b3f..c42729ca69 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -251,11 +251,8 @@ export function useTableRows({ }) } -/** Merges a freshly-fetched page into the cached page while preserving row - * object identity for unchanged rows (by `updatedAt`). Returns the original - * `prev` reference unchanged when nothing has actually changed — callers can - * use a `===` check to skip a `setQueryData` write entirely. */ -function mergePagePreservingIdentity( +/** @internal — exported for testing only. */ +export function _mergePagePreservingIdentity( prev: TableRowsResponse, fresh: TableRowsResponse ): TableRowsResponse { @@ -264,7 +261,8 @@ function mergePagePreservingIdentity( let allSame = true const nextRows = fresh.rows.map((freshRow) => { const prevRow = prevById.get(freshRow.id) - if (prevRow && String(prevRow.updatedAt) === String(freshRow.updatedAt)) return prevRow + if (prevRow && new Date(prevRow.updatedAt).getTime() === new Date(freshRow.updatedAt).getTime()) + return prevRow allSame = false return freshRow }) @@ -343,7 +341,12 @@ export function useInfiniteTableRows({ const tick = async () => { if (cancelled) return let hasDirty = false - if (queryClient.isMutating() === 0) { + if (queryClient.isMutating() !== 0) { + // Mutation in progress — skip network fetch to avoid racing optimistic + // updates, but stay on the short interval so we catch up quickly once + // the mutation settles. + hasDirty = true + } else { const data = queryClient.getQueryData>(queryKey) const dirty: number[] = [] if (data) { @@ -374,7 +377,7 @@ export function useInfiniteTableRows({ if (!prev) return prev const idx = prev.pageParams.indexOf(offset) if (idx === -1) return prev - const merged = mergePagePreservingIdentity(prev.pages[idx], fresh) + const merged = _mergePagePreservingIdentity(prev.pages[idx], fresh) if (merged === prev.pages[idx]) return prev const nextPages = prev.pages.slice() nextPages[idx] = merged From 783d397acee79964e3d4c82a10359e23a8a49095 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 11:18:24 -0700 Subject: [PATCH 12/20] =?UTF-8?q?improvement(tables):=20cleanup=20?= =?UTF-8?q?=E2=80=94=20extract=20components,=20stabilize=20callbacks,=20fi?= =?UTF-8?q?x=20ref=20sync?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/table-grid/constants.ts | 18 + .../components/table-grid/data-row.tsx | 322 ++++++++ .../components/table-grid/table-grid.tsx | 710 +++--------------- .../table-grid/table-primitives.tsx | 114 +++ .../[tableId]/components/table-grid/utils.ts | 43 ++ apps/sim/hooks/queries/tables.test.ts | 16 +- apps/sim/hooks/queries/tables.ts | 4 +- 7 files changed, 624 insertions(+), 603 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/data-row.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-primitives.tsx diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts index 69db8b7b4f..5d991202f1 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/constants.ts @@ -5,6 +5,24 @@ export const SELECTION_TINT_BG = 'bg-[rgba(37,99,235,0.06)]' * been measured yet and as the initial width for newly-added columns. */ export const COL_WIDTH = 160 +/** Width of the "add column" placeholder column in pixels. */ +export const ADD_COL_WIDTH = 120 + /** Column config sidebar width in pixels — drives both the sidebar's own width * and the table's reserved padding-right while a sidebar is open. */ export const COLUMN_SIDEBAR_WIDTH = 400 + +/** Number of skeleton rows shown while the table body is loading. */ +export const SKELETON_ROW_COUNT = 10 + +export const CELL = + 'border-[var(--border)] border-r border-b px-2 py-[7px] align-middle select-none' +export const CELL_CHECKBOX = + 'sticky left-0 z-[6] border-[var(--border)] border-r border-b bg-[var(--bg)] px-1 py-[7px] align-middle select-none' +export const CELL_HEADER_CHECKBOX = + 'sticky left-0 z-[12] border-[var(--border)] border-r border-b bg-[var(--bg)] px-1 py-[7px] text-center align-middle' +/** Fixed height (not min-) so a Badge-rendered status pill doesn't make the row grow vs a plain-text neighbor. */ +export const CELL_CONTENT = + 'relative flex h-[22px] min-w-0 items-center overflow-clip text-ellipsis whitespace-nowrap text-small' +export const SELECTION_OVERLAY = + 'pointer-events-none absolute -top-px -right-px -bottom-px z-[5] border-[2px] border-[var(--selection)]' diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/data-row.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/data-row.tsx new file mode 100644 index 0000000000..35b28912fd --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/data-row.tsx @@ -0,0 +1,322 @@ +'use client' + +import React from 'react' +import { Button, Checkbox } from '@/components/emcn' +import { PlayOutline, Square } from '@/components/emcn/icons' +import { cn } from '@/lib/core/utils/cn' +import type { TableRow as TableRowType, WorkflowGroup } from '@/lib/table' +import { getUnmetGroupDeps } from '@/lib/table/deps' +import type { SaveReason } from '../../types' +import { CellContent } from './cells' +import { + CELL, + CELL_CHECKBOX, + CELL_CONTENT, + SELECTION_OVERLAY, + SELECTION_TINT_BG, +} from './constants' +import type { DisplayColumn } from './types' +import { type NormalizedSelection, readExecution } from './utils' + +export interface DataRowProps { + row: TableRowType + columns: DisplayColumn[] + rowIndex: number + isFirstRow: boolean + editingColumnName: string | null + initialCharacter: string | null + pendingCellValue: Record | null + normalizedSelection: NormalizedSelection | null + onClick: (rowId: string, columnName: string, options?: { toggleBoolean?: boolean }) => void + onDoubleClick: (rowId: string, columnName: string, columnKey: string) => void + onSave: (rowId: string, columnName: string, value: unknown, reason: SaveReason) => void + onCancel: () => void + onContextMenu: (e: React.MouseEvent, row: TableRowType) => void + onCellMouseDown: (rowIndex: number, colIndex: number, shiftKey: boolean) => void + onCellMouseEnter: (rowIndex: number, colIndex: number) => void + isRowChecked: boolean + onRowToggle: (rowIndex: number, shiftKey: boolean) => void + /** Number of workflow cells in this row currently in a running/queued state. */ + runningCount: number + /** Whether the table has at least one workflow column — controls whether a run/stop icon is rendered. */ + hasWorkflowColumns: boolean + /** Width of the row-number inner div in px, derived from the table's maxRows digit count. */ + numDivWidth: number + onStopRow: (rowId: string) => void + onRunRow: (rowId: string) => void + /** + * The table's workflow groups, used to compute per-row "Waiting on …" labels + * for empty workflow-output cells whose group has unmet dependencies. + */ + workflowGroups: WorkflowGroup[] +} + +function cellRangeRowChanged( + rowIndex: number, + colCount: number, + prev: NormalizedSelection | null, + next: NormalizedSelection | null +): boolean { + const pIn = prev !== null && rowIndex >= prev.startRow && rowIndex <= prev.endRow + const nIn = next !== null && rowIndex >= next.startRow && rowIndex <= next.endRow + const pAnchor = prev !== null && rowIndex === prev.anchorRow + const nAnchor = next !== null && rowIndex === next.anchorRow + + if (!pIn && !nIn && !pAnchor && !nAnchor) return false + if (pIn !== nIn || pAnchor !== nAnchor) return true + + if (pIn && nIn) { + if (prev!.startCol !== next!.startCol || prev!.endCol !== next!.endCol) return true + if ((rowIndex === prev!.startRow) !== (rowIndex === next!.startRow)) return true + if ((rowIndex === prev!.endRow) !== (rowIndex === next!.endRow)) return true + const pMulti = prev!.startRow !== prev!.endRow || prev!.startCol !== prev!.endCol + const nMulti = next!.startRow !== next!.endRow || next!.startCol !== next!.endCol + if (pMulti !== nMulti) return true + const pFull = prev!.startCol === 0 && prev!.endCol === colCount - 1 + const nFull = next!.startCol === 0 && next!.endCol === colCount - 1 + if (pFull !== nFull) return true + } + + if (pAnchor && nAnchor && prev!.anchorCol !== next!.anchorCol) return true + + return false +} + +function dataRowPropsAreEqual(prev: DataRowProps, next: DataRowProps): boolean { + if ( + prev.row !== next.row || + prev.columns !== next.columns || + prev.rowIndex !== next.rowIndex || + prev.isFirstRow !== next.isFirstRow || + prev.editingColumnName !== next.editingColumnName || + prev.pendingCellValue !== next.pendingCellValue || + prev.onClick !== next.onClick || + prev.onDoubleClick !== next.onDoubleClick || + prev.onSave !== next.onSave || + prev.onCancel !== next.onCancel || + prev.onContextMenu !== next.onContextMenu || + prev.onCellMouseDown !== next.onCellMouseDown || + prev.onCellMouseEnter !== next.onCellMouseEnter || + prev.isRowChecked !== next.isRowChecked || + prev.onRowToggle !== next.onRowToggle || + prev.runningCount !== next.runningCount || + prev.hasWorkflowColumns !== next.hasWorkflowColumns || + prev.numDivWidth !== next.numDivWidth || + prev.onStopRow !== next.onStopRow || + prev.onRunRow !== next.onRunRow || + prev.workflowGroups !== next.workflowGroups + ) { + return false + } + if ( + (prev.editingColumnName !== null || next.editingColumnName !== null) && + prev.initialCharacter !== next.initialCharacter + ) { + return false + } + + return !cellRangeRowChanged( + prev.rowIndex, + prev.columns.length, + prev.normalizedSelection, + next.normalizedSelection + ) +} + +export const DataRow = React.memo(function DataRow({ + row, + columns, + rowIndex, + isFirstRow, + editingColumnName, + initialCharacter, + pendingCellValue, + normalizedSelection, + isRowChecked, + onClick, + onDoubleClick, + onSave, + onCancel, + onContextMenu, + onCellMouseDown, + onCellMouseEnter, + onRowToggle, + runningCount, + hasWorkflowColumns, + numDivWidth, + onStopRow, + onRunRow, + workflowGroups, +}: DataRowProps) { + const sel = normalizedSelection + /** + * Per-row "Waiting on …" labels keyed by group id. A group has labels iff + * at least one of its dependencies is unmet for this row — drives the + * "Waiting" pill rendered by `CellContent` for empty workflow-output cells. + * Computed once per render rather than per cell so all cells in a group + * share the same array reference. + */ + const waitingByGroupId = React.useMemo(() => { + if (workflowGroups.length === 0) return null + const map = new Map() + for (const group of workflowGroups) { + // autoRun=false groups never fire from the scheduler — there's nothing + // to wait on. The cell stays empty until the user clicks Run manually. + if (group.autoRun === false) continue + const unmet = getUnmetGroupDeps(group, row) + if (unmet.columns.length === 0) continue + map.set(group.id, unmet.columns) + } + return map + }, [workflowGroups, row]) + const isMultiCell = sel !== null && (sel.startRow !== sel.endRow || sel.startCol !== sel.endCol) + const isRowSelected = isRowChecked + + return ( + onContextMenu(e, row)}> + +
+
{ + if (e.button !== 0) return + onRowToggle(rowIndex, e.shiftKey) + }} + > + + {rowIndex + 1} + +
+ +
+
+ {hasWorkflowColumns && ( + + )} +
+ + {columns.map((column, colIndex) => { + const inRange = + sel !== null && + rowIndex >= sel.startRow && + rowIndex <= sel.endRow && + colIndex >= sel.startCol && + colIndex <= sel.endCol + const isAnchor = sel !== null && rowIndex === sel.anchorRow && colIndex === sel.anchorCol + const isEditing = editingColumnName === column.name + const isHighlighted = inRange || isRowChecked + + const isTopEdge = inRange ? rowIndex === sel!.startRow : isRowChecked + const isBottomEdge = inRange ? rowIndex === sel!.endRow : isRowChecked + const isLeftEdge = inRange ? colIndex === sel!.startCol : colIndex === 0 + const isRightEdge = inRange ? colIndex === sel!.endCol : colIndex === columns.length - 1 + + return ( + { + if (e.button !== 0 || isEditing) return + onCellMouseDown(rowIndex, colIndex, e.shiftKey) + }} + onMouseEnter={() => onCellMouseEnter(rowIndex, colIndex)} + onClick={(e) => + onClick(row.id, column.name, { + toggleBoolean: + !e.shiftKey && + Boolean((e.target as HTMLElement).closest('[data-boolean-cell-toggle]')), + }) + } + onDoubleClick={() => onDoubleClick(row.id, column.name, column.key)} + > + {isHighlighted && (isMultiCell || isRowChecked) && ( +
+ )} + {isAnchor && ( +
+ )} +
+ onSave(row.id, column.name, value, reason)} + onCancel={onCancel} + waitingOnLabels={ + column.workflowGroupId + ? (waitingByGroupId?.get(column.workflowGroupId) ?? undefined) + : undefined + } + /> +
+ + ) + })} + + ) +}, dataRowPropsAreEqual) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index 0b6c444e9b..c24939ec10 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -1,17 +1,18 @@ 'use client' -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import type React from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createLogger } from '@sim/logger' import { useParams } from 'next/navigation' import { usePostHog } from 'posthog-js/react' -import { Button, Checkbox, Skeleton, toast } from '@/components/emcn' -import { PlayOutline, Plus, Square, TableX } from '@/components/emcn/icons' +import { Skeleton, toast } from '@/components/emcn' +import { TableX } from '@/components/emcn/icons' import type { RunMode } from '@/lib/api/contracts/tables' import { cn } from '@/lib/core/utils/cn' import { captureEvent } from '@/lib/posthog/client' -import type { ColumnDefinition, TableRow as TableRowType, WorkflowGroup } from '@/lib/table' +import type { ColumnDefinition, TableRow as TableRowType } from '@/lib/table' import { TABLE_LIMITS } from '@/lib/table/constants' -import { getUnmetGroupDeps, isExecInFlight } from '@/lib/table/deps' +import { isExecInFlight } from '@/lib/table/deps' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' import { useAddTableColumn, @@ -40,89 +41,45 @@ import { ContextMenu } from '../context-menu' import { NewColumnDropdown } from '../new-column-dropdown' import { RunStatusControl } from '../run-status-control' import type { WorkflowConfig } from '../workflow-sidebar' -import { CellContent, ExpandedCellPopover } from './cells' -import { COL_WIDTH, SELECTION_TINT_BG } from './constants' +import { ExpandedCellPopover } from './cells' +import { ADD_COL_WIDTH, CELL_HEADER_CHECKBOX, COL_WIDTH, SELECTION_TINT_BG } from './constants' +import { DataRow } from './data-row' import { ColumnHeaderMenu, WorkflowGroupMetaCell } from './headers' +import { + AddRowButton, + SelectAllCheckbox, + TableBodySkeleton, + TableColGroup, +} from './table-primitives' import type { DisplayColumn } from './types' import { buildHeaderGroups, type CellCoord, + checkboxColLayout, classifyExecStatusMix, collectRowSnapshots, computeNormalizedSelection, type ExecStatusMix, expandToDisplayColumns, moveCell, - type NormalizedSelection, - readExecution, + ROW_SELECTION_ALL, + ROW_SELECTION_NONE, + type RowSelection, + rowSelectionCoversAll, + rowSelectionIncludes, + rowSelectionIsEmpty, + rowSelectionMaterialize, } from './utils' const logger = createLogger('TableView') -type RowSelection = { kind: 'none' } | { kind: 'some'; ids: Set } | { kind: 'all' } - -const ROW_SELECTION_NONE: RowSelection = { kind: 'none' } -const ROW_SELECTION_ALL: RowSelection = { kind: 'all' } - -function rowSelectionIncludes(sel: RowSelection, id: string): boolean { - if (sel.kind === 'all') return true - if (sel.kind === 'some') return sel.ids.has(id) - return false -} - -function rowSelectionIsEmpty(sel: RowSelection): boolean { - if (sel.kind === 'none') return true - if (sel.kind === 'some') return sel.ids.size === 0 - return false -} - -function rowSelectionMaterialize(sel: RowSelection, rows: TableRowType[]): Set { - if (sel.kind === 'all') return new Set(rows.map((r) => r.id)) - if (sel.kind === 'some') return new Set(sel.ids) - return new Set() -} - -function rowSelectionCoversAll(sel: RowSelection, rows: TableRowType[]): boolean { - if (rows.length === 0) return false - if (sel.kind === 'all') return true - if (sel.kind === 'none') return false - if (sel.ids.size < rows.length) return false - for (const r of rows) if (!sel.ids.has(r.id)) return false - return true -} - const COL_WIDTH_MIN = 80 const COL_WIDTH_AUTO_FIT_MAX = 1000 -const ADD_COL_WIDTH = 120 - -/** Returns sticky row-number column dimensions sized to the digit count of `maxRows`. */ -function checkboxColLayout( - maxRows: number, - hasWorkflowCols: boolean -): { colWidth: number; numDivWidth: number } { - const digits = maxRows > 0 ? Math.floor(Math.log10(maxRows)) + 1 : 1 - const numDivWidth = Math.max(20, digits * 8 + 4) - const colWidth = Math.max(32, numDivWidth + 8) + (hasWorkflowCols ? 16 : 0) - return { colWidth, numDivWidth } -} const SKELETON_COL_COUNT = 4 -const SKELETON_ROW_COUNT = 10 const ROW_HEIGHT_ESTIMATE = 35 -const CELL = 'border-[var(--border)] border-r border-b px-2 py-[7px] align-middle select-none' -const CELL_CHECKBOX = - 'sticky left-0 z-[6] border-[var(--border)] border-r border-b bg-[var(--bg)] px-1 py-[7px] align-middle select-none' const CELL_HEADER = 'border-[var(--border)] border-r border-b bg-[var(--bg)] px-2 py-[7px] text-left align-middle' -const CELL_HEADER_CHECKBOX = - 'sticky left-0 z-[12] border-[var(--border)] border-r border-b bg-[var(--bg)] px-1 py-[7px] text-center align-middle' -// Fixed height (not min-) so a Badge-rendered status pill doesn't make the row -// grow vs a plain-text neighbor. Sized to comfortably contain the badge; the -// flex centers plain text + badges on the same baseline. -const CELL_CONTENT = - 'relative flex h-[22px] min-w-0 items-center overflow-clip text-ellipsis whitespace-nowrap text-small' -const SELECTION_OVERLAY = - 'pointer-events-none absolute -top-px -right-px -bottom-px z-[5] border-[2px] border-[var(--selection)]' /** * Snapshot of grid selection state the wrapper needs to render ``. @@ -372,12 +329,9 @@ export function TableGrid({ const deleteWorkflowGroupMutation = useDeleteWorkflowGroup({ workspaceId, tableId }) const updateWorkflowGroupMutation = useUpdateWorkflowGroup({ workspaceId, tableId }) - const handleRunColumn = useCallback( - (groupId: string, runMode: RunMode = 'all', rowIds?: string[]) => { - onRunColumn(groupId, runMode, rowIds) - }, - [onRunColumn] - ) + function handleRunColumn(groupId: string, runMode: RunMode = 'all', rowIds?: string[]) { + onRunColumn(groupId, runMode, rowIds) + } const handleViewWorkflow = useCallback( (workflowId: string) => { @@ -575,6 +529,12 @@ export function TableGrid({ selectionAnchorRef.current = selectionAnchor selectionFocusRef.current = selectionFocus isColumnSelectionRef.current = isColumnSelection + anchorRowIdRef.current = selectionAnchor + ? (rowsRef.current[selectionAnchor.rowIndex]?.id ?? null) + : null + focusRowIdRef.current = selectionFocus + ? (rowsRef.current[selectionFocus.rowIndex]?.id ?? null) + : null const columnRename = useInlineRename({ onSave: (columnName, newName) => { @@ -599,7 +559,7 @@ export function TableGrid({ [] ) - const handleContextMenuEditCell = useCallback(() => { + function handleContextMenuEditCell() { if (contextMenu.row && contextMenu.columnName) { const column = columnsRef.current.find((c) => c.name === contextMenu.columnName) if (column?.type === 'boolean') { @@ -614,9 +574,9 @@ export function TableGrid({ } } closeContextMenu() - }, [contextMenu.row, contextMenu.columnName, closeContextMenu]) + } - const handleContextMenuDelete = useCallback(() => { + function handleContextMenuDelete() { const contextRow = contextMenu.row if (!contextRow) { closeContextMenu() @@ -653,68 +613,54 @@ export function TableGrid({ } closeContextMenu() - }, [contextMenu.row, closeContextMenu, onRequestDeleteRows]) - - const handleInsertRow = useCallback( - (offset: 0 | 1) => { - if (!contextMenu.row) return - const position = contextMenu.row.position + offset - createRef.current( - { data: {}, position }, - { - onSuccess: (response: Record) => { - const newRowId = extractCreatedRowId(response) - if (newRowId) { - pushUndoRef.current({ type: 'create-row', rowId: newRowId, position }) - } - }, - } - ) - closeContextMenu() - }, - [contextMenu.row, closeContextMenu] - ) + } - const handleInsertRowAbove = useCallback(() => handleInsertRow(0), [handleInsertRow]) - const handleInsertRowBelow = useCallback(() => handleInsertRow(1), [handleInsertRow]) + function handleInsertRow(offset: 0 | 1) { + if (!contextMenu.row) return + const position = contextMenu.row.position + offset + createRef.current( + { data: {}, position }, + { + onSuccess: (response: Record) => { + const newRowId = extractCreatedRowId(response) + if (newRowId) { + pushUndoRef.current({ type: 'create-row', rowId: newRowId, position }) + } + }, + } + ) + closeContextMenu() + } - const contextMenuColumnInfo = useMemo<{ - isWorkflowColumn: boolean - executionId: string | null - hasStartedRun: boolean - }>(() => { - if (!contextMenu.row || !contextMenu.columnName) { - return { isWorkflowColumn: false, executionId: null, hasStartedRun: false } - } - const column = columnsRef.current.find((c) => c.name === contextMenu.columnName) - const groupId = column?.workflowGroupId - if (!column || !groupId) { - return { isWorkflowColumn: false, executionId: null, hasStartedRun: false } - } - const exec = contextMenu.row.executions?.[groupId] - // Only `completed` / `error` / `running` cells are guaranteed to have a - // server-side execution log. `queued` / `pending` haven't started yet; - // `cancelled` may have been cancelled before the worker ever picked the - // job up, so its executionId can't be relied on either. - const hasStartedRun = - exec?.status === 'completed' || exec?.status === 'error' || exec?.status === 'running' - return { - isWorkflowColumn: true, - executionId: exec?.executionId ?? null, - hasStartedRun, + const handleInsertRowAbove = () => handleInsertRow(0) + const handleInsertRowBelow = () => handleInsertRow(1) + + let contextMenuExecutionId: string | null = null + let contextMenuIsWorkflowColumn = false + let contextMenuHasStartedRun = false + if (contextMenu.row && contextMenu.columnName) { + const _col = columnsRef.current.find((c) => c.name === contextMenu.columnName) + const _gid = _col?.workflowGroupId + if (_col && _gid) { + const _exec = contextMenu.row.executions?.[_gid] + contextMenuIsWorkflowColumn = true + // Only `completed` / `error` / `running` cells are guaranteed to have a + // server-side execution log. `queued` / `pending` haven't started yet; + // `cancelled` may have been cancelled before the worker ever picked the + // job up, so its executionId can't be relied on either. + contextMenuHasStartedRun = + _exec?.status === 'completed' || _exec?.status === 'error' || _exec?.status === 'running' + contextMenuExecutionId = _exec?.executionId ?? null } - }, [contextMenu.row, contextMenu.columnName]) - const contextMenuExecutionId = contextMenuColumnInfo.executionId - const contextMenuIsWorkflowColumn = contextMenuColumnInfo.isWorkflowColumn - const contextMenuHasStartedRun = contextMenuColumnInfo.hasStartedRun + } - const handleViewExecution = useCallback(() => { + function handleViewExecution() { if (!contextMenuExecutionId) return onOpenExecutionDetails(contextMenuExecutionId) closeContextMenu() - }, [contextMenuExecutionId, onOpenExecutionDetails, closeContextMenu]) + } - const handleDuplicateRow = useCallback(() => { + function handleDuplicateRow() { const contextRow = contextMenu.row if (!contextRow) return const rowData = { ...contextRow.data } @@ -742,7 +688,7 @@ export function TableGrid({ }, } ) - }, [contextMenu.row, closeContextMenu]) + } const handleAppendRow = useCallback(async () => { if (isAppendingRowRef.current) return @@ -1395,18 +1341,6 @@ export function TableGrid({ } }, []) - useEffect(() => { - anchorRowIdRef.current = selectionAnchor - ? (rowsRef.current[selectionAnchor.rowIndex]?.id ?? null) - : null - }, [selectionAnchor]) - - useEffect(() => { - focusRowIdRef.current = selectionFocus - ? (rowsRef.current[selectionFocus.rowIndex]?.id ?? null) - : null - }, [selectionFocus]) - useEffect(() => { // Skip during transient empty-rows state (initial load of a new sort/filter // before keepPreviousData kicks in) — clearing here would lose the user's @@ -1536,6 +1470,12 @@ export function TableGrid({ const updateMetadataRef = useRef(updateMetadataMutation.mutate) updateMetadataRef.current = updateMetadataMutation.mutate + const deleteWorkflowGroupRef = useRef(deleteWorkflowGroupMutation.mutate) + deleteWorkflowGroupRef.current = deleteWorkflowGroupMutation.mutate + + const updateWorkflowGroupRef = useRef(updateWorkflowGroupMutation.mutate) + updateWorkflowGroupRef.current = updateWorkflowGroupMutation.mutate + const toggleBooleanCellRef = useRef(toggleBooleanCell) toggleBooleanCellRef.current = toggleBooleanCell @@ -2476,17 +2416,14 @@ export function TableGrid({ * Open the column-config sidebar pre-seeded with the chosen scalar type. * Nothing is persisted until the user fills in the name and hits Save. */ - const handleAddColumnOfType = useCallback( - (type: ColumnDefinition['type']) => { - onOpenColumnConfig({ mode: 'create', proposedName: generateColumnName(), type }) - }, - [generateColumnName, onOpenColumnConfig] - ) + function handleAddColumnOfType(type: ColumnDefinition['type']) { + onOpenColumnConfig({ mode: 'create', proposedName: generateColumnName(), type }) + } /** Open the workflow-config sidebar to spawn a brand-new workflow group. */ - const handleAddWorkflowColumn = useCallback(() => { + function handleAddWorkflowColumn() { onOpenWorkflowConfig({ mode: 'create', proposedName: generateColumnName() }) - }, [generateColumnName, onOpenWorkflowConfig]) + } const handleConfigureColumn = useCallback( (columnName: string) => { @@ -2508,12 +2445,9 @@ export function TableGrid({ [onOpenWorkflowConfig] ) - const handleDeleteWorkflowGroup = useCallback( - (groupId: string) => { - deleteWorkflowGroupMutation.mutate({ groupId }) - }, - [deleteWorkflowGroupMutation] - ) + const handleDeleteWorkflowGroup = useCallback((groupId: string) => { + deleteWorkflowGroupRef.current({ groupId }) + }, []) /** * Computes the names slated for deletion given a click on `columnName` and @@ -2547,35 +2481,32 @@ export function TableGrid({ * logs. Only valid when removing the columns leaves every affected group * with at least one surviving output — caller must check first. */ - const hideWorkflowOutputColumns = useCallback( - (names: string[]) => { - const schemaCols = schemaColumnsRef.current - const groups = workflowGroupsRef.current - const removalsByGroup = new Map>() - for (const name of names) { - const def = schemaCols.find((c) => c.name === name) - if (!def?.workflowGroupId) return false - const set = removalsByGroup.get(def.workflowGroupId) ?? new Set() - set.add(name) - removalsByGroup.set(def.workflowGroupId, set) - } - for (const [groupId, removed] of removalsByGroup) { - const group = groups.find((g) => g.id === groupId) - if (!group) return false - const remaining = group.outputs.filter((o) => !removed.has(o.columnName)) - if (remaining.length === 0) return false - updateWorkflowGroupMutation.mutate({ - groupId: group.id, - workflowId: group.workflowId, - name: group.name, - dependencies: group.dependencies, - outputs: remaining, - }) - } - return true - }, - [updateWorkflowGroupMutation] - ) + const hideWorkflowOutputColumns = useCallback((names: string[]) => { + const schemaCols = schemaColumnsRef.current + const groups = workflowGroupsRef.current + const removalsByGroup = new Map>() + for (const name of names) { + const def = schemaCols.find((c) => c.name === name) + if (!def?.workflowGroupId) return false + const set = removalsByGroup.get(def.workflowGroupId) ?? new Set() + set.add(name) + removalsByGroup.set(def.workflowGroupId, set) + } + for (const [groupId, removed] of removalsByGroup) { + const group = groups.find((g) => g.id === groupId) + if (!group) return false + const remaining = group.outputs.filter((o) => !removed.has(o.columnName)) + if (remaining.length === 0) return false + updateWorkflowGroupRef.current({ + groupId: group.id, + workflowId: group.workflowId, + name: group.name, + dependencies: group.dependencies, + outputs: remaining, + }) + } + return true + }, []) const handleDeleteColumn = useCallback( (columnName: string) => { @@ -2965,13 +2896,6 @@ export function TableGrid({ singleWorkflowCell, ]) - const handleRunRow = useCallback( - (rowId: string) => { - onRunRow(rowId) - }, - [onRunRow] - ) - if (!isLoadingTable && !tableData) { return (
@@ -3213,7 +3137,7 @@ export function TableGrid({ hasWorkflowColumns={hasWorkflowColumns} numDivWidth={numDivWidth} onStopRow={onStopRow} - onRunRow={handleRunRow} + onRunRow={onRunRow} workflowGroups={tableWorkflowGroups} /> ))} @@ -3293,403 +3217,3 @@ export function TableGrid({
) } - -const TableColGroup = React.memo(function TableColGroup({ - columns, - columnWidths, - checkboxColWidth, -}: { - columns: DisplayColumn[] - columnWidths: Record - checkboxColWidth: number -}) { - return ( - - - {columns.map((col) => ( - - ))} - - - ) -}) - -interface DataRowProps { - row: TableRowType - columns: DisplayColumn[] - rowIndex: number - isFirstRow: boolean - editingColumnName: string | null - initialCharacter: string | null - pendingCellValue: Record | null - normalizedSelection: NormalizedSelection | null - onClick: (rowId: string, columnName: string, options?: { toggleBoolean?: boolean }) => void - onDoubleClick: (rowId: string, columnName: string, columnKey: string) => void - onSave: (rowId: string, columnName: string, value: unknown, reason: SaveReason) => void - onCancel: () => void - onContextMenu: (e: React.MouseEvent, row: TableRowType) => void - onCellMouseDown: (rowIndex: number, colIndex: number, shiftKey: boolean) => void - onCellMouseEnter: (rowIndex: number, colIndex: number) => void - isRowChecked: boolean - onRowToggle: (rowIndex: number, shiftKey: boolean) => void - /** Number of workflow cells in this row currently in a running/queued state. */ - runningCount: number - /** Whether the table has at least one workflow column — controls whether a run/stop icon is rendered. */ - hasWorkflowColumns: boolean - /** Width of the row-number inner div in px, derived from the table's maxRows digit count. */ - numDivWidth: number - onStopRow: (rowId: string) => void - onRunRow: (rowId: string) => void - /** - * The table's workflow groups, used to compute per-row "Waiting on …" labels - * for empty workflow-output cells whose group has unmet dependencies. - */ - workflowGroups: WorkflowGroup[] -} - -function cellRangeRowChanged( - rowIndex: number, - colCount: number, - prev: NormalizedSelection | null, - next: NormalizedSelection | null -): boolean { - const pIn = prev !== null && rowIndex >= prev.startRow && rowIndex <= prev.endRow - const nIn = next !== null && rowIndex >= next.startRow && rowIndex <= next.endRow - const pAnchor = prev !== null && rowIndex === prev.anchorRow - const nAnchor = next !== null && rowIndex === next.anchorRow - - if (!pIn && !nIn && !pAnchor && !nAnchor) return false - if (pIn !== nIn || pAnchor !== nAnchor) return true - - if (pIn && nIn) { - if (prev!.startCol !== next!.startCol || prev!.endCol !== next!.endCol) return true - if ((rowIndex === prev!.startRow) !== (rowIndex === next!.startRow)) return true - if ((rowIndex === prev!.endRow) !== (rowIndex === next!.endRow)) return true - const pMulti = prev!.startRow !== prev!.endRow || prev!.startCol !== prev!.endCol - const nMulti = next!.startRow !== next!.endRow || next!.startCol !== next!.endCol - if (pMulti !== nMulti) return true - const pFull = prev!.startCol === 0 && prev!.endCol === colCount - 1 - const nFull = next!.startCol === 0 && next!.endCol === colCount - 1 - if (pFull !== nFull) return true - } - - if (pAnchor && nAnchor && prev!.anchorCol !== next!.anchorCol) return true - - return false -} - -function dataRowPropsAreEqual(prev: DataRowProps, next: DataRowProps): boolean { - if ( - prev.row !== next.row || - prev.columns !== next.columns || - prev.rowIndex !== next.rowIndex || - prev.isFirstRow !== next.isFirstRow || - prev.editingColumnName !== next.editingColumnName || - prev.pendingCellValue !== next.pendingCellValue || - prev.onClick !== next.onClick || - prev.onDoubleClick !== next.onDoubleClick || - prev.onSave !== next.onSave || - prev.onCancel !== next.onCancel || - prev.onContextMenu !== next.onContextMenu || - prev.onCellMouseDown !== next.onCellMouseDown || - prev.onCellMouseEnter !== next.onCellMouseEnter || - prev.isRowChecked !== next.isRowChecked || - prev.onRowToggle !== next.onRowToggle || - prev.runningCount !== next.runningCount || - prev.hasWorkflowColumns !== next.hasWorkflowColumns || - prev.numDivWidth !== next.numDivWidth || - prev.onStopRow !== next.onStopRow || - prev.onRunRow !== next.onRunRow || - prev.workflowGroups !== next.workflowGroups - ) { - return false - } - if ( - (prev.editingColumnName !== null || next.editingColumnName !== null) && - prev.initialCharacter !== next.initialCharacter - ) { - return false - } - - return !cellRangeRowChanged( - prev.rowIndex, - prev.columns.length, - prev.normalizedSelection, - next.normalizedSelection - ) -} - -const DataRow = React.memo(function DataRow({ - row, - columns, - rowIndex, - isFirstRow, - editingColumnName, - initialCharacter, - pendingCellValue, - normalizedSelection, - isRowChecked, - onClick, - onDoubleClick, - onSave, - onCancel, - onContextMenu, - onCellMouseDown, - onCellMouseEnter, - onRowToggle, - runningCount, - hasWorkflowColumns, - numDivWidth, - onStopRow, - onRunRow, - workflowGroups, -}: DataRowProps) { - const sel = normalizedSelection - /** - * Per-row "Waiting on …" labels keyed by group id. A group has labels iff - * at least one of its dependencies is unmet for this row — drives the - * "Waiting" pill rendered by `CellContent` for empty workflow-output cells. - * Computed once per render rather than per cell so all cells in a group - * share the same array reference. - */ - const waitingByGroupId = React.useMemo(() => { - if (workflowGroups.length === 0) return null - const map = new Map() - for (const group of workflowGroups) { - // autoRun=false groups never fire from the scheduler — there's nothing - // to wait on. The cell stays empty until the user clicks Run manually. - if (group.autoRun === false) continue - const unmet = getUnmetGroupDeps(group, row) - if (unmet.columns.length === 0) continue - map.set(group.id, unmet.columns) - } - return map - }, [workflowGroups, row]) - const isMultiCell = sel !== null && (sel.startRow !== sel.endRow || sel.startCol !== sel.endCol) - const isRowSelected = isRowChecked - - return ( - onContextMenu(e, row)}> - -
-
{ - if (e.button !== 0) return - onRowToggle(rowIndex, e.shiftKey) - }} - > - - {rowIndex + 1} - -
- -
-
- {hasWorkflowColumns && ( - - )} -
- - {columns.map((column, colIndex) => { - const inRange = - sel !== null && - rowIndex >= sel.startRow && - rowIndex <= sel.endRow && - colIndex >= sel.startCol && - colIndex <= sel.endCol - const isAnchor = sel !== null && rowIndex === sel.anchorRow && colIndex === sel.anchorCol - const isEditing = editingColumnName === column.name - const isHighlighted = inRange || isRowChecked - - const isTopEdge = inRange ? rowIndex === sel!.startRow : isRowChecked - const isBottomEdge = inRange ? rowIndex === sel!.endRow : isRowChecked - const isLeftEdge = inRange ? colIndex === sel!.startCol : colIndex === 0 - const isRightEdge = inRange ? colIndex === sel!.endCol : colIndex === columns.length - 1 - - return ( - { - if (e.button !== 0 || isEditing) return - onCellMouseDown(rowIndex, colIndex, e.shiftKey) - }} - onMouseEnter={() => onCellMouseEnter(rowIndex, colIndex)} - onClick={(e) => - onClick(row.id, column.name, { - toggleBoolean: - !e.shiftKey && - Boolean((e.target as HTMLElement).closest('[data-boolean-cell-toggle]')), - }) - } - onDoubleClick={() => onDoubleClick(row.id, column.name, column.key)} - > - {isHighlighted && (isMultiCell || isRowChecked) && ( -
- )} - {isAnchor && ( -
- )} -
- onSave(row.id, column.name, value, reason)} - onCancel={onCancel} - waitingOnLabels={ - column.workflowGroupId - ? (waitingByGroupId?.get(column.workflowGroupId) ?? undefined) - : undefined - } - /> -
- - ) - })} - - ) -}, dataRowPropsAreEqual) - -const TableBodySkeleton = React.memo(function TableBodySkeleton({ - colCount, -}: { - colCount: number -}) { - return ( - <> - {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - - -
- - {rowIndex + 1} - -
- - {Array.from({ length: colCount }).map((_, colIndex) => { - const width = 72 + ((rowIndex + colIndex) % 4) * 24 - return ( - -
- -
- - ) - })} - - ))} - - ) -}) - -const SelectAllCheckbox = React.memo(function SelectAllCheckbox({ - checked, - onCheckedChange, -}: { - checked: boolean - onCheckedChange: () => void -}) { - return ( - { - if (e.button !== 0) return - onCheckedChange() - }} - onKeyDown={(e) => { - if (e.key !== ' ' && e.key !== 'Enter') return - e.preventDefault() - onCheckedChange() - }} - > -
- -
- - ) -}) - -const AddRowButton = React.memo(function AddRowButton({ onClick }: { onClick: () => void }) { - return ( -
- -
- ) -}) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-primitives.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-primitives.tsx new file mode 100644 index 0000000000..20b8d02db8 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-primitives.tsx @@ -0,0 +1,114 @@ +'use client' + +import React from 'react' +import { Button, Checkbox, Skeleton } from '@/components/emcn' +import { Plus } from '@/components/emcn/icons' +import { cn } from '@/lib/core/utils/cn' +import { + ADD_COL_WIDTH, + CELL, + CELL_CHECKBOX, + CELL_HEADER_CHECKBOX, + COL_WIDTH, + SKELETON_ROW_COUNT, +} from './constants' +import type { DisplayColumn } from './types' + +export const TableColGroup = React.memo(function TableColGroup({ + columns, + columnWidths, + checkboxColWidth, +}: { + columns: DisplayColumn[] + columnWidths: Record + checkboxColWidth: number +}) { + return ( + + + {columns.map((col) => ( + + ))} + + + ) +}) + +export const TableBodySkeleton = React.memo(function TableBodySkeleton({ + colCount, +}: { + colCount: number +}) { + return ( + <> + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + +
+ + {rowIndex + 1} + +
+ + {Array.from({ length: colCount }).map((_, colIndex) => { + const width = 72 + ((rowIndex + colIndex) % 4) * 24 + return ( + +
+ +
+ + ) + })} + + ))} + + ) +}) + +export const SelectAllCheckbox = React.memo(function SelectAllCheckbox({ + checked, + onCheckedChange, +}: { + checked: boolean + onCheckedChange: () => void +}) { + return ( + { + if (e.button !== 0) return + onCheckedChange() + }} + onKeyDown={(e) => { + if (e.key !== ' ' && e.key !== 'Enter') return + e.preventDefault() + onCheckedChange() + }} + > +
+ +
+ + ) +}) + +export const AddRowButton = React.memo(function AddRowButton({ onClick }: { onClick: () => void }) { + return ( +
+ +
+ ) +}) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/utils.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/utils.ts index 73fa8db9c4..a0efce3b87 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/utils.ts @@ -8,6 +8,49 @@ import type { import type { DeletedRowSnapshot } from '@/stores/table/types' import type { DisplayColumn } from './types' +export type RowSelection = { kind: 'none' } | { kind: 'some'; ids: Set } | { kind: 'all' } + +export const ROW_SELECTION_NONE: RowSelection = { kind: 'none' } +export const ROW_SELECTION_ALL: RowSelection = { kind: 'all' } + +export function rowSelectionIncludes(sel: RowSelection, id: string): boolean { + if (sel.kind === 'all') return true + if (sel.kind === 'some') return sel.ids.has(id) + return false +} + +export function rowSelectionIsEmpty(sel: RowSelection): boolean { + if (sel.kind === 'none') return true + if (sel.kind === 'some') return sel.ids.size === 0 + return false +} + +export function rowSelectionMaterialize(sel: RowSelection, rows: TableRowType[]): Set { + if (sel.kind === 'all') return new Set(rows.map((r) => r.id)) + if (sel.kind === 'some') return new Set(sel.ids) + return new Set() +} + +export function rowSelectionCoversAll(sel: RowSelection, rows: TableRowType[]): boolean { + if (rows.length === 0) return false + if (sel.kind === 'all') return true + if (sel.kind === 'none') return false + if (sel.ids.size < rows.length) return false + for (const r of rows) if (!sel.ids.has(r.id)) return false + return true +} + +/** Returns sticky row-number column dimensions sized to the digit count of `maxRows`. */ +export function checkboxColLayout( + maxRows: number, + hasWorkflowCols: boolean +): { colWidth: number; numDivWidth: number } { + const digits = maxRows > 0 ? Math.floor(Math.log10(maxRows)) + 1 : 1 + const numDivWidth = Math.max(20, digits * 8 + 4) + const colWidth = Math.max(32, numDivWidth + 8) + (hasWorkflowCols ? 16 : 0) + return { colWidth, numDivWidth } +} + export interface CellCoord { rowIndex: number colIndex: number diff --git a/apps/sim/hooks/queries/tables.test.ts b/apps/sim/hooks/queries/tables.test.ts index 9424b9f027..b26fc0e199 100644 --- a/apps/sim/hooks/queries/tables.test.ts +++ b/apps/sim/hooks/queries/tables.test.ts @@ -82,7 +82,7 @@ vi.mock('@/components/emcn', () => ({ })) import { - _mergePagePreservingIdentity, + mergePagePreservingIdentity, tableKeys, tableRowsInfiniteOptions, tableRowsParamsKey, @@ -372,7 +372,7 @@ describe('tableRowsInfiniteOptions', () => { }) }) -describe('_mergePagePreservingIdentity', () => { +describe('mergePagePreservingIdentity', () => { const ts = '2024-01-01T00:00:00.000Z' const ts2 = '2024-01-02T00:00:00.000Z' @@ -383,7 +383,7 @@ describe('_mergePagePreservingIdentity', () => { it('returns fresh when totalCount differs', () => { const prev = { rows: [makeRow('r1', ts)], totalCount: 1, nextOffset: undefined } const fresh = { rows: [makeRow('r1', ts)], totalCount: 2, nextOffset: undefined } - const result = _mergePagePreservingIdentity(prev, fresh) + const result = mergePagePreservingIdentity(prev, fresh) expect(result).toBe(fresh) }) @@ -394,7 +394,7 @@ describe('_mergePagePreservingIdentity', () => { totalCount: 2, nextOffset: undefined, } - const result = _mergePagePreservingIdentity(prev, fresh) + const result = mergePagePreservingIdentity(prev, fresh) expect(result).toBe(fresh) }) @@ -404,7 +404,7 @@ describe('_mergePagePreservingIdentity', () => { const prev = { rows: [row1, row2], totalCount: 2, nextOffset: undefined } const freshRow1 = makeRow('r1', ts) const fresh = { rows: [freshRow1, makeRow('r2', ts)], totalCount: 2, nextOffset: undefined } - const result = _mergePagePreservingIdentity(prev, fresh) + const result = mergePagePreservingIdentity(prev, fresh) expect(result).toBe(prev) }) @@ -414,7 +414,7 @@ describe('_mergePagePreservingIdentity', () => { const prev = { rows: [row1, row2], totalCount: 2, nextOffset: undefined } const updatedRow2 = makeRow('r2', ts2, { extra: 'new' }) const fresh = { rows: [makeRow('r1', ts), updatedRow2], totalCount: 2, nextOffset: undefined } - const result = _mergePagePreservingIdentity(prev, fresh) + const result = mergePagePreservingIdentity(prev, fresh) expect(result).not.toBe(prev) expect(result.rows[0]).toBe(row1) expect(result.rows[1]).toBe(updatedRow2) @@ -425,7 +425,7 @@ describe('_mergePagePreservingIdentity', () => { const prev = { rows: [row1, makeRow('r2', ts)], totalCount: 2, nextOffset: undefined } const newRow = makeRow('r3', ts) const fresh = { rows: [makeRow('r1', ts), newRow], totalCount: 2, nextOffset: undefined } - const result = _mergePagePreservingIdentity(prev, fresh) + const result = mergePagePreservingIdentity(prev, fresh) expect(result.rows[1]).toBe(newRow) }) @@ -439,7 +439,7 @@ describe('_mergePagePreservingIdentity', () => { totalCount: 1, nextOffset: undefined, } - const result = _mergePagePreservingIdentity(prev, fresh) + const result = mergePagePreservingIdentity(prev, fresh) expect(result).toBe(prev) }) }) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index c42729ca69..a6b72da91d 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -252,7 +252,7 @@ export function useTableRows({ } /** @internal — exported for testing only. */ -export function _mergePagePreservingIdentity( +export function mergePagePreservingIdentity( prev: TableRowsResponse, fresh: TableRowsResponse ): TableRowsResponse { @@ -377,7 +377,7 @@ export function useInfiniteTableRows({ if (!prev) return prev const idx = prev.pageParams.indexOf(offset) if (idx === -1) return prev - const merged = _mergePagePreservingIdentity(prev.pages[idx], fresh) + const merged = mergePagePreservingIdentity(prev.pages[idx], fresh) if (merged === prev.pages[idx]) return prev const nextPages = prev.pages.slice() nextPages[idx] = merged From e3626f1caa6c81cf6190310b66488130b023032f Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 11:36:32 -0700 Subject: [PATCH 13/20] improvement(tables): remove polling, eager drain, and parallelize batch updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Drop the per-page polling loop — SSE stream already patches execution cell state in real time and invalidates on buffer prune; polling was redundant and burned CPU/network on every open table - Remove eager mount drain (fetchNextPage loop in use-table.ts); scroll handler and ensureAllRowsLoaded handle progressive/on-demand loading - Parallelize chunkBatchUpdates with a 3-worker pool instead of serial chunks, reducing bulk-op round-trips by ~3x - Delete mergePagePreservingIdentity and its tests (no longer called) --- .../components/table-grid/table-grid.tsx | 13 +- .../tables/[tableId]/hooks/use-table.ts | 9 +- apps/sim/hooks/queries/tables.test.ts | 73 ----------- apps/sim/hooks/queries/tables.ts | 119 +----------------- 4 files changed, 15 insertions(+), 199 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index c24939ec10..4710893f0a 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -198,6 +198,8 @@ interface TableGridProps { * an all-or-nothing result and partial success cannot leave the table in an * ambiguous half-cleared state. */ +const CHUNK_CONCURRENCY = 3 + async function chunkBatchUpdates( updates: Array<{ rowId: string; data: Record }>, mutateAsync: (args: { @@ -205,9 +207,18 @@ async function chunkBatchUpdates( }) => Promise ): Promise { const size = TABLE_LIMITS.MAX_BULK_OPERATION_SIZE + const chunks: Array }>> = [] for (let i = 0; i < updates.length; i += size) { - await mutateAsync({ updates: updates.slice(i, i + size) }) + chunks.push(updates.slice(i, i + size)) } + let cursor = 0 + await Promise.all( + Array.from({ length: Math.min(CHUNK_CONCURRENCY, chunks.length) }, async () => { + while (cursor < chunks.length) { + await mutateAsync({ updates: chunks[cursor++]! }) + } + }) + ) } export function TableGrid({ diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts index 12e4e7a3da..2b36bda1a9 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.ts @@ -1,6 +1,6 @@ 'use client' -import { useCallback, useEffect, useMemo } from 'react' +import { useCallback, useMemo } from 'react' import { useQueryClient } from '@tanstack/react-query' import type { ColumnDefinition, TableDefinition, TableRow, WorkflowGroup } from '@/lib/table' import { TABLE_LIMITS } from '@/lib/table/constants' @@ -84,13 +84,6 @@ export function useTable({ workspaceId, tableId, queryOptions }: UseTableParams) enabled: Boolean(workspaceId && tableId), }) - // prefetchInfiniteQuery is a no-op when data is fresh (staleTime not exceeded), - // so drive the drain through fetchNextPage — it appends one page at a time. - useEffect(() => { - if (!workspaceId || !tableId || !hasNextPage || isFetchingNextPage) return - void fetchNextPage() - }, [workspaceId, tableId, hasNextPage, isFetchingNextPage, fetchNextPage]) - const rows = useMemo( () => rowsData?.pages.flatMap((p) => p.rows) ?? [], [rowsData?.pages] diff --git a/apps/sim/hooks/queries/tables.test.ts b/apps/sim/hooks/queries/tables.test.ts index b26fc0e199..70e8411df5 100644 --- a/apps/sim/hooks/queries/tables.test.ts +++ b/apps/sim/hooks/queries/tables.test.ts @@ -82,7 +82,6 @@ vi.mock('@/components/emcn', () => ({ })) import { - mergePagePreservingIdentity, tableKeys, tableRowsInfiniteOptions, tableRowsParamsKey, @@ -371,75 +370,3 @@ describe('tableRowsInfiniteOptions', () => { expect(JSON.stringify(opts1.queryKey)).not.toBe(JSON.stringify(opts2.queryKey)) }) }) - -describe('mergePagePreservingIdentity', () => { - const ts = '2024-01-01T00:00:00.000Z' - const ts2 = '2024-01-02T00:00:00.000Z' - - function makeRow(id: string, updatedAt: string, extra?: Record) { - return { id, updatedAt, data: { value: id, ...extra } } - } - - it('returns fresh when totalCount differs', () => { - const prev = { rows: [makeRow('r1', ts)], totalCount: 1, nextOffset: undefined } - const fresh = { rows: [makeRow('r1', ts)], totalCount: 2, nextOffset: undefined } - const result = mergePagePreservingIdentity(prev, fresh) - expect(result).toBe(fresh) - }) - - it('returns fresh when row counts differ', () => { - const prev = { rows: [makeRow('r1', ts)], totalCount: 2, nextOffset: undefined } - const fresh = { - rows: [makeRow('r1', ts), makeRow('r2', ts)], - totalCount: 2, - nextOffset: undefined, - } - const result = mergePagePreservingIdentity(prev, fresh) - expect(result).toBe(fresh) - }) - - it('returns prev (same reference) when all rows are unchanged', () => { - const row1 = makeRow('r1', ts) - const row2 = makeRow('r2', ts) - const prev = { rows: [row1, row2], totalCount: 2, nextOffset: undefined } - const freshRow1 = makeRow('r1', ts) - const fresh = { rows: [freshRow1, makeRow('r2', ts)], totalCount: 2, nextOffset: undefined } - const result = mergePagePreservingIdentity(prev, fresh) - expect(result).toBe(prev) - }) - - it('preserves identity for unchanged rows, uses fresh for updated rows', () => { - const row1 = makeRow('r1', ts) - const row2 = makeRow('r2', ts) - const prev = { rows: [row1, row2], totalCount: 2, nextOffset: undefined } - const updatedRow2 = makeRow('r2', ts2, { extra: 'new' }) - const fresh = { rows: [makeRow('r1', ts), updatedRow2], totalCount: 2, nextOffset: undefined } - const result = mergePagePreservingIdentity(prev, fresh) - expect(result).not.toBe(prev) - expect(result.rows[0]).toBe(row1) - expect(result.rows[1]).toBe(updatedRow2) - }) - - it('uses fresh row when ID is not found in prev', () => { - const row1 = makeRow('r1', ts) - const prev = { rows: [row1, makeRow('r2', ts)], totalCount: 2, nextOffset: undefined } - const newRow = makeRow('r3', ts) - const fresh = { rows: [makeRow('r1', ts), newRow], totalCount: 2, nextOffset: undefined } - const result = mergePagePreservingIdentity(prev, fresh) - expect(result.rows[1]).toBe(newRow) - }) - - it('compares updatedAt as dates, not strings (ISO vs different string forms)', () => { - const row1 = makeRow('r1', ts) - const prev = { rows: [row1], totalCount: 1, nextOffset: undefined } - // Same point in time, different ISO string representation (with trailing Z vs +00:00) - const sameTimeDifferentFormat = '2024-01-01T00:00:00+00:00' - const fresh = { - rows: [makeRow('r1', sameTimeDifferentFormat)], - totalCount: 1, - nextOffset: undefined, - } - const result = mergePagePreservingIdentity(prev, fresh) - expect(result).toBe(prev) - }) -}) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index a6b72da91d..64f9b94c7f 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -4,7 +4,6 @@ * React Query hooks for managing user-defined tables. */ -import { useEffect, useMemo } from 'react' import { createLogger } from '@sim/logger' import { type InfiniteData, @@ -70,17 +69,10 @@ import type { WorkflowGroupDependencies, WorkflowGroupOutput, } from '@/lib/table' -import { - areOutputsFilled, - hasRunningGroupExecution, - optimisticallyScheduleNewlyEligibleGroups, -} from '@/lib/table/deps' +import { areOutputsFilled, optimisticallyScheduleNewlyEligibleGroups } from '@/lib/table/deps' const logger = createLogger('TableQueries') -const ROWS_POLL_INTERVAL_WHILE_RUNNING_MS = 2_000 -const ROWS_POLL_INTERVAL_IDLE_MS = 30_000 - type TableQueryScope = 'active' | 'archived' | 'all' export const tableKeys = { @@ -251,24 +243,6 @@ export function useTableRows({ }) } -/** @internal — exported for testing only. */ -export function mergePagePreservingIdentity( - prev: TableRowsResponse, - fresh: TableRowsResponse -): TableRowsResponse { - if (prev.totalCount !== fresh.totalCount || prev.rows.length !== fresh.rows.length) return fresh - const prevById = new Map(prev.rows.map((r) => [r.id, r])) - let allSame = true - const nextRows = fresh.rows.map((freshRow) => { - const prevRow = prevById.get(freshRow.id) - if (prevRow && new Date(prevRow.updatedAt).getTime() === new Date(freshRow.updatedAt).getTime()) - return prevRow - allSame = false - return freshRow - }) - return allSame ? prev : { ...fresh, rows: nextRows } -} - export function tableRowsParamsKey({ pageSize, filter, @@ -316,99 +290,10 @@ export function useInfiniteTableRows({ sort, enabled = true, }: InfiniteTableRowsParams) { - const queryClient = useQueryClient() - const paramsKey = tableRowsParamsKey({ pageSize, filter, sort }) - // Memoize the key so the polling useEffect below doesn't fire on every render. - const queryKey = useMemo(() => tableKeys.infiniteRows(tableId, paramsKey), [tableId, paramsKey]) - - const query = useInfiniteQuery({ + return useInfiniteQuery({ ...tableRowsInfiniteOptions({ workspaceId, tableId, pageSize, filter, sort }), - queryKey, enabled: Boolean(workspaceId && tableId) && enabled, }) - - /** - * Per-page polling. Built-in `refetchInterval` would refetch every loaded - * page on each tick — wasteful when only one page has running cells. - * Instead, walk pages each tick and refetch ONLY the dirty ones, splicing - * results back into the cache. Polling stops when no page has in-flight - * cells, or while a mutation is running (optimistic-update guard). - */ - useEffect(() => { - if (!enabled || !workspaceId || !tableId) return - let cancelled = false - let timeoutId: ReturnType | null = null - const tick = async () => { - if (cancelled) return - let hasDirty = false - if (queryClient.isMutating() !== 0) { - // Mutation in progress — skip network fetch to avoid racing optimistic - // updates, but stay on the short interval so we catch up quickly once - // the mutation settles. - hasDirty = true - } else { - const data = queryClient.getQueryData>(queryKey) - const dirty: number[] = [] - if (data) { - for (let i = 0; i < data.pages.length; i++) { - if (hasRunningGroupExecution(data.pages[i].rows)) { - dirty.push(data.pageParams[i] ?? i * pageSize) - } - } - } - hasDirty = dirty.length > 0 - if (hasDirty) { - await Promise.all( - dirty.map(async (offset) => { - try { - const fresh = await fetchTableRows({ - workspaceId, - tableId, - limit: pageSize, - offset, - filter, - sort, - includeTotal: offset === 0, - }) - if (cancelled) return - queryClient.setQueryData>( - queryKey, - (prev) => { - if (!prev) return prev - const idx = prev.pageParams.indexOf(offset) - if (idx === -1) return prev - const merged = mergePagePreservingIdentity(prev.pages[idx], fresh) - if (merged === prev.pages[idx]) return prev - const nextPages = prev.pages.slice() - nextPages[idx] = merged - return { ...prev, pages: nextPages } - } - ) - } catch { - // Transient fetch failure — next tick retries. Don't kill the loop. - } - }) - ) - } - } - if (cancelled) return - // Recursive setTimeout instead of setInterval so a slow tick can't - // overlap the next one — out-of-order responses would otherwise let - // stale data overwrite fresh. Use a long interval when idle so tables - // with no running executions don't burn CPU on constant cache reads. - timeoutId = setTimeout( - () => void tick(), - hasDirty ? ROWS_POLL_INTERVAL_WHILE_RUNNING_MS : ROWS_POLL_INTERVAL_IDLE_MS - ) - } - timeoutId = setTimeout(() => void tick(), ROWS_POLL_INTERVAL_WHILE_RUNNING_MS) - return () => { - cancelled = true - if (timeoutId !== null) clearTimeout(timeoutId) - } - }, [enabled, workspaceId, tableId, pageSize, filter, sort, queryClient, queryKey]) - - return query } /** From e8b3c9524a1afc87dacb18a07b51eec296030b8d Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 11:40:52 -0700 Subject: [PATCH 14/20] chore(tables): remove stale comments and dead defensive code - Fix chunkBatchUpdates JSDoc to reflect parallel dispatch (was "sequentially") - Inline CHUNK_CONCURRENCY=3, single-use constant needs no abstraction - Drop stale "Polls while any cell is in flight" from useTableRows JSDoc - Remove two generic "Validation errors surfaced by caller" comments - Remove ASCII separator line from workflow group mutations section - Remove dead `if (!variables) return` guard in useImportCsvIntoTable onSettled (TanStack v5 always provides variables to onSettled) --- .../[tableId]/components/table-grid/table-grid.tsx | 11 ++++------- apps/sim/hooks/queries/tables.ts | 10 ---------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index 4710893f0a..0101f18013 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -193,13 +193,10 @@ interface TableGridProps { } /** - * Split updates into chunks that fit within the server's batch-size limit, - * running each chunk sequentially. Throws on first failure so callers see - * an all-or-nothing result and partial success cannot leave the table in an - * ambiguous half-cleared state. + * Split updates into chunks bounded by the server batch-size limit, dispatching + * up to 3 chunks concurrently. Throws on first failure — `Promise.all` rejects + * immediately, so partial success cannot leave the table in an ambiguous state. */ -const CHUNK_CONCURRENCY = 3 - async function chunkBatchUpdates( updates: Array<{ rowId: string; data: Record }>, mutateAsync: (args: { @@ -213,7 +210,7 @@ async function chunkBatchUpdates( } let cursor = 0 await Promise.all( - Array.from({ length: Math.min(CHUNK_CONCURRENCY, chunks.length) }, async () => { + Array.from({ length: Math.min(3, chunks.length) }, async () => { while (cursor < chunks.length) { await mutateAsync({ updates: chunks[cursor++]! }) } diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index 64f9b94c7f..bc847a7241 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -210,11 +210,6 @@ interface InfiniteTableRowsParams { enabled?: boolean } -/** - * Fetch a single page of rows for a table with pagination/filter/sort. Polls - * while any cell is in flight so cells reach their terminal state without a - * manual refresh. - */ export function useTableRows({ workspaceId, tableId, @@ -416,7 +411,6 @@ export function useCreateTableRow({ workspaceId, tableId }: RowMutationContext) reconcileCreatedRow(queryClient, tableId, row) }, onError: (error) => { - // Validation errors are surfaced inline by the caller (see useUpdateColumn). if (isValidationError(error)) return toast.error(error.message, { duration: 5000 }) }, @@ -771,7 +765,6 @@ export function useUpdateColumn({ workspaceId, tableId }: RowMutationContext) { queryClient.setQueryData(key, data) } } - // Validation errors are surfaced as inline FieldErrors by the caller. if (isValidationError(error)) return toast.error(error.message, { duration: 5000 }) }, @@ -1011,7 +1004,6 @@ export function useImportCsvIntoTable() { logger.error('Failed to import CSV into table:', error) }, onSettled: (_data, _error, variables) => { - if (!variables) return invalidateRowCount(queryClient, variables.tableId) }, }) @@ -1291,8 +1283,6 @@ export function useRunColumn({ workspaceId, tableId }: RowMutationContext) { }) } -// ───────────────────────── Workflow group mutations ───────────────────────── - interface AddWorkflowGroupVariables { group: WorkflowGroup outputColumns: AddWorkflowGroupBodyInput['outputColumns'] From 3f0da1773a6a1fa289d3f727e31f665f456530bf Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 11:53:14 -0700 Subject: [PATCH 15/20] fix(tables): run-all selection sends all rows to server, not just loaded pages When rowSelection.kind === 'all', selectedRunScope now flags allRows: true. The action-bar run handlers pass rowIds: undefined to the server when allRows is set, matching the server contract (missing rowIds = run all eligible rows). Stop likewise routes through scope: 'all' instead of per-row cancels. Previously, selecting all rows and clicking Run would silently only run the rows loaded in the current infinite-query cache (potentially one page of 1000 on a 5000-row table). --- .../components/table-grid/table-grid.tsx | 12 +++---- .../[workspaceId]/tables/[tableId]/table.tsx | 34 +++++++++++++------ 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index 0101f18013..90dfb738a0 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -97,7 +97,7 @@ export interface SelectionSnapshot { hasWorkflowColumns: boolean /** Cells the Play / Refresh / Stop buttons act on. Null when the selection * contains no workflow output cells. */ - selectedRunScope: { groupIds: string[]; rowIds: string[] } | null + selectedRunScope: { groupIds: string[]; rowIds: string[]; allRows: boolean } | null /** Drives Play (`hasIncompleteOrFailed`) / Refresh (`hasCompleted`) / * Stop (`hasInFlight`) visibility on the action bar. */ selectionStats: ExecStatusMix @@ -2804,12 +2804,12 @@ export function TableGrid({ const selectedRunScope = useMemo(() => { if (tableWorkflowGroupIds.length === 0) return null if (!rowSelectionIsEmpty(rowSelection)) { - const rowIds: string[] = [] - for (const row of rows) { - if (rowSelectionIncludes(rowSelection, row.id)) rowIds.push(row.id) + if (rowSelection.kind === 'all') { + return { groupIds: tableWorkflowGroupIds, rowIds: rows.map((r) => r.id), allRows: true } } + const rowIds = rows.filter((r) => rowSelectionIncludes(rowSelection, r.id)).map((r) => r.id) if (rowIds.length === 0) return null - return { groupIds: tableWorkflowGroupIds, rowIds } + return { groupIds: tableWorkflowGroupIds, rowIds, allRows: false } } const sel = normalizedSelection if (!sel) return null @@ -2827,7 +2827,7 @@ export function TableGrid({ if (row) rowIds.push(row.id) } if (rowIds.length === 0) return null - return { groupIds: [...groupIdsInRect], rowIds } + return { groupIds: [...groupIdsInRect], rowIds, allRows: false } }, [rowSelection, normalizedSelection, rows, displayColumns, tableWorkflowGroupIds]) const selectionStats = useMemo(() => { diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx index 91eeb93595..9ce165deb3 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx @@ -513,17 +513,29 @@ export function Table({ hasWorkflowColumns={selection.hasWorkflowColumns} showPlay={selection.selectionStats.hasIncompleteOrFailed} showRefresh={selection.selectionStats.hasCompleted} - onPlay={() => - selection.selectedRunScope && - runScope({ ...selection.selectedRunScope, runMode: 'incomplete' }) - } - onRefresh={() => - selection.selectedRunScope && - runScope({ ...selection.selectedRunScope, runMode: 'all' }) - } - onStopWorkflows={() => - selection.selectedRunScope && onStopRows(selection.selectedRunScope.rowIds) - } + onPlay={() => { + const scope = selection.selectedRunScope + if (!scope) return + runScope({ + groupIds: scope.groupIds, + rowIds: scope.allRows ? undefined : scope.rowIds, + runMode: 'incomplete', + }) + }} + onRefresh={() => { + const scope = selection.selectedRunScope + if (!scope) return + runScope({ + groupIds: scope.groupIds, + rowIds: scope.allRows ? undefined : scope.rowIds, + runMode: 'all', + }) + }} + onStopWorkflows={() => { + const scope = selection.selectedRunScope + if (!scope) return + scope.allRows ? onStopAll() : onStopRows(scope.rowIds) + }} onViewExecution={ selection.singleWorkflowCell?.canViewExecution && selection.singleWorkflowCell.executionId From bf98e8c7f51dc1d66168d35c24f6a573089ca195 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 11:57:56 -0700 Subject: [PATCH 16/20] test(tables): remove background-drain describe block (behavior intentionally removed) --- .../tables/[tableId]/hooks/use-table.test.ts | 66 ------------------- 1 file changed, 66 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts index 70fe267d8d..6283732daf 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table.test.ts @@ -70,7 +70,6 @@ vi.mock('@/lib/table/constants', () => ({ })) import { useTable } from '@/app/workspace/[workspaceId]/tables/[tableId]/hooks/use-table' -import { useInfiniteTableRows } from '@/hooks/queries/tables' const WORKSPACE_ID = 'ws-1' const TABLE_ID = 'tbl-1' @@ -237,68 +236,3 @@ describe('useTable – ensureAllRowsLoaded', () => { expect(JSON.stringify(queryKey)).toContain('Alice') }) }) - -describe('useTable – background drain on mount', () => { - it('calls fetchNextPage when hasNextPage is true', () => { - vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ - data: { pages: [] }, - isLoading: false, - refetch: vi.fn().mockResolvedValue(undefined), - fetchNextPage: mockFetchNextPage, - hasNextPage: true, - isFetchingNextPage: false, - }) - useTable({ workspaceId: WORKSPACE_ID, tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) - for (const effect of capturedEffects) effect() - expect(mockFetchNextPage).toHaveBeenCalled() - }) - - it('does not call fetchNextPage when hasNextPage is false', () => { - // Default mock already returns hasNextPage: false. - useTable({ workspaceId: WORKSPACE_ID, tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) - for (const effect of capturedEffects) effect() - expect(mockFetchNextPage).not.toHaveBeenCalled() - }) - - it('does not call fetchNextPage when isFetchingNextPage is true', () => { - vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ - data: { pages: [] }, - isLoading: false, - refetch: vi.fn().mockResolvedValue(undefined), - fetchNextPage: mockFetchNextPage, - hasNextPage: true, - isFetchingNextPage: true, - }) - useTable({ workspaceId: WORKSPACE_ID, tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) - for (const effect of capturedEffects) effect() - expect(mockFetchNextPage).not.toHaveBeenCalled() - }) - - it('does not drain when workspaceId is empty', () => { - vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ - data: { pages: [] }, - isLoading: false, - refetch: vi.fn().mockResolvedValue(undefined), - fetchNextPage: mockFetchNextPage, - hasNextPage: true, - isFetchingNextPage: false, - }) - useTable({ workspaceId: '', tableId: TABLE_ID, queryOptions: QUERY_OPTIONS }) - for (const effect of capturedEffects) effect() - expect(mockFetchNextPage).not.toHaveBeenCalled() - }) - - it('does not drain when tableId is empty', () => { - vi.mocked(useInfiniteTableRows).mockReturnValueOnce({ - data: { pages: [] }, - isLoading: false, - refetch: vi.fn().mockResolvedValue(undefined), - fetchNextPage: mockFetchNextPage, - hasNextPage: true, - isFetchingNextPage: false, - }) - useTable({ workspaceId: WORKSPACE_ID, tableId: '', queryOptions: QUERY_OPTIONS }) - for (const effect of capturedEffects) effect() - expect(mockFetchNextPage).not.toHaveBeenCalled() - }) -}) From e3f2da46f6b39d04b9606f19dd67131d85e4a47b Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 12:12:54 -0700 Subject: [PATCH 17/20] fix(tables): surface CSV import error toast; remove dead hasRunningGroupExecution --- apps/sim/hooks/queries/tables.ts | 1 + apps/sim/lib/table/deps.ts | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/sim/hooks/queries/tables.ts b/apps/sim/hooks/queries/tables.ts index bc847a7241..e53b77be0c 100644 --- a/apps/sim/hooks/queries/tables.ts +++ b/apps/sim/hooks/queries/tables.ts @@ -1002,6 +1002,7 @@ export function useImportCsvIntoTable() { }, onError: (error) => { logger.error('Failed to import CSV into table:', error) + toast.error(error.message, { duration: 5000 }) }, onSettled: (_data, _error, variables) => { invalidateRowCount(queryClient, variables.tableId) diff --git a/apps/sim/lib/table/deps.ts b/apps/sim/lib/table/deps.ts index fabe8909c9..d9b33f59db 100644 --- a/apps/sim/lib/table/deps.ts +++ b/apps/sim/lib/table/deps.ts @@ -24,15 +24,6 @@ export function isExecInFlight(exec: RowExecutionMetadata | undefined): boolean return false } -export function hasRunningGroupExecution(rows: TableRow[]): boolean { - for (const row of rows) { - for (const exec of Object.values(row.executions)) { - if (isExecInFlight(exec)) return true - } - } - return false -} - /** * True when every output column the group writes still has a non-empty value * on this row. The "completed" exec status is metadata, but the cells are the From e7b5a01949eae2c687da9d23393ce1053db94057 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 12:26:36 -0700 Subject: [PATCH 18/20] fix(tables): make runWithoutRecording async-aware so undoRedoInProgress covers full undo execution --- apps/sim/hooks/use-table-undo.test.ts | 2 +- apps/sim/hooks/use-table-undo.ts | 10 ++-------- apps/sim/stores/table/store.ts | 9 +++++---- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/sim/hooks/use-table-undo.test.ts b/apps/sim/hooks/use-table-undo.test.ts index e39db3a03a..de9a1019eb 100644 --- a/apps/sim/hooks/use-table-undo.test.ts +++ b/apps/sim/hooks/use-table-undo.test.ts @@ -50,7 +50,7 @@ const storeState = { vi.mock('@/stores/table/store', () => ({ useTableUndoStore: vi.fn((selector: (s: typeof storeState) => unknown) => selector(storeState)), - runWithoutRecording: (fn: () => void) => fn(), + runWithoutRecording: (fn: () => unknown) => Promise.resolve(fn()), })) import { useTableUndo } from '@/hooks/use-table-undo' diff --git a/apps/sim/hooks/use-table-undo.ts b/apps/sim/hooks/use-table-undo.ts index d27f3826f7..8a364d5469 100644 --- a/apps/sim/hooks/use-table-undo.ts +++ b/apps/sim/hooks/use-table-undo.ts @@ -355,19 +355,13 @@ export function useTableUndo({ const undo = useCallback(() => { const entry = popUndo(tableId) if (!entry) return - - runWithoutRecording(() => { - void executeAction(entry.action, 'undo') - }) + void runWithoutRecording(() => executeAction(entry.action, 'undo')) }, [popUndo, tableId, executeAction]) const redo = useCallback(() => { const entry = popRedo(tableId) if (!entry) return - - runWithoutRecording(() => { - void executeAction(entry.action, 'redo') - }) + void runWithoutRecording(() => executeAction(entry.action, 'redo')) }, [popRedo, tableId, executeAction]) return { pushUndo, undo, redo, canUndo, canRedo } diff --git a/apps/sim/stores/table/store.ts b/apps/sim/stores/table/store.ts index 47d1e973f6..fc4df2808c 100644 --- a/apps/sim/stores/table/store.ts +++ b/apps/sim/stores/table/store.ts @@ -81,13 +81,14 @@ function patchRowIdInEntry(entry: UndoEntry, oldRowId: string, newRowId: string) } /** - * Run a function without recording undo entries. - * Used by the hook when executing undo/redo mutations to prevent recursive recording. + * Run a function without recording undo entries. Supports async functions — + * `undoRedoInProgress` stays true until the returned Promise settles, so + * mutations inside `executeAction` don't accidentally push new undo entries. */ -export function runWithoutRecording(fn: () => T): T { +export async function runWithoutRecording(fn: () => T | Promise): Promise { undoRedoInProgress = true try { - return fn() + return await fn() } finally { undoRedoInProgress = false } From 685ae544c94083b7ab0028b295f23e55cc342881 Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 9 May 2026 12:42:34 -0700 Subject: [PATCH 19/20] feat(tables): render URL cells with favicon and clickable link --- .../table-grid/cells/cell-render.tsx | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx index 2de71e2a9e..ed0e6a1e9e 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx @@ -38,6 +38,7 @@ export type CellRenderKind = | { kind: 'boolean'; checked: boolean } | { kind: 'json'; text: string } | { kind: 'date'; text: string } + | { kind: 'url'; text: string; href: string; domain: string } | { kind: 'text'; text: string } // Universal fallback | { kind: 'empty' } @@ -113,6 +114,12 @@ export function resolveCellRender({ if (isNull) return { kind: 'empty' } if (column.type === 'json') return { kind: 'json', text: JSON.stringify(value) } if (column.type === 'date') return { kind: 'date', text: String(value) } + if (column.type === 'string') { + const text = stringifyValue(value) + const urlInfo = extractUrlInfo(text) + if (urlInfo) return { kind: 'url', text, href: urlInfo.href, domain: urlInfo.domain } + return { kind: 'text', text } + } return { kind: 'text', text: stringifyValue(value) } } @@ -122,6 +129,78 @@ function stringifyValue(value: unknown): string { return JSON.stringify(value) } +/** Matches bare hostnames: `microsoft.com`, `www.linkedin.com`, `sub.domain.co.uk` */ +const BARE_DOMAIN_RE = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/ + +/** + * File extensions that are also valid TLDs but should never be treated as URLs. + * Without this, strings like `config.json` or `readme.md` would resolve as domains. + */ +const FILE_EXTENSION_TLDS = new Set([ + 'txt', + 'json', + 'yaml', + 'yml', + 'xml', + 'html', + 'htm', + 'css', + 'js', + 'ts', + 'tsx', + 'jsx', + 'md', + 'mdx', + 'csv', + 'pdf', + 'doc', + 'docx', + 'xls', + 'xlsx', + 'ppt', + 'pptx', + 'zip', + 'gz', + 'tar', + 'rar', + 'png', + 'jpg', + 'jpeg', + 'gif', + 'svg', + 'webp', + 'mp4', + 'mp3', + 'wav', + 'mov', + 'py', + 'rb', + 'go', + 'rs', + 'sh', + 'bat', + 'log', + 'env', +]) + +function extractUrlInfo(text: string): { href: string; domain: string } | null { + if (!text) return null + if (/^https?:\/\//i.test(text)) { + try { + const url = new URL(text) + return { href: text, domain: url.hostname } + } catch { + return null + } + } + if (BARE_DOMAIN_RE.test(text)) { + const tld = text.split('.').pop()?.toLowerCase() ?? '' + if (FILE_EXTENSION_TLDS.has(tld)) return null + return { href: `https://${text}`, domain: text } + } + return null +} + interface CellRenderProps { kind: CellRenderKind /** When true the static content sits underneath the InlineEditor overlay @@ -237,6 +316,31 @@ export function CellRender({ kind, isEditing }: CellRenderProps): React.ReactEle ) + case 'url': + return ( + + { + e.currentTarget.style.display = 'none' + }} + /> + e.stopPropagation()} + > + {kind.text} + + + ) + case 'text': return ( Date: Sat, 9 May 2026 13:01:37 -0700 Subject: [PATCH 20/20] feat(tables): clickable URL cells with favicons using tldts --- .../table-grid/cells/cell-render.tsx | 138 +------ apps/sim/package.json | 1 + bun.lock | 377 +++++++----------- 3 files changed, 163 insertions(+), 353 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx index ed0e6a1e9e..c2c78971d9 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx @@ -1,6 +1,7 @@ 'use client' import type React from 'react' +import { parse } from 'tldts' import { Badge, Checkbox, Tooltip } from '@/components/emcn' import { cn } from '@/lib/core/utils/cn' import type { RowExecutionMetadata } from '@/lib/table' @@ -8,22 +9,6 @@ import { StatusBadge } from '@/app/workspace/[workspaceId]/logs/utils' import { storageToDisplay } from '../../../utils' import type { DisplayColumn } from '../types' -/** - * Discriminated union describing every shape a table cell can take. - * - * Workflow-output cells follow a status state machine: they always render - * *something* (a value, a status pill, or a dash), driven by the combination - * of `executions[groupId]` state and dep satisfaction. Plain (non-workflow) - * cells just render the typed value or empty. - * - * `'empty'` is the universal fallback used by both workflow cells (no exec, - * no value, no waiting) and plain cells (null/undefined value). - * - * Adding a new cell appearance is a three-step mechanical change: add a - * variant here, pick it in `resolveCellRender`, render it in `CellRender`. - * TypeScript's exhaustiveness check on the renderer's `switch` (the - * unreachable default) flags any branch you forgot. - */ export type CellRenderKind = // Workflow-output cells | { kind: 'value'; text: string } @@ -47,20 +32,9 @@ interface ResolveCellRenderInput { value: unknown exec: RowExecutionMetadata | undefined column: DisplayColumn - /** Empty / undefined → not waiting; non-empty → render the Waiting pill. */ waitingOnLabels: string[] | undefined } -/** - * Decide which `CellRenderKind` to render for a cell. Pure — easily - * unit-testable in isolation, no JSX involved. - * - * Order matters for workflow cells: block-error wins over a value (the user - * cares about the failure), value wins over running/queued (we have data - * already), and the running/queued branch deliberately collapses pre-enqueue - * `pending` and post-enqueue `queued` into one `Queued` pill so the cell - * doesn't flicker as the row transitions from one to the other. - */ export function resolveCellRender({ value, exec, @@ -77,31 +51,20 @@ export function resolveCellRender({ if (blockError) return { kind: 'block-error' } - // Active re-run of THIS column wins over its prior value — the value is - // about to be overwritten and the user should see the cell is changing. const inFlight = exec?.status === 'running' || exec?.status === 'queued' || exec?.status === 'pending' if (inFlight && blockRunning) return { kind: 'running' } - // Value wins over `pending-upstream`: once this column's output has - // landed, the cell is done from the user's perspective — even if the - // group is still running other blocks downstream. Without this, mid-run - // partial-write events (`status: 'running'` carrying outputs but tagging - // a different block as running) would flip a finished column back to the - // amber Pending pill until the terminal `completed` event arrives. + // Value wins over pending-upstream: a finished column stays finished even + // while other blocks in the group are still running. if (!isNull) return { kind: 'value', text: stringifyValue(value) } if (inFlight && !(groupHasBlockErrors && !blockRunning)) { if (exec?.status === 'queued' || exec?.status === 'pending') return { kind: 'queued' } - // `running` with this block not in `runningBlockIds` and no value yet = - // upstream block still going; surface as the amber Pending pill. return { kind: 'pending-upstream' } } - // Waiting wins over a stale terminal state: if deps are unmet right now, - // the prior `cancelled` / `error` is informational at best — the cell - // can't actually run until the user fills the missing input. Surface the - // actionable state instead of the stale one. + // Waiting wins over a stale terminal status — show the actionable state. if (waitingOnLabels && waitingOnLabels.length > 0) { return { kind: 'waiting', labels: waitingOnLabels } } @@ -129,91 +92,32 @@ function stringifyValue(value: unknown): string { return JSON.stringify(value) } -/** Matches bare hostnames: `microsoft.com`, `www.linkedin.com`, `sub.domain.co.uk` */ const BARE_DOMAIN_RE = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/ -/** - * File extensions that are also valid TLDs but should never be treated as URLs. - * Without this, strings like `config.json` or `readme.md` would resolve as domains. - */ -const FILE_EXTENSION_TLDS = new Set([ - 'txt', - 'json', - 'yaml', - 'yml', - 'xml', - 'html', - 'htm', - 'css', - 'js', - 'ts', - 'tsx', - 'jsx', - 'md', - 'mdx', - 'csv', - 'pdf', - 'doc', - 'docx', - 'xls', - 'xlsx', - 'ppt', - 'pptx', - 'zip', - 'gz', - 'tar', - 'rar', - 'png', - 'jpg', - 'jpeg', - 'gif', - 'svg', - 'webp', - 'mp4', - 'mp3', - 'wav', - 'mov', - 'py', - 'rb', - 'go', - 'rs', - 'sh', - 'bat', - 'log', - 'env', -]) - function extractUrlInfo(text: string): { href: string; domain: string } | null { - if (!text) return null - if (/^https?:\/\//i.test(text)) { + const trimmed = text.trim() + if (!trimmed) return null + if (/^https?:\/\//i.test(trimmed)) { try { - const url = new URL(text) - return { href: text, domain: url.hostname } + const url = new URL(trimmed) + return { href: trimmed, domain: url.hostname } } catch { return null } } - if (BARE_DOMAIN_RE.test(text)) { - const tld = text.split('.').pop()?.toLowerCase() ?? '' - if (FILE_EXTENSION_TLDS.has(tld)) return null - return { href: `https://${text}`, domain: text } + if (BARE_DOMAIN_RE.test(trimmed)) { + const parsed = parse(trimmed) + if (!parsed.isIcann) return null + return { href: `https://${trimmed}`, domain: trimmed } } return null } interface CellRenderProps { kind: CellRenderKind - /** When true the static content sits underneath the InlineEditor overlay - * and should be visually hidden (but kept in flow to preserve cell size). */ isEditing: boolean } -/** - * Pure renderer: takes a `CellRenderKind` and returns the JSX. No business - * logic — adding a new cell appearance means adding a new `case` here. The - * exhaustiveness check on the `switch` (the unreachable default) flags any - * variant you forgot to handle. - */ export function CellRender({ kind, isEditing }: CellRenderProps): React.ReactElement | null { switch (kind.kind) { case 'value': @@ -320,7 +224,7 @@ export function CellRender({ kind, isEditing }: CellRenderProps): React.ReactEle return ( e.stopPropagation()} + onDoubleClick={(e) => e.stopPropagation()} > {kind.text} @@ -357,20 +265,12 @@ export function CellRender({ kind, isEditing }: CellRenderProps): React.ReactEle return null default: { - // Exhaustiveness guard: TypeScript flags this branch if a new - // `CellRenderKind` variant is added without a matching `case` above. const _exhaustive: never = kind return _exhaustive } } } -/** - * Workflow-output cells are hand-editable; while editing, the static content - * must stay in flow (so the cell doesn't collapse) but be visually hidden so - * the InlineEditor overlay shows through. Plain wrapper around any non-text - * variant. - */ function Wrap({ isEditing, children }: { isEditing: boolean; children: React.ReactNode }) { if (!isEditing) return <>{children} return
{children}
diff --git a/apps/sim/package.json b/apps/sim/package.json index dab333326b..766b04cb56 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -195,6 +195,7 @@ "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "three": "0.177.0", + "tldts": "7.0.30", "twilio": "5.9.0", "unified": "11.0.5", "unpdf": "1.4.0", diff --git a/bun.lock b/bun.lock index 29c91ea34b..d682cb37cd 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,6 @@ { "lockfileVersion": 1, - "configVersion": 0, + "configVersion": 1, "workspaces": { "": { "name": "simstudio", @@ -250,6 +250,7 @@ "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "three": "0.177.0", + "tldts": "7.0.30", "twilio": "5.9.0", "unified": "11.0.5", "unpdf": "1.4.0", @@ -492,39 +493,39 @@ "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], - "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@3.0.98", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.78", "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-zVMBSYVWYxTK7PM2LCnyRc1YGUHvOcDXGz2Xvsb4FvNFpFGTVdxp9PMFYkM12IXzpYtMNn7z6H9WRZeZ4BnPyQ=="], + "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@3.0.99", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.79", "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-d/WsYOlqjQeEwTewawjrlhoWfHt3q1vRT5/XdFJ6U+KYd/3HnAlrA3rg0+T7xMk98XmctaILJb45Ct/8zrGxSA=="], - "@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.78", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-88zglac49Dyf0osHVKX8Cgim5mo+xfVACSMbNlVt7q97S2hWTuMeVSPCyDM8UCJQ6m3jNNLlMZLEwVdOdxZjBg=="], + "@ai-sdk/anthropic": ["@ai-sdk/anthropic@2.0.79", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-K0U09FPDO1kmLPjRLXFcNSvmnKHJBMARCb8r3Ulw7wU6/+Zh9djWcFDiPPNsklg6yAezcdLTcYPszgWJJ6iOTA=="], - "@ai-sdk/azure": ["@ai-sdk/azure@2.0.106", "", { "dependencies": { "@ai-sdk/openai": "2.0.104", "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-mJ3ZJag/A0Al1dTLOHAIQT0jep6Bh4pNWsmu4es0cYfFEQWPkFS+zKhi29dYikicmb50Gy3GKDJGXazWdHQWuA=="], + "@ai-sdk/azure": ["@ai-sdk/azure@2.0.108", "", { "dependencies": { "@ai-sdk/openai": "2.0.106", "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-/F+lx3glCDiqJfqkZP9IOCubYlWABX2Jg9Yzm/JIxZR5qHfo9rsLwS4zVtghbELVbEjxakaFlDT/c6uTBj0uug=="], - "@ai-sdk/cerebras": ["@ai-sdk/cerebras@1.0.42", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.37", "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-zKubak4yiU4jcCyVNgUxvsc2Hj1fBC+LRfGNcPuN/3A8juHyp67rQ714tuJR04mOhtTOFNipa1A/fN8hDsH5Uw=="], + "@ai-sdk/cerebras": ["@ai-sdk/cerebras@1.0.44", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.39", "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-2w7+jq0bWEF6McgWPb2gjaEx1TpqdUq4eyX/gPLTp7HzfDZKEVmmVXRvnKvjzBP/VH7xW4OT5jhTpTPTfYNYYQ=="], - "@ai-sdk/deepseek": ["@ai-sdk/deepseek@1.0.38", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-mxwHlryNx2r7k/w5ftiDnt+RRjzmsQ/Lx92DFFMbYlzO7fZvHwZKGsnbrm5DxpjDDVDKAsDKAGcT1NROQUI/sA=="], + "@ai-sdk/deepseek": ["@ai-sdk/deepseek@1.0.39", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-5TXw7Pm0+/YL2WdnZpXBgruPayhqBgBMNDL95V14Sf4MQz+RmNMhansvK8Fv9Dcgp3Y0p7EasNsPWYJOfj0zoA=="], - "@ai-sdk/gateway": ["@ai-sdk/gateway@2.0.83", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-qgxu2++9tJTPZtC+VGczu21YNXTtzfrLQunqh7xcCaWSogAluchrGiKFS3IZkX7Se9dEt1yYZ6+d+cGo4cko6Q=="], + "@ai-sdk/gateway": ["@ai-sdk/gateway@2.0.87", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-9aPUt/pJb2NY1HPeJIGHBPUxZiZu+EX1aNyBCGDynHtLzCBaZCANMWUxrluxmGLpoYTRik+WxLzUMSZS/FEGew=="], - "@ai-sdk/google": ["@ai-sdk/google@2.0.71", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-98KQxlPEU1zL0wp/098EQZou36C6hIhiXnhGEatqb1l0xGsta/DsQ614GpRK8nCfeqAO2Q27vLcgX3oltujBbA=="], + "@ai-sdk/google": ["@ai-sdk/google@2.0.72", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-BjDY6l+rV4CmHKjZe4H0uRXW3M2o+g7PaYM8oFpW+9PP1qKNEybnJ6//Si7BSf6DT+86dKARrtEl09lxSSaMaA=="], - "@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@3.0.133", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.78", "@ai-sdk/google": "2.0.71", "@ai-sdk/openai-compatible": "1.0.37", "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-jlM/a/lKfXwAbU29TQf5hCt4fnROlE4G/Yk+DmP2mTbWvAgHpSYx7CwMjldvUoTTpyNHk6yg8FxkTSOLA0Stcg=="], + "@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@3.0.137", "", { "dependencies": { "@ai-sdk/anthropic": "2.0.79", "@ai-sdk/google": "2.0.72", "@ai-sdk/openai-compatible": "1.0.39", "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-vDtCmwMy4CzVsv3PESmkE96qDSqnsArDDEc22eggujZI/WxmIeKa+8vyUYjJUx9HZLOCPo7HhYDXjH0R2mcM+Q=="], - "@ai-sdk/groq": ["@ai-sdk/groq@2.0.39", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-S3fp415JjLvoe//bzIWWT0wEz+C9dEFx5vhJ5QS1RjuWSHNXfp46xkpS3fvHl3y6uVnxzsgghm5C1V002NGDIA=="], + "@ai-sdk/groq": ["@ai-sdk/groq@2.0.40", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-1EL8D1tyjOKjCFUt8XspDoA6zxDcalMsLR2O56ji8QklWsAPaf4TuMJAvf5x5KDrkuJaSAjk94KvPH5hOX+VNQ=="], - "@ai-sdk/mistral": ["@ai-sdk/mistral@2.0.32", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-hs4CCm4OrVhNA2F766CPV5LUt0RlL4oOOvNXLpVZnbLzvkUDx2oLHQU/xERX1fxHzdegv8TEgB+VuUKp9TGhlg=="], + "@ai-sdk/mistral": ["@ai-sdk/mistral@2.0.33", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-oBR9nJQ8TRFU0JIIXF+0cFTo8VVEreA1V8AMD3c77BJj/1NUSBLrhyqAbX9k7YAtztvZHUdFcm3+vK8KIx0sUQ=="], - "@ai-sdk/openai": ["@ai-sdk/openai@2.0.104", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-pRK41FjpaHvq0tNO0c+Ye9WfrdBLmPVMPivXC4Z9fpqBKcUsmh9bo0xdPt6dEQtD/si8ygoMn4Q+6yj83NwiRg=="], + "@ai-sdk/openai": ["@ai-sdk/openai@2.0.106", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-EFC0rpo1wfe4HIz5KZCE72edP2J7fOeR7wPXzjCDljaTRB1wectKDIKRLowpU4F0mbcJ+XScAsoYNPK/Z20aVQ=="], - "@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.37", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-DZzoZHeCYGG4IBujzT+aSjodxecp1NxNZYIrfSzCzTOWnvvuZgzLE5Hwi3ZWANwRnxBbsVXVQ1b5ghxtRbkoxg=="], + "@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@1.0.39", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-001hdQPPXxYBWrz5d+eAmBVYmwzsB+guIey1DFXi1ZEE5H3j7fRrhPpX55MdM9Fle2DS7WZ8b3qkumCIWE92YQ=="], - "@ai-sdk/perplexity": ["@ai-sdk/perplexity@2.0.29", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-n1BX39P2fSKjQvEXWnMb6VbBq3kiKNYPaS1/Q+7hnR2Su9FR3juW7oKa0wEV+shldQKRpcZzcX14MhBeD0g37A=="], + "@ai-sdk/perplexity": ["@ai-sdk/perplexity@2.0.30", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ymXWoItR4tRCIQlJcpn0zk4jBUU+j4SDnliz/z1f5U6rWxNY1ttxFCk4uZ+6Zt9e3VjQTpA9FK6cOJt18JRrKQ=="], - "@ai-sdk/provider": ["@ai-sdk/provider@2.0.2", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Epf0oKdUxNRK97Qm4l/Sp05TnwzE8FsyRF5p6nncOp8zH0GTuwK2uZoyzE/3uVjRdZNLyQ6Jw/SBjlOScMQy1Q=="], + "@ai-sdk/provider": ["@ai-sdk/provider@2.0.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-h88OPkavHTiN9tMn2l5awAznGB0lXzjcLhgR1/rvjB2zlLprsNxbM2tt6OJsHUxduLC3klq0/eqaSf6fX5XVww=="], - "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.24", "", { "dependencies": { "@ai-sdk/provider": "2.0.2", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Zq6olgYvpMgfstQNpDwgqDC2wBEE+OnMnMuq4JyIu+aWjL8JJl+6u1sbKJNPxASErWrRlmOPIkat2fHiN4puhA=="], + "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.25", "", { "dependencies": { "@ai-sdk/provider": "2.0.3", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-CvsRu+32Y8a167s+lrIBtsybvgTHp8j9y+6BeTvLeoW3Q+okw/b4CnNUFOLIXsRaKHQKAH+IHNJPYWywfpw0LA=="], - "@ai-sdk/togetherai": ["@ai-sdk/togetherai@1.0.40", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.37", "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-p/tUlmcV/xKEElQliPnWn/TcqaxuC++HmZXICcfzqooMXyDfrxBBS55XWJl6QZ3IwfniDr8PrnsheYD4ECdkJg=="], + "@ai-sdk/togetherai": ["@ai-sdk/togetherai@1.0.42", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.39", "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-V9reHPfWeaIt6fu03lVbjZDuxfdplS5jdmzVchVBeUug9VqIK+9KQELcPvdWKdxf+ov+sCoShN/O6dYfPPD5Ng=="], - "@ai-sdk/xai": ["@ai-sdk/xai@2.0.69", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.37", "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-xnbMYsbqBawFP/fbqCswcHXaU3GB3EcuENc+EpCCTEZi6yRj4XgRs2RFRkgmmb6Pwl2XcohCj/7+SMf/VeZnGA=="], + "@ai-sdk/xai": ["@ai-sdk/xai@2.0.72", "", { "dependencies": { "@ai-sdk/openai-compatible": "1.0.39", "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-RXpfCTliybesXOmc+jGB7NhobJzzZc2rr7gSy7kGj0eHDYXkCmoo4/llpE8yKIUJMwU098DP1cBGdltPezNRiw=="], "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], @@ -586,31 +587,29 @@ "@aws-sdk/client-sqs": ["@aws-sdk/client-sqs@3.1032.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.1", "@aws-sdk/credential-provider-node": "^3.972.32", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-sdk-sqs": "^3.972.20", "@aws-sdk/middleware-user-agent": "^3.972.31", "@aws-sdk/region-config-resolver": "^3.972.12", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.7", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.17", "@smithy/config-resolver": "^4.4.16", "@smithy/core": "^3.23.15", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/md5-js": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.30", "@smithy/middleware-retry": "^4.5.3", "@smithy/middleware-serde": "^4.2.18", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.5.3", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.11", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.47", "@smithy/util-defaults-mode-node": "^4.2.52", "@smithy/util-endpoints": "^3.4.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-n102sARTLi53Da0JT/2Kvg/bQ4bv+JqA+YQ8OlaM4CgsPn61sMv0x9PxdF6s/KbgZ2HMwYBszNzuvUttN+Beqg=="], - "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A=="], - "@aws-sdk/client-sso-admin": ["@aws-sdk/client-sso-admin@3.1032.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.1", "@aws-sdk/credential-provider-node": "^3.972.32", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.31", "@aws-sdk/region-config-resolver": "^3.972.12", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.7", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.17", "@smithy/config-resolver": "^4.4.16", "@smithy/core": "^3.23.15", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.30", "@smithy/middleware-retry": "^4.5.3", "@smithy/middleware-serde": "^4.2.18", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.5.3", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.11", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.47", "@smithy/util-defaults-mode-node": "^4.2.52", "@smithy/util-endpoints": "^3.4.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-nQZibW7Uwflbn7wC3CnA1hXIo34f2oxvPsfmAnzqyOhSHL6v1LNwElQywmZStiFjmATIlJVQKvCaj+/MAKscNw=="], "@aws-sdk/client-sts": ["@aws-sdk/client-sts@3.1032.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.1", "@aws-sdk/credential-provider-node": "^3.972.32", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.31", "@aws-sdk/region-config-resolver": "^3.972.12", "@aws-sdk/signature-v4-multi-region": "^3.996.18", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.7", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.17", "@smithy/config-resolver": "^4.4.16", "@smithy/core": "^3.23.15", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.30", "@smithy/middleware-retry": "^4.5.3", "@smithy/middleware-serde": "^4.2.18", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.5.3", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.11", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.47", "@smithy/util-defaults-mode-node": "^4.2.52", "@smithy/util-endpoints": "^3.4.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-FCLc5VWb+yz1xb/Jv0sXFGqIIs+bHZQWBKbPQKCuypF3wU/7UFygXuSXo9uJfwISKNGVHJwp+0136f8mqmzRcA=="], - "@aws-sdk/core": ["@aws-sdk/core@3.974.6", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws-sdk/xml-builder": "^3.972.20", "@smithy/core": "^3.23.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.5", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-8Vu7zGxu+39ChR/s5J7nXBw3a2kMHAi0OfKT8ohgTVjX0qYed/8mIfdBb638oBmKrWCwwKjYAM5J/4gMJ8nAJA=="], + "@aws-sdk/core": ["@aws-sdk/core@3.974.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws-sdk/xml-builder": "^3.972.22", "@smithy/core": "^3.23.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.6", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw=="], "@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.972.7", "", { "dependencies": { "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.32", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-7vA4GHg8NSmQxquJHSBcSM3RgB4ZaaRi6u4+zGFKOmOH6aqlgr2Sda46clkZDYzlirgfY96w15Zj0jh6PT48ng=="], + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.34", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.34", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/types": "^3.973.8", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/node-http-handler": "^4.6.1", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-stream": "^4.5.25", "tslib": "^2.6.2" } }, "sha512-vBrhWujFCLp1u8ptJRWYlipMutzPptb8pDQ00rKVH9q67T7rGd3VTWIj63aKrlLuY6qSsw1Rt5F/D/7wnNgryA=="], + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.36", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/node-http-handler": "^4.6.1", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-stream": "^4.5.25", "tslib": "^2.6.2" } }, "sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.36", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/credential-provider-env": "^3.972.32", "@aws-sdk/credential-provider-http": "^3.972.34", "@aws-sdk/credential-provider-login": "^3.972.36", "@aws-sdk/credential-provider-process": "^3.972.32", "@aws-sdk/credential-provider-sso": "^3.972.36", "@aws-sdk/credential-provider-web-identity": "^3.972.36", "@aws-sdk/nested-clients": "^3.997.4", "@aws-sdk/types": "^3.973.8", "@smithy/credential-provider-imds": "^4.2.14", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-FBHyCmV8EB0gUvh1d+CZm87zt2PrdC7OyWexLRoH3I5zWSOUGa+9t58Y5jbxRfwUp3AWpHAFvKY6YzgR845sVA=="], + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/credential-provider-env": "^3.972.34", "@aws-sdk/credential-provider-http": "^3.972.36", "@aws-sdk/credential-provider-login": "^3.972.38", "@aws-sdk/credential-provider-process": "^3.972.34", "@aws-sdk/credential-provider-sso": "^3.972.38", "@aws-sdk/credential-provider-web-identity": "^3.972.38", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/credential-provider-imds": "^4.2.14", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.36", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/nested-clients": "^3.997.4", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-IFap01lJKxQc0C/OHmZwZQr/cKq0DhrcmKedRrdnnl42D+P0SImnnnWQjv07uIPqpEdtqmkPXb9TiPYTU+prxQ=="], + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.37", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.32", "@aws-sdk/credential-provider-http": "^3.972.34", "@aws-sdk/credential-provider-ini": "^3.972.36", "@aws-sdk/credential-provider-process": "^3.972.32", "@aws-sdk/credential-provider-sso": "^3.972.36", "@aws-sdk/credential-provider-web-identity": "^3.972.36", "@aws-sdk/types": "^3.973.8", "@smithy/credential-provider-imds": "^4.2.14", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-/WFixFAAiw8WpmjZcI0l4t3DerXLmVinOIfuotmRZnu2qmsFPoqqmstASz0z8bi1pGdFXzeLzf6bwucM3mZcUQ=="], + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.39", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.34", "@aws-sdk/credential-provider-http": "^3.972.36", "@aws-sdk/credential-provider-ini": "^3.972.38", "@aws-sdk/credential-provider-process": "^3.972.34", "@aws-sdk/credential-provider-sso": "^3.972.38", "@aws-sdk/credential-provider-web-identity": "^3.972.38", "@aws-sdk/types": "^3.973.8", "@smithy/credential-provider-imds": "^4.2.14", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.32", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-uZp4tlGbpczV8QxmtIwOpSkcyGtBRR8/T4BAumRKfAt1nwCig3FSCZvrKl6ARDIDVRYn5p2oRcAsfFR01EgMGA=="], + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.34", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.36", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/nested-clients": "^3.997.4", "@aws-sdk/token-providers": "3.1038.0", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-DsLr0UHMyKzRJKe2bjlwU8q1cfoXg8TIJKV/xwvnalAemiZLOZunFzj/whGnFDZIBVLdnbLiwv5SvRf1+CSwkg=="], + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/token-providers": "3.1041.0", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.36", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/nested-clients": "^3.997.4", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-uzrURO7frJhHQVVNR5zBJcCYeMYflmXcWBK1+MiBym2Dfjh6nXATrMixrmGZi+97Q7ETZ+y/4lUwAy0Nfnznjw=="], + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw=="], "@aws-sdk/dynamodb-codec": ["@aws-sdk/dynamodb-codec@3.973.8", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@smithy/core": "^3.23.17", "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-dYQ/cQqHZd23hcl8oEGwPphTqyGnmvf2HrVmz4J90Q5Bv89oJjlwcBcifiiTvApqsVpx7Pr0IebMpkYwWJvZlQ=="], @@ -628,7 +627,7 @@ "@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ=="], - "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.974.14", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "^3.974.6", "@aws-sdk/crc64-nvme": "^3.972.7", "@aws-sdk/types": "^3.973.8", "@smithy/is-array-buffer": "^4.2.2", "@smithy/node-config-provider": "^4.3.14", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-stream": "^4.5.25", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-mhTO3amGzYv/DQNbbqZo6UkHquBHlEEVRZwXmjeRqLmy1l9z3xCiFzglPL7n9JpVc2DZc9kjaraAn3JQrueZbw=="], + "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.974.16", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "^3.974.8", "@aws-sdk/crc64-nvme": "^3.972.7", "@aws-sdk/types": "^3.973.8", "@smithy/is-array-buffer": "^4.2.2", "@smithy/node-config-provider": "^4.3.14", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-stream": "^4.5.25", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-6ru8doI0/XzszqLIPXf0E/V7HhAw1Pu94010XCKYtBUfD0LxF0BuOzrUf8OQGR6j2o6wgKTHUniOmndQycHwCA=="], "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg=="], @@ -638,23 +637,23 @@ "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.11", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ=="], - "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.972.35", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/core": "^3.23.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-stream": "^4.5.25", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-lLppaNTAz+wNgLdi4FtHzrlwrGF0ODTnBWHBaFg85SKs0eJ+M+tP5ifrA8f/0lNd+Ak3MC1NGC6RavV3ny4HTg=="], + "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.972.37", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/core": "^3.23.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-stream": "^4.5.25", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA=="], "@aws-sdk/middleware-sdk-sqs": ["@aws-sdk/middleware-sdk-sqs@3.972.22", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-DtR3mEiOUJcnEX/QuXmvbJto6xvQzp2ftnHb29c0aQYdmmzbKf0gsu9ovx1i/yy4ZR6m0rttTucS0iiP32dlGA=="], "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw=="], - "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.36", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.8", "@smithy/core": "^3.23.17", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "@smithy/util-retry": "^4.3.5", "tslib": "^2.6.2" } }, "sha512-O2beToxguBvrZFFZ+fFgPbbae8MvyIBjQ6lImee4APHEXXNAD5ZJ2ayLF1mb7rsKw86TM81y5czg82bZncjSjg=="], + "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.8", "@smithy/core": "^3.23.17", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "@smithy/util-retry": "^4.3.6", "tslib": "^2.6.2" } }, "sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A=="], "@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.16", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-format-url": "^3.972.10", "@smithy/eventstream-codec": "^4.2.14", "@smithy/eventstream-serde-browser": "^4.2.14", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-86+S9oCyRVGzoMRpQhxkArp7kD2K75GPmaNevd9B6EyNhWoNvnCZZ3WbgN4j7ZT+jvtvBCGZvI2XHsWZJ+BRIg=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.4", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.6", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.36", "@aws-sdk/region-config-resolver": "^3.972.13", "@aws-sdk/signature-v4-multi-region": "^3.996.23", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.8", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.22", "@smithy/config-resolver": "^4.4.17", "@smithy/core": "^3.23.17", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.32", "@smithy/middleware-retry": "^4.5.6", "@smithy/middleware-serde": "^4.2.20", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.6.1", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.49", "@smithy/util-defaults-mode-node": "^4.2.54", "@smithy/util-endpoints": "^3.4.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.5", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-4Sf+WY1lMJzXlw5MiyCMe/UzdILCwvuaHThbqMXS6dfh9gZy3No360I42RXquOI/ULUOhWy2HCyU0Fp20fQGPQ=="], + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.6", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.8", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.38", "@aws-sdk/region-config-resolver": "^3.972.13", "@aws-sdk/signature-v4-multi-region": "^3.996.25", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.8", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.24", "@smithy/config-resolver": "^4.4.17", "@smithy/core": "^3.23.17", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.32", "@smithy/middleware-retry": "^4.5.7", "@smithy/middleware-serde": "^4.2.20", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.6.1", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.49", "@smithy/util-defaults-mode-node": "^4.2.54", "@smithy/util-endpoints": "^3.4.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.6", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w=="], "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.13", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/config-resolver": "^4.4.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A=="], "@aws-sdk/s3-request-presigner": ["@aws-sdk/s3-request-presigner@3.1032.0", "", { "dependencies": { "@aws-sdk/signature-v4-multi-region": "^3.996.18", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-format-url": "^3.972.10", "@smithy/middleware-endpoint": "^4.4.30", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.11", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-LFaI5JQhiOmJDjKK02ir9oERU9AmxdyEvzv332oPDzAzWeNH06sZ1WsF3xRBBE5tbEH2jIc79N8EqDCY0s5kKQ=="], - "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.23", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "^3.972.35", "@aws-sdk/types": "^3.973.8", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-wBbys3Y53Ikly556vyADurKpYQHXS7Jjaskbz+Ga9PZCz7PB/9f3VdKbDlz7dqIzn+xwz7L/a6TR4iXcOi8IRw=="], + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.25", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "^3.972.37", "@aws-sdk/types": "^3.973.8", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw=="], "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1032.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.1", "@aws-sdk/nested-clients": "^3.996.21", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-n+PU8Z+gll7p3wDrH+Wo6fkt8sPrVnq30YYM6Ryga95oJlEneNMEbDHj0iqjMX3V7gaGdJo/hJWyPo4lscP+mA=="], @@ -672,9 +671,9 @@ "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/types": "^4.14.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g=="], - "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.22", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.36", "@aws-sdk/types": "^3.973.8", "@smithy/node-config-provider": "^4.3.14", "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-YTYqTmOUrwbm1h99Ee4y/mVYpFRl0oSO/amtP5cc1BZZWdaAVWs9zj3TkyRHWvR9aI/ZS8m3mS6awXtYUlWyaw=="], + "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.24", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.38", "@aws-sdk/types": "^3.973.8", "@smithy/node-config-provider": "^4.3.14", "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw=="], - "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.21", "", { "dependencies": { "@nodable/entities": "2.1.0", "@smithy/types": "^4.14.1", "fast-xml-parser": "5.7.2", "tslib": "^2.6.2" } }, "sha512-qxNiHUtlrsjTeSlrPWiFkWps7uD6YB4eKzg7eLAFH8jbiHTlt0ePNlo2Xu+WlftP38JIcMaIX4jTUjOlE2ySWw=="], + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.22", "", { "dependencies": { "@nodable/entities": "2.1.0", "@smithy/types": "^4.14.1", "fast-xml-parser": "5.7.2", "tslib": "^2.6.2" } }, "sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA=="], "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], @@ -710,7 +709,7 @@ "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + "@babel/compat-data": ["@babel/compat-data@7.29.3", "", {}, "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg=="], "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], @@ -734,7 +733,7 @@ "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], - "@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], + "@babel/parser": ["@babel/parser@7.29.3", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA=="], "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], @@ -820,7 +819,7 @@ "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], - "@e2b/code-interpreter": ["@e2b/code-interpreter@2.4.1", "", { "dependencies": { "e2b": "^2.19.2" } }, "sha512-9T+NcQPtB3Utm0KAB3vdhx6vC1X+Y3cV6oydk2GnVuEqn0lUAY+9/8WdHuh/0l4L15aO2JynufP5oQwub7gDhw=="], + "@e2b/code-interpreter": ["@e2b/code-interpreter@2.4.2", "", { "dependencies": { "e2b": "^2.19.4" } }, "sha512-udLYysT+Jrue5citQc6Wr6N7Et9Eiw8FTeQpf6NQdLEg4RM6aZJoi7QFC0oqr+rv6g+I4W1KGdrxW1eBtKbnRw=="], "@electric-sql/client": ["@electric-sql/client@1.0.14", "", { "dependencies": { "@microsoft/fetch-event-source": "^2.0.1" }, "optionalDependencies": { "@rollup/rollup-darwin-arm64": "^4.18.1" } }, "sha512-LtPAfeMxXRiYS0hyDQ5hue2PjljUiK9stvzsVyVb4nwxWQxfOWTSF42bHTs/o5i3x1T4kAQ7mwHpxa4A+f8X7Q=="], @@ -916,7 +915,7 @@ "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], - "@iconify/utils": ["@iconify/utils@3.1.1", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.2" } }, "sha512-MwzoDtw9rO1x+qfgLTV/IVXsHDBqeYZoMIQC8SfxfYSlaSUG+oWiAcoiB1yajAda6mqblm4/1/w2E8tRu7a7Tw=="], + "@iconify/utils": ["@iconify/utils@3.1.2", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "import-meta-resolve": "^4.2.0" } }, "sha512-jVf75icVVgSVGf9+QWBeCHdFL35yZ06HMHl9sCa059pITTP781lOacvRazfwAmXDKiBiUdQQMWVnuiw/RaQNhQ=="], "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], @@ -994,8 +993,6 @@ "@jsonhero/path": ["@jsonhero/path@1.0.21", "", {}, "sha512-gVUDj/92acpVoJwsVJ/RuWOaHyG4oFzn898WNGQItLCTQ+hOaVlEaImhwE1WqOTf+l3dGOUkbSiVKlb3q1hd1Q=="], - "@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="], - "@langchain/core": ["@langchain/core@0.3.80", "", { "dependencies": { "@cfworker/json-schema": "^4.0.2", "ansi-styles": "^5.0.0", "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", "langsmith": "^0.3.67", "mustache": "^4.2.0", "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^10.0.0", "zod": "^3.25.32", "zod-to-json-schema": "^3.22.3" } }, "sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA=="], "@langchain/openai": ["@langchain/openai@0.4.9", "", { "dependencies": { "js-tiktoken": "^1.0.12", "openai": "^4.87.3", "zod": "^3.22.4", "zod-to-json-schema": "^3.22.3" }, "peerDependencies": { "@langchain/core": ">=0.3.39 <0.4.0" } }, "sha512-NAsaionRHNdqaMjVLPkFCyjUDze+OqRHghA1Cn4fPoAafz+FXcl9c7LlEl9Xo0FH6/8yiCl7Rw2t780C/SBVxQ=="], @@ -1020,7 +1017,7 @@ "@monaco-editor/react": ["@monaco-editor/react@4.7.0", "", { "dependencies": { "@monaco-editor/loader": "^1.5.0" }, "peerDependencies": { "monaco-editor": ">= 0.25.0 < 1", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA=="], - "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.9", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-RXSxsokhAF/4nWys8An8npsqOI33Ex1Hlzqjw2pZOO+GKtMAR2noGnUdsFiGwsaO/xXI+56mtjTmDA3JXJsvmA=="], + "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.11", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA=="], "@napi-rs/canvas": ["@napi-rs/canvas@0.1.100", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.100", "@napi-rs/canvas-darwin-arm64": "0.1.100", "@napi-rs/canvas-darwin-x64": "0.1.100", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", "@napi-rs/canvas-linux-arm64-musl": "0.1.100", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", "@napi-rs/canvas-linux-x64-gnu": "0.1.100", "@napi-rs/canvas-linux-x64-musl": "0.1.100", "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", "@napi-rs/canvas-win32-x64-msvc": "0.1.100" } }, "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA=="], @@ -1144,7 +1141,7 @@ "@opentelemetry/propagator-jaeger": ["@opentelemetry/propagator-jaeger@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-Mbm/LSFyAtQKP0AQah4AfGgsD+vsZcyreZoQ5okFBk33hU7AquU4TltgyL9dvaO8/Zkoud8/0gEvwfOZ5d7EPA=="], - "@opentelemetry/resources": ["@opentelemetry/resources@2.7.0", "", { "dependencies": { "@opentelemetry/core": "2.7.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-K+oi0hNMv94EpZbnW3eyu2X6SGVpD3O5DhG2NIp65Hc7lhAj9brRXTAVzh3wB82+q3ThakEf7Zd7RsFUqcTc7A=="], + "@opentelemetry/resources": ["@opentelemetry/resources@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ=="], "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-VZG870063NLfObmQQNtCVcdXXLzI3vOjjrRENmU37HYiPFa0ZXpXVDsTD02Nh3AT3xYJzQaWKl2X2lQ2l7TWJA=="], @@ -1164,27 +1161,29 @@ "@pdf-lib/upng": ["@pdf-lib/upng@1.0.1", "", { "dependencies": { "pako": "^1.0.10" } }, "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ=="], - "@peculiar/asn1-android": ["@peculiar/asn1-android@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ=="], + "@peculiar/asn1-android": ["@peculiar/asn1-android@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-iD3VskhVQnM4nE3PN9cBdPTR7JrqZy3FYk+uD2CeG6DUqKoANqaEfx0f7izPmW+Qm5JBM35ek+viLCmjy18ByQ=="], - "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "@peculiar/asn1-x509-attr": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw=="], + "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/asn1-x509": "^2.7.0", "@peculiar/asn1-x509-attr": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-hew63shtzzvBcSHbhm+cyAmKe6AIfinT9hzEqSPjDC6opTTMKmTkQ0gHuN2KsWlvqiKw1S/fS94fhag/FJkioQ=="], - "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w=="], + "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-VVsAyGqErT9D1SY4aEqozThXMVI+ssVRiv2DDeYuvpBKLIgZ3hYs3Ay3u/VSoKq6ESFi9cf6rf3IOOzfwh7oMA=="], - "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g=="], + "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-n7KEs/Q/wrB415cxy4fHOBhegp4NdJ15fkJPwcB/3/8iNBQC2L/N7SChJPKDJPZGYH0jD4Tg4/0vnHmwghnbKw=="], - "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.6.1", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.1", "@peculiar/asn1-pkcs8": "^2.6.1", "@peculiar/asn1-rsa": "^2.6.1", "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw=="], + "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.7.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.7.0", "@peculiar/asn1-pkcs8": "^2.7.0", "@peculiar/asn1-rsa": "^2.7.0", "@peculiar/asn1-schema": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-V/nrlQVmhg7lYAsM7E13UDL5erAwFv6kCIVFqNaMIHSVi7dngcT839JkRTkQBqznMG98l2XjxYk74ZztAohZzA=="], - "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw=="], + "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-9GTl1nE8Mx1kTZ+7QyYatDyKsm34QcWRBFkY1iPvWC3X4Dona5s/tlLiQsx5WzVdZqiMBZNYT0buyw4/vbhnjw=="], - "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.6.1", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.1", "@peculiar/asn1-pfx": "^2.6.1", "@peculiar/asn1-pkcs8": "^2.6.1", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "@peculiar/asn1-x509-attr": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw=="], + "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.7.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.7.0", "@peculiar/asn1-pfx": "^2.7.0", "@peculiar/asn1-pkcs8": "^2.7.0", "@peculiar/asn1-schema": "^2.7.0", "@peculiar/asn1-x509": "^2.7.0", "@peculiar/asn1-x509-attr": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-Bh7m+OuIaSEllPQcSd9OSp93F4ROWH7sbITWV8MI+8dwsjE5111/87VxiWVvYFKyww3vp39geLv9ENqhwWHcew=="], - "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA=="], + "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-/qvENQrXyTZURjMqSeofHul0JJt2sNSzSwk36pl2olkHbaioMQgrASDZAlHXl0xUlnVbHj0uGgOrBMTb5x2aJQ=="], - "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.6.0", "", { "dependencies": { "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg=="], + "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.7.0", "", { "dependencies": { "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg=="], - "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA=="], + "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-mUn9RRrkGDnG4ALfunDmzyRW5dg+sWCj/pfnCCqEHYbkGxEpvUt6iVJv8Yw1cyp6SWZ26ZE5oSmI5SqEaen15g=="], - "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ=="], + "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.7.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-NS8e7SOgXipkzUPLF/sce7ukpMpWjhxYsH0n6Y+bHYo4TTxOb95Zv7hqwSuL212mj5YxovjdOKQOgH1As3E94w=="], + + "@peculiar/utils": ["@peculiar/utils@2.0.3", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ=="], "@peculiar/x509": ["@peculiar/x509@1.14.3", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.0", "@peculiar/asn1-csr": "^2.6.0", "@peculiar/asn1-ecc": "^2.6.0", "@peculiar/asn1-pkcs9": "^2.6.0", "@peculiar/asn1-rsa": "^2.6.0", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", "tslib": "^2.8.1", "tsyringe": "^4.10.0" } }, "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA=="], @@ -1388,55 +1387,55 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.2", "", { "os": "android", "cpu": "arm" }, "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.3", "", { "os": "android", "cpu": "arm" }, "sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.2", "", { "os": "android", "cpu": "arm64" }, "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.3", "", { "os": "android", "cpu": "arm64" }, "sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.2", "", { "os": "linux", "cpu": "arm" }, "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.3", "", { "os": "linux", "cpu": "arm" }, "sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.2", "", { "os": "linux", "cpu": "arm" }, "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.3", "", { "os": "linux", "cpu": "arm" }, "sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.3", "", { "os": "linux", "cpu": "none" }, "sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA=="], - "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.3", "", { "os": "linux", "cpu": "none" }, "sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ=="], - "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ=="], + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.3", "", { "os": "linux", "cpu": "none" }, "sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.3", "", { "os": "linux", "cpu": "none" }, "sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.2", "", { "os": "linux", "cpu": "x64" }, "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.3", "", { "os": "linux", "cpu": "x64" }, "sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.2", "", { "os": "linux", "cpu": "x64" }, "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA=="], - "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg=="], + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q=="], - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.2", "", { "os": "none", "cpu": "arm64" }, "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.3", "", { "os": "none", "cpu": "arm64" }, "sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA=="], - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.2", "", { "os": "win32", "cpu": "x64" }, "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.3", "", { "os": "win32", "cpu": "x64" }, "sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.3", "", { "os": "win32", "cpu": "x64" }, "sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA=="], "@s2-dev/streamstore": ["@s2-dev/streamstore@0.22.5", "", { "dependencies": { "@protobuf-ts/runtime": "^2.11.1", "debug": "^4.4.3" } }, "sha512-GqdOKIbIoIxT+40fnKzHbrsHB6gBqKdECmFe7D3Ojk4FoN1Hu0LhFzZv6ZmVMjoHHU+55debS1xSWjZwQmbIyQ=="], @@ -1580,7 +1579,7 @@ "@smithy/util-middleware": ["@smithy/util-middleware@4.2.14", "", { "dependencies": { "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw=="], - "@smithy/util-retry": ["@smithy/util-retry@4.3.6", "", { "dependencies": { "@smithy/service-error-classification": "^4.3.1", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-p6/FO1n2KxMeQyna067i0uJ6TSbb165ZhnRtCpWh4Foxqbfc6oW+XITaL8QkFJj3KFnDe2URt4gOhgU06EP9ew=="], + "@smithy/util-retry": ["@smithy/util-retry@4.3.8", "", { "dependencies": { "@smithy/service-error-classification": "^4.3.1", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-LUIxbTBi+OpvXpg91poGA6BdyoleMDLnfXjVDqyi2RvZmTveY5loE/FgYUBCR5LU2BThW2SoZRh8dTIIy38IPw=="], "@smithy/util-stream": ["@smithy/util-stream@4.5.25", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.17", "@smithy/node-http-handler": "^4.6.1", "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-/PFpG4k8Ze8Ei+mMKj3oiPICYekthuzePZMgZbCqMiXIHHf4n2aZ4Ps0aSRShycFTGuj/J6XldmC0x0DwednIA=="], @@ -1608,9 +1607,9 @@ "@t3-oss/env-nextjs": ["@t3-oss/env-nextjs@0.13.4", "", { "dependencies": { "@t3-oss/env-core": "0.13.4" }, "peerDependencies": { "typescript": ">=5.0.0", "valibot": "^1.0.0-beta.7 || ^1.0.0", "zod": "^3.24.0 || ^4.0.0-beta.0" }, "optionalPeers": ["typescript", "valibot", "zod"] }, "sha512-6ecXR7SH7zJKVcBODIkB7wV9QLMU23uV8D9ec6P+ULHJ5Ea/YXEHo+Z/2hSYip5i9ptD/qZh8VuOXyldspvTTg=="], - "@tabler/icons": ["@tabler/icons@3.41.1", "", {}, "sha512-OaRnVbRmH2nHtFeg+RmMJ/7m2oBIF9XCJAUD5gQnMrpK9f05ydj8MZrAf3NZQqOXyxGN1UBL0D5IKLLEUfr74Q=="], + "@tabler/icons": ["@tabler/icons@3.42.0", "", {}, "sha512-h0nFIRgwrE/9iVgN+GuLijbiLIBWJ3chNvIWhqUZhy4D9fv3tkoQ3EYFAvxvfdvQUNNVAhJhj+ar54y6t016Vg=="], - "@tabler/icons-react": ["@tabler/icons-react@3.41.1", "", { "dependencies": { "@tabler/icons": "3.41.1" }, "peerDependencies": { "react": ">= 16" } }, "sha512-kUgweE+DJtAlMZVIns1FTDdcbpRVnkK7ZpUOXmoxy3JAF0rSHj0TcP4VHF14+gMJGnF+psH2Zt26BLT6owetBA=="], + "@tabler/icons-react": ["@tabler/icons-react@3.42.0", "", { "dependencies": { "@tabler/icons": "3.42.0" }, "peerDependencies": { "react": ">= 16" } }, "sha512-WvKhHYLdJaZbiY4Jm31fmTbzIwxokXcE1HM/m9rmXvh7UoHG4mM8n+9NOB6xEwB5SZQ+G/Z102eMj1F3NqDMVg=="], "@tailwindcss/node": ["@tailwindcss/node@4.2.4", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.4" } }, "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA=="], @@ -1838,7 +1837,7 @@ "@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.5", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-yURCknZhvywvQItHMMmFSo+fq5arCUIyz/CVk7jD89MSai7dkaX8ufjCWp3NttLojoTVbcE72ri+be/TnEbMHw=="], - "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.1", "", {}, "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ=="], "@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="], @@ -1886,7 +1885,7 @@ "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], - "ai": ["ai@5.0.180", "", { "dependencies": { "@ai-sdk/gateway": "2.0.83", "@ai-sdk/provider": "2.0.2", "@ai-sdk/provider-utils": "3.0.24", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-tJctEJpgyoJtD8lVDY67r2uuqiWPMNv9BRce5bKeOj7Rf8tkBPAr8MnzwhQD2ZHqdblvA8GcZ/855DsTbGdl0A=="], + "ai": ["ai@5.0.185", "", { "dependencies": { "@ai-sdk/gateway": "2.0.87", "@ai-sdk/provider": "2.0.3", "@ai-sdk/provider-utils": "3.0.25", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-TQrpK5+R1xsQQH1YwY2Qnt1usZTVSDLiDg0Lda6vspC/G4a40aBs4b741Lr1ZNl8g1fu6gANyeK9C8Hz9p3O5A=="], "ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], @@ -1940,9 +1939,9 @@ "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], - "axios": ["axios@1.15.2", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A=="], + "axios": ["axios@1.16.0", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w=="], - "b4a": ["b4a@1.8.0", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg=="], + "b4a": ["b4a@1.8.1", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw=="], "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], @@ -1952,19 +1951,19 @@ "bare-fs": ["bare-fs@4.7.1", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4", "bare-url": "^2.2.2", "fast-fifo": "^1.3.2" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw=="], - "bare-os": ["bare-os@3.9.0", "", {}, "sha512-JTjuZyNIDpw+GytMO4a6TK1VXdVKKJr6DRxEHasyuYyShV2deuiHJK/ahGZlebc+SG0/wJCB9XK8gprBGDFi/Q=="], + "bare-os": ["bare-os@3.9.1", "", {}, "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ=="], "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], "bare-stream": ["bare-stream@2.13.1", "", { "dependencies": { "streamx": "^2.25.0", "teex": "^1.0.1" }, "peerDependencies": { "bare-abort-controller": "*", "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-abort-controller", "bare-buffer", "bare-events"] }, "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow=="], - "bare-url": ["bare-url@2.4.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-/9a2j4ac6ckpmAHvod/ob7x439OAHst/drc2Clnq+reRYd/ovddwcF4LfoxHyNk5AuGBnPg+HqFjmE/Zpq6v0A=="], + "bare-url": ["bare-url@2.4.3", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.24", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-I2NkZOOrj2XuguvWCK6OVh9GavsNjZjK908Rq3mIBK25+GD8vPX5w2WdxVqnQ7xx3SrZJiCiZFu+/Oz50oSYSA=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.27", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA=="], "basic-auth": ["basic-auth@2.0.1", "", { "dependencies": { "safe-buffer": "5.1.2" } }, "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg=="], @@ -2034,7 +2033,7 @@ "camelize": ["camelize@1.0.1", "", {}, "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ=="], - "caniuse-lite": ["caniuse-lite@1.0.30001791", "", {}, "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ=="], + "caniuse-lite": ["caniuse-lite@1.0.30001792", "", {}, "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw=="], "caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="], @@ -2054,8 +2053,6 @@ "chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="], - "chart.js": ["chart.js@4.5.1", "", { "dependencies": { "@kurkle/color": "^0.3.0" } }, "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw=="], - "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], "cheerio": ["cheerio@1.1.2", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.12.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg=="], @@ -2064,7 +2061,7 @@ "chevrotain": ["chevrotain@12.0.0", "", { "dependencies": { "@chevrotain/cst-dts-gen": "12.0.0", "@chevrotain/gast": "12.0.0", "@chevrotain/regexp-to-ast": "12.0.0", "@chevrotain/types": "12.0.0", "@chevrotain/utils": "12.0.0" } }, "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ=="], - "chevrotain-allstar": ["chevrotain-allstar@0.4.1", "", { "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { "chevrotain": "^12.0.0" } }, "sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA=="], + "chevrotain-allstar": ["chevrotain-allstar@0.4.3", "", { "dependencies": { "lodash-es": "^4.18.1" }, "peerDependencies": { "chevrotain": "^12.0.0" } }, "sha512-2X4mkroolSMKqW+H22pyPMUVDqYZzPhephTmg/NODKb1IGYPHfxfhcW0EjS7wcPJNbze2i4vBWT7zT5FKF2lrQ=="], "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], @@ -2182,7 +2179,7 @@ "csv-parse": ["csv-parse@6.1.0", "", {}, "sha512-CEE+jwpgLn+MmtCpVcPtiCZpVtB6Z2OKPTr34pycYYoL7sxdOkXDdQ4lRiw6ioC0q6BLqhc6cKweCVvral8yhw=="], - "cytoscape": ["cytoscape@3.33.2", "", {}, "sha512-sj4HXd3DokGhzZAdjDejGvTPLqlt84vNFN8m7bGsOzDY5DyVcxIb2ejIXat2Iy7HxWhdT/N1oKyheJ5YdpsGuw=="], + "cytoscape": ["cytoscape@3.33.3", "", {}, "sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g=="], "cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="], @@ -2336,7 +2333,7 @@ "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], - "dompurify": ["dompurify@3.4.1", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw=="], + "dompurify": ["dompurify@3.4.2", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA=="], "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], @@ -2354,7 +2351,7 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "e2b": ["e2b@2.19.2", "", { "dependencies": { "@bufbuild/protobuf": "^2.6.2", "@connectrpc/connect": "2.0.0-rc.3", "@connectrpc/connect-web": "2.0.0-rc.3", "chalk": "^5.3.0", "compare-versions": "^6.1.0", "dockerfile-ast": "^0.7.1", "glob": "^11.1.0", "openapi-fetch": "^0.14.1", "platform": "^1.3.6", "tar": "^7.5.11" } }, "sha512-AJtaQ72XIjdOBGnsvzVuYveYmy4ZDALLzZddN7sFIgd49eCY7u7Nwx7TXp97vZLPTEgfCwEqn1U9mehDrQMp3g=="], + "e2b": ["e2b@2.19.5", "", { "dependencies": { "@bufbuild/protobuf": "^2.6.2", "@connectrpc/connect": "2.0.0-rc.3", "@connectrpc/connect-web": "2.0.0-rc.3", "chalk": "^5.3.0", "compare-versions": "^6.1.0", "dockerfile-ast": "^0.7.1", "glob": "^11.1.0", "openapi-fetch": "^0.14.1", "platform": "^1.3.6", "tar": "^7.5.11", "undici": "^7.25.0" } }, "sha512-pd1LvDrf5CWn1kHRK0CzKvnHJGeoaH/4//QOhkV+oyFPhBNtvPnUvSv60Zd1vdcuNRFM5b3j0Krg+44hVkLuRg=="], "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], @@ -2364,7 +2361,7 @@ "effect": ["effect@3.21.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ=="], - "electron-to-chromium": ["electron-to-chromium@1.5.344", "", {}, "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg=="], + "electron-to-chromium": ["electron-to-chromium@1.5.349", "", {}, "sha512-QsWVGyRuY07Aqb234QytTfwd5d9AJlfNIQ5wIOl1L+PZDzI9d9+Fn0FRale/QYlFxt/bUnB0/nLd1jFPGxGK1A=="], "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], @@ -2372,8 +2369,6 @@ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], - "encoding-japanese": ["encoding-japanese@2.2.0", "", {}, "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A=="], "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], @@ -2422,7 +2417,7 @@ "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], - "esrap": ["esrap@2.2.5", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, "peerDependencies": { "@typescript-eslint/types": "^8.2.0" }, "optionalPeers": ["@typescript-eslint/types"] }, "sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig=="], + "esrap": ["esrap@2.2.6", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, "peerDependencies": { "@typescript-eslint/types": "^8.2.0" }, "optionalPeers": ["@typescript-eslint/types"] }, "sha512-WN0clHt0a4mzC780UBVVBpsj4vSSjOFNRd2WjYtduB9HeKxm1sjHMNUwLEHVjI3FdCQD/Hurgz9ftbKEzP79Ow=="], "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], @@ -2468,7 +2463,7 @@ "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], - "express-rate-limit": ["express-rate-limit@8.4.1", "", { "dependencies": { "ip-address": "10.1.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-NGVYwQSAyEQgzxX1iCM978PP9AdO/hW93gMcF6ZwQCm+rFvLsBH6w4xcXWTcliS8La5EPRN3p9wzItqBwJrfNw=="], + "express-rate-limit": ["express-rate-limit@8.5.1", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ=="], "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], @@ -2494,11 +2489,11 @@ "fast-sha256": ["fast-sha256@1.3.0", "", {}, "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="], - "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], + "fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="], - "fast-xml-builder": ["fast-xml-builder@1.1.5", "", { "dependencies": { "path-expression-matcher": "^1.1.3" } }, "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA=="], + "fast-xml-builder": ["fast-xml-builder@1.1.9", "", { "dependencies": { "path-expression-matcher": "^1.1.3" } }, "sha512-jcyKVSEX13iseJqg7n/KWw+xnu/7fdrZ333Fac54KjHDIELVCfDDJXYIm6DTJ0Su4gSzrhqiK0DzY/wZbF40mw=="], - "fast-xml-parser": ["fast-xml-parser@5.7.2", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.5", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w=="], + "fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="], "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], @@ -2654,7 +2649,7 @@ "hex-rgb": ["hex-rgb@4.3.0", "", {}, "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw=="], - "hono": ["hono@4.12.15", "", {}, "sha512-qM0jDhFEaCBb4TxoW7f53Qrpv9RBiayUHo0S52JudprkhvpjIrGoU1mnnr29Fvd1U335ZFPZQY1wlkqgfGXyLg=="], + "hono": ["hono@4.12.18", "", {}, "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ=="], "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="], @@ -2702,6 +2697,8 @@ "import-in-the-middle": ["import-in-the-middle@1.15.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA=="], + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], @@ -2718,7 +2715,7 @@ "ioredis": ["ioredis@5.10.1", "", { "dependencies": { "@ioredis/commands": "1.5.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA=="], - "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], + "ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], "ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], @@ -2730,7 +2727,7 @@ "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], @@ -2834,9 +2831,9 @@ "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], - "kysely": ["kysely@0.28.16", "", {}, "sha512-3i5pmOiZvMDj00qhrIVbH0AnioVTx22DMP7Vn5At4yJO46iy+FM8Y/g61ltenLVSo3fiO8h8Q3QOFgf/gQ72ww=="], + "kysely": ["kysely@0.28.17", "", {}, "sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q=="], - "langium": ["langium@4.2.2", "", { "dependencies": { "@chevrotain/regexp-to-ast": "~12.0.0", "chevrotain": "~12.0.0", "chevrotain-allstar": "~0.4.1", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.1.0" } }, "sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ=="], + "langium": ["langium@4.2.3", "", { "dependencies": { "@chevrotain/regexp-to-ast": "~12.0.0", "chevrotain": "~12.0.0", "chevrotain-allstar": "~0.4.3", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.1.0" } }, "sha512-sOPIi4hISFnY7twwV97ca1TsxpBtXq0URu/LL1AvxwccPG/RIBBlKS7a/f/EL6w8lTNaS0EFs/F+IdSOaqYpng=="], "langsmith": ["langsmith@0.3.87", "", { "dependencies": { "@types/uuid": "^10.0.0", "chalk": "^4.1.2", "console-table-printer": "^2.12.1", "p-queue": "^6.6.2", "semver": "^7.6.3", "uuid": "^10.0.0" }, "peerDependencies": { "@opentelemetry/api": "*", "@opentelemetry/exporter-trace-otlp-proto": "*", "@opentelemetry/sdk-trace-base": "*", "openai": "*" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/exporter-trace-otlp-proto", "@opentelemetry/sdk-trace-base", "openai"] }, "sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q=="], @@ -2928,7 +2925,7 @@ "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], - "lru-cache": ["lru-cache@11.3.5", "", {}, "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw=="], + "lru-cache": ["lru-cache@11.3.6", "", {}, "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A=="], "lru.min": ["lru.min@1.1.4", "", {}, "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA=="], @@ -3146,7 +3143,7 @@ "nano-spawn": ["nano-spawn@1.0.3", "", {}, "sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA=="], - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], "nanostores": ["nanostores@1.3.0", "", {}, "sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA=="], @@ -3170,7 +3167,7 @@ "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], - "node-abi": ["node-abi@3.89.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA=="], + "node-abi": ["node-abi@3.92.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ=="], "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], @@ -3290,7 +3287,7 @@ "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + "path-to-regexp": ["path-to-regexp@0.1.13", "", {}, "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -3342,7 +3339,7 @@ "popper.js": ["popper.js@1.16.1", "", {}, "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="], - "postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="], + "postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="], "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], @@ -3436,7 +3433,7 @@ "react-floater": ["react-floater@0.7.9", "", { "dependencies": { "deepmerge": "^4.3.1", "is-lite": "^0.8.2", "popper.js": "^1.16.0", "prop-types": "^15.8.1", "tree-changes": "^0.9.1" }, "peerDependencies": { "react": "15 - 18", "react-dom": "15 - 18" } }, "sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg=="], - "react-hook-form": ["react-hook-form@7.74.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-yR6wHr99p9wFv686jhRWVSFhUvDvNbdUf2dKlbno8/VKOCuoNobDGC6S+M2dua9A9Yo8vpcrp8assIYbsZCQ9g=="], + "react-hook-form": ["react-hook-form@7.75.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw=="], "react-innertext": ["react-innertext@1.1.5", "", { "peerDependencies": { "@types/react": ">=0.0.0 <=99", "react": ">=0.0.0 <=99" } }, "sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q=="], @@ -3548,7 +3545,7 @@ "robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="], - "rollup": ["rollup@4.60.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.2", "@rollup/rollup-android-arm64": "4.60.2", "@rollup/rollup-darwin-arm64": "4.60.2", "@rollup/rollup-darwin-x64": "4.60.2", "@rollup/rollup-freebsd-arm64": "4.60.2", "@rollup/rollup-freebsd-x64": "4.60.2", "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", "@rollup/rollup-linux-arm-musleabihf": "4.60.2", "@rollup/rollup-linux-arm64-gnu": "4.60.2", "@rollup/rollup-linux-arm64-musl": "4.60.2", "@rollup/rollup-linux-loong64-gnu": "4.60.2", "@rollup/rollup-linux-loong64-musl": "4.60.2", "@rollup/rollup-linux-ppc64-gnu": "4.60.2", "@rollup/rollup-linux-ppc64-musl": "4.60.2", "@rollup/rollup-linux-riscv64-gnu": "4.60.2", "@rollup/rollup-linux-riscv64-musl": "4.60.2", "@rollup/rollup-linux-s390x-gnu": "4.60.2", "@rollup/rollup-linux-x64-gnu": "4.60.2", "@rollup/rollup-linux-x64-musl": "4.60.2", "@rollup/rollup-openbsd-x64": "4.60.2", "@rollup/rollup-openharmony-arm64": "4.60.2", "@rollup/rollup-win32-arm64-msvc": "4.60.2", "@rollup/rollup-win32-ia32-msvc": "4.60.2", "@rollup/rollup-win32-x64-gnu": "4.60.2", "@rollup/rollup-win32-x64-msvc": "4.60.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ=="], + "rollup": ["rollup@4.60.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.3", "@rollup/rollup-android-arm64": "4.60.3", "@rollup/rollup-darwin-arm64": "4.60.3", "@rollup/rollup-darwin-x64": "4.60.3", "@rollup/rollup-freebsd-arm64": "4.60.3", "@rollup/rollup-freebsd-x64": "4.60.3", "@rollup/rollup-linux-arm-gnueabihf": "4.60.3", "@rollup/rollup-linux-arm-musleabihf": "4.60.3", "@rollup/rollup-linux-arm64-gnu": "4.60.3", "@rollup/rollup-linux-arm64-musl": "4.60.3", "@rollup/rollup-linux-loong64-gnu": "4.60.3", "@rollup/rollup-linux-loong64-musl": "4.60.3", "@rollup/rollup-linux-ppc64-gnu": "4.60.3", "@rollup/rollup-linux-ppc64-musl": "4.60.3", "@rollup/rollup-linux-riscv64-gnu": "4.60.3", "@rollup/rollup-linux-riscv64-musl": "4.60.3", "@rollup/rollup-linux-s390x-gnu": "4.60.3", "@rollup/rollup-linux-x64-gnu": "4.60.3", "@rollup/rollup-linux-x64-musl": "4.60.3", "@rollup/rollup-openbsd-x64": "4.60.3", "@rollup/rollup-openharmony-arm64": "4.60.3", "@rollup/rollup-win32-arm64-msvc": "4.60.3", "@rollup/rollup-win32-ia32-msvc": "4.60.3", "@rollup/rollup-win32-x64-gnu": "4.60.3", "@rollup/rollup-win32-x64-msvc": "4.60.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A=="], "rou3": ["rou3@0.5.1", "", {}, "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ=="], @@ -3772,7 +3769,7 @@ "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], - "tar": ["tar@7.5.13", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng=="], + "tar": ["tar@7.5.14", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-/7sHKgQO3JLP9ESlwTYUUftHUadOURUqq23xs1vjcnp8Vss6k0wCfzulyEtk5g91pjvnuriimGlyG7k6msrzRw=="], "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], @@ -3812,9 +3809,9 @@ "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], - "tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], + "tldts": ["tldts@7.0.30", "", { "dependencies": { "tldts-core": "^7.0.30" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw=="], - "tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], + "tldts-core": ["tldts-core@7.0.30", "", {}, "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -3866,7 +3863,7 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], "uid2": ["uid2@1.0.0", "", {}, "sha512-+I6aJUv63YAcY9n4mQreLUt0d4lvwkkopDNmpomkAUz0fAkEMV9pRWxN0EjhW1YfRhcuyHg2v3mwddCDW1+LFQ=="], @@ -3924,7 +3921,7 @@ "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], - "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], + "uuid": ["uuid@11.1.1", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ=="], "uzip": ["uzip@0.20201231.0", "", {}, "sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng=="], @@ -3992,7 +3989,7 @@ "ws": ["ws@8.20.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA=="], - "xlsx": ["xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", { "bin": { "xlsx": "./bin/xlsx.njs" } }], + "xlsx": ["xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", { "bin": { "xlsx": "./bin/xlsx.njs" } }, "sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA=="], "xml": ["xml@1.0.1", "", {}, "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw=="], @@ -4018,7 +4015,7 @@ "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], - "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], + "yaml": ["yaml@2.8.4", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -4042,7 +4039,7 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@antfu/install-pkg/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], + "@antfu/install-pkg/tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="], "@asamuzakjp/css-color/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -4054,29 +4051,9 @@ "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-sdk/client-sso/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], - - "@aws-sdk/client-sso/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], - - "@aws-sdk/client-sso/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], - - "@aws-sdk/client-sso/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], - - "@aws-sdk/client-sso/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], - - "@aws-sdk/client-sso/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - - "@aws-sdk/client-sso/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], - - "@aws-sdk/client-sso/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], - - "@aws-sdk/client-sso/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], - - "@aws-sdk/client-sso/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], - - "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1038.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.6", "@aws-sdk/nested-clients": "^3.997.4", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-Qniru+9oGGb/HNK/gGZWbV3jsD0k71ngE7qMQ/x6gYNYLd2EOwHCS6E2E6jfkaqO4i0d+nNKmfRy8bNcshKdGQ=="], + "@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1041.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw=="], - "@aws-sdk/dynamodb-codec/@aws-sdk/core": ["@aws-sdk/core@3.974.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws-sdk/xml-builder": "^3.972.22", "@smithy/core": "^3.23.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.6", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw=="], + "@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.2", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.5", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w=="], "@azure/communication-email/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], @@ -4098,8 +4075,6 @@ "@browserbasehq/stagehand/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.39.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg=="], - "@browserbasehq/stagehand/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.3", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ=="], - "@cerebras/cerebras_cloud_sdk/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], "@cerebras/cerebras_cloud_sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], @@ -4142,7 +4117,7 @@ "@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="], - "@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.7.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-DT12SXVwV2eoJrGf4nnsvZojxxeQo+LlNAsoYGRRObPWTeN6APiqZ2+nqDCQDvQX40eLi1AePONS0onoASp3yQ=="], + "@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.7.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw=="], "@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="], @@ -4212,7 +4187,7 @@ "@socket.io/redis-adapter/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "@tailwindcss/node/jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], @@ -4222,7 +4197,7 @@ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], - "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -4268,6 +4243,8 @@ "@trigger.dev/sdk/cronstrue": ["cronstrue@2.61.0", "", { "bin": { "cronstrue": "bin/cli.js" } }, "sha512-ootN5bvXbIQI9rW94+QsXN5eROtXWwew6NkdGxIRpS/UFWRggL0G5Al7a9GTBFEsuvVhJ2K3CntIIVt7L2ILhA=="], + "@trigger.dev/sdk/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], + "@trigger.dev/sdk/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], "@types/cors/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], @@ -4278,8 +4255,6 @@ "@types/node-fetch/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], - "@types/nodemailer/@aws-sdk/client-sesv2": ["@aws-sdk/client-sesv2@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-jDQ4x2HwB2/UXBS7CTeSDiIb+sVsYGDyxTeXdrRAtqNdGv8kC54fbwokDiJ/mnMyB2gyXWw57BqeDJNkZuLmsw=="], - "@types/nodemailer/@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], "@types/papaparse/@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], @@ -4296,6 +4271,8 @@ "ai/@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], @@ -4312,6 +4289,8 @@ "c12/confbox": ["confbox@0.2.4", "", {}, "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ=="], + "c12/jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "c12/pkg-types": ["pkg-types@2.3.1", "", { "dependencies": { "confbox": "^0.2.4", "exsolve": "^1.0.8", "pathe": "^2.0.3" } }, "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg=="], "chrome-launcher/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], @@ -4340,14 +4319,12 @@ "docx/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], - "docx/nanoid": ["nanoid@5.1.9", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-ZUvP7KeBLe3OZ1ypw6dI/TzYJuvHP77IM4Ry73waSQTLn8/g8rpdjfyVAh7t1/+FjBtG4lCP42MEbDxOsRpBMw=="], + "docx/nanoid": ["nanoid@5.1.11", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg=="], "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "e2b/glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], - "encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - "encoding-sniffer/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "engine.io/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], @@ -4380,7 +4357,7 @@ "fumadocs-mdx/esbuild": ["esbuild@0.28.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.0", "@esbuild/android-arm": "0.28.0", "@esbuild/android-arm64": "0.28.0", "@esbuild/android-x64": "0.28.0", "@esbuild/darwin-arm64": "0.28.0", "@esbuild/darwin-x64": "0.28.0", "@esbuild/freebsd-arm64": "0.28.0", "@esbuild/freebsd-x64": "0.28.0", "@esbuild/linux-arm": "0.28.0", "@esbuild/linux-arm64": "0.28.0", "@esbuild/linux-ia32": "0.28.0", "@esbuild/linux-loong64": "0.28.0", "@esbuild/linux-mips64el": "0.28.0", "@esbuild/linux-ppc64": "0.28.0", "@esbuild/linux-riscv64": "0.28.0", "@esbuild/linux-s390x": "0.28.0", "@esbuild/linux-x64": "0.28.0", "@esbuild/netbsd-arm64": "0.28.0", "@esbuild/netbsd-x64": "0.28.0", "@esbuild/openbsd-arm64": "0.28.0", "@esbuild/openbsd-x64": "0.28.0", "@esbuild/openharmony-arm64": "0.28.0", "@esbuild/sunos-x64": "0.28.0", "@esbuild/win32-arm64": "0.28.0", "@esbuild/win32-ia32": "0.28.0", "@esbuild/win32-x64": "0.28.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw=="], - "fumadocs-mdx/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], + "fumadocs-mdx/tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="], "fumadocs-openapi/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], @@ -4420,8 +4397,6 @@ "isomorphic-unfetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "json-schema-to-typescript/js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - "katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], "langsmith/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -4542,6 +4517,8 @@ "restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + "sim/@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], "sim/lucide-react": ["lucide-react@0.479.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-aBhNnveRhorBOK7uA4gDjgaf+YlHMdMhQ/3cupk6exM10hWlEU+2QtWYOfhXhjAsmdb6LeKR+NZnow4UxRRiTQ=="], @@ -4564,11 +4541,9 @@ "socket.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - "socks/ip-address": ["ip-address@10.1.1", "", {}, "sha512-1FMu8/N15Ck1BL551Jf42NYIoin2unWjLQ2Fze/DXryJRl5twqtwNHlO39qERGbIOcKYWHdgRryhOC+NG4eaLw=="], - "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "streamdown/marked": ["marked@17.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ=="], + "streamdown/marked": ["marked@17.0.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA=="], "string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -4588,6 +4563,8 @@ "test-exclude/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "tough-cookie/tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], + "tsx/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], @@ -4624,10 +4601,6 @@ "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], - - "@aws-sdk/dynamodb-codec/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.22", "", { "dependencies": { "@nodable/entities": "2.1.0", "@smithy/types": "^4.14.1", "fast-xml-parser": "5.7.2", "tslib": "^2.6.2" } }, "sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA=="], - "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "@browserbasehq/sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], @@ -4638,10 +4611,6 @@ "@browserbasehq/stagehand/@anthropic-ai/sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "@browserbasehq/stagehand/@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], - - "@browserbasehq/stagehand/@modelcontextprotocol/sdk/jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="], - "@cerebras/cerebras_cloud_sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], "@cerebras/cerebras_cloud_sdk/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], @@ -4694,7 +4663,7 @@ "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], - "@puppeteer/browsers/tar-fs/tar-stream": ["tar-stream@3.1.8", "", { "dependencies": { "b4a": "^1.6.4", "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ=="], + "@puppeteer/browsers/tar-fs/tar-stream": ["tar-stream@3.2.0", "", { "dependencies": { "b4a": "^1.6.4", "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg=="], "@radix-ui/react-label/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], @@ -4746,30 +4715,6 @@ "@types/node-fetch/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ugHZEoktD/bG6mdgmhzLDjMP2VrYRAUPRPF1DpCyiZexkH7DCU7XrSJyXMvkcf0DHV+URk0q2sLf/oqn1D2uYw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], - "@types/nodemailer/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], "@types/papaparse/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], @@ -4808,8 +4753,6 @@ "express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "fetch-cookie/tough-cookie/tldts": ["tldts@7.0.29", "", { "dependencies": { "tldts-core": "^7.0.29" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-JIXCerhudr/N6OWLwLF1HVsTTUo7ry6qHa5eWZEkiMuxsIiAACL55tGLfqfHfoH7QaMQUW8fngD7u7TxWexYQg=="], - "ffmpeg-static/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], @@ -5000,8 +4943,6 @@ "oauth2-mock-server/express/merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], - "oauth2-mock-server/express/path-to-regexp": ["path-to-regexp@0.1.13", "", {}, "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA=="], - "oauth2-mock-server/express/qs": ["qs@6.14.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q=="], "oauth2-mock-server/express/send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], @@ -5054,6 +4995,8 @@ "test-exclude/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "tough-cookie/tldts/tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], @@ -5166,8 +5109,6 @@ "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - "@aws-sdk/client-sso/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - "@browserbasehq/sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "@browserbasehq/sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -5190,26 +5131,8 @@ "@trigger.dev/core/socket.io/engine.io/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="], - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-JYkLjgS1wLoKHJ40G63+afM1ehmsPsjcmrHirKh8+kSCx4ip7+nL1e/twV4Zicxr8RJi9Y0Ahq5mDvneilDDKQ=="], - "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "fetch-cookie/tough-cookie/tldts/tldts-core": ["tldts-core@7.0.29", "", {}, "sha512-W99NuU7b1DcG3uJ3v9k9VztCH3WialNbBkBft5wCs8V8mexu0XQqaZEYb9l9RNNzK8+3EJ9PKWB0/RUtTQ/o+Q=="], - "fumadocs-core/shiki/@shikijs/core/@shikijs/primitive": ["@shikijs/primitive@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw=="], "fumadocs-openapi/shiki/@shikijs/core/@shikijs/primitive": ["@shikijs/primitive@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw=="], @@ -5288,18 +5211,6 @@ "@trigger.dev/core/socket.io/engine.io/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw=="], - - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/signature-v4-multi-region/@aws-sdk/middleware-sdk-s3/@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.893.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA=="], - "lint-staged/listr2/cli-truncate/string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], "lint-staged/listr2/log-update/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], @@ -5324,8 +5235,6 @@ "test-exclude/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "@types/nodemailer/@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw=="], - "lint-staged/listr2/cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "lint-staged/listr2/log-update/cli-cursor/restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],