diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
index b3e422d5328..b662036f2ce 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
+++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts
@@ -74,7 +74,6 @@ import {
TERMINAL_SESSION_RESOURCE_ID,
} from '@/lib/copilot/resources/types'
import { executeBrowserToolOnClient } from '@/lib/copilot/tools/client/browser-tool-execution'
-import { executeLocalFilesystemTool } from '@/lib/copilot/tools/client/local-filesystem'
import {
bindRunToolToExecution,
cancelRunToolExecution,
@@ -2009,11 +2008,49 @@ export function useChat(
return
}
handledClientLocalFilesystemToolIdsRef.current.add(toolCallId)
- executeLocalFilesystemTool(toolCallId, toolName, toolArgs, {
+ const options = {
workspaceId,
chatId: chatIdRef.current ?? selectedChatIdRef.current,
signal: abortControllerRef.current?.signal,
- })
+ }
+ /**
+ * Dynamic on purpose: the local-filesystem executor only runs for desktop-local
+ * VFS tool calls, and a static import kept it in the shared chat chunk on every
+ * surface that mounts the composer. The guard, the dedupe add, and the option
+ * capture above stay synchronous, so re-entrancy behaviour is unchanged. If the
+ * chunk fails to load (deploy skew), the server-side tool call must still settle:
+ * report an error completion rather than leaving it hanging with the dedupe ref
+ * already marked handled.
+ */
+ import('@/lib/copilot/tools/client/local-filesystem').then(
+ (m) => m.executeLocalFilesystemTool(toolCallId, toolName, toolArgs, options),
+ async (error) => {
+ logger.error('Failed to load local filesystem tool executor', { error })
+ /**
+ * The recovery itself can reject (the helper chunks or the completion POST can
+ * fail for the same reason the executor chunk did). Contain it: an unhandled
+ * rejection here would settle nothing and surface as a console error, exactly
+ * like the executor's own report-failure path, which also degrades to a log.
+ */
+ try {
+ const [{ reportClientToolCompletion }, { ASYNC_TOOL_CONFIRMATION_STATUS }] =
+ await Promise.all([
+ import('@/lib/copilot/tools/client/completion'),
+ import('@/lib/copilot/async-runs/lifecycle'),
+ ])
+ await reportClientToolCompletion(
+ toolCallId,
+ ASYNC_TOOL_CONFIRMATION_STATUS.error,
+ 'Local filesystem tool failed to load'
+ )
+ } catch (reportError) {
+ logger.error('Failed to report local filesystem tool load failure', {
+ toolCallId,
+ error: reportError,
+ })
+ }
+ }
+ )
},
[workspaceId]
)
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
index 32a08870988..7e5d1e45483 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx
@@ -77,7 +77,13 @@ import {
useFolderAncestors,
} from '@/app/workspace/[workspaceId]/components/folders'
import { DocumentsEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state'
-import { DocumentTagsModal } from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/components'
+/**
+ * Deep import on purpose: the `[documentId]/components` barrel also exports `ChunkEditor`,
+ * which needs exact token counts and therefore `js-tiktoken` (~2.5 MB gzip of BPE rank
+ * tables). Importing the modal through the barrel shipped the tokenizer to the document
+ * LIST route, which never edits chunks.
+ */
+import { DocumentTagsModal } from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/components/document-tags-modal'
import {
ActionBar,
AddConnectorModal,
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts b/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts
index c8b8e357e15..b374e4f738c 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts
@@ -1,6 +1,5 @@
export { Dashboard } from './dashboard'
export { LogDetails, LogDetailsContent } from './log-details'
-export { ExecutionSnapshot } from './log-details/components/execution-snapshot'
export { FileCards } from './log-details/components/file-download'
export { TraceView } from './log-details/components/trace-view'
export { LogRowContextMenu } from './log-row-context-menu'
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/index.ts b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/index.ts
deleted file mode 100644
index a80bf4e337d..00000000000
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { ExecutionSnapshot } from './execution-snapshot'
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary.test.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary.test.tsx
new file mode 100644
index 00000000000..221aa5892e4
--- /dev/null
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary.test.tsx
@@ -0,0 +1,116 @@
+/**
+ * @vitest-environment jsdom
+ */
+import { act, type ReactNode } from 'react'
+import { createRoot, type Root } from 'react-dom/client'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+
+const { mockToastError } = vi.hoisted(() => ({
+ mockToastError: vi.fn(),
+}))
+
+vi.mock('@sim/emcn', () => ({
+ Loader: () => ,
+ Modal: ({
+ children,
+ open,
+ onOpenChange,
+ }: {
+ children: ReactNode
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ }) =>
+ open ? (
+
+ {children}
+
+
+ ) : null,
+ ModalBody: ({ children }: { children: ReactNode }) => {children}
,
+ ModalContent: ({ children }: { children: ReactNode }) => {children}
,
+ ModalDescription: ({ children }: { children: ReactNode }) => {children}
,
+ ModalHeader: ({ children }: { children: ReactNode }) => {children}
,
+ toast: { error: mockToastError },
+}))
+
+import {
+ SnapshotBoundary,
+ SnapshotModalFallback,
+} from '@/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary'
+
+const LOAD_ERROR = new Error('snapshot chunk failed')
+
+function ThrowingSnapshot() {
+ throw LOAD_ERROR
+}
+
+describe('SnapshotBoundary', () => {
+ let container: HTMLDivElement
+ let root: Root
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+ container = document.createElement('div')
+ document.body.appendChild(container)
+ act(() => {
+ root = createRoot(container)
+ })
+ })
+
+ afterEach(() => {
+ act(() => root.unmount())
+ container.remove()
+ })
+
+ it('contains a background pre-warm failure without notifying or closing', () => {
+ const onLoadError = vi.fn()
+
+ act(() => {
+ root.render(
+
+
+
+ )
+ })
+
+ expect(container.childNodes).toHaveLength(0)
+ expect(mockToastError).not.toHaveBeenCalled()
+ expect(onLoadError).not.toHaveBeenCalled()
+ })
+
+ it('notifies and closes an explicitly opened snapshot after a load failure', () => {
+ const onLoadError = vi.fn()
+
+ act(() => {
+ root.render(
+
+
+
+ )
+ })
+
+ expect(container.childNodes).toHaveLength(0)
+ expect(mockToastError).toHaveBeenCalledWith(
+ 'Could not load the workflow snapshot. Refresh and try again.'
+ )
+ expect(onLoadError).toHaveBeenCalledOnce()
+ })
+
+ it('keeps the modal shell visible while the snapshot bundle loads', () => {
+ const onClose = vi.fn()
+
+ act(() => {
+ root.render()
+ })
+
+ expect(container.textContent).toContain('Workflow State')
+ expect(container.textContent).toContain('Loading run snapshot…')
+
+ const closeButton = container.querySelector('button')
+ expect(closeButton).not.toBeNull()
+ act(() => closeButton?.click())
+ expect(onClose).toHaveBeenCalledOnce()
+ })
+})
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary.tsx
new file mode 100644
index 00000000000..3b7367282fa
--- /dev/null
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary.tsx
@@ -0,0 +1,101 @@
+'use client'
+
+import { Component, type ErrorInfo, type ReactNode } from 'react'
+import {
+ Loader,
+ Modal,
+ ModalBody,
+ ModalContent,
+ ModalDescription,
+ ModalHeader,
+ toast,
+} from '@sim/emcn'
+import { createLogger } from '@sim/logger'
+
+const logger = createLogger('ExecutionSnapshotBoundary')
+
+interface SnapshotBoundaryProps {
+ children: ReactNode
+ isOpen: boolean
+ onLoadError: () => void
+}
+
+interface SnapshotBoundaryState {
+ hasError: boolean
+}
+
+const reportedErrors = new WeakSet()
+
+interface SnapshotModalFallbackProps {
+ isOpen: boolean
+ onClose: () => void
+}
+
+export function SnapshotModalFallback({ isOpen, onClose }: SnapshotModalFallbackProps) {
+ return (
+ {
+ if (!open) onClose()
+ }}
+ >
+
+ Workflow State
+
+
+ Loading the workflow state snapshot for this execution
+
+
+
+ Loading run snapshot…
+
+
+
+
+ )
+}
+
+/**
+ * Error boundary for the lazily loaded execution snapshot.
+ *
+ * `Suspense` handles the pending state of the lazy import but not its
+ * rejection — a failed chunk load (deploy skew, offline) would otherwise
+ * unwind to the route-level boundary and replace the whole logs page with an
+ * error view over an optional modal. Mirrors `PreviewErrorBoundary` in the
+ * file viewer: contain, log, degrade. The snapshot is an overlay, so the
+ * degraded state renders nothing. Closed snapshots are mounted to pre-warm
+ * their chunk and data, so a background failure is logged without interrupting
+ * the user. If the user actually opens a failed snapshot, the caller closes
+ * the modal state and a toast explains why it did not open.
+ *
+ * Callers must remount this boundary when the snapshot identity changes and
+ * when a pre-warmed snapshot is explicitly opened. Error boundaries reset only
+ * via remount; without both transitions, a failed pre-warm would leave the
+ * later open action stuck in the already-tripped state.
+ */
+export class SnapshotBoundary extends Component {
+ public state: SnapshotBoundaryState = { hasError: false }
+
+ public static getDerivedStateFromError(): SnapshotBoundaryState {
+ return { hasError: true }
+ }
+
+ public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
+ if (!reportedErrors.has(error)) {
+ reportedErrors.add(error)
+ logger.error('Execution snapshot failed to load', {
+ error: error.message,
+ componentStack: errorInfo.componentStack,
+ })
+ }
+
+ if (this.props.isOpen) {
+ toast.error('Could not load the workflow snapshot. Refresh and try again.')
+ this.props.onLoadError()
+ }
+ }
+
+ public render() {
+ return this.state.hasError ? null : this.props.children
+ }
+}
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx
index 33adb2639ff..1d9348154b8 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx
@@ -1,6 +1,16 @@
'use client'
-import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
+import {
+ lazy,
+ memo,
+ Suspense,
+ useCallback,
+ useEffect,
+ useLayoutEffect,
+ useMemo,
+ useRef,
+ useState,
+} from 'react'
import {
Badge,
Button,
@@ -48,11 +58,17 @@ import { filterHiddenOutputKeys } from '@/lib/logs/execution/trace-spans/trace-s
import type { TraceSpan } from '@/lib/logs/types'
import { sendMothershipMessage } from '@/lib/mothership/events'
import { DELETED_WORKFLOW_LABEL } from '@/lib/workflows/workflow-labels'
+/**
+ * Deep imports on purpose: importing these back through the parent `logs/components`
+ * barrel forms a parent->child cycle that would keep the barrel edge to the snapshot
+ * alive and silently defeat the ExecutionSnapshot lazy split below.
+ */
import {
- ExecutionSnapshot,
- FileCards,
- TraceView,
-} from '@/app/workspace/[workspaceId]/logs/components'
+ SnapshotBoundary,
+ SnapshotModalFallback,
+} from '@/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary'
+import { FileCards } from '@/app/workspace/[workspaceId]/logs/components/log-details/components/file-download'
+import { TraceView } from '@/app/workspace/[workspaceId]/logs/components/log-details/components/trace-view'
import { useLogDetailsResize } from '@/app/workspace/[workspaceId]/logs/hooks'
import {
logDetailsTabParam,
@@ -73,6 +89,17 @@ import { useLogDetailsUIStore } from '@/stores/logs/store'
import { MAX_LOG_DETAILS_WIDTH_RATIO, MIN_LOG_DETAILS_WIDTH } from '@/stores/logs/utils'
import type { ChatContext } from '@/stores/panel'
+/**
+ * Lazy per the code-splitting rule in `sim-imports.md`: the snapshot renders the workflow
+ * preview canvas, whose graph is ~7.6 MB of source. Rendering is gated on the detail's
+ * open state, so the chunk is fetched on first use, never during SSR or hydration.
+ */
+const ExecutionSnapshot = lazy(() =>
+ import(
+ '@/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/execution-snapshot'
+ ).then((m) => ({ default: m.ExecutionSnapshot }))
+)
+
/**
* Renders an already-apportioned integer credit value. `dollars` is only used
* to distinguish a genuine zero ("0 credits") from a sub-credit charge that
@@ -679,13 +706,28 @@ export function LogDetailsContent({ log, onActiveTabChange }: LogDetailsContentP
{/* Frozen Canvas Modal */}
{log.executionId && (
- setIsExecutionSnapshotOpen(false)}
- />
+ onLoadError={() => setIsExecutionSnapshotOpen(false)}
+ >
+ setIsExecutionSnapshotOpen(false)}
+ />
+ }
+ >
+ setIsExecutionSnapshotOpen(false)}
+ />
+
+
)}
>
)
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
index d94f7de1b02..6f78db43a6d 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx
@@ -1,6 +1,8 @@
'use client'
import {
+ lazy,
+ Suspense,
useCallback,
useEffect,
useEffectEvent,
@@ -64,6 +66,10 @@ import {
type ResourceTableHandle,
} from '@/app/workspace/[workspaceId]/components'
import { LogsEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state'
+import {
+ SnapshotBoundary,
+ SnapshotModalFallback,
+} from '@/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/snapshot-boundary'
import { useLogFilters } from '@/app/workspace/[workspaceId]/logs/hooks/use-log-filters'
import { useSearchState } from '@/app/workspace/[workspaceId]/logs/hooks/use-search-state'
import {
@@ -93,7 +99,7 @@ import { useDebounce } from '@/hooks/use-debounce'
import { useUrlSort } from '@/hooks/use-url-sort'
import { useFilterStore } from '@/stores/logs/filters/store'
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
-import { Dashboard, ExecutionSnapshot, LogDetails, LogRowContextMenu } from './components'
+import { Dashboard, LogDetails, LogRowContextMenu } from './components'
import {
formatDate,
getDisplayStatus,
@@ -106,6 +112,20 @@ import {
workflowEditorPath,
} from './utils'
+/**
+ * Lazy per the code-splitting rule in `sim-imports.md`: the snapshot renders the workflow
+ * preview canvas, whose graph is ~7.6 MB of source (the editor's sub-block components and
+ * the generated tool metadata). Both render sites are gated on client-only state (a preview
+ * selection / an opened detail), so the chunk is fetched on first use, never during SSR or
+ * hydration. The now-dead barrel re-export is deleted — with no `sideEffects: false`, a
+ * leftover re-export would silently defeat this split.
+ */
+const ExecutionSnapshot = lazy(() =>
+ import(
+ '@/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/execution-snapshot'
+ ).then((m) => ({ default: m.ExecutionSnapshot }))
+)
+
const LOGS_PER_PAGE = 50 as const
const REFRESH_SPINNER_DURATION_MS = 1000 as const
const LIVE_REFRESH_INTERVAL_MS = 10_000 as const
@@ -1259,13 +1279,21 @@ export default function Logs() {
/>
{previewLogId !== null && previewDetailQuery.data?.executionId && (
-
+
+ }>
+
+
+
)}
>
)
diff --git a/apps/sim/app/workspace/[workspaceId]/skills/components/utils.ts b/apps/sim/app/workspace/[workspaceId]/skills/components/utils.ts
index bdb862bf939..68216e2a579 100644
--- a/apps/sim/app/workspace/[workspaceId]/skills/components/utils.ts
+++ b/apps/sim/app/workspace/[workspaceId]/skills/components/utils.ts
@@ -1,4 +1,3 @@
-import JSZip from 'jszip'
import { isApiClientError } from '@/lib/api/client/errors'
export interface ParsedSkill {
@@ -91,6 +90,12 @@ function inferNameFromHeading(markdown: string): string {
export async function extractSkillFromZip(
data: File | Blob | ArrayBuffer | Uint8Array
): Promise {
+ /**
+ * Dynamic on purpose (mirrors `lib/workflows/operations/import-export.ts`): jszip is
+ * ~28 KB gzip and this user-triggered upload path is the only reason it would sit in
+ * the initial bundle of every route that links the skills surface.
+ */
+ const { default: JSZip } = await import('jszip')
const zip = await JSZip.loadAsync(data)
const candidates: string[] = []
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
index 14bb7d539c5..c605d805cc3 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
@@ -151,8 +151,9 @@ import { useUndoRedoStore } from '@/stores/undo-redo'
import { useVariablesModalStore } from '@/stores/variables/modal'
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
import { useWorkflowSearchReplaceStore } from '@/stores/workflow-search-replace/store'
+import { prepareBlockState } from '@/stores/workflows/prepare-block-state'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
-import { getUniqueBlockName, prepareBlockState } from '@/stores/workflows/utils'
+import { getUniqueBlockName } from '@/stores/workflows/utils'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
import type { BlockState } from '@/stores/workflows/workflow/types'
diff --git a/apps/sim/lib/api/contracts/index.ts b/apps/sim/lib/api/contracts/index.ts
index 3694225fb23..28bf25a3190 100644
--- a/apps/sim/lib/api/contracts/index.ts
+++ b/apps/sim/lib/api/contracts/index.ts
@@ -1,3 +1,11 @@
+/**
+ * Deliberately NOT re-exported from this barrel: `./tools` (per-integration tool
+ * contracts), `./selectors`, `./v1` (admin API), and `./demo-requests`. All of their
+ * consumers import those files directly, and re-exporting them here shipped their Zod
+ * schema construction (~60 KB gzip) to every route that touches any contract — schema
+ * objects are built at module scope, so `export *` defeats tree-shaking for them.
+ * Import from the specific contract file instead.
+ */
export * from './admin'
export * from './api-keys'
export * from './audit-logs'
@@ -7,7 +15,6 @@ export * from './cli-auth'
export * from './common'
export * from './copilot'
export * from './credentials'
-export * from './demo-requests'
export * from './desktop-auth'
export * from './desktop-tool-authorization'
export * from './environment'
@@ -23,15 +30,12 @@ export * from './primitives'
export * from './sandboxes'
export * from './secret-mount-policy'
export * from './secrets'
-export * from './selectors'
export * from './skills'
export * from './storage-transfer'
export * from './subscription'
export * from './tool-primitives'
-export * from './tools'
export * from './types'
export * from './user'
-export * from './v1'
export * from './workflows'
export * from './workspace-file-folders'
export * from './workspace-files'
diff --git a/apps/sim/lib/pptx-renderer/parser/zip-parser.ts b/apps/sim/lib/pptx-renderer/parser/zip-parser.ts
index 78243649c71..50e5fca9d16 100644
--- a/apps/sim/lib/pptx-renderer/parser/zip-parser.ts
+++ b/apps/sim/lib/pptx-renderer/parser/zip-parser.ts
@@ -4,7 +4,6 @@
*/
import type { JSZipObject } from 'jszip'
-import JSZip from 'jszip'
export interface PptxFiles {
contentTypes: string
@@ -80,6 +79,9 @@ export async function parseZip(
throwZipLimitExceeded(`maxConcurrency ${limits.maxConcurrency} must be an integer >= 1`)
}
+ /** Dynamic on purpose — keeps jszip out of the initial bundle of routes that only
+ * *can* open a PPTX; the archive load below is already async. */
+ const { default: JSZip } = await import('jszip')
const zip = await JSZip.loadAsync(buffer)
const entries = Object.entries(zip.files).filter(([, file]) => !file.dir)
diff --git a/apps/sim/lib/table/import-runner.ts b/apps/sim/lib/table/import-runner.ts
index 2ddf3ffe220..1a98496d408 100644
--- a/apps/sim/lib/table/import-runner.ts
+++ b/apps/sim/lib/table/import-runner.ts
@@ -12,7 +12,6 @@ import {
CSV_SCHEMA_SAMPLE_SIZE,
type CsvHeaderMapping,
coerceRowsForTable,
- createCsvParser,
inferColumnType,
inferSchemaFromCsv,
sanitizeName,
@@ -29,6 +28,7 @@ import {
deleteAllTableRows,
setTableSchemaForImport,
} from '@/lib/table/import-data'
+import { createCsvParser } from '@/lib/table/import-stream'
import {
markJobFailedInWorkspace,
markJobReadyInWorkspace,
diff --git a/apps/sim/lib/table/import-stream.ts b/apps/sim/lib/table/import-stream.ts
new file mode 100644
index 00000000000..f629440b7a6
--- /dev/null
+++ b/apps/sim/lib/table/import-stream.ts
@@ -0,0 +1,27 @@
+/**
+ * Streaming CSV parsing — server-only.
+ *
+ * Split from `lib/table/import.ts` because the streaming `parse` export of
+ * `csv-parse` is a Node `Transform`, so a value import pins Next's stream
+ * polyfills (~35 KB gzip) into any client bundle that reaches it — and
+ * `lib/table/index.ts` re-exports `import.ts` to plenty of client code. This
+ * module is deliberately NOT re-exported from the `lib/table` barrel; the two
+ * consumers (the import runner and the import orchestration) are server-only
+ * and import it directly. The client CSV dialog keeps using the dynamic
+ * `csv-parse/sync` path and is unaffected.
+ */
+
+import { type Parser, parse as parseCsvStream } from 'csv-parse'
+import { csvParseOptions } from '@/lib/table/import'
+
+/**
+ * Returns a streaming `csv-parse` parser (a `Transform`/async-iterable). Pipe a
+ * file stream into it and iterate records with `for await`; backpressure flows
+ * back to the source while each record is processed. Use this for HTTP uploads
+ * so the file is never fully buffered in memory.
+ *
+ * `onHeaders` fires once, before the first record, with the full header row.
+ */
+export function createCsvParser(delimiter = ',', onHeaders?: (headers: string[]) => void): Parser {
+ return parseCsvStream(csvParseOptions(delimiter, onHeaders))
+}
diff --git a/apps/sim/lib/table/import.test.ts b/apps/sim/lib/table/import.test.ts
index f58565ee118..46904728f69 100644
--- a/apps/sim/lib/table/import.test.ts
+++ b/apps/sim/lib/table/import.test.ts
@@ -12,7 +12,6 @@ import {
CsvImportValidationError,
coerceRowsForTable,
coerceValue,
- createCsvParser,
csvParseOptions,
dedupeHeaders,
detectCsvDelimiter,
@@ -22,6 +21,7 @@ import {
sanitizeName,
validateMapping,
} from '@/lib/table/import'
+import { createCsvParser } from '@/lib/table/import-stream'
import type { TableSchema } from '@/lib/table/types'
describe('import', () => {
diff --git a/apps/sim/lib/table/import.ts b/apps/sim/lib/table/import.ts
index 44f857baf1a..e3707b74a99 100644
--- a/apps/sim/lib/table/import.ts
+++ b/apps/sim/lib/table/import.ts
@@ -11,7 +11,7 @@
* parsers share {@link csvParseOptions} so their behavior can't drift.
*/
-import { type Options as CsvParseOptions, type Parser, parse as parseCsvStream } from 'csv-parse'
+import type { Options as CsvParseOptions } from 'csv-parse'
import { OrchestrationError } from '@/lib/core/orchestration/types'
import { getColumnId } from '@/lib/table/column-keys'
import type { ColumnType } from '@/lib/table/column-types'
@@ -76,18 +76,6 @@ export function csvParseOptions(
}
}
-/**
- * Returns a streaming `csv-parse` parser (a `Transform`/async-iterable). Pipe a
- * file stream into it and iterate records with `for await`; backpressure flows
- * back to the source while each record is processed. Use this for HTTP uploads
- * so the file is never fully buffered in memory.
- *
- * `onHeaders` fires once, before the first record, with the full header row.
- */
-export function createCsvParser(delimiter = ',', onHeaders?: (headers: string[]) => void): Parser {
- return parseCsvStream(csvParseOptions(delimiter, onHeaders))
-}
-
/**
* Drops later exact-duplicate header names, preserving first-occurrence order. Mirrors how
* `csv-parse` collapses duplicate column names into a single record key (last value wins), so
diff --git a/apps/sim/lib/table/orchestration/import.ts b/apps/sim/lib/table/orchestration/import.ts
index 7a799540458..04ec6a78540 100644
--- a/apps/sim/lib/table/orchestration/import.ts
+++ b/apps/sim/lib/table/orchestration/import.ts
@@ -21,13 +21,13 @@ import {
type CsvHeaderMapping,
CsvImportValidationError,
coerceRowsForTable,
- createCsvParser,
inferColumnType,
inferSchemaFromCsv,
sanitizeName,
validateMapping,
} from '@/lib/table/import'
import { importAppendRows, importReplaceRows } from '@/lib/table/import-data'
+import { createCsvParser } from '@/lib/table/import-stream'
import { markTableJobRunning, releaseJobClaim } from '@/lib/table/jobs/service'
import { TableLockedError } from '@/lib/table/mutation-locks'
import { createExactEmptyTableRowSecretProvenance } from '@/lib/table/rows/secret-provenance'
diff --git a/apps/sim/stores/workflows/prepare-block-state.ts b/apps/sim/stores/workflows/prepare-block-state.ts
new file mode 100644
index 00000000000..e039021a292
--- /dev/null
+++ b/apps/sim/stores/workflows/prepare-block-state.ts
@@ -0,0 +1,154 @@
+/**
+ * Seeds a new block's state from its registry config.
+ *
+ * Split out of `stores/workflows/utils.ts` because this is the only function there
+ * that needs the block registry and the generated tool-outputs artifact
+ * (`getBlock`, `getEffectiveBlockOutputs`). `utils.ts` is reached by the persistent
+ * workspace shell through the workflow list hooks, so housing this here kept
+ * `tools/generated/tool-outputs.ts` (~476 KB gzip) on the cold path of every
+ * workspace route for a function only the canvas drop handler calls.
+ */
+
+import type { SeedValueGate } from '@/lib/permission-groups/operation-access'
+import { getEffectiveBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
+import { createDefaultInputFormatField } from '@/lib/workflows/input-format'
+import { buildDefaultCanonicalModes } from '@/lib/workflows/subblocks/visibility'
+import { hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils'
+import { getBlock } from '@/blocks'
+import type { BlockState, Position, SubBlockState } from '@/stores/workflows/workflow/types'
+
+export interface PrepareBlockStateOptions {
+ id: string
+ type: string
+ name: string
+ position: Position
+ data?: Record
+ parentId?: string
+ extent?: 'parent'
+ triggerMode?: boolean
+ /**
+ * Vetoes a declared default that the creator's permission group denies —
+ * today the `operation` and `model` fields, both of which blocks pre-fill.
+ *
+ * A vetoed field is seeded with nothing rather than a substitute. The editor's
+ * own permission-aware pickers already resolve the right replacement (first
+ * allowed operation; preferred-then-first allowed model) and they only fill a
+ * field that is empty, so leaving it empty hands the choice to the one place
+ * that knows how to make it. Substituting here instead would also drift from
+ * `getDefaultBlockName`, which names the block after its *declared* default.
+ *
+ * Omit it entirely only where permission gating does not apply, in which case
+ * declared defaults are seeded unchanged. A caller that cannot yet answer —
+ * config still loading — vetoes rather than omitting, since a value written
+ * here is never revisited.
+ */
+ isSeededValueAllowed?: SeedValueGate
+}
+
+/**
+ * Prepares a BlockState object from block type and configuration.
+ * Generates subBlocks and outputs from the block registry.
+ */
+export function prepareBlockState(options: PrepareBlockStateOptions): BlockState {
+ const {
+ id,
+ type,
+ name,
+ position,
+ data,
+ parentId,
+ extent,
+ triggerMode = false,
+ isSeededValueAllowed,
+ } = options
+
+ const blockConfig = getBlock(type)
+
+ const blockData: Record = { ...(data || {}) }
+ if (parentId) blockData.parentId = parentId
+ if (extent) blockData.extent = extent
+
+ if (!blockConfig) {
+ return {
+ id,
+ type,
+ name,
+ position,
+ data: blockData,
+ subBlocks: {},
+ outputs: {},
+ enabled: true,
+ horizontalHandles: true,
+ advancedMode: false,
+ triggerMode,
+ height: 0,
+ }
+ }
+
+ const subBlocks: Record = {}
+
+ if (blockConfig.subBlocks) {
+ blockConfig.subBlocks.forEach((subBlock) => {
+ let initialValue: unknown = null
+
+ if (typeof subBlock.value === 'function') {
+ try {
+ initialValue = subBlock.value({})
+ } catch {
+ initialValue = null
+ }
+ } else if (subBlock.defaultValue !== undefined) {
+ initialValue = subBlock.defaultValue
+ } else if (subBlock.type === 'input-format' || subBlock.type === 'response-format') {
+ initialValue = [createDefaultInputFormatField()]
+ } else if (subBlock.type === 'table') {
+ initialValue = []
+ }
+
+ if (
+ isSeededValueAllowed &&
+ typeof initialValue === 'string' &&
+ initialValue !== '' &&
+ !isSeededValueAllowed(subBlock.id, initialValue)
+ ) {
+ initialValue = null
+ }
+
+ subBlocks[subBlock.id] = {
+ id: subBlock.id,
+ type: subBlock.type,
+ value: initialValue as SubBlockState['value'],
+ }
+ })
+ }
+
+ const isTriggerCapable = hasTriggerCapability(blockConfig)
+ const effectiveTriggerMode = Boolean(triggerMode && isTriggerCapable)
+ const outputs = getEffectiveBlockOutputs(type, subBlocks, {
+ triggerMode: effectiveTriggerMode,
+ preferToolOutputs: !effectiveTriggerMode,
+ })
+
+ if (blockConfig.subBlocks) {
+ const canonicalModes = buildDefaultCanonicalModes(blockConfig.subBlocks)
+ if (Object.keys(canonicalModes).length > 0) {
+ blockData.canonicalModes = canonicalModes
+ }
+ }
+
+ return {
+ id,
+ type,
+ name,
+ position,
+ data: blockData,
+ subBlocks,
+ outputs,
+ enabled: true,
+ horizontalHandles: true,
+ advancedMode: false,
+ triggerMode,
+ height: 0,
+ locked: false,
+ }
+}
diff --git a/apps/sim/stores/workflows/utils.test.ts b/apps/sim/stores/workflows/utils.test.ts
index 622feb67662..c01bf0200d7 100644
--- a/apps/sim/stores/workflows/utils.test.ts
+++ b/apps/sim/stores/workflows/utils.test.ts
@@ -10,7 +10,8 @@ import type { Edge } from 'reactflow'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { getBlock } from '@/blocks/registry'
import { normalizeName } from '@/executor/constants'
-import { filterNewEdges, getUniqueBlockName, prepareBlockState, regenerateBlockIds } from './utils'
+import { prepareBlockState } from './prepare-block-state'
+import { filterNewEdges, getUniqueBlockName, regenerateBlockIds } from './utils'
describe('normalizeName', () => {
it.concurrent('should convert to lowercase', () => {
diff --git a/apps/sim/stores/workflows/utils.ts b/apps/sim/stores/workflows/utils.ts
index 34a5cc1a54a..e7226650716 100644
--- a/apps/sim/stores/workflows/utils.ts
+++ b/apps/sim/stores/workflows/utils.ts
@@ -2,15 +2,9 @@ import { generateId } from '@sim/utils/id'
import { mergeSubblockStateWithValues } from '@sim/workflow-persistence/subblocks'
import { filterUniqueWorkflowEdges } from '@sim/workflow-types/workflow'
import type { Edge } from 'reactflow'
-import type { SeedValueGate } from '@/lib/permission-groups/operation-access'
import { DEFAULT_DUPLICATE_OFFSET } from '@/lib/workflows/autolayout/constants'
-import { getEffectiveBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
import { remapConditionBlockIds, remapConditionEdgeHandle } from '@/lib/workflows/condition-ids'
import { isDynamicHandleSubblock } from '@/lib/workflows/dynamic-handle-topology'
-import { createDefaultInputFormatField } from '@/lib/workflows/input-format'
-import { buildDefaultCanonicalModes } from '@/lib/workflows/subblocks/visibility'
-import { hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils'
-import { getBlock } from '@/blocks'
import { escapeRegExp, normalizeName } from '@/executor/constants'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
@@ -93,142 +87,6 @@ export function getUniqueBlockName(baseName: string, existingBlocks: Record
- parentId?: string
- extent?: 'parent'
- triggerMode?: boolean
- /**
- * Vetoes a declared default that the creator's permission group denies —
- * today the `operation` and `model` fields, both of which blocks pre-fill.
- *
- * A vetoed field is seeded with nothing rather than a substitute. The editor's
- * own permission-aware pickers already resolve the right replacement (first
- * allowed operation; preferred-then-first allowed model) and they only fill a
- * field that is empty, so leaving it empty hands the choice to the one place
- * that knows how to make it. Substituting here instead would also drift from
- * `getDefaultBlockName`, which names the block after its *declared* default.
- *
- * Omit it entirely only where permission gating does not apply, in which case
- * declared defaults are seeded unchanged. A caller that cannot yet answer —
- * config still loading — vetoes rather than omitting, since a value written
- * here is never revisited.
- */
- isSeededValueAllowed?: SeedValueGate
-}
-
-/**
- * Prepares a BlockState object from block type and configuration.
- * Generates subBlocks and outputs from the block registry.
- */
-export function prepareBlockState(options: PrepareBlockStateOptions): BlockState {
- const {
- id,
- type,
- name,
- position,
- data,
- parentId,
- extent,
- triggerMode = false,
- isSeededValueAllowed,
- } = options
-
- const blockConfig = getBlock(type)
-
- const blockData: Record = { ...(data || {}) }
- if (parentId) blockData.parentId = parentId
- if (extent) blockData.extent = extent
-
- if (!blockConfig) {
- return {
- id,
- type,
- name,
- position,
- data: blockData,
- subBlocks: {},
- outputs: {},
- enabled: true,
- horizontalHandles: true,
- advancedMode: false,
- triggerMode,
- height: 0,
- }
- }
-
- const subBlocks: Record = {}
-
- if (blockConfig.subBlocks) {
- blockConfig.subBlocks.forEach((subBlock) => {
- let initialValue: unknown = null
-
- if (typeof subBlock.value === 'function') {
- try {
- initialValue = subBlock.value({})
- } catch {
- initialValue = null
- }
- } else if (subBlock.defaultValue !== undefined) {
- initialValue = subBlock.defaultValue
- } else if (subBlock.type === 'input-format' || subBlock.type === 'response-format') {
- initialValue = [createDefaultInputFormatField()]
- } else if (subBlock.type === 'table') {
- initialValue = []
- }
-
- if (
- isSeededValueAllowed &&
- typeof initialValue === 'string' &&
- initialValue !== '' &&
- !isSeededValueAllowed(subBlock.id, initialValue)
- ) {
- initialValue = null
- }
-
- subBlocks[subBlock.id] = {
- id: subBlock.id,
- type: subBlock.type,
- value: initialValue as SubBlockState['value'],
- }
- })
- }
-
- const isTriggerCapable = hasTriggerCapability(blockConfig)
- const effectiveTriggerMode = Boolean(triggerMode && isTriggerCapable)
- const outputs = getEffectiveBlockOutputs(type, subBlocks, {
- triggerMode: effectiveTriggerMode,
- preferToolOutputs: !effectiveTriggerMode,
- })
-
- if (blockConfig.subBlocks) {
- const canonicalModes = buildDefaultCanonicalModes(blockConfig.subBlocks)
- if (Object.keys(canonicalModes).length > 0) {
- blockData.canonicalModes = canonicalModes
- }
- }
-
- return {
- id,
- type,
- name,
- position,
- data: blockData,
- subBlocks,
- outputs,
- enabled: true,
- horizontalHandles: true,
- advancedMode: false,
- triggerMode,
- height: 0,
- locked: false,
- }
-}
-
/**
* Merges workflow block states with the sub-block store's values while maintaining
* block structure. Resolves the active workflow when no workflowId is given.
diff --git a/scripts/check-tool-registry-boundary.baseline.json b/scripts/check-tool-registry-boundary.baseline.json
index ded2d08310d..fa13ab72b6a 100644
--- a/scripts/check-tool-registry-boundary.baseline.json
+++ b/scripts/check-tool-registry-boundary.baseline.json
@@ -10,29 +10,29 @@
"gateways": {}
},
"app/workspace/[workspaceId]/chat/[chatId]/page.tsx": {
- "modules": 3073,
+ "modules": 2994,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/home/home.tsx": 1383,
- "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx": 1033,
- "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/index.ts": 894,
- "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/index.ts": 891,
+ "apps/sim/app/workspace/[workspaceId]/home/home.tsx": 1388,
+ "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx": 1034,
+ "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/index.ts": 895,
+ "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/index.ts": 892,
"apps/sim/triggers/registry.ts": 472,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx": 334,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx": 343,
"apps/sim/blocks/registry.ts": 315,
"apps/sim/lib/auth/index.ts": 230
}
},
"app/workspace/[workspaceId]/files/[fileId]/page.tsx": {
- "modules": 2030,
+ "modules": 1947,
"gateways": {
"apps/sim/triggers/registry.ts": 472,
"apps/sim/blocks/registry.ts": 341,
- "apps/sim/app/workspace/[workspaceId]/files/files.tsx": 273,
- "apps/sim/lib/auth/index.ts": 236,
- "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/index.ts": 151,
- "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx": 134,
- "apps/sim/lib/api/contracts/index.ts": 109,
- "apps/sim/lib/webhooks/providers/index.ts": 109
+ "apps/sim/app/workspace/[workspaceId]/files/files.tsx": 274,
+ "apps/sim/lib/auth/index.ts": 244,
+ "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/index.ts": 152,
+ "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx": 135,
+ "apps/sim/lib/webhooks/providers/index.ts": 109,
+ "apps/sim/lib/webhooks/providers/registry.ts": 107
}
},
"app/workspace/[workspaceId]/files/[fileId]/view/page.tsx": {
@@ -43,16 +43,16 @@
}
},
"app/workspace/[workspaceId]/files/page.tsx": {
- "modules": 2030,
+ "modules": 1947,
"gateways": {
"apps/sim/triggers/registry.ts": 472,
"apps/sim/blocks/registry.ts": 341,
- "apps/sim/app/workspace/[workspaceId]/files/files.tsx": 275,
- "apps/sim/lib/auth/index.ts": 236,
- "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/index.ts": 151,
- "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx": 134,
- "apps/sim/lib/api/contracts/index.ts": 109,
- "apps/sim/lib/webhooks/providers/index.ts": 109
+ "apps/sim/app/workspace/[workspaceId]/files/files.tsx": 276,
+ "apps/sim/lib/auth/index.ts": 244,
+ "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/index.ts": 152,
+ "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx": 135,
+ "apps/sim/lib/webhooks/providers/index.ts": 109,
+ "apps/sim/lib/webhooks/providers/registry.ts": 107
}
},
"app/workspace/[workspaceId]/home/layout.tsx": {
@@ -60,120 +60,120 @@
"gateways": {}
},
"app/workspace/[workspaceId]/home/page.tsx": {
- "modules": 3073,
+ "modules": 2994,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/home/home.tsx": 1383,
- "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx": 1033,
- "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/index.ts": 894,
- "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/index.ts": 891,
+ "apps/sim/app/workspace/[workspaceId]/home/home.tsx": 1388,
+ "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx": 1034,
+ "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/index.ts": 895,
+ "apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/index.ts": 892,
"apps/sim/triggers/registry.ts": 472,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx": 334,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx": 343,
"apps/sim/blocks/registry.ts": 315,
"apps/sim/lib/auth/index.ts": 230
}
},
"app/workspace/[workspaceId]/integrations/[block]/page.tsx": {
- "modules": 1350,
+ "modules": 1247,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail.tsx": 1324,
- "apps/sim/triggers/index.ts": 509,
- "apps/sim/blocks/registry.ts": 447,
- "apps/sim/lib/api/contracts/index.ts": 129,
- "apps/sim/blocks/blocks/credential-group.ts": 106,
- "apps/sim/stores/workflows/registry/store.ts": 81,
- "apps/sim/hooks/queries/deployments.ts": 74,
- "apps/sim/lib/workflows/comparison/compare.ts": 71
+ "apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail.tsx": 1221,
+ "apps/sim/triggers/index.ts": 510,
+ "apps/sim/triggers/registry.ts": 508,
+ "apps/sim/blocks/registry.ts": 491,
+ "apps/sim/blocks/blocks/credential-group.ts": 145,
+ "apps/sim/stores/workflows/registry/store.ts": 128,
+ "apps/sim/hooks/queries/deployments.ts": 121,
+ "apps/sim/lib/workflows/comparison/describe.ts": 111
}
},
"app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx": {
- "modules": 1328,
+ "modules": 1225,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/connected-credential-detail.tsx": 1327,
+ "apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/connected-credential-detail.tsx": 1224,
"apps/sim/triggers/registry.ts": 508,
- "apps/sim/blocks/registry.ts": 348,
- "apps/sim/lib/api/contracts/index.ts": 135,
- "apps/sim/stores/workflows/registry/store.ts": 77,
- "apps/sim/hooks/queries/deployments.ts": 74,
- "apps/sim/lib/workflows/comparison/compare.ts": 71,
- "apps/sim/lib/workflows/comparison/resolve-values.ts": 68
+ "apps/sim/blocks/registry.ts": 349,
+ "apps/sim/stores/workflows/registry/store.ts": 124,
+ "apps/sim/hooks/queries/deployments.ts": 121,
+ "apps/sim/lib/workflows/comparison/describe.ts": 111,
+ "apps/sim/hooks/selectors/registry.ts": 106,
+ "apps/sim/app/workspace/[workspaceId]/components/credential-detail/index.ts": 54
}
},
"app/workspace/[workspaceId]/integrations/page.tsx": {
- "modules": 1335,
+ "modules": 1232,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx": 1045,
- "apps/sim/blocks/registry.ts": 961,
- "apps/sim/triggers/index.ts": 509,
- "apps/sim/lib/api/contracts/index.ts": 131,
- "apps/sim/blocks/blocks/credential-group.ts": 107,
- "apps/sim/stores/workflows/registry/store.ts": 81,
- "apps/sim/hooks/queries/deployments.ts": 74,
- "apps/sim/lib/workflows/comparison/compare.ts": 71
+ "apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx": 1090,
+ "apps/sim/blocks/registry.ts": 1005,
+ "apps/sim/triggers/index.ts": 510,
+ "apps/sim/triggers/registry.ts": 508,
+ "apps/sim/blocks/blocks/credential-group.ts": 146,
+ "apps/sim/stores/workflows/registry/store.ts": 128,
+ "apps/sim/hooks/queries/deployments.ts": 121,
+ "apps/sim/lib/workflows/comparison/describe.ts": 111
}
},
"app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx": {
- "modules": 1530,
+ "modules": 1432,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx": 1237,
+ "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx": 1287,
"apps/sim/triggers/registry.ts": 508,
"apps/sim/blocks/registry.ts": 344,
"apps/sim/blocks/registry-maps.ts": 341,
- "apps/sim/lib/api/contracts/index.ts": 129,
+ "apps/sim/hooks/selectors/registry.ts": 91,
"apps/sim/connectors/registry.ts": 65,
- "apps/sim/app/workspace/[workspaceId]/components/index.ts": 61,
- "apps/sim/lib/api/contracts/tools/index.ts": 60
+ "apps/sim/app/workspace/[workspaceId]/components/index.ts": 60,
+ "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/index.ts": 51
}
},
"app/workspace/[workspaceId]/knowledge/[id]/page.tsx": {
- "modules": 1542,
+ "modules": 1435,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx": 1248,
+ "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx": 1289,
"apps/sim/triggers/registry.ts": 508,
"apps/sim/blocks/registry.ts": 349,
"apps/sim/blocks/registry-maps.ts": 346,
- "apps/sim/lib/api/contracts/index.ts": 129,
+ "apps/sim/hooks/selectors/registry.ts": 91,
"apps/sim/connectors/registry.ts": 65,
- "apps/sim/app/workspace/[workspaceId]/components/index.ts": 61,
- "apps/sim/lib/api/contracts/tools/index.ts": 60
+ "apps/sim/app/workspace/[workspaceId]/components/index.ts": 60,
+ "apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/index.ts": 44
}
},
"app/workspace/[workspaceId]/knowledge/page.tsx": {
- "modules": 2253,
+ "modules": 2170,
"gateways": {
"apps/sim/triggers/registry.ts": 472,
"apps/sim/blocks/registry.ts": 339,
"apps/sim/app/workspace/[workspaceId]/knowledge/prefetch.ts": 290,
"apps/sim/lib/knowledge/application/knowledge-bases.ts": 234,
- "apps/sim/lib/auth/index.ts": 183,
+ "apps/sim/lib/auth/index.ts": 192,
"apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx": 154,
"apps/sim/lib/knowledge/orchestration/index.ts": 147,
"apps/sim/lib/knowledge/orchestration/connectors.ts": 141
}
},
"app/workspace/[workspaceId]/layout.tsx": {
- "modules": 2106,
+ "modules": 2031,
"gateways": {
"apps/sim/triggers/registry.ts": 472,
"apps/sim/blocks/registry.ts": 340,
- "apps/sim/lib/auth/index.ts": 307,
- "apps/sim/app/workspace/[workspaceId]/components/workspace-chrome/index.ts": 305,
- "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx": 297,
- "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/index.ts": 205,
- "apps/sim/lib/api/contracts/index.ts": 109,
- "apps/sim/lib/webhooks/providers/index.ts": 109
+ "apps/sim/lib/auth/index.ts": 314,
+ "apps/sim/app/workspace/[workspaceId]/components/workspace-chrome/index.ts": 310,
+ "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx": 305,
+ "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/index.ts": 210,
+ "apps/sim/lib/webhooks/providers/index.ts": 109,
+ "apps/sim/lib/webhooks/providers/registry.ts": 107
}
},
"app/workspace/[workspaceId]/logs/page.tsx": {
- "modules": 1769,
+ "modules": 1681,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/logs/logs.tsx": 1478,
+ "apps/sim/app/workspace/[workspaceId]/logs/logs.tsx": 1538,
"apps/sim/triggers/registry.ts": 508,
- "apps/sim/app/workspace/[workspaceId]/logs/components/index.ts": 399,
- "apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/index.ts": 345,
+ "apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/execution-snapshot/execution-snapshot.tsx": 360,
"apps/sim/blocks/registry.ts": 335,
- "apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-editor/index.ts": 301,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/index.ts": 297,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx": 265
+ "apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-editor/index.ts": 314,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/index.ts": 308,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx": 270,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/index.ts": 259
}
},
"app/workspace/[workspaceId]/page.tsx": {
@@ -185,16 +185,16 @@
"gateways": {}
},
"app/workspace/[workspaceId]/settings/[section]/page.tsx": {
- "modules": 2125,
+ "modules": 2082,
"gateways": {
"apps/sim/triggers/registry.ts": 472,
- "apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx": 445,
+ "apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx": 453,
"apps/sim/blocks/registry.ts": 339,
- "apps/sim/lib/auth/index.ts": 316,
+ "apps/sim/lib/auth/index.ts": 304,
"apps/sim/lib/webhooks/providers/index.ts": 109,
- "apps/sim/lib/api/contracts/index.ts": 107,
"apps/sim/lib/webhooks/providers/registry.ts": 107,
- "apps/sim/lib/api/contracts/tools/index.ts": 59
+ "apps/sim/hooks/selectors/registry.ts": 71,
+ "apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/recently-deleted.tsx": 45
}
},
"app/workspace/[workspaceId]/settings/billing/credit-usage/layout.tsx": {
@@ -202,16 +202,16 @@
"gateways": {}
},
"app/workspace/[workspaceId]/settings/billing/credit-usage/page.tsx": {
- "modules": 1687,
+ "modules": 1601,
"gateways": {
- "apps/sim/lib/auth/index.ts": 1550,
- "apps/sim/blocks/registry.ts": 616,
- "apps/sim/blocks/registry-maps.ts": 613,
- "apps/sim/triggers/index.ts": 473,
- "apps/sim/blocks/blocks/credential-group.ts": 271,
- "apps/sim/stores/workflows/registry/store.ts": 253,
- "apps/sim/hooks/queries/deployments.ts": 245,
- "apps/sim/lib/workflows/comparison/compare.ts": 240
+ "apps/sim/lib/auth/index.ts": 1464,
+ "apps/sim/blocks/registry.ts": 530,
+ "apps/sim/blocks/registry-maps.ts": 527,
+ "apps/sim/triggers/index.ts": 474,
+ "apps/sim/triggers/registry.ts": 472,
+ "apps/sim/blocks/blocks/credential-group.ts": 185,
+ "apps/sim/stores/workflows/registry/store.ts": 168,
+ "apps/sim/hooks/queries/deployments.ts": 160
}
},
"app/workspace/[workspaceId]/settings/layout.tsx": {
@@ -223,159 +223,157 @@
"gateways": {}
},
"app/workspace/[workspaceId]/settings/secrets/[credentialId]/page.tsx": {
- "modules": 1375,
+ "modules": 1272,
"gateways": {
"apps/sim/triggers/registry.ts": 508,
- "apps/sim/blocks/registry.ts": 350,
- "apps/sim/blocks/registry-maps.ts": 347,
- "apps/sim/lib/api/contracts/index.ts": 136,
- "apps/sim/app/workspace/[workspaceId]/settings/secrets/[credentialId]/secret-detail.tsx": 77,
- "apps/sim/stores/workflows/registry/store.ts": 76,
- "apps/sim/hooks/queries/deployments.ts": 73,
- "apps/sim/lib/workflows/comparison/compare.ts": 70
+ "apps/sim/blocks/registry.ts": 351,
+ "apps/sim/blocks/registry-maps.ts": 348,
+ "apps/sim/stores/workflows/registry/store.ts": 123,
+ "apps/sim/hooks/queries/deployments.ts": 120,
+ "apps/sim/lib/workflows/comparison/describe.ts": 110,
+ "apps/sim/hooks/selectors/registry.ts": 105,
+ "apps/sim/app/workspace/[workspaceId]/settings/secrets/[credentialId]/secret-detail.tsx": 77
}
},
"app/workspace/[workspaceId]/skills/[skillId]/page.tsx": {
- "modules": 1451,
+ "modules": 1352,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/skills/[skillId]/skill-detail.tsx": 1450,
+ "apps/sim/app/workspace/[workspaceId]/skills/[skillId]/skill-detail.tsx": 1351,
"apps/sim/triggers/registry.ts": 508,
"apps/sim/blocks/registry.ts": 349,
"apps/sim/blocks/registry-maps.ts": 347,
- "apps/sim/lib/api/contracts/index.ts": 127,
- "apps/sim/app/workspace/[workspaceId]/skills/components/skill-fields/index.ts": 89,
- "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-field.tsx": 86,
- "apps/sim/lib/api/contracts/tools/index.ts": 60
+ "apps/sim/app/workspace/[workspaceId]/skills/components/skill-fields/index.ts": 93,
+ "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-field.tsx": 90,
+ "apps/sim/hooks/queries/deployments.ts": 90,
+ "apps/sim/lib/workflows/comparison/describe.ts": 83
}
},
"app/workspace/[workspaceId]/skills/new/page.tsx": {
- "modules": 1449,
+ "modules": 1350,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/skills/new/skill-create.tsx": 1448,
+ "apps/sim/app/workspace/[workspaceId]/skills/new/skill-create.tsx": 1349,
"apps/sim/triggers/registry.ts": 508,
"apps/sim/blocks/registry.ts": 349,
"apps/sim/blocks/registry-maps.ts": 347,
- "apps/sim/lib/api/contracts/index.ts": 127,
- "apps/sim/app/workspace/[workspaceId]/skills/components/skill-fields/index.ts": 89,
- "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-field.tsx": 86,
- "apps/sim/lib/api/contracts/tools/index.ts": 60
+ "apps/sim/app/workspace/[workspaceId]/skills/components/skill-fields/index.ts": 93,
+ "apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-field.tsx": 90,
+ "apps/sim/hooks/queries/deployments.ts": 90,
+ "apps/sim/lib/workflows/comparison/describe.ts": 83
}
},
"app/workspace/[workspaceId]/skills/page.tsx": {
- "modules": 1318,
+ "modules": 1215,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/skills/skills.tsx": 1028,
- "apps/sim/app/workspace/[workspaceId]/integrations/components/showcase-with-explore/index.ts": 1016,
- "apps/sim/blocks/registry.ts": 1004,
- "apps/sim/blocks/registry-maps.ts": 1002,
- "apps/sim/triggers/index.ts": 509,
- "apps/sim/lib/api/contracts/index.ts": 136,
- "apps/sim/blocks/blocks/credential-group.ts": 120,
- "apps/sim/stores/workflows/registry/store.ts": 92
+ "apps/sim/app/workspace/[workspaceId]/skills/skills.tsx": 1073,
+ "apps/sim/app/workspace/[workspaceId]/integrations/components/showcase-with-explore/index.ts": 1061,
+ "apps/sim/blocks/registry.ts": 1049,
+ "apps/sim/blocks/registry-maps.ts": 1047,
+ "apps/sim/triggers/index.ts": 510,
+ "apps/sim/triggers/registry.ts": 508,
+ "apps/sim/blocks/blocks/credential-group.ts": 160,
+ "apps/sim/stores/workflows/registry/store.ts": 140
}
},
"app/workspace/[workspaceId]/tables/[tableId]/page.tsx": {
- "modules": 2298,
+ "modules": 2219,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx": 564,
+ "apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx": 571,
"apps/sim/triggers/registry.ts": 472,
- "apps/sim/lib/auth/index.ts": 338,
- "apps/sim/app/workspace/[workspaceId]/w/components/preview/index.ts": 315,
+ "apps/sim/lib/auth/index.ts": 341,
+ "apps/sim/app/workspace/[workspaceId]/w/components/preview/index.ts": 320,
"apps/sim/blocks/registry.ts": 315,
- "apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-editor/index.ts": 273,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/index.ts": 269,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx": 238
+ "apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-editor/index.ts": 275,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/index.ts": 271,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx": 239
}
},
"app/workspace/[workspaceId]/tables/page.tsx": {
- "modules": 1875,
+ "modules": 1789,
"gateways": {
"apps/sim/triggers/registry.ts": 472,
- "apps/sim/blocks/registry.ts": 340,
- "apps/sim/lib/auth/index.ts": 327,
- "apps/sim/lib/api/contracts/index.ts": 116,
+ "apps/sim/blocks/registry.ts": 341,
+ "apps/sim/lib/auth/index.ts": 336,
"apps/sim/lib/webhooks/providers/index.ts": 109,
"apps/sim/lib/webhooks/providers/registry.ts": 107,
"apps/sim/app/workspace/[workspaceId]/tables/tables.tsx": 106,
- "apps/sim/lib/api/contracts/tools/index.ts": 60
+ "apps/sim/stores/workflows/registry/store.ts": 98,
+ "apps/sim/lib/workflows/comparison/describe.ts": 88
}
},
"app/workspace/[workspaceId]/upgrade/page.tsx": {
- "modules": 273,
+ "modules": 132,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/upgrade/upgrade.tsx": 266,
- "apps/sim/app/workspace/[workspaceId]/upgrade/hooks/index.ts": 218,
- "apps/sim/lib/billing/client/upgrade.ts": 210,
- "apps/sim/hooks/queries/organization.ts": 206,
- "apps/sim/hooks/queries/workspace.ts": 197,
- "apps/sim/lib/api/contracts/index.ts": 195,
- "apps/sim/lib/api/contracts/tools/index.ts": 61,
- "apps/sim/lib/api/contracts/v1/index.ts": 38
+ "apps/sim/app/workspace/[workspaceId]/upgrade/upgrade.tsx": 125,
+ "apps/sim/app/workspace/[workspaceId]/upgrade/hooks/index.ts": 77,
+ "apps/sim/lib/billing/client/upgrade.ts": 69,
+ "apps/sim/hooks/queries/organization.ts": 65,
+ "apps/sim/hooks/queries/workspace.ts": 56,
+ "apps/sim/lib/api/contracts/index.ts": 54
}
},
"app/workspace/[workspaceId]/w/[workflowId]/layout.tsx": {
- "modules": 2263,
+ "modules": 2192,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx": 2262,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts": 548,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx": 2191,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts": 552,
"apps/sim/triggers/registry.ts": 508,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/index.ts": 465,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/index.ts": 468,
"apps/sim/blocks/registry.ts": 335,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/index.ts": 290,
- "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx": 182,
- "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/index.ts": 151
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/index.ts": 293,
+ "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx": 188,
+ "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/index.ts": 157
}
},
"app/workspace/[workspaceId]/w/[workflowId]/page.tsx": {
- "modules": 2293,
+ "modules": 2223,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx": 2292,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx": 2222,
"apps/sim/triggers/registry.ts": 508,
"apps/sim/blocks/registry.ts": 335,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts": 309,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/index.ts": 271,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/index.ts": 228,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx": 176,
- "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx": 174
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts": 312,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/index.ts": 274,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/index.ts": 231,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx": 182,
+ "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx": 180
}
},
"app/workspace/[workspaceId]/w/page.tsx": {
- "modules": 2263,
+ "modules": 2192,
"gateways": {
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts": 955,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts": 978,
"apps/sim/triggers/registry.ts": 508,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/index.ts": 465,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/index.ts": 468,
"apps/sim/blocks/registry.ts": 335,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/index.ts": 290,
- "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx": 163,
- "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/index.ts": 151,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/index.ts": 293,
+ "apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx": 169,
+ "apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/index.ts": 157,
"apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/index.ts": 146
}
},
"app/workspace/layout.tsx": {
- "modules": 1263,
+ "modules": 1160,
"gateways": {
- "apps/sim/app/workspace/providers/socket-provider.tsx": 1253,
+ "apps/sim/app/workspace/providers/socket-provider.tsx": 1150,
"apps/sim/triggers/registry.ts": 508,
- "apps/sim/blocks/registry.ts": 350,
- "apps/sim/blocks/registry-maps.ts": 347,
- "apps/sim/stores/workflows/registry/store.ts": 275,
- "apps/sim/hooks/queries/deployments.ts": 272,
- "apps/sim/lib/workflows/comparison/compare.ts": 266,
- "apps/sim/lib/workflows/comparison/resolve-values.ts": 263
+ "apps/sim/blocks/registry.ts": 351,
+ "apps/sim/blocks/registry-maps.ts": 348,
+ "apps/sim/stores/workflows/registry/store.ts": 180,
+ "apps/sim/hooks/queries/deployments.ts": 177,
+ "apps/sim/lib/workflows/comparison/describe.ts": 166,
+ "apps/sim/hooks/selectors/registry.ts": 106
}
},
"app/workspace/page.tsx": {
- "modules": 1258,
+ "modules": 1157,
"gateways": {
- "apps/sim/lib/auth/stale-session-recovery.ts": 1021,
- "apps/sim/triggers/index.ts": 509,
- "apps/sim/blocks/registry.ts": 350,
- "apps/sim/blocks/registry-maps.ts": 347,
- "apps/sim/lib/api/contracts/index.ts": 139,
- "apps/sim/stores/workflows/registry/store.ts": 82,
- "apps/sim/hooks/queries/deployments.ts": 75,
- "apps/sim/lib/workflows/comparison/compare.ts": 72
+ "apps/sim/lib/auth/stale-session-recovery.ts": 1068,
+ "apps/sim/triggers/index.ts": 510,
+ "apps/sim/triggers/registry.ts": 508,
+ "apps/sim/blocks/registry.ts": 351,
+ "apps/sim/blocks/registry-maps.ts": 348,
+ "apps/sim/stores/workflows/registry/store.ts": 130,
+ "apps/sim/hooks/queries/deployments.ts": 123,
+ "apps/sim/lib/workflows/comparison/describe.ts": 113
}
}
}