diff --git a/.claude/rules/emcn-components.md b/.claude/rules/emcn-components.md index c21cad945cd..f302a07fa85 100644 --- a/.claude/rules/emcn-components.md +++ b/.claude/rules/emcn-components.md @@ -12,7 +12,7 @@ Import components, `cn`, and tokens from the `@sim/emcn` barrel; icons come from Never hand-roll the chip pill from raw class strings (they go stale). Compose from the canonical sources: -- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFilledSurfaceTokens`, `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells), and the row-state pair `chipHoverSurfaceClass` / `chipActiveSurfaceClass` (hover vs. selected — mutually exclusive, so a selected row holds its surface through hover; every hand-rolled row imports these rather than restating the literals). All are re-exported from the `@sim/emcn` barrel — no subpath import needed. +- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells), and the row-state pair `chipHoverSurfaceClass` / `chipActiveSurfaceClass` (hover vs. selected — mutually exclusive, so a selected row holds its surface through hover; every hand-rolled row imports these rather than restating the literals). All are re-exported from the `@sim/emcn` barrel — no subpath import needed. - **Pill geometry:** `chip/chip.tsx` — `chipVariants` (30px tall, `rounded-lg`, `px-2`, icon↔text `gap-1.5`). Every pill-shaped trigger (`ChipDropdown`, `ChipSelect`, `ChipSwitch`) reuses it for visual parity. Canonical look: normal font-weight (never `font-medium`/`font-semibold`), value text `--text-body`, icons `--text-icon` at `size-[14px]`, placeholder `--text-muted`, `transition-colors`, **no focus ring** (the caret marks focus). Filled surface is `--surface-5` light / `--surface-4` dark with a `--border` border (`chip-chrome.ts` still spells it through the legacy alias `--border-1`; new code writes `--border`). @@ -54,6 +54,6 @@ Declare keyboard intent on the action-owning primitive; never add document-level - **Discriminated-union props for modes** (e.g. `multiple`, the modal field `type`) instead of near-duplicate components. - **Delete legacy variants after migration** — leave no dead paths. - **Verify CSS vars exist.** An undefined var resolves to `currentColor`, which draws black borders. Align to the canonical tokens: normal weight, `--text-body`, `--text-icon`. -- Use Radix UI primitives for accessibility. Export the component and its `variants` (when using CVA). Document with TSDoc + a usage example. +- Use Radix UI primitives for accessibility. Export the component; export its CVA `variants` once another module composes them (`check:unused-exports` flags an export nothing imports). Document with TSDoc + a usage example. Color tokens and icon-size conventions are canonical in `.claude/rules/sim-styling.md` — follow it rather than restating. diff --git a/.cursor/rules/emcn-components.mdc b/.cursor/rules/emcn-components.mdc index d77a4082838..3ed219f6479 100644 --- a/.cursor/rules/emcn-components.mdc +++ b/.cursor/rules/emcn-components.mdc @@ -13,7 +13,7 @@ Import components, `cn`, and tokens from the `@sim/emcn` barrel; icons come from Never hand-roll the chip pill from raw class strings (they go stale). Compose from the canonical sources: -- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFilledSurfaceTokens`, `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells), and the row-state pair `chipHoverSurfaceClass` / `chipActiveSurfaceClass` (hover vs. selected — mutually exclusive, so a selected row holds its surface through hover; every hand-rolled row imports these rather than restating the literals). All are re-exported from the `@sim/emcn` barrel — no subpath import needed. +- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells), and the row-state pair `chipHoverSurfaceClass` / `chipActiveSurfaceClass` (hover vs. selected — mutually exclusive, so a selected row holds its surface through hover; every hand-rolled row imports these rather than restating the literals). All are re-exported from the `@sim/emcn` barrel — no subpath import needed. - **Pill geometry:** `chip/chip.tsx` — `chipVariants` (30px tall, `rounded-lg`, `px-2`, icon↔text `gap-1.5`). Every pill-shaped trigger (`ChipDropdown`, `ChipSelect`, `ChipSwitch`) reuses it for visual parity. Canonical look: normal font-weight (never `font-medium`/`font-semibold`), value text `--text-body`, icons `--text-icon` at `size-[14px]`, placeholder `--text-muted`, `transition-colors`, **no focus ring** (the caret marks focus). Filled surface is `--surface-5` light / `--surface-4` dark with a `--border` border (`chip-chrome.ts` still spells it through the legacy alias `--border-1`; new code writes `--border`). @@ -55,6 +55,6 @@ Declare keyboard intent on the action-owning primitive; never add document-level - **Discriminated-union props for modes** (e.g. `multiple`, the modal field `type`) instead of near-duplicate components. - **Delete legacy variants after migration** — leave no dead paths. - **Verify CSS vars exist.** An undefined var resolves to `currentColor`, which draws black borders. Align to the canonical tokens: normal weight, `--text-body`, `--text-icon`. -- Use Radix UI primitives for accessibility. Export the component and its `variants` (when using CVA). Document with TSDoc + a usage example. +- Use Radix UI primitives for accessibility. Export the component; export its CVA `variants` once another module composes them (`check:unused-exports` flags an export nothing imports). Document with TSDoc + a usage example. Color tokens and icon-size conventions are canonical in `.claude/rules/sim-styling.md` — follow it rather than restating. diff --git a/CLAUDE.md b/CLAUDE.md index c04bd72e209..0b70bd052b8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file (also `AGENTS.md`) holds the repo-wide rules. Area detail lives in `.c - **Logging**: `createLogger` from `@sim/logger`; `logger.info` / `logger.warn` / `logger.error`, never `console.log`. Inside `withRouteHandler` the logger already carries the request ID — no manual `withMetadata({ requestId })`. - **Comments**: name things so the code explains itself. TSDoc documents exported APIs and non-obvious modules. An inline `//` is only for a terse, non-obvious *why*, or for a script-enforced `// : ` annotation (`boundary-raw-fetch`, `double-cast-allowed`, `boundary-raw-json`, `untyped-response`, `rq-lint-allow`, `client-boundary-allow`, `utils-lint-allow`, …). History belongs in the commit message. No `====` separators or commented-out code (`check:comment-hygiene` enforces this). The `/you-might-not-need-a-comment` skill applies this to a diff. - **ID generation**: `generateId()` (UUID v4, the default) or `generateShortId(size?)` (URL-safe, 21 chars by default) from `@sim/utils/id` — never `crypto.randomUUID()`, `nanoid`, or `uuid`. Both use `crypto.getRandomValues()`, so they also work in non-secure (HTTP) browsers. For other randomness, `@sim/utils/random` (`randomInt`, `randomFloat`, `randomItem`, `generateRandomBytes`, `generateRandomHex`) — never `Math.random()` or `crypto.randomBytes()`. -- **Common utilities**: use the shared helpers from `@sim/utils` instead of inline implementations (`check:utils` bans most of the inline forms below): +- **Common utilities**: use the shared helpers from the `@sim/utils/` subpaths instead of inline implementations (`check:utils` bans most of the inline forms below): - `sleep(ms)` from `@sim/utils/helpers` — never `new Promise(resolve => setTimeout(resolve, ms))` - `toError(e)` from `@sim/utils/errors` — normalize caught values to `Error`; never `e instanceof Error ? e : new Error(String(e))` - `getErrorMessage(e, fallback?)` from `@sim/utils/errors` — never `e instanceof Error ? e.message : 'fallback'` diff --git a/apps/sim/lib/credentials/application/discover-managed-mcp-tools.test.ts b/apps/sim/lib/credentials/application/discover-managed-mcp-tools.test.ts index 88ea6e613a0..85d9f375e0f 100644 --- a/apps/sim/lib/credentials/application/discover-managed-mcp-tools.test.ts +++ b/apps/sim/lib/credentials/application/discover-managed-mcp-tools.test.ts @@ -42,7 +42,7 @@ vi.mock('@/lib/mcp/application/use-cases', () => mcpUseCasesMock) vi.mock('@/lib/workspaces/application/workspace-context', () => workspaceContextMock) vi.mock('@/lib/permission-groups/config-scope.server', () => permissionGroupScopeMock) vi.mock('@/lib/workflows/application/context', () => workflowContextMock) -vi.mock('@sim/workflow-persistence', () => ({ +vi.mock('@sim/workflow-persistence/load', () => ({ loadWorkflowFromNormalizedTablesRaw: hoisted.loadWorkflow, })) diff --git a/apps/sim/lib/mcp/application/execute-managed-tool.test.ts b/apps/sim/lib/mcp/application/execute-managed-tool.test.ts index 3ab913fadc5..5ba7deeb835 100644 --- a/apps/sim/lib/mcp/application/execute-managed-tool.test.ts +++ b/apps/sim/lib/mcp/application/execute-managed-tool.test.ts @@ -18,7 +18,7 @@ const hoisted = vi.hoisted(() => ({ saveToolSnapshot: vi.fn(), })) -vi.mock('@sim/workflow-persistence', () => ({ +vi.mock('@sim/workflow-persistence/load', () => ({ loadWorkflowFromNormalizedTablesRaw: hoisted.loadWorkflow, })) diff --git a/apps/sim/lib/mcp/application/execute-tool.test.ts b/apps/sim/lib/mcp/application/execute-tool.test.ts index a7c829ebca8..4de6ad29275 100644 --- a/apps/sim/lib/mcp/application/execute-tool.test.ts +++ b/apps/sim/lib/mcp/application/execute-tool.test.ts @@ -25,7 +25,7 @@ const hoisted = vi.hoisted(() => ({ getServer: vi.fn(), })) -vi.mock('@sim/workflow-persistence', () => ({ +vi.mock('@sim/workflow-persistence/load', () => ({ loadWorkflowFromNormalizedTablesRaw: hoisted.loadWorkflow, })) diff --git a/apps/sim/lib/mcp/application/operation-access.test.ts b/apps/sim/lib/mcp/application/operation-access.test.ts index 682d4127257..f3511058883 100644 --- a/apps/sim/lib/mcp/application/operation-access.test.ts +++ b/apps/sim/lib/mcp/application/operation-access.test.ts @@ -3,7 +3,9 @@ import { queueTableRows, resetDbChainMock, schemaMock } from '@sim/testing' import { beforeEach, describe, expect, it, vi } from 'vitest' const { loadWorkflow } = vi.hoisted(() => ({ loadWorkflow: vi.fn() })) -vi.mock('@sim/workflow-persistence', () => ({ loadWorkflowFromNormalizedTablesRaw: loadWorkflow })) +vi.mock('@sim/workflow-persistence/load', () => ({ + loadWorkflowFromNormalizedTablesRaw: loadWorkflow, +})) import { loadMcpOperationAccess, diff --git a/apps/sim/lib/mcp/application/operation-access.ts b/apps/sim/lib/mcp/application/operation-access.ts index b04a397cd4c..c495724468c 100644 --- a/apps/sim/lib/mcp/application/operation-access.ts +++ b/apps/sim/lib/mcp/application/operation-access.ts @@ -2,7 +2,7 @@ import type { Principal } from '@sim/auth/principal' import { db } from '@sim/db' import { workflowDeploymentVersion } from '@sim/db/schema' import { isPlainRecord } from '@sim/utils/object' -import { loadWorkflowFromNormalizedTablesRaw } from '@sim/workflow-persistence' +import { loadWorkflowFromNormalizedTablesRaw } from '@sim/workflow-persistence/load' import { and, eq } from 'drizzle-orm' import { OrchestrationError } from '@/lib/core/orchestration/types' import { diff --git a/apps/sim/stores/workflows/workflow/types.ts b/apps/sim/stores/workflows/workflow/types.ts index 3dbb7d8ffd6..3c602455450 100644 --- a/apps/sim/stores/workflows/workflow/types.ts +++ b/apps/sim/stores/workflows/workflow/types.ts @@ -38,7 +38,7 @@ export type { Variable, WorkflowState, } -export { isValidSubflowType, SUBFLOW_TYPES } from '@sim/workflow-types/workflow' +export { SUBFLOW_TYPES } from '@sim/workflow-types/workflow' export interface WorkflowActions { updateNodeDimensions: (id: string, dimensions: { width: number; height: number }) => void diff --git a/knip.jsonc b/knip.jsonc index 4ab2873da7a..68c63368a0e 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -4,19 +4,22 @@ // Unused exports, types, and duplicates are ratcheted by check:unused-exports, // which reuses this config in the same knip pass. "include": ["files", "dependencies", "unlisted", "unresolved"], - // knip's default, stated so it is a decision: no entry file's exports are reported. - // That keeps package `exports`/`main`/`bin` contracts (ts-sdk, emcn, cli, …) and framework - // entries (Next routes, Trigger tasks) public, and also exempts the other configured entries - // (scripts, `*.integration.ts`, `background/**`, desktop and SDK examples). - "includeEntryExports": false, + // On by default: every workspace's `exports` map serves only this monorepo, so an entry export + // no workspace imports is dead. The workspaces below turn it off because their entries are + // public or standalone: the apps (framework entries such as Next routes and Trigger tasks), the + // published packages (cli, sim-cli, sim-setup, ts-sdk), db (standalone scripts), and the root + // (scripts). A new private package is checked without opting in. + "includeEntryExports": true, "workspaces": { ".": { + "includeEntryExports": false, "entry": ["scripts/**/*.{ts,tsx}", "vitest.shared.ts"], "paths": { "@/*": ["./apps/sim/*"] }, // This alias selects the native tsc binary; see check-native-typecheck.ts. "ignoreDependencies": ["@typescript/native"] }, "apps/sim": { + "includeEntryExports": false, "entry": [ // Container bootstrap and Trigger's directory-discovered task graph. "bootstrap.ts", @@ -69,8 +72,9 @@ // Live test spawns this path with cwd=MSHIP_WORKER_ROOT (a sibling repo). "ignoreUnresolved": ["tools/probes/src/controller-run-read.ts"] }, - "apps/realtime": { "entry": ["src/bootstrap.ts"] }, + "apps/realtime": { "includeEntryExports": false, "entry": ["src/bootstrap.ts"] }, "apps/desktop": { + "includeEntryExports": false, // scripts/build.ts and e2e/updater.spec.ts supply these to esbuild by path. "entry": [ "src/main/index.ts", @@ -83,7 +87,11 @@ // ensure-pty-prebuilds.ts assembles these package names for universal builds. "ignoreDependencies": ["@lydell/node-pty-darwin-arm64", "@lydell/node-pty-darwin-x64"] }, + "apps/docs": { "includeEntryExports": false }, + "apps/pii": { "includeEntryExports": false }, + "packages/cli": { "includeEntryExports": false }, "packages/db": { + "includeEntryExports": false, "entry": [ "scripts/*.ts", "script-migrations/*.ts", @@ -91,16 +99,18 @@ "vitest.integration.setup.ts" ] }, - "packages/sim-cli": { - "entry": ["src/index.ts", "src/runtime.ts", "scripts/*.ts"] - }, - "packages/ts-sdk": { "entry": ["examples/*.ts"] }, // The contract audit reads this snapshot by filename. // Generated, so its export surface is not ratcheted either. "packages/desktop-bridge": { "entry": ["contract-snapshot.ts"], "ignoreIssues": { "contract-snapshot.ts": ["exports", "types", "duplicates"] } }, + "packages/sim-cli": { + "includeEntryExports": false, + "entry": ["src/index.ts", "src/runtime.ts", "scripts/*.ts"] + }, + "packages/sim-setup": { "includeEntryExports": false }, + "packages/ts-sdk": { "includeEntryExports": false, "entry": ["examples/*.ts"] }, // This shared config is consumed by apps that own the Next dependency. "packages/tsconfig": { "ignoreUnresolved": ["next"] } } diff --git a/packages/auth/src/principal.ts b/packages/auth/src/principal.ts index 7f0f7cb1ce7..700f541819f 100644 --- a/packages/auth/src/principal.ts +++ b/packages/auth/src/principal.ts @@ -12,7 +12,7 @@ export type Principal = | SlackAppPrincipal /** Verified app-wide ingress authority; installation lookup grants no human access. */ -export interface SlackAppPrincipal { +interface SlackAppPrincipal { kind: 'slack_app' appId: string appRevision: string @@ -94,7 +94,7 @@ export interface ExternalUserSubject { } /** Email address proven by a deployment's OTP or SSO authentication gate. */ -export interface AuthenticatedEmailSubject { +interface AuthenticatedEmailSubject { kind: 'authenticated_email' email: string } @@ -106,7 +106,7 @@ interface ActorlessSystemPrincipal { workflowId: string } -export interface ChatSystemPrincipal { +interface ChatSystemPrincipal { kind: 'system' serviceId: 'chat' workspaceId: string @@ -124,10 +124,7 @@ export interface WebhookSystemPrincipal { subject?: ExternalUserSubject } -export type SystemPrincipal = - | ActorlessSystemPrincipal - | ChatSystemPrincipal - | WebhookSystemPrincipal +type SystemPrincipal = ActorlessSystemPrincipal | ChatSystemPrincipal | WebhookSystemPrincipal interface DelegatedPrincipalBase { kind: 'delegated' @@ -153,7 +150,7 @@ export interface SubjectDelegatedPrincipal extends DelegatedPrincipalBase { subjectUserId: string } -export interface WorkflowExecutionDelegationContext { +interface WorkflowExecutionDelegationContext { kind: 'workflow_execution' workflowId: string executionId?: string diff --git a/packages/auth/src/verify.ts b/packages/auth/src/verify.ts index 432d25d4cda..62db3b08858 100644 --- a/packages/auth/src/verify.ts +++ b/packages/auth/src/verify.ts @@ -16,7 +16,7 @@ export interface VerifyAuthOptions { * created by `apps/sim`'s full auth config, so it can carry plugin fields * (e.g. `activeOrganizationId`) this minimal instance does not configure. */ -export interface VerifiedOneTimeTokenSession { +interface VerifiedOneTimeTokenSession { user: { id: string name: string | null diff --git a/packages/browser-protocol/src/index.ts b/packages/browser-protocol/src/index.ts index aae31c887e3..4aab432ff1c 100644 --- a/packages/browser-protocol/src/index.ts +++ b/packages/browser-protocol/src/index.ts @@ -57,23 +57,20 @@ export const CURRENT_BROWSER_TOOL_NAMES = [ export type CurrentBrowserToolName = (typeof CURRENT_BROWSER_TOOL_NAMES)[number] -export const RETIRED_BROWSER_TOOL_NAMES = ['browser_request_takeover'] as const +const RETIRED_BROWSER_TOOL_NAMES = ['browser_request_takeover'] as const -export const BROWSER_TOOL_NAMES = [ - ...CURRENT_BROWSER_TOOL_NAMES, - ...RETIRED_BROWSER_TOOL_NAMES, -] as const +const BROWSER_TOOL_NAMES = [...CURRENT_BROWSER_TOOL_NAMES, ...RETIRED_BROWSER_TOOL_NAMES] as const export type BrowserToolName = (typeof BROWSER_TOOL_NAMES)[number] -export const BROWSER_WAIT_FOR_DEFAULT_TIMEOUT_MS = 10_000 -export const BROWSER_WAIT_FOR_MAX_TIMEOUT_MS = 120_000 -export const BROWSER_WAIT_FOR_RENDERER_GRACE_MS = 15_000 +const BROWSER_WAIT_FOR_DEFAULT_TIMEOUT_MS = 10_000 +const BROWSER_WAIT_FOR_MAX_TIMEOUT_MS = 120_000 +const BROWSER_WAIT_FOR_RENDERER_GRACE_MS = 15_000 export const BROWSER_TOOL_AUTHORIZATION_TIMEOUT_MS = 8_000 export const BROWSER_NAVIGATION_NATIVE_WATCHDOG_MS = 60_000 export const BROWSER_TOOL_QUEUE_WAIT_TIMEOUT_MS = BROWSER_NAVIGATION_NATIVE_WATCHDOG_MS const BROWSER_RENDERER_TRANSPORT_GRACE_MS = 2_000 -export const BROWSER_NAVIGATION_RENDERER_TIMEOUT_MS = +const BROWSER_NAVIGATION_RENDERER_TIMEOUT_MS = BROWSER_TOOL_AUTHORIZATION_TIMEOUT_MS + BROWSER_TOOL_QUEUE_WAIT_TIMEOUT_MS + BROWSER_NAVIGATION_NATIVE_WATCHDOG_MS + @@ -132,7 +129,7 @@ export function browserToolRendererTimeoutMs( } } -export const BROWSER_THEMES = ['system', 'light', 'dark'] as const +const BROWSER_THEMES = ['system', 'light', 'dark'] as const /** Sim appearance preference mirrored into browser-tab media queries. */ export type BrowserTheme = (typeof BROWSER_THEMES)[number] diff --git a/packages/deployment-config/src/env-capabilities.ts b/packages/deployment-config/src/env-capabilities.ts index 27e09d0f3d6..66443facd41 100644 --- a/packages/deployment-config/src/env-capabilities.ts +++ b/packages/deployment-config/src/env-capabilities.ts @@ -28,7 +28,7 @@ export type EnvCapabilityValues = | ReadonlyMap | Readonly> -export type EnvValueValidation = +type EnvValueValidation = | { kind: 'integer' min?: number @@ -79,13 +79,13 @@ export interface AnyOfRequirement { requirements: readonly EnvRequirement[] } -export type EnvRequirement = EnvFieldRequirement | AllOfRequirement | AnyOfRequirement +type EnvRequirement = EnvFieldRequirement | AllOfRequirement | AnyOfRequirement -export type EnvProviderActivation = +type EnvProviderActivation = | { mode: 'any-present'; keys: readonly string[] } | { mode: 'enabled'; key: string } -export interface EnvProviderValidationIssue { +interface EnvProviderValidationIssue { kind: 'missing' | 'invalid' fields: readonly string[] message: string @@ -119,7 +119,7 @@ export interface FallbackCapabilityDefinition< providers: readonly TProvider[] } -export type EnvDefaultProviderDefinition = +type EnvDefaultProviderDefinition = | { id: string; kind: 'built-in'; label: string } | { id: string; kind: 'provider' } @@ -180,11 +180,6 @@ export interface SelectedCapabilityInspection< error: EnvCapabilityConfigurationError | null } -export type CapabilityInspection = - TDefinition extends SelectedCapabilityDefinition - ? SelectedCapabilityInspection, DeclaredProviderId> - : FallbackCapabilityInspection> - export class EnvCapabilityConfigurationError extends Error { constructor( readonly capabilityId: string, @@ -237,11 +232,11 @@ export function envField( return { type: 'field', key, ...options } } -export function allOf(...requirements: readonly EnvRequirement[]): AllOfRequirement { +function allOf(...requirements: readonly EnvRequirement[]): AllOfRequirement { return { type: 'allOf', requirements } } -export function anyOf(...requirements: readonly EnvRequirement[]): AnyOfRequirement { +function anyOf(...requirements: readonly EnvRequirement[]): AnyOfRequirement { return { type: 'anyOf', requirements } } @@ -352,7 +347,7 @@ export function defineCapability } /** Returns the canonical command for configuring a runtime capability. */ -export function getCapabilitySetupCommand(definition: CapabilityDefinition): string { +function getCapabilitySetupCommand(definition: CapabilityDefinition): string { return `npx sim-setup add ${definition.id}` } @@ -540,7 +535,7 @@ function inspectRequiredProvider( } } -export function inspectProvider( +function inspectProvider( provider: TProvider, values: EnvCapabilityValues ): ProviderInspection { @@ -1637,6 +1632,11 @@ export function resolveOAuthClientCapabilityId(serviceId: string): OAuthClientCa return normalized in OAUTH_CLIENT_CAPABILITIES ? (normalized as OAuthClientCapabilityId) : null } +/** + * Env fields that configure a service's OAuth client. + * + * @public scripts/generate-docs.ts loads this module by file path, which knip cannot trace. + */ export function getOAuthClientCapabilityFields(serviceId: string): readonly string[] | null { const providerId = resolveOAuthClientCapabilityId(serviceId) return providerId ? OAUTH_CLIENT_CAPABILITIES[providerId] : null diff --git a/packages/desktop-bridge/src/index.ts b/packages/desktop-bridge/src/index.ts index efc6853efc6..5a922d7a698 100644 --- a/packages/desktop-bridge/src/index.ts +++ b/packages/desktop-bridge/src/index.ts @@ -33,7 +33,7 @@ import type { TerminalToolResponse, } from '@sim/terminal-protocol' -export const PENDING_DESKTOP_SCOPE_PREFIX = 'pending:' as const +const PENDING_DESKTOP_SCOPE_PREFIX = 'pending:' as const /** Boolean results preserve compatibility with older installed desktop shells. */ export type TerminalPasteResult = boolean | 'too-large' @@ -305,7 +305,7 @@ export interface SimDesktopBrowserAgentApi { onScopeSuspended(callback: (scopeId: string) => void): () => void } -export type BrowserDownloadState = 'progressing' | 'completed' | 'interrupted' | 'cancelled' +type BrowserDownloadState = 'progressing' | 'completed' | 'interrupted' | 'cancelled' /** Safe renderer metadata for a native browser download; host paths never cross the bridge. */ export interface BrowserDownloadInfo { @@ -409,7 +409,7 @@ export interface BrowserSiteInfo { importedAt?: string } -export interface SimDesktopBrowserImportApi { +interface SimDesktopBrowserImportApi { /** Chrome profiles detected on this device; empty when none are readable. */ listChromeProfiles(): Promise /** @@ -507,7 +507,7 @@ export interface BrowserFillAvailability { * management calls require the Sim app origin, filling additionally requires * a real user gesture, and no browser tool maps to these channels. */ -export interface SimDesktopBrowserCredentialsApi { +interface SimDesktopBrowserCredentialsApi { /** False when OS-backed encryption is unavailable and passwords are disabled. */ isAvailable(): Promise /** Saved credentials, without passwords. */ @@ -575,7 +575,7 @@ export interface LocalFilesystemEntry { modifiedAt?: string } -export interface LocalFilesystemStat { +interface LocalFilesystemStat { name: string uri: string kind: LocalFilesystemEntryKind @@ -583,7 +583,7 @@ export interface LocalFilesystemStat { modifiedAt: string } -export interface LocalFilesystemReadResult { +interface LocalFilesystemReadResult { uri: string content: string startLine: number @@ -785,7 +785,7 @@ export const TERMINAL_DARK_THEME = { brightWhite: '#f0f6fc', } as const satisfies TerminalThemePalette -export type TerminalThemeSource = 'terminal' | 'iterm2' +type TerminalThemeSource = 'terminal' | 'iterm2' export interface TerminalSelectedProfile { /** Stable source profile id used to restore this selection. */ @@ -928,7 +928,7 @@ export function resolveDesktopZoom( return Math.min(bounds.max, Math.max(bounds.min, next)) } -export const DESKTOP_APPEARANCE_THEMES = ['app', 'light', 'dark'] as const +const DESKTOP_APPEARANCE_THEMES = ['app', 'light', 'dark'] as const export type DesktopAppearanceTheme = (typeof DESKTOP_APPEARANCE_THEMES)[number] @@ -957,7 +957,7 @@ export interface DesktopNotificationPayload { } /** Device-level settings owned by the desktop shell. */ -export interface SimDesktopSettingsApi { +interface SimDesktopSettingsApi { getPreferences(): Promise setPreference( key: K, @@ -981,7 +981,7 @@ export interface SimDesktopSettingsApi { setTerminalDefaultZoom(zoom: DesktopZoomPercent): Promise } -export interface SimDesktopTerminalThemesApi { +interface SimDesktopTerminalThemesApi { listProfiles(): Promise selectProfile(profileId: string): Promise } @@ -991,13 +991,7 @@ export interface SimDesktopTerminalThemesApi { * automatic downloads are disabled or the shell requires a manual installer; * self-updating shells with automatic downloads enabled move to `downloading`. */ -export type DesktopUpdateStatus = - | 'idle' - | 'checking' - | 'available' - | 'downloading' - | 'ready' - | 'error' +type DesktopUpdateStatus = 'idle' | 'checking' | 'available' | 'downloading' | 'ready' | 'error' export interface DesktopUpdateState { status: DesktopUpdateStatus @@ -1014,7 +1008,7 @@ export interface DesktopUpdateState { } /** The shell updater surface. */ -export interface SimDesktopUpdatesApi { +interface SimDesktopUpdatesApi { getState(): Promise /** * Advances the pipeline: checks for an update, downloads an available @@ -1067,7 +1061,7 @@ export type DesktopServerChangeResult = * to must stay reachable when that server cannot be reached at all, and must * never be drivable by a page the current server serves. */ -export interface SimDesktopServerApi { +interface SimDesktopServerApi { /** Opens the shell's native server-selection window. */ open(): void getConfiguration(): Promise @@ -1132,5 +1126,4 @@ export { DESKTOP_TITLE_BAR_ATTRIBUTE, type DesktopTitleBarMode, observeDesktopTitleBar, - supportsDesktopTitleBar, } from './title-bar' diff --git a/packages/desktop-bridge/src/title-bar.ts b/packages/desktop-bridge/src/title-bar.ts index 50371a40005..36ff3f0dd5c 100644 --- a/packages/desktop-bridge/src/title-bar.ts +++ b/packages/desktop-bridge/src/title-bar.ts @@ -3,7 +3,7 @@ import type { SimDesktopWindowStateApi } from '@sim/desktop-bridge' export type DesktopTitleBarMode = 'fullscreen' | 'inset' | null export const DESKTOP_TITLE_BAR_ATTRIBUTE = 'data-sim-desktop-title-bar' -export function supportsDesktopTitleBar(userAgent: string, hasDesktopBridge: boolean): boolean { +function supportsDesktopTitleBar(userAgent: string, hasDesktopBridge: boolean): boolean { return hasDesktopBridge && /Mac/i.test(userAgent) } diff --git a/packages/emcn/src/components/avatar/avatar.tsx b/packages/emcn/src/components/avatar/avatar.tsx index d3040921d74..cbb6a268d48 100644 --- a/packages/emcn/src/components/avatar/avatar.tsx +++ b/packages/emcn/src/components/avatar/avatar.tsx @@ -213,11 +213,4 @@ const AvatarFallback = React.forwardRef< }) AvatarFallback.displayName = 'AvatarFallback' -export { - Avatar, - AvatarImage, - AvatarFallback, - avatarVariants, - avatarStatusVariants, - avatarFallbackVariants, -} +export { Avatar, AvatarImage, AvatarFallback } diff --git a/packages/emcn/src/components/bulk-action-button/bulk-action-button.tsx b/packages/emcn/src/components/bulk-action-button/bulk-action-button.tsx index b24e402e274..5ca771fa464 100644 --- a/packages/emcn/src/components/bulk-action-button/bulk-action-button.tsx +++ b/packages/emcn/src/components/bulk-action-button/bulk-action-button.tsx @@ -5,7 +5,7 @@ import { Button, type ButtonProps } from '../button/button' import { chipFilledFillTokens, chipRadiusClass } from '../chip/chip-chrome' /** The shared 28px geometry and brand-hover treatment of selection action bars. */ -export const bulkActionButtonVariants = cva( +const bulkActionButtonVariants = cva( `${chipRadiusClass} size-[28px] p-0 hover-hover:bg-[var(--brand-secondary)] hover-hover:text-[var(--text-inverse)]!`, { variants: { diff --git a/packages/emcn/src/components/button/button.tsx b/packages/emcn/src/components/button/button.tsx index 4ad21bc4a37..928a4f7a61f 100644 --- a/packages/emcn/src/components/button/button.tsx +++ b/packages/emcn/src/components/button/button.tsx @@ -98,4 +98,4 @@ const Button = forwardRef( Button.displayName = 'Button' -export { Button, buttonVariants } +export { Button } diff --git a/packages/emcn/src/components/calendar/calendar.tsx b/packages/emcn/src/components/calendar/calendar.tsx index 14869f40df8..471ad120a12 100644 --- a/packages/emcn/src/components/calendar/calendar.tsx +++ b/packages/emcn/src/components/calendar/calendar.tsx @@ -55,7 +55,7 @@ function toDateString(year: number, month: number, day: number): string { * is parsed as local time to avoid the off-by-one day that `new Date('2026-05-08')` * (UTC midnight) produces in negative-offset timezones. */ -export function parseDateValue(value: string | Date | undefined): Date | null { +function parseDateValue(value: string | Date | undefined): Date | null { if (!value) return null if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value if (/^\d{4}-\d{2}-\d{2}/.test(value)) { diff --git a/packages/emcn/src/components/charts/bar-chart.tsx b/packages/emcn/src/components/charts/bar-chart.tsx index 60b0e72d90f..9f48f67c92a 100644 --- a/packages/emcn/src/components/charts/bar-chart.tsx +++ b/packages/emcn/src/components/charts/bar-chart.tsx @@ -27,7 +27,7 @@ import { useIsDarkTheme, } from '@sim/emcn' -export interface BarChartPoint { +interface BarChartPoint { timestamp: string value: number } diff --git a/packages/emcn/src/components/charts/chart-geometry.ts b/packages/emcn/src/components/charts/chart-geometry.ts index 3d6ee534d0a..fab6a5cda76 100644 --- a/packages/emcn/src/components/charts/chart-geometry.ts +++ b/packages/emcn/src/components/charts/chart-geometry.ts @@ -21,7 +21,7 @@ export const CHART_AXIS_LABEL_GAP = 8 const CHART_AXIS_GUTTER_STEP = 8 /** Estimate SVG label width before layout, allowing extra space to prevent clipping. */ -export function estimateAxisLabelWidth(text: string): number { +function estimateAxisLabelWidth(text: string): number { let width = 0 for (const character of text) { width += NARROW_GLYPH.test(character) ? 0.3 : 0.58 diff --git a/packages/emcn/src/components/charts/chart-legend.tsx b/packages/emcn/src/components/charts/chart-legend.tsx index 4beeef6fd1a..9c74c95f308 100644 --- a/packages/emcn/src/components/charts/chart-legend.tsx +++ b/packages/emcn/src/components/charts/chart-legend.tsx @@ -3,7 +3,7 @@ import { Chip, cn } from '@sim/emcn' import { cva, type VariantProps } from 'class-variance-authority' -export const chartLegendVariants = cva('flex min-w-0 flex-1 gap-0.5', { +const chartLegendVariants = cva('flex min-w-0 flex-1 gap-0.5', { variants: { layout: { column: 'flex-col', row: 'flex-wrap items-center' }, }, diff --git a/packages/emcn/src/components/charts/chart-tooltip.tsx b/packages/emcn/src/components/charts/chart-tooltip.tsx index 9350bc8d97a..432f636068b 100644 --- a/packages/emcn/src/components/charts/chart-tooltip.tsx +++ b/packages/emcn/src/components/charts/chart-tooltip.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from 'react' import { CHART_PADDING, type ChartPadding } from '@sim/emcn' -export const CHART_TOOLTIP_CLASSES = +const CHART_TOOLTIP_CLASSES = 'pointer-events-none absolute rounded-lg border border-[var(--border)] bg-[var(--surface-1)] px-2 py-1.5 text-xs shadow-overlay' interface PositionChartTooltipArgs { diff --git a/packages/emcn/src/components/charts/dashboard-metric.tsx b/packages/emcn/src/components/charts/dashboard-metric.tsx index 26d8914f3a1..04b0d2ebfae 100644 --- a/packages/emcn/src/components/charts/dashboard-metric.tsx +++ b/packages/emcn/src/components/charts/dashboard-metric.tsx @@ -4,7 +4,7 @@ import type { CSSProperties } from 'react' import { AnimatedNumber, cn, Tooltip } from '@sim/emcn' import { cva, type VariantProps } from 'class-variance-authority' -export const dashboardMetricValueVariants = cva( +const dashboardMetricValueVariants = cva( 'flex min-w-0 items-baseline gap-1 whitespace-nowrap text-[var(--text-body)] tabular-nums', { variants: { diff --git a/packages/emcn/src/components/charts/index.ts b/packages/emcn/src/components/charts/index.ts index e8b18a5a6a8..194c656c0cd 100644 --- a/packages/emcn/src/components/charts/index.ts +++ b/packages/emcn/src/components/charts/index.ts @@ -1,12 +1,11 @@ export { AnimatedNumber } from './animated-number' -export { BarChart, type BarChartPoint, type BarChartProps, type BarChartSeries } from './bar-chart' +export { BarChart, type BarChartSeries } from './bar-chart' export { ChartDataTable } from './chart-data-table' export * from './chart-format' export { ChartFrame } from './chart-frame' export * from './chart-geometry' -export { ChartLegend, type ChartLegendItem, chartLegendVariants } from './chart-legend' +export { ChartLegend, type ChartLegendItem } from './chart-legend' export * from './chart-tooltip' -export { DashboardMetric, dashboardMetricValueVariants } from './dashboard-metric' -export { LineChart, type LineChartMultiSeries, type LineChartPoint } from './line-chart' -export { RadarChart, type RadarChartAxis } from './radar-chart' +export { DashboardMetric } from './dashboard-metric' +export { LineChart } from './line-chart' export { useChartWidth, useIsDarkTheme } from './use-chart-theme' diff --git a/packages/emcn/src/components/charts/line-chart.tsx b/packages/emcn/src/components/charts/line-chart.tsx index 29f7ef2d673..ecf85764afc 100644 --- a/packages/emcn/src/components/charts/line-chart.tsx +++ b/packages/emcn/src/components/charts/line-chart.tsx @@ -27,12 +27,12 @@ import { useIsDarkTheme, } from '@sim/emcn' -export interface LineChartPoint { +interface LineChartPoint { timestamp: string value: number } -export interface LineChartMultiSeries { +interface LineChartMultiSeries { id: string label: string color: string diff --git a/packages/emcn/src/components/charts/radar-chart.tsx b/packages/emcn/src/components/charts/radar-chart.tsx deleted file mode 100644 index c4285306476..00000000000 --- a/packages/emcn/src/components/charts/radar-chart.tsx +++ /dev/null @@ -1,239 +0,0 @@ -'use client' - -import { memo, useId, useMemo, useState } from 'react' -import { - CHART_GRID_FRACTIONS, - CHART_TICK_FILL, - CHART_TICK_FONT_SIZE, - ChartTooltip, - ChartTooltipRow, - estimateAxisLabelWidth, - estimateTooltipHeight, - estimateTooltipWidth, - positionChartTooltip, - useChartWidth, - useIsDarkTheme, -} from '@sim/emcn' -import { truncate } from '@sim/utils/string' - -export interface RadarChartAxis { - label: string - value: number - /** Text shown for `value` in the hover row. Defaults to the raw number. */ - display?: string -} - -interface RadarChartProps { - axes: RadarChartAxis[] - color: string - height?: number -} - -/** Room above and below the web for the captions on the vertical centreline. */ -const LABEL_GUTTER = 52 - -/** Gap between the outer ring and a caption anchored beyond it. */ -const LABEL_GAP = 12 - -/** Cap captions to prevent overflow; tooltips retain the full label. */ -const MAX_LABEL_LENGTH = 16 - -/** Start at twelve o’clock so categories follow clockwise in list order. */ -function axisPoint(index: number, count: number, radius: number, cx: number, cy: number) { - const angle = (index / count) * Math.PI * 2 - Math.PI / 2 - return { x: cx + Math.cos(angle) * radius, y: cy + Math.sin(angle) * radius } -} - -function polygon(points: ReadonlyArray<{ x: number; y: number }>): string { - return points.map((p) => `${p.x.toFixed(2)},${p.y.toFixed(2)}`).join(' ') -} - -/** Compares category values on a shared radial scale normalized to the largest value. */ -function RadarChartComponent({ axes, color, height = 200 }: RadarChartProps) { - const uniqueId = useId().replace(/:/g, '') - const [containerRef, containerWidth] = useChartWidth() - const isDark = useIsDarkTheme() - const [hoverIndex, setHoverIndex] = useState(null) - - const width = containerWidth ?? 0 - const cx = width / 2 - const cy = height / 2 - /** Reserve caption width and reuse geometry during hover updates. */ - const { maxValue, radius, points } = useMemo(() => { - const labelWidth = axes.reduce( - (max, axis) => Math.max(max, estimateAxisLabelWidth(truncate(axis.label, MAX_LABEL_LENGTH))), - 0 - ) - const webRadius = Math.max( - 0, - Math.min(width / 2 - labelWidth - LABEL_GAP, height / 2 - LABEL_GUTTER / 2) - ) - const peak = Math.max(...axes.map((axis) => axis.value), 0) - return { - maxValue: peak, - radius: webRadius, - points: axes.map((axis, index) => { - const fraction = peak > 0 ? axis.value / peak : 0 - return { - axis, - outer: axisPoint(index, axes.length, webRadius, cx, cy), - value: axisPoint(index, axes.length, webRadius * fraction, cx, cy), - label: axisPoint(index, axes.length, webRadius + LABEL_GAP, cx, cy), - } - }), - } - }, [axes, width, height, cx, cy]) - - if (containerWidth === null) { - return
- } - - /** - Three axes are the fewest that enclose an area; below that the "polygon" is a - line or a point and reads as a rendering fault rather than as a distribution. - */ - if (axes.length < 3 || maxValue <= 0) { - return ( -
-

No data

-
- ) - } - - const hovered = hoverIndex !== null ? points[hoverIndex] : null - - return ( - /** Anchor tooltips to the plot so they scroll with it. */ -
-
- - - - - - - - - {[...CHART_GRID_FRACTIONS, 1].map((fraction) => ( - axisPoint(index, axes.length, radius * fraction, cx, cy)) - )} - fill='none' - stroke='var(--border)' - strokeOpacity={fraction === 1 ? 1 : 0.35} - strokeWidth='1' - /> - ))} - {points.map((point, index) => ( - - ))} - - - point.value))} - fill={`url(#radar-${uniqueId})`} - stroke={color} - strokeWidth={isDark ? 1.7 : 2} - strokeLinejoin='round' - /> - {points.map((point, index) => ( - - ))} - - - {points.map((point) => ( - cx ? 'start' : 'end' - } - dominantBaseline={ - Math.abs(point.label.x - cx) >= 1 - ? 'middle' - : point.label.y > cy - ? 'hanging' - : 'auto' - } - fontSize={CHART_TICK_FONT_SIZE} - fill={CHART_TICK_FILL} - > - {truncate(point.axis.label, MAX_LABEL_LENGTH)} - - ))} - - {/** Arc sectors cover the outer vertices; triangular targets leave gaps at low axis counts. */} - {points.map((point, index) => { - const half = Math.PI / axes.length - const angle = (index / axes.length) * Math.PI * 2 - Math.PI / 2 - const reach = radius + LABEL_GUTTER / 2 - const a = { - x: cx + Math.cos(angle - half) * reach, - y: cy + Math.sin(angle - half) * reach, - } - const b = { - x: cx + Math.cos(angle + half) * reach, - y: cy + Math.sin(angle + half) * reach, - } - return ( - setHoverIndex(index)} - onMouseLeave={() => setHoverIndex(null)} - /> - ) - })} - - - {hovered && - (() => { - const value = hovered.axis.display ?? String(hovered.axis.value) - /** Place tooltips beside the vertex, using caption clearance instead of axis gutters. */ - const { left, top } = positionChartTooltip({ - anchorX: hovered.value.x, - anchorY: hovered.value.y, - width, - height, - tooltipMaxWidth: estimateTooltipWidth( - Math.max(hovered.axis.label.length, value.length) - ), - tooltipHeight: estimateTooltipHeight(1, true), - padding: { top: 0, right: LABEL_GAP, bottom: 0, left: LABEL_GAP }, - }) - return ( - - - - ) - })()} -
-
- ) -} - -export const RadarChart = memo(RadarChartComponent) diff --git a/packages/emcn/src/components/chip-button-group/chip-button-group.tsx b/packages/emcn/src/components/chip-button-group/chip-button-group.tsx index 5b779537ff6..8e7aa465f03 100644 --- a/packages/emcn/src/components/chip-button-group/chip-button-group.tsx +++ b/packages/emcn/src/components/chip-button-group/chip-button-group.tsx @@ -30,7 +30,7 @@ function useChipButtonGroupContext() { return context } -export interface ChipButtonGroupProps +interface ChipButtonGroupProps extends Omit, 'onChange'>, VariantProps { /** Currently selected value */ @@ -91,8 +91,7 @@ function ChipButtonGroup({ const chipButtonGroupItemVariants = segmentedControlItemVariants -export interface ChipButtonGroupItemProps - extends Omit, 'onClick'> { +interface ChipButtonGroupItemProps extends Omit, 'onClick'> { /** Value associated with this item */ value: string /** Disables this specific item */ @@ -130,9 +129,4 @@ function ChipButtonGroupItem({ ChipButtonGroup.displayName = 'ChipButtonGroup' ChipButtonGroupItem.displayName = 'ChipButtonGroupItem' -export { - ChipButtonGroup, - ChipButtonGroupItem, - chipButtonGroupVariants, - chipButtonGroupItemVariants, -} +export { ChipButtonGroup, ChipButtonGroupItem } diff --git a/packages/emcn/src/components/chip-date-picker/chip-date-picker.tsx b/packages/emcn/src/components/chip-date-picker/chip-date-picker.tsx index ca65061ab31..74b6a45b7f3 100644 --- a/packages/emcn/src/components/chip-date-picker/chip-date-picker.tsx +++ b/packages/emcn/src/components/chip-date-picker/chip-date-picker.tsx @@ -66,7 +66,7 @@ interface ChipDatePickerRangeProps extends ChipDatePickerBaseProps { onClear?: () => void } -export type ChipDatePickerProps = ChipDatePickerSingleProps | ChipDatePickerRangeProps +type ChipDatePickerProps = ChipDatePickerSingleProps | ChipDatePickerRangeProps /** * Date counterpart to {@link ChipDropdown} — a chip-styled trigger that opens a diff --git a/packages/emcn/src/components/chip-modal/chip-modal.tsx b/packages/emcn/src/components/chip-modal/chip-modal.tsx index fe0f428bbfa..5527ea3720d 100644 --- a/packages/emcn/src/components/chip-modal/chip-modal.tsx +++ b/packages/emcn/src/components/chip-modal/chip-modal.tsx @@ -190,7 +190,7 @@ function handleChipModalEnter(event: React.KeyboardEvent): void action.click() } -export interface ChipModalProps { +interface ChipModalProps { /** Controlled open state. */ open: boolean /** Open-state change handler. */ @@ -298,7 +298,7 @@ function ChipModal({ ChipModal.displayName = 'ChipModal' -export interface ChipModalHeaderProps extends React.HTMLAttributes { +interface ChipModalHeaderProps extends React.HTMLAttributes { /** Optional leading icon. Pass `null`/omit for a title-only header. */ icon?: React.ComponentType<{ className?: string }> | null /** Invoked when the trailing close button is activated. Always rendered. */ @@ -362,7 +362,7 @@ const ChipModalHeader = React.forwardRef( ChipModalHeader.displayName = 'ChipModalHeader' /** Tab entry for {@link ChipModalTabs}. */ -export interface ChipModalTab { +interface ChipModalTab { /** Stable value used to track the active tab. */ value: string /** Visible tab label. */ @@ -371,7 +371,7 @@ export interface ChipModalTab { icon?: React.ComponentType<{ className?: string }> } -export interface ChipModalTabsProps { +interface ChipModalTabsProps { /** Tab definitions in display order. */ tabs: ReadonlyArray /** Currently-active tab value. */ @@ -433,7 +433,7 @@ ChipModalTabs.displayName = 'ChipModalTabs' * content exceeds the viewport cap (`max-h-[84vh]` on `ModalContent`), so * header and footer stay pinned. */ -export interface ChipModalBodyProps extends React.HTMLAttributes { +interface ChipModalBodyProps extends React.HTMLAttributes { /** Removes the field gutter and scrolling chrome for one edge-to-edge surface. */ fullBleed?: boolean } @@ -455,70 +455,12 @@ const ChipModalBody = React.forwardRef( ChipModalBody.displayName = 'ChipModalBody' -export interface ChipModalPromptBodyProps extends React.HTMLAttributes { - /** - * Minimum body height in pixels, so the prompt surface presents as an open - * canvas rather than collapsing to a single line. - * @default 140 - */ - minHeight?: number -} - -/** - * Body variant whose ENTIRE content is a single borderless multi-line text - * surface — an Attio-style prompt modal. Compose it exactly like - * {@link ChipModalBody} (same header above, same footer below); only the body - * differs: instead of labeled `ChipModalField` rows, the one child is a - * full-bleed prompt editor (canonically the home `PromptEditor`, which brings - * `@`-mention and `/`-skill chips, caret-anchored menus, and the overlay chip - * rendering of the chat input). - * - * Gutter math: the editor's mirror field carries its own `px-1 py-1` text - * padding, so this container pads `px-3 pt-3 pb-3.5` — text lands at the same - * effective `px-4 pt-4 pb-4.5` as `ChipModalBody` + `ChipModalField`, aligned - * with the `px-4` header/footer. The first child (the editor) is stretched so - * the whole body acts as one clickable text surface; any trailing sibling - * (e.g. a `ChipModalError`) keeps its natural height. - * - * @example - * ```tsx - * const editor = usePromptEditor({ workspaceId }) - * - * New task - * - * - * - * - * - * ``` - */ -const ChipModalPromptBody = React.forwardRef( - ({ className, style, minHeight = 140, children, ...props }, ref) => ( -
:first-child]:flex-1', - className - )} - style={{ ...style, minHeight }} - {...props} - > - {children} -
- ) -) - -ChipModalPromptBody.displayName = 'ChipModalPromptBody' - /** * Option entry for the `dropdown` branch of {@link ChipModalField}. Aliases the * canonical {@link ChipDropdownOption} so the modal dropdown stays in lockstep * with `ChipDropdown` (gains the optional leading `icon`). */ -export type ChipModalDropdownOption = ChipDropdownOption +type ChipModalDropdownOption = ChipDropdownOption /** * Props shared by every {@link ChipModalField} branch. @@ -710,7 +652,7 @@ interface ChipModalFileFieldProps extends ChipModalFieldBaseProps { * `variant` is not forwarded: the field always uses the tall `block` chip * surface so it stacks as a peer with `textarea` fields. */ -export interface ChipModalEmailsFieldProps +interface ChipModalEmailsFieldProps extends ChipModalFieldBaseProps, Omit { type: 'emails' @@ -753,7 +695,7 @@ interface ChipModalCustomFieldProps extends ChipModalFieldBaseProps { children: React.ReactNode | ((aria: ChipModalFieldAria) => React.ReactNode) } -export type ChipModalFieldProps = +type ChipModalFieldProps = | ChipModalInputFieldProps | ChipModalEmailFieldProps | ChipModalTextareaFieldProps @@ -1235,15 +1177,15 @@ export type ChipModalFooterAction = ChipModalFooterActionBase & * margin. The primary action stays declarative by design; only * `secondaryActions` accepts custom controls. */ -export interface ChipModalFooterCustomAction { +interface ChipModalFooterCustomAction { /** Chip-chrome control rendered verbatim in the slot. */ custom: React.ReactNode } /** One entry of the footer's left-docked `secondaryActions` cluster. */ -export type ChipModalFooterSlotAction = ChipModalFooterAction | ChipModalFooterCustomAction +type ChipModalFooterSlotAction = ChipModalFooterAction | ChipModalFooterCustomAction -export type ChipModalFooterDefaultAction = 'primary' | 'dismiss' | 'none' +type ChipModalFooterDefaultAction = 'primary' | 'dismiss' | 'none' interface ChipModalFooterCommonProps { /** Label for the dismiss action, such as Cancel, Later, or Stay. */ @@ -1307,7 +1249,7 @@ type ChipModalFooterCancelProps = hideCancel: true } -export type ChipModalFooterProps = ChipModalFooterCommonProps & +type ChipModalFooterProps = ChipModalFooterCommonProps & ChipModalFooterCancelProps & ( | { @@ -1459,7 +1401,7 @@ ChipModalFooter.displayName = 'ChipModalFooter' * while the async action runs and the primitive disables BOTH buttons (so the * dismiss can't be clicked mid-mutation) and swaps in `pendingLabel`. */ -export interface ChipConfirmAction { +interface ChipConfirmAction { /** Resting button label (e.g. `'Delete'`). */ label: string /** Invoked when the user confirms. */ @@ -1525,9 +1467,9 @@ export type ChipConfirmTextSegment = * single-style sentences, or an ordered run of {@link ChipConfirmTextSegment}s * when parts need emphasis or error coloring. */ -export type ChipConfirmText = string | readonly ChipConfirmTextSegment[] +type ChipConfirmText = string | readonly ChipConfirmTextSegment[] -export type ChipConfirmDefaultAction = 'confirm' | 'dismiss' | 'none' +type ChipConfirmDefaultAction = 'confirm' | 'dismiss' | 'none' /** True when `text` resolves to at least one non-empty run. */ function hasChipConfirmText(text: ChipConfirmText | undefined): text is ChipConfirmText { @@ -1568,7 +1510,7 @@ function renderChipConfirmText(text: ChipConfirmText): React.ReactNode { }) } -export interface ChipConfirmModalProps { +interface ChipConfirmModalProps { /** Controlled open state. */ open: boolean /** @@ -1765,7 +1707,7 @@ function ChipConfirmModal({ ChipConfirmModal.displayName = 'ChipConfirmModal' -export interface ChipModalErrorProps extends React.HTMLAttributes { +interface ChipModalErrorProps extends React.HTMLAttributes { /** Error message. When falsy the component renders nothing. */ children?: React.ReactNode } @@ -1809,6 +1751,5 @@ export { ChipModalField, ChipModalFooter, ChipModalHeader, - ChipModalPromptBody, ChipModalTabs, } diff --git a/packages/emcn/src/components/chip-switch/chip-switch.tsx b/packages/emcn/src/components/chip-switch/chip-switch.tsx index f3001005d1d..a8a6d75e7af 100644 --- a/packages/emcn/src/components/chip-switch/chip-switch.tsx +++ b/packages/emcn/src/components/chip-switch/chip-switch.tsx @@ -11,7 +11,7 @@ import { scrollFadeAttributes, scrollFadeXClass } from '../scroll-fade/scroll-fa * One segment in a {@link ChipSwitch}. `label` accepts a `ReactNode` so callers * can render colored accents (e.g. a discount badge) inline. */ -export interface ChipSwitchOption { +interface ChipSwitchOption { /** The value associated with this option — passed to `onChange` on select. */ value: T /** Visible label content; `ReactNode` allows inline badges or colored spans. */ diff --git a/packages/emcn/src/components/chip-time-picker/chip-time-picker.tsx b/packages/emcn/src/components/chip-time-picker/chip-time-picker.tsx index 6bebb61d419..917b69df89d 100644 --- a/packages/emcn/src/components/chip-time-picker/chip-time-picker.tsx +++ b/packages/emcn/src/components/chip-time-picker/chip-time-picker.tsx @@ -41,7 +41,7 @@ function parseTimeInput(raw: string): string | null { return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}` } -export interface ChipTimePickerProps { +interface ChipTimePickerProps { /** Selected time as an `HH:mm` (24h) string. */ value?: string /** Called with the committed time in `HH:mm` format. */ diff --git a/packages/emcn/src/components/chip/chip-chrome.ts b/packages/emcn/src/components/chip/chip-chrome.ts index b4c5d63c52c..6b4f811d682 100644 --- a/packages/emcn/src/components/chip/chip-chrome.ts +++ b/packages/emcn/src/components/chip/chip-chrome.ts @@ -6,7 +6,7 @@ export const chipFilledFillTokens = 'bg-[var(--surface-5)] dark:bg-[var(--surfac * ({@link chipFilledFillTokens}); pill triggers (`ChipDropdown`/`ChipSelect`/ * `ChipDatePicker`) opt into the border via `TRIGGER_BORDER_CLASS`. */ -export const chipFilledSurfaceTokens = `border border-[var(--border-1)] ${chipFilledFillTokens}` +const chipFilledSurfaceTokens = `border border-[var(--border-1)] ${chipFilledFillTokens}` /** * The primary (inverse) chip fill at rest — dark fill, inverse text, mirrored in * dark mode. `chipVariants`' `primary` variant composes this with its hover diff --git a/packages/emcn/src/components/combobox/combobox.tsx b/packages/emcn/src/components/combobox/combobox.tsx index e77eeda0007..fcffa3492ac 100644 --- a/packages/emcn/src/components/combobox/combobox.tsx +++ b/packages/emcn/src/components/combobox/combobox.tsx @@ -1145,4 +1145,4 @@ const Combobox = memo( Combobox.displayName = 'Combobox' -export { Combobox, comboboxVariants } +export { Combobox } diff --git a/packages/emcn/src/components/composer-action-button/composer-action-button.tsx b/packages/emcn/src/components/composer-action-button/composer-action-button.tsx index 806f128a179..e69940ed00f 100644 --- a/packages/emcn/src/components/composer-action-button/composer-action-button.tsx +++ b/packages/emcn/src/components/composer-action-button/composer-action-button.tsx @@ -4,7 +4,7 @@ import { cn } from '../../lib/cn' import { Button, type ButtonProps } from '../button/button' /** Shared circular send, stop and search appearance, including the compact chat treatment. */ -export const composerActionButtonVariants = cva('rounded-full p-0', { +const composerActionButtonVariants = cva('rounded-full p-0', { variants: { size: { sm: 'size-[22px]', diff --git a/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx b/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx index ae0f078db0b..8b763065770 100644 --- a/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx +++ b/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx @@ -85,7 +85,7 @@ const MENU_ROW_SELECTED_CLASS = const MENU_ROW_SINGLE_LINE_CLASS = 'whitespace-nowrap [&>span]:min-w-0 [&>span:not([data-overflow-text])]:overflow-hidden [&>span:not([data-overflow-text])]:text-clip' -export type DropdownMenuItemLabelProps = Omit +type DropdownMenuItemLabelProps = Omit /** Canonical fade-only label for a menu row with icons, checks, or actions. */ const DropdownMenuItemLabel = React.memo(function DropdownMenuItemLabel({ @@ -192,16 +192,6 @@ function DropdownMenu({ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger -const DropdownMenuGroup = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DropdownMenuGroup.displayName = DropdownMenuPrimitive.Group.displayName - -const DropdownMenuPortal = DropdownMenuPrimitive.Portal - const DropdownMenuSub = DropdownMenuPrimitive.Sub const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup @@ -320,7 +310,7 @@ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName export const dropdownMenuRowClass = `relative flex ${MENU_ROW_HEIGHT_CLASS} min-w-0 cursor-pointer select-none items-center ${chipContentGap} ${MENU_ROW_RADIUS_CLASS} px-2 text-[var(--text-body)] text-small outline-hidden ${MENU_ROW_TRANSITION_CLASS} data-[disabled]:pointer-events-none data-[disabled]:opacity-50 ${MENU_ROW_SINGLE_LINE_CLASS} [&_svg]:pointer-events-none [&_svg]:size-[14px] [&_svg]:shrink-0 [&_svg]:text-[var(--text-icon)]` /** Large rows match the sidebar's chip geometry without changing menu behavior. */ -export const dropdownMenuItemVariants = cva(dropdownMenuRowClass, { +const dropdownMenuItemVariants = cva(dropdownMenuRowClass, { variants: { size: { default: '', lg: chipGeometryClass }, }, @@ -644,8 +634,6 @@ export { DropdownMenuSeparator, DropdownMenuSearchInput, DropdownMenuShortcut, - DropdownMenuGroup, - DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, diff --git a/packages/emcn/src/components/index.ts b/packages/emcn/src/components/index.ts index 975d060b136..da21429fe6d 100644 --- a/packages/emcn/src/components/index.ts +++ b/packages/emcn/src/components/index.ts @@ -1,16 +1,8 @@ export { Avatar, AvatarFallback, AvatarImage } from './avatar/avatar' export { Badge, type BadgeProps, badgeVariants } from './badge/badge' export { Banner } from './banner/banner' -export { - BulkActionButton, - type BulkActionButtonProps, - bulkActionButtonVariants, -} from './bulk-action-button/bulk-action-button' -export { Button, buttonVariants } from './button/button' -export { - CalendarDayCell, - type CalendarDayCellProps, -} from './calendar/calendar-day-cell' +export { BulkActionButton } from './bulk-action-button/bulk-action-button' +export { Button } from './button/button' export { Checkbox, checkboxIconVariants, checkboxVariants } from './checkbox/checkbox' export { Chip, @@ -32,9 +24,7 @@ export { chipFieldSurfaceClass, chipFieldTextClass, chipFilledFillTokens, - chipFilledSurfaceTokens, chipGeometryClass, - chipGeometryUnroundedClass, chipHoverSurfaceClass, chipIconSlotClass, chipPrimaryFillTokens, @@ -44,73 +34,40 @@ export { export { ChipButtonGroup, ChipButtonGroupItem, - type ChipButtonGroupItemProps, - type ChipButtonGroupProps, - chipButtonGroupItemVariants, - chipButtonGroupVariants, } from './chip-button-group/chip-button-group' export { ChipCombobox } from './chip-combobox/chip-combobox' -export { - ChipCopyInput, - type ChipCopyInputProps, -} from './chip-copy-input/chip-copy-input' +export { ChipCopyInput } from './chip-copy-input/chip-copy-input' export { ChipDatePicker } from './chip-date-picker/chip-date-picker' export { ChipDropdown, type ChipDropdownOption, type ChipDropdownProps, } from './chip-dropdown/chip-dropdown' -export { - ChipEmailsInput, - type ChipEmailsInputProps, -} from './chip-emails-input/chip-emails-input' +export { ChipEmailsInput } from './chip-emails-input/chip-emails-input' export { ChipInput, type ChipInputProps } from './chip-input/chip-input' export { - type ChipConfirmAction, - type ChipConfirmDefaultAction, ChipConfirmModal, - type ChipConfirmModalProps, - type ChipConfirmText, type ChipConfirmTextSegment, ChipModal, ChipModalBody, - type ChipModalBodyProps, ChipModalDescription, - type ChipModalDescriptionProps, - type ChipModalDropdownOption, - type ChipModalEmailsFieldProps, ChipModalError, - type ChipModalErrorProps, ChipModalField, type ChipModalFieldAria, - type ChipModalFieldProps, ChipModalFooter, type ChipModalFooterAction, - type ChipModalFooterCustomAction, - type ChipModalFooterDefaultAction, - type ChipModalFooterProps, - type ChipModalFooterSlotAction, ChipModalHeader, - type ChipModalHeaderProps, - ChipModalPromptBody, - type ChipModalPromptBodyProps, - type ChipModalProps, ChipModalSeparator, ChipModalSurface, - type ChipModalTab, ChipModalTabs, - type ChipModalTabsProps, focusChipModalContent, } from './chip-modal/chip-modal' -export { ChipSelect, type ChipSelectOption, type ChipSelectProps } from './chip-select/chip-select' -export { - ChipSwitch, - type ChipSwitchOption, - type ChipSwitchProps, -} from './chip-switch/chip-switch' -export { ChipTag, type ChipTagProps, chipTagVariants } from './chip-tag/chip-tag' -export { ChipTextarea, type ChipTextareaProps } from './chip-textarea/chip-textarea' -export { ChipTimePicker, type ChipTimePickerProps } from './chip-time-picker/chip-time-picker' +export { ChipSelect, type ChipSelectOption } from './chip-select/chip-select' +export { ChipSwitch } from './chip-switch/chip-switch' +export { ChipTag, chipTagVariants } from './chip-tag/chip-tag' +export { ChipTextarea } from './chip-textarea/chip-textarea' +/** @public The documented time sibling of `ChipDatePicker`; consumers import it from the barrel. */ +export { ChipTimePicker } from './chip-time-picker/chip-time-picker' export { CODE_LINE_HEIGHT_PX, Code, @@ -119,29 +76,21 @@ export { } from './code/code' export { CopyCodeButton } from './code/copy-code-button' export { highlight, languages } from './code/prism' -export { CollapsibleCard, type CollapsibleCardProps } from './collapsible-card/collapsible-card' +export { CollapsibleCard } from './collapsible-card/collapsible-card' export { Combobox, type ComboboxOption, type ComboboxOptionGroup, } from './combobox/combobox' -export { - ComposerActionButton, - type ComposerActionButtonProps, - composerActionButtonVariants, -} from './composer-action-button/composer-action-button' -export { DetailsPanel, type DetailsPanelProps } from './details-panel/details-panel' +export { ComposerActionButton } from './composer-action-button/composer-action-button' +export { DetailsPanel } from './details-panel/details-panel' export { DropdownMenu, - DropdownMenuCheckboxItem, DropdownMenuContent, - DropdownMenuGroup, DropdownMenuItem, DropdownMenuItemAction, DropdownMenuItemLabel, - type DropdownMenuItemLabelProps, DropdownMenuLabel, - DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSearchInput, @@ -159,18 +108,13 @@ export { Info } from './info/info' export { InfoCard, InfoCardItem, - type InfoCardItemProps, InfoCardList, - type InfoCardListProps, - type InfoCardProps, } from './info-card/info-card' -export { Input, type InputProps } from './input/input' -export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from './input-otp/input-otp' +export { Input } from './input/input' +export { InputOTP, InputOTPGroup, InputOTPSlot } from './input-otp/input-otp' export { Label } from './label/label' -export { Lightbox, type LightboxProps } from './lightbox/lightbox' -export { focusFirstTextInput, focusFirstTextInputIn } from './modal/auto-focus' +export { Lightbox } from './lightbox/lightbox' export { - MODAL_SIZES, Modal, ModalBody, ModalClose, @@ -178,8 +122,6 @@ export { ModalDescription, ModalFooter, ModalHeader, - ModalOverlay, - ModalPortal, ModalTabs, ModalTabsContent, ModalTabsList, @@ -188,12 +130,10 @@ export { ModalTrigger, NATIVE_SURFACE_OCCLUSION_PREPARE_EVENT, type NativeSurfaceOcclusionPrepareDetail, - useModalDismissDisabled, useNativeSurfaceOcclusionReady, } from './modal/modal' export { OverflowText, - type OverflowTextProps, overflowFadeSizeClass, overflowTextClipClass, overflowTextFadeClass, @@ -215,16 +155,15 @@ export { } from './popover/popover' export { POPOVER_ANIMATION_CLASSES } from './popover/popover-animation' export { ProgressItem } from './progress-item/progress-item' -export { RowActions, type RowActionsProps, rowActionsGroupClass } from './row-actions/row-actions' +export { RowActions, rowActionsGroupClass } from './row-actions/row-actions' export { SecretInput } from './secret-input/secret-input' export { SecretReveal } from './secret-reveal/secret-reveal' export { WORDMARK_PATHS, WORDMARK_VIEW_BOX } from './sim-wordmark/paths' -export { SimWordmark, type SimWordmarkProps } from './sim-wordmark/sim-wordmark' +export { SimWordmark } from './sim-wordmark/sim-wordmark' export { Skeleton } from './skeleton/skeleton' export { Slider } from './slider/slider' export { LogoPage, - type LogoPageProps, PAGE_CONTENT_WIDTH, PAGE_GUTTER, StatusPageContent, @@ -235,14 +174,10 @@ export { TabStrip, type TabStripDragContext, type TabStripItem, - type TabStripProps, type TabStripSelectionSource, - type TabStripVariant, - tabDropIndex, tabStripItemSelector, - tabStripWheelPosition, } from './tab-strip/tab-strip' -export { TabStripAction, type TabStripActionProps } from './tab-strip/tab-strip-action' +export { TabStripAction } from './tab-strip/tab-strip-action' export { Table, TableBody, @@ -253,24 +188,16 @@ export { TableHeader, TableRow, } from './table/table' -export { type FileInputOptions, TagInput, type TagItem } from './tag-input/tag-input' +export { TagInput, type TagItem } from './tag-input/tag-input' export { Textarea } from './textarea/textarea' -export { TimePicker, timePickerVariants } from './time-picker/time-picker' +export { TimePicker } from './time-picker/time-picker' export { ToastProvider, toast, useToast } from './toast/toast' export { - clamp, FloatingTooltip, - type FloatingTooltipHandlers, - type FloatingTooltipState, - isFocusVisible, isTextClipped, Tooltip, - type UseFloatingTooltipOptions, useFloatingTooltip, useIsOverflowing, } from './tooltip/tooltip' -export { - UploadPreviewButton, - type UploadPreviewButtonProps, -} from './upload-preview-button/upload-preview-button' +export { UploadPreviewButton } from './upload-preview-button/upload-preview-button' export { Wizard } from './wizard/wizard' diff --git a/packages/emcn/src/components/info-card/info-card.tsx b/packages/emcn/src/components/info-card/info-card.tsx index 11fd521792c..2913ce6054e 100644 --- a/packages/emcn/src/components/info-card/info-card.tsx +++ b/packages/emcn/src/components/info-card/info-card.tsx @@ -23,7 +23,7 @@ import * as React from 'react' import { Check } from '../../icons' import { cn } from '../../lib/cn' -export interface InfoCardProps extends React.HTMLAttributes {} +interface InfoCardProps extends React.HTMLAttributes {} /** * Root container. Owns the chip-input chrome — same tokens as `Input` and @@ -43,7 +43,7 @@ const InfoCard = React.forwardRef(({ className, . InfoCard.displayName = 'InfoCard' -export interface InfoCardListProps extends React.HTMLAttributes { +interface InfoCardListProps extends React.HTMLAttributes { /** * Tailwind class controlling the scrollable region's max height. * @default 'max-h-[200px]' @@ -69,7 +69,7 @@ const InfoCardList = React.forwardRef( InfoCardList.displayName = 'InfoCardList' -export interface InfoCardItemProps extends React.LiHTMLAttributes { +interface InfoCardItemProps extends React.LiHTMLAttributes { /** * Leading glyph. Defaults to `Check`. Pass `null` to omit. */ diff --git a/packages/emcn/src/components/input-otp/input-otp.tsx b/packages/emcn/src/components/input-otp/input-otp.tsx index cf5da3a0569..128d9b5abbd 100644 --- a/packages/emcn/src/components/input-otp/input-otp.tsx +++ b/packages/emcn/src/components/input-otp/input-otp.tsx @@ -22,13 +22,11 @@ * @see InputOTP - Root component wrapping OTPInput * @see InputOTPGroup - Groups slots together * @see InputOTPSlot - Individual digit slot - * @see InputOTPSeparator - Visual separator between groups */ 'use client' import * as React from 'react' import { OTPInput, OTPInputContext } from 'input-otp' -import { Minus } from '../../icons' import { cn } from '../../lib/cn' /** @@ -94,17 +92,4 @@ const InputOTPSlot = React.forwardRef< }) InputOTPSlot.displayName = 'InputOTPSlot' -/** - * Visual separator between OTP slot groups. - */ -const InputOTPSeparator = React.forwardRef< - React.ElementRef<'div'>, - React.ComponentPropsWithoutRef<'div'> ->(({ ...props }, ref) => ( -
- -
-)) -InputOTPSeparator.displayName = 'InputOTPSeparator' - -export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } +export { InputOTP, InputOTPGroup, InputOTPSlot } diff --git a/packages/emcn/src/components/input/input.tsx b/packages/emcn/src/components/input/input.tsx index fe0a4c1806a..2382fd777b7 100644 --- a/packages/emcn/src/components/input/input.tsx +++ b/packages/emcn/src/components/input/input.tsx @@ -31,7 +31,7 @@ import { cn } from '../../lib/cn' const INPUT_CLASS = 'flex w-full touch-manipulation rounded-sm border border-[var(--border-1)] bg-[var(--surface-5)] px-2 py-1.5 font-sans text-sm text-[var(--text-primary)] [letter-spacing:inherit] transition-colors placeholder:text-[var(--text-muted)] outline-hidden disabled:cursor-not-allowed disabled:opacity-50 scroll-pr-1' -export type InputProps = React.InputHTMLAttributes +type InputProps = React.InputHTMLAttributes /** Minimal input component matching the textarea styling. */ const Input = React.forwardRef( diff --git a/packages/emcn/src/components/label/label.tsx b/packages/emcn/src/components/label/label.tsx index 412f12e8dc7..0b8f651cc7d 100644 --- a/packages/emcn/src/components/label/label.tsx +++ b/packages/emcn/src/components/label/label.tsx @@ -3,7 +3,7 @@ import * as LabelPrimitive from '@radix-ui/react-label' import { cn } from '../../lib/cn' -export interface LabelProps extends React.ComponentPropsWithoutRef {} +interface LabelProps extends React.ComponentPropsWithoutRef {} /** * EMCN Label component built on Radix UI Label primitive. diff --git a/packages/emcn/src/components/modal/modal.tsx b/packages/emcn/src/components/modal/modal.tsx index bbf47f5e36e..833d4fabb62 100644 --- a/packages/emcn/src/components/modal/modal.tsx +++ b/packages/emcn/src/components/modal/modal.tsx @@ -424,8 +424,7 @@ const MODAL_SIZES = { export type ModalSize = keyof typeof MODAL_SIZES -export interface ModalContentProps - extends React.ComponentPropsWithoutRef { +interface ModalContentProps extends React.ComponentPropsWithoutRef { /** Backdrop styling for specialized surfaces such as media viewers. */ overlayClassName?: string /** @@ -893,8 +892,5 @@ export { ModalTabsTrigger, ModalTabsContent, ModalFooter, - ModalPortal, - ModalOverlay, ModalClose, - MODAL_SIZES, } diff --git a/packages/emcn/src/components/popover/popover.tsx b/packages/emcn/src/components/popover/popover.tsx index a81f0c02686..a0024cc5885 100644 --- a/packages/emcn/src/components/popover/popover.tsx +++ b/packages/emcn/src/components/popover/popover.tsx @@ -184,7 +184,7 @@ const usePopoverContext = () => { return context } -export interface PopoverProps extends PopoverPrimitive.PopoverProps { +interface PopoverProps extends PopoverPrimitive.PopoverProps { /** * Size variant of the popover * - sm: 11px text, compact spacing (for logs, notifications, context menus) diff --git a/packages/emcn/src/components/progress-item/progress-item.tsx b/packages/emcn/src/components/progress-item/progress-item.tsx index fe08f64dde3..165cbbb4792 100644 --- a/packages/emcn/src/components/progress-item/progress-item.tsx +++ b/packages/emcn/src/components/progress-item/progress-item.tsx @@ -26,7 +26,7 @@ function StatusIcon({ status }: { status: ProgressStatus }) { return } -export interface ProgressItemProps +interface ProgressItemProps extends Omit, 'title'>, VariantProps { status: ProgressStatus @@ -100,4 +100,4 @@ const ProgressItem = forwardRef(function Prog }) ProgressItem.displayName = 'ProgressItem' -export { ProgressItem, progressItemVariants } +export { ProgressItem } diff --git a/packages/emcn/src/components/tab-strip/tab-strip.tsx b/packages/emcn/src/components/tab-strip/tab-strip.tsx index c79c29d9e8e..3c0d08497f3 100644 --- a/packages/emcn/src/components/tab-strip/tab-strip.tsx +++ b/packages/emcn/src/components/tab-strip/tab-strip.tsx @@ -166,7 +166,7 @@ export interface TabStripDragContext { * it suits a panel header that sits above content it does not own. */ /** Underline tabs use an active bottom indicator without a filled tab surface. */ -export type TabStripVariant = 'attached' | 'floating' | 'underline' +type TabStripVariant = 'attached' | 'floating' | 'underline' /** How a tab selection was initiated. */ export type TabStripSelectionSource = 'pointer' | 'keyboard' @@ -268,7 +268,7 @@ export function tabStripItemSelector(id: string): string { } /** Final horizontal position for a wheel gesture, or null when it cannot move the strip. */ -export function tabStripWheelPosition( +function tabStripWheelPosition( scrollLeft: number, scrollWidth: number, clientWidth: number, diff --git a/packages/emcn/src/components/table/table.tsx b/packages/emcn/src/components/table/table.tsx index 6717785bc2e..daa661774d9 100644 --- a/packages/emcn/src/components/table/table.tsx +++ b/packages/emcn/src/components/table/table.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { cva, type VariantProps } from 'class-variance-authority' import { cn } from '../../lib/cn' -export const tableVariants = cva('w-full caption-bottom text-small', { +const tableVariants = cva('w-full caption-bottom text-small', { variants: { variant: { default: '', diff --git a/packages/emcn/src/components/tag-input/tag-input.tsx b/packages/emcn/src/components/tag-input/tag-input.tsx index aee34b89725..7dee9855621 100644 --- a/packages/emcn/src/components/tag-input/tag-input.tsx +++ b/packages/emcn/src/components/tag-input/tag-input.tsx @@ -93,7 +93,7 @@ export interface TagItem { /** * Options for enabling file input functionality. */ -export interface FileInputOptions { +interface FileInputOptions { /** Whether file input is enabled */ enabled: boolean /** Accepted file types (default: '.csv,.txt,text/csv,text/plain') */ @@ -517,4 +517,4 @@ const TagInput = React.forwardRef( TagInput.displayName = 'TagInput' -export { TagInput, tagInputVariants } +export { TagInput } diff --git a/packages/emcn/src/components/time-picker/time-picker.tsx b/packages/emcn/src/components/time-picker/time-picker.tsx index 009f2815beb..2494a3d707e 100644 --- a/packages/emcn/src/components/time-picker/time-picker.tsx +++ b/packages/emcn/src/components/time-picker/time-picker.tsx @@ -308,4 +308,4 @@ const TimePicker = React.forwardRef( TimePicker.displayName = 'TimePicker' -export { TimePicker, timePickerVariants } +export { TimePicker } diff --git a/packages/emcn/src/components/tooltip/tooltip.tsx b/packages/emcn/src/components/tooltip/tooltip.tsx index 6a7195b8c78..e314be8dc00 100644 --- a/packages/emcn/src/components/tooltip/tooltip.tsx +++ b/packages/emcn/src/components/tooltip/tooltip.tsx @@ -389,7 +389,7 @@ function isVisiblyRendered(element: HTMLElement): boolean { } /** Clamps `value` to the inclusive `[min, max]` range. */ -export function clamp(value: number, min: number, max: number): number { +function clamp(value: number, min: number, max: number): number { return Math.max(min, Math.min(max, value)) } @@ -406,7 +406,7 @@ function quantize(value: number): number { * mouse click). Used to keep the tooltip from re-appearing/repositioning when the trigger is * clicked. Falls back to `true` where the selector can't be queried. */ -export function isFocusVisible(element: Element): boolean { +function isFocusVisible(element: Element): boolean { try { return element.matches(':focus-visible') } catch { diff --git a/packages/emcn/src/hooks/use-copy-to-clipboard.ts b/packages/emcn/src/hooks/use-copy-to-clipboard.ts index d8fc0397ae9..b5eb0dae282 100644 --- a/packages/emcn/src/hooks/use-copy-to-clipboard.ts +++ b/packages/emcn/src/hooks/use-copy-to-clipboard.ts @@ -7,7 +7,7 @@ interface UseCopyToClipboardOptions { resetMs?: number } -export interface DeferredClipboardContent { +interface DeferredClipboardContent { /** Safe text that can be written immediately when promise-backed writes are unavailable. */ fallback: string /** Produces the preferred text when the browser supports promise-backed clipboard items. */ diff --git a/packages/emcn/src/icons/animate/pills-ring.module.css b/packages/emcn/src/icons/animate/pills-ring.module.css deleted file mode 100644 index 5ba88317291..00000000000 --- a/packages/emcn/src/icons/animate/pills-ring.module.css +++ /dev/null @@ -1,28 +0,0 @@ -/** - * PillsRing icon animation - * Pills arranged in a ring fade in/out sequentially, - * creating a chasing spinner effect. - * Individual pill delays are set via inline style. - */ - -@keyframes pill-fade { - 0%, - 50%, - 100% { - opacity: 0.15; - } - 25% { - opacity: 1; - } -} - -.animated-pills-ring-svg .pill { - animation: pill-fade 1.2s ease-in-out infinite; - will-change: opacity; -} - -@media (prefers-reduced-motion: reduce) { - .animated-pills-ring-svg .pill { - animation: none; - } -} diff --git a/packages/emcn/src/icons/fingerprint.tsx b/packages/emcn/src/icons/fingerprint.tsx deleted file mode 100644 index d801a4c3609..00000000000 --- a/packages/emcn/src/icons/fingerprint.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { SVGProps } from 'react' - -/** - * Fingerprint icon component — unique constraint indicator - * @param props - SVG properties including className, fill, etc. - */ -export function Fingerprint(props: SVGProps) { - return ( - - ) -} diff --git a/packages/emcn/src/icons/index.ts b/packages/emcn/src/icons/index.ts index f6234788e00..ec59f6d3006 100644 --- a/packages/emcn/src/icons/index.ts +++ b/packages/emcn/src/icons/index.ts @@ -65,7 +65,6 @@ export { File } from './file' export { FileText } from './file-text' export { FileX } from './file-x' export { Files } from './files' -export { Fingerprint } from './fingerprint' export { Folder } from './folder' export { FolderCode } from './folder-code' export { FolderInput } from './folder-input' @@ -85,7 +84,6 @@ export { Highlighter } from './highlighter' export { Home } from './home' export { HtmlIcon } from './html-icon' export { ImageUp } from './image-up' -export { InfinityIcon, InfinityIcon as Infinity } from './infinity' export { Integration } from './integration' export { Italic } from './italic' export { JsonIcon } from './json-icon' @@ -109,7 +107,6 @@ export { MarkdownIcon } from './markdown-icon' export { Menu } from './menu' export { MessageSquareText } from './message-square-text' export { Mic } from './mic' -export { MicOff } from './mic-off' export { Minus } from './minus' export { Moon } from './moon' export { MoreHorizontal } from './more-horizontal' @@ -118,14 +115,11 @@ export { Music } from './music' export { NoWrap } from './no-wrap' export { Palette } from './palette' export { PanelLeft } from './panel-left' -export { PanelRight } from './panel-right' export { Paperclip } from './paperclip' -export { Pause } from './pause' export { PdfIcon } from './pdf-icon' export { Pencil } from './pencil' export { Phone } from './phone' export { Pilcrow } from './pilcrow' -export { PillsRing } from './pills-ring' export { Pin } from './pin' export { PinOff } from './pin-off' export { Play, PlayOutline } from './play' @@ -147,7 +141,6 @@ export { Settings } from './settings' export { Share } from './share' export { ShieldCheck } from './shield-check' export { Shuffle } from './shuffle' -export { Sim } from './sim' export { SkipForward } from './skip-forward' export { Slash } from './slash' export { SlidersHorizontal } from './sliders-horizontal' @@ -181,7 +174,6 @@ export { Undo } from './undo' export { Unlink } from './unlink' export { Unlock } from './unlock' export { Upload } from './upload' -export { User } from './user' export { Users } from './users' export { VideoIcon } from './video-icon' export { Wand } from './wand' diff --git a/packages/emcn/src/icons/infinity.tsx b/packages/emcn/src/icons/infinity.tsx deleted file mode 100644 index 8a0bd923eff..00000000000 --- a/packages/emcn/src/icons/infinity.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { SVGProps } from 'react' - -/** - * Infinity icon component - lemniscate drawn as one continuous stroke - * @param props - SVG properties including className, fill, etc. - */ -export function InfinityIcon(props: SVGProps) { - return ( - - ) -} diff --git a/packages/emcn/src/icons/layout.tsx b/packages/emcn/src/icons/layout.tsx index c2eea996ffe..6ea0e9d188f 100644 --- a/packages/emcn/src/icons/layout.tsx +++ b/packages/emcn/src/icons/layout.tsx @@ -2,7 +2,7 @@ import type { SVGProps } from 'react' import { cn } from '../lib/cn' import styles from './animate/layout.module.css' -export type LayoutAnimationVariant = 'clockwise' | 'counterclockwise' +type LayoutAnimationVariant = 'clockwise' | 'counterclockwise' export interface LayoutProps extends SVGProps { /** diff --git a/packages/emcn/src/icons/mic-off.tsx b/packages/emcn/src/icons/mic-off.tsx deleted file mode 100644 index a434155ad7d..00000000000 --- a/packages/emcn/src/icons/mic-off.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { SVGProps } from 'react' - -/** - * MicOff icon component - microphone with diagonal strike-through for the muted state - * @param props - SVG properties including className, fill, etc. - */ -export function MicOff(props: SVGProps) { - return ( - - ) -} diff --git a/packages/emcn/src/icons/panel-right.tsx b/packages/emcn/src/icons/panel-right.tsx deleted file mode 100644 index b862215be85..00000000000 --- a/packages/emcn/src/icons/panel-right.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { SVGProps } from 'react' - -/** - * PanelRight icon component - sidebar panel docked to the right edge - * @param props - SVG properties including className, fill, etc. - */ -export function PanelRight(props: SVGProps) { - return ( - - ) -} diff --git a/packages/emcn/src/icons/pause.tsx b/packages/emcn/src/icons/pause.tsx deleted file mode 100644 index abb83672a77..00000000000 --- a/packages/emcn/src/icons/pause.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { SVGProps } from 'react' - -/** - * Pause icon component - two vertical bars - * @param props - SVG properties including className, fill, etc. - */ -export function Pause(props: SVGProps) { - return ( - - ) -} diff --git a/packages/emcn/src/icons/pills-ring.tsx b/packages/emcn/src/icons/pills-ring.tsx deleted file mode 100644 index c1ba467ad2b..00000000000 --- a/packages/emcn/src/icons/pills-ring.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import type { SVGProps } from 'react' -import { cn } from '../lib/cn' -import styles from './animate/pills-ring.module.css' - -export interface PillsRingProps extends SVGProps { - /** - * Enable the chasing fade animation - * @default false - */ - animate?: boolean -} - -const PILL_COUNT = 8 -const DURATION_S = 1.2 - -/** - * Ring of pill-shaped elements with optional chasing fade animation. - * Static render shows pills at graded opacities; animated render - * fades them sequentially around the ring via CSS module keyframes. - * @param props - SVG properties including className, animate, etc. - */ -export function PillsRing({ animate = false, className, ...props }: PillsRingProps) { - const svgClassName = cn(animate && styles['animated-pills-ring-svg'], className) - - return ( - - ) -} diff --git a/packages/emcn/src/icons/sim.tsx b/packages/emcn/src/icons/sim.tsx deleted file mode 100644 index c43b45e0b6b..00000000000 --- a/packages/emcn/src/icons/sim.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { SVGProps } from 'react' - -/** - * Sim brand logo icon component - * @param props - SVG properties including className, fill, etc. - */ -export function Sim(props: SVGProps) { - return ( - - ) -} diff --git a/packages/emcn/src/icons/user.tsx b/packages/emcn/src/icons/user.tsx deleted file mode 100644 index 3241e182688..00000000000 --- a/packages/emcn/src/icons/user.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { SVGProps } from 'react' - -/** - * User icon component - single person silhouette - * @param props - SVG properties including className, fill, etc. - */ -export function User(props: SVGProps) { - return ( - - ) -} diff --git a/packages/emcn/src/index.ts b/packages/emcn/src/index.ts index f89fbb7afd2..57ad244f26f 100644 --- a/packages/emcn/src/index.ts +++ b/packages/emcn/src/index.ts @@ -4,7 +4,7 @@ export * from './components' * glyph). Like `Table` above, this explicit re-export resolves the barrel to * the COMPONENT; the icon stays available from `@sim/emcn/icons`. */ -export { Calendar, type CalendarProps } from './components/calendar/calendar' +export { Calendar } from './components/calendar/calendar' export * from './components/charts' /** * `Code` exists in BOTH `./components` (the code editor) and `./icons` (a @@ -19,8 +19,6 @@ export { } from './components/code/code' export { SCROLL_FADE_BAND_PX, - type ScrollEdges, - type ScrollEdgesX, scrollFadeAttributes, scrollFadeClass, scrollFadeXClass, @@ -41,7 +39,6 @@ export { TableHead, TableHeader, TableRow, - tableVariants, } from './components/table/table' export { type ClipboardContent, @@ -52,5 +49,5 @@ export { usePrefersReducedMotion } from './hooks/use-prefers-reduced-motion' export { useScrollEdges } from './hooks/use-scroll-edges' export * from './icons' export { cn } from './lib/cn' -export { handleKeyboardActivation, isKeyboardActivation } from './lib/keyboard' +export { handleKeyboardActivation } from './lib/keyboard' export { bindPreviewHorizontalWheel, bindPreviewWheelZoom } from './lib/preview-wheel-zoom' diff --git a/packages/emcn/src/lib/keyboard.ts b/packages/emcn/src/lib/keyboard.ts index 1d91eda8a3a..4b52c0d7fd5 100644 --- a/packages/emcn/src/lib/keyboard.ts +++ b/packages/emcn/src/lib/keyboard.ts @@ -4,7 +4,7 @@ interface KeyboardActivationOptions { stopPropagation?: boolean } -export function isKeyboardActivation(event: KeyboardEvent) { +function isKeyboardActivation(event: KeyboardEvent) { return event.key === 'Enter' || event.key === ' ' } diff --git a/packages/platform-authz/src/rooms.ts b/packages/platform-authz/src/rooms.ts index f2e86ff3bbd..cc779ff8202 100644 --- a/packages/platform-authz/src/rooms.ts +++ b/packages/platform-authz/src/rooms.ts @@ -7,13 +7,13 @@ import { resolveEffectiveWorkspacePermission, } from './workspace' -export type { PermissionType, RoomRef, RoomType } +export type { PermissionType, RoomRef } /** * The owning workspace of a room, plus the org that owns that workspace — the * exact inputs {@link resolveEffectiveWorkspacePermission} needs. */ -export interface RoomWorkspace { +interface RoomWorkspace { workspaceId: string workspaceOrganizationId: string | null } @@ -24,7 +24,7 @@ export interface RoomWorkspace { * result). One resolver per workspace-scoped {@link RoomType}; this is the single * place a new such room type declares its resource→workspace lookup. */ -export type RoomWorkspaceResolver = (roomId: string) => Promise +type RoomWorkspaceResolver = (roomId: string) => Promise async function resolveWorkspaceRoomWorkspace(workspaceId: string): Promise { const [row] = await db diff --git a/packages/platform-authz/src/workflow.ts b/packages/platform-authz/src/workflow.ts index 7e50f880a2c..18b253e838a 100644 --- a/packages/platform-authz/src/workflow.ts +++ b/packages/platform-authz/src/workflow.ts @@ -6,8 +6,6 @@ import { resolveEffectiveWorkspacePermission, } from './workspace' -export type { PermissionType } - export type ActiveWorkflowRecord = typeof workflow.$inferSelect export interface ActiveWorkflowContext { @@ -50,16 +48,6 @@ export async function getActiveWorkflowRecord( return context?.workflow ?? null } -export async function assertActiveWorkflowContext( - workflowId: string -): Promise { - const context = await getActiveWorkflowContext(workflowId) - if (!context) { - throw new Error(`Active workflow not found: ${workflowId}`) - } - return context -} - type WorkflowRecord = typeof workflow.$inferSelect export class WorkflowLockedError extends Error { @@ -80,7 +68,7 @@ export class FolderLockedError extends Error { } } -export interface LockStatus { +interface LockStatus { locked: boolean directLocked: boolean inheritedLocked: boolean @@ -88,7 +76,7 @@ export interface LockStatus { lockedFolderId: string | null } -export async function getFolderLockStatus(folderId: string | null): Promise { +async function getFolderLockStatus(folderId: string | null): Promise { if (!folderId) { return { locked: false, @@ -145,7 +133,7 @@ export async function getFolderLockStatus(folderId: string | null): Promise { +async function getWorkflowLockStatus(workflowId: string): Promise { const [wf] = await db .select({ locked: workflow.locked, diff --git a/packages/realtime-protocol/src/constants.ts b/packages/realtime-protocol/src/constants.ts index 1bae03b498c..d342834cda0 100644 --- a/packages/realtime-protocol/src/constants.ts +++ b/packages/realtime-protocol/src/constants.ts @@ -16,8 +16,6 @@ export const BLOCK_OPERATIONS = { TOGGLE_HANDLES: 'toggle-handles', } as const -export type BlockOperation = (typeof BLOCK_OPERATIONS)[keyof typeof BLOCK_OPERATIONS] - export const BLOCKS_OPERATIONS = { BATCH_UPDATE_POSITIONS: 'batch-update-positions', BATCH_ADD_BLOCKS: 'batch-add-blocks', @@ -28,28 +26,20 @@ export const BLOCKS_OPERATIONS = { BATCH_TOGGLE_LOCKED: 'batch-toggle-locked', } as const -export type BlocksOperation = (typeof BLOCKS_OPERATIONS)[keyof typeof BLOCKS_OPERATIONS] - export const EDGE_OPERATIONS = { ADD: 'add', REMOVE: 'remove', } as const -export type EdgeOperation = (typeof EDGE_OPERATIONS)[keyof typeof EDGE_OPERATIONS] - export const EDGES_OPERATIONS = { BATCH_ADD_EDGES: 'batch-add-edges', BATCH_REMOVE_EDGES: 'batch-remove-edges', } as const -export type EdgesOperation = (typeof EDGES_OPERATIONS)[keyof typeof EDGES_OPERATIONS] - export const SUBFLOW_OPERATIONS = { UPDATE: 'update', } as const -export type SubflowOperation = (typeof SUBFLOW_OPERATIONS)[keyof typeof SUBFLOW_OPERATIONS] - export const VARIABLE_OPERATIONS = { ADD: 'add', REMOVE: 'remove', @@ -62,16 +52,12 @@ export const WORKFLOW_OPERATIONS = { REPLACE_STATE: 'replace-state', } as const -export type WorkflowOperation = (typeof WORKFLOW_OPERATIONS)[keyof typeof WORKFLOW_OPERATIONS] - export const SUBBLOCK_OPERATIONS = { UPDATE: 'subblock-update', BATCH_UPDATE: 'subblock-batch-update', UPDATE_WITH_CANONICAL_MODES: 'subblock-update-with-canonical-modes', } as const -export type SubblockOperation = (typeof SUBBLOCK_OPERATIONS)[keyof typeof SUBBLOCK_OPERATIONS] - export const OPERATION_TARGETS = { BLOCK: 'block', BLOCKS: 'blocks', diff --git a/packages/realtime-protocol/src/rooms.ts b/packages/realtime-protocol/src/rooms.ts index c1751ba1a04..a05d881f50d 100644 --- a/packages/realtime-protocol/src/rooms.ts +++ b/packages/realtime-protocol/src/rooms.ts @@ -58,7 +58,7 @@ export const ROOM_TYPES = { export type RoomType = (typeof ROOM_TYPES)[keyof typeof ROOM_TYPES] /** Every known room type, for exhaustive iteration/validation. */ -export const ALL_ROOM_TYPES = Object.values(ROOM_TYPES) as readonly RoomType[] +const ALL_ROOM_TYPES = Object.values(ROOM_TYPES) as readonly RoomType[] /** * The presence-free, workspace-scoped live-list rooms. They share one contract derived entirely @@ -79,7 +79,7 @@ export interface RoomRef { } /** Type guard: whether an arbitrary string is a known {@link RoomType}. */ -export function isRoomType(value: string): value is RoomType { +function isRoomType(value: string): value is RoomType { return (ALL_ROOM_TYPES as readonly string[]).includes(value) } diff --git a/packages/realtime-protocol/src/schemas.ts b/packages/realtime-protocol/src/schemas.ts index 5de6d60397a..2cb07c02595 100644 --- a/packages/realtime-protocol/src/schemas.ts +++ b/packages/realtime-protocol/src/schemas.ts @@ -38,7 +38,7 @@ const AutoConnectEdgeSchema = z.object({ const CanonicalModeSchema = z.enum(['basic', 'advanced']) -export const BlockOperationSchema = z.object({ +const BlockOperationSchema = z.object({ operation: z.enum([ BLOCK_OPERATIONS.UPDATE_POSITION, BLOCK_OPERATIONS.UPDATE_NAME, @@ -77,7 +77,7 @@ export const BlockOperationSchema = z.object({ operationId: z.string().optional(), }) -export const BatchPositionUpdateSchema = z.object({ +const BatchPositionUpdateSchema = z.object({ operation: z.literal(BLOCKS_OPERATIONS.BATCH_UPDATE_POSITIONS), target: z.literal(OPERATION_TARGETS.BLOCKS), payload: z.object({ @@ -92,7 +92,7 @@ export const BatchPositionUpdateSchema = z.object({ operationId: z.string().optional(), }) -export const EdgeOperationSchema = z.object({ +const EdgeOperationSchema = z.object({ operation: z.enum([EDGE_OPERATIONS.ADD, EDGE_OPERATIONS.REMOVE]), target: z.literal(OPERATION_TARGETS.EDGE), payload: z.object({ @@ -106,7 +106,7 @@ export const EdgeOperationSchema = z.object({ operationId: z.string().optional(), }) -export const SubflowOperationSchema = z.object({ +const SubflowOperationSchema = z.object({ operation: z.literal(SUBFLOW_OPERATIONS.UPDATE), target: z.literal(OPERATION_TARGETS.SUBFLOW), payload: z.object({ @@ -118,7 +118,7 @@ export const SubflowOperationSchema = z.object({ operationId: z.string().optional(), }) -export const VariableOperationSchema = z.union([ +const VariableOperationSchema = z.union([ z.object({ operation: z.literal(VARIABLE_OPERATIONS.ADD), target: z.literal(OPERATION_TARGETS.VARIABLE), @@ -143,7 +143,7 @@ export const VariableOperationSchema = z.union([ }), ]) -export const WorkflowStateOperationSchema = z.object({ +const WorkflowStateOperationSchema = z.object({ operation: z.literal(WORKFLOW_OPERATIONS.REPLACE_STATE), target: z.literal(OPERATION_TARGETS.WORKFLOW), payload: z.object({ @@ -153,7 +153,7 @@ export const WorkflowStateOperationSchema = z.object({ operationId: z.string().optional(), }) -export const SubblockOperationSchema = z.object({ +const SubblockOperationSchema = z.object({ operation: z.literal(SUBBLOCK_OPERATIONS.BATCH_UPDATE), target: z.literal(OPERATION_TARGETS.SUBBLOCK), payload: z.object({ @@ -175,7 +175,7 @@ export const SubblockOperationSchema = z.object({ * A `tool-input` keys its tools' modes by array position, so a reorder or removal must persist * both together or a failure between two separate writes leaves modes on the wrong tools. */ -export const SubblockCanonicalModesUpdateSchema = z.object({ +const SubblockCanonicalModesUpdateSchema = z.object({ operation: z.literal(SUBBLOCK_OPERATIONS.UPDATE_WITH_CANONICAL_MODES), target: z.literal(OPERATION_TARGETS.SUBBLOCK), payload: z.object({ @@ -188,7 +188,7 @@ export const SubblockCanonicalModesUpdateSchema = z.object({ operationId: z.string().optional(), }) -export const BatchAddBlocksSchema = z.object({ +const BatchAddBlocksSchema = z.object({ operation: z.literal(BLOCKS_OPERATIONS.BATCH_ADD_BLOCKS), target: z.literal(OPERATION_TARGETS.BLOCKS), payload: z.object({ @@ -202,7 +202,7 @@ export const BatchAddBlocksSchema = z.object({ operationId: z.string().optional(), }) -export const BatchRemoveBlocksSchema = z.object({ +const BatchRemoveBlocksSchema = z.object({ operation: z.literal(BLOCKS_OPERATIONS.BATCH_REMOVE_BLOCKS), target: z.literal(OPERATION_TARGETS.BLOCKS), payload: z.object({ @@ -212,7 +212,7 @@ export const BatchRemoveBlocksSchema = z.object({ operationId: z.string().optional(), }) -export const BatchRemoveEdgesSchema = z.object({ +const BatchRemoveEdgesSchema = z.object({ operation: z.literal(EDGES_OPERATIONS.BATCH_REMOVE_EDGES), target: z.literal(OPERATION_TARGETS.EDGES), payload: z.object({ @@ -222,7 +222,7 @@ export const BatchRemoveEdgesSchema = z.object({ operationId: z.string().optional(), }) -export const BatchAddEdgesSchema = z.object({ +const BatchAddEdgesSchema = z.object({ operation: z.literal(EDGES_OPERATIONS.BATCH_ADD_EDGES), target: z.literal(OPERATION_TARGETS.EDGES), payload: z.object({ @@ -240,7 +240,7 @@ export const BatchAddEdgesSchema = z.object({ operationId: z.string().optional(), }) -export const BatchToggleEnabledSchema = z.object({ +const BatchToggleEnabledSchema = z.object({ operation: z.literal(BLOCKS_OPERATIONS.BATCH_TOGGLE_ENABLED), target: z.literal(OPERATION_TARGETS.BLOCKS), payload: z.object({ @@ -251,7 +251,7 @@ export const BatchToggleEnabledSchema = z.object({ operationId: z.string().optional(), }) -export const BatchToggleHandlesSchema = z.object({ +const BatchToggleHandlesSchema = z.object({ operation: z.literal(BLOCKS_OPERATIONS.BATCH_TOGGLE_HANDLES), target: z.literal(OPERATION_TARGETS.BLOCKS), payload: z.object({ @@ -262,7 +262,7 @@ export const BatchToggleHandlesSchema = z.object({ operationId: z.string().optional(), }) -export const BatchToggleLockedSchema = z.object({ +const BatchToggleLockedSchema = z.object({ operation: z.literal(BLOCKS_OPERATIONS.BATCH_TOGGLE_LOCKED), target: z.literal(OPERATION_TARGETS.BLOCKS), payload: z.object({ @@ -273,7 +273,7 @@ export const BatchToggleLockedSchema = z.object({ operationId: z.string().optional(), }) -export const BatchUpdateParentSchema = z.object({ +const BatchUpdateParentSchema = z.object({ operation: z.literal(BLOCKS_OPERATIONS.BATCH_UPDATE_PARENT), target: z.literal(OPERATION_TARGETS.BLOCKS), payload: z.object({ diff --git a/packages/security/src/ip.ts b/packages/security/src/ip.ts index 1acb82e1930..dd3111f75a8 100644 --- a/packages/security/src/ip.ts +++ b/packages/security/src/ip.ts @@ -7,7 +7,7 @@ interface TrustedNetwork { prefixLength: number } -export interface ForwardedIpHeaders { +interface ForwardedIpHeaders { get(name: string): string | null } diff --git a/packages/terminal-protocol/src/index.ts b/packages/terminal-protocol/src/index.ts index b3de2a9fc85..50ff3ae8095 100644 --- a/packages/terminal-protocol/src/index.ts +++ b/packages/terminal-protocol/src/index.ts @@ -24,25 +24,6 @@ import { truncate } from '@sim/utils/string' /** The single tool the model calls; what it does is in `operation`. */ export const TERMINAL_TOOL_NAME = 'terminal' -/** - * Names this surface used to expose, one tool per operation. Kept so rows in - * conversations recorded before the consolidation still render with a real - * title instead of a humanized tool name. - */ -export const LEGACY_TERMINAL_TOOL_NAMES = [ - 'terminal_run', - 'terminal_input', - 'terminal_read', - 'terminal_kill', - 'terminal_cwd', - 'terminal_list', - 'terminal_new', - 'terminal_switch', - 'terminal_close', -] as const - -export type LegacyTerminalToolName = (typeof LEGACY_TERMINAL_TOOL_NAMES)[number] - /** * What one `terminal` call does. * @@ -52,7 +33,7 @@ export type LegacyTerminalToolName = (typeof LEGACY_TERMINAL_TOOL_NAMES)[number] * inspects them rather than Sim mirroring them into the tab strip. `handoff` * gives the terminal to the user and waits. */ -export const TERMINAL_OPERATIONS = [ +const TERMINAL_OPERATIONS = [ 'run', 'read', 'input', @@ -128,7 +109,7 @@ export const PROMPT_IDLE_MS = 2_500 export const MAX_INPUT_KEYS = 20 /** Control keys the agent may send to a running foreground process. */ -export const TERMINAL_CONTROL_KEYS = [ +const TERMINAL_CONTROL_KEYS = [ 'ctrl-c', 'ctrl-d', 'ctrl-z', @@ -149,7 +130,7 @@ export function isTerminalControlKey(value: unknown): value is TerminalControlKe return typeof value === 'string' && TERMINAL_CONTROL_KEY_SET.has(value) } -export type TerminalSignal = 'SIGINT' | 'SIGTERM' | 'SIGKILL' +type TerminalSignal = 'SIGINT' | 'SIGTERM' | 'SIGKILL' /** * Arguments for every operation, flattened into one object. @@ -197,17 +178,12 @@ export interface TerminalToolArgs { reason?: string } -export interface TerminalToolCall { - operation: TerminalOperation - args?: TerminalToolArgs -} - /** * How a `terminal_run` ended. Only `completed` means the command is finished * and the terminal is free; in every other case it is still running and still * holds the foreground. */ -export type TerminalRunStatus = +type TerminalRunStatus = /** Exited on its own. `exitCode` is set. */ | 'completed' /** @@ -476,12 +452,6 @@ export interface TerminalStartOptions { rows: number } -/** One batch of PTY bytes, tagged with the terminal that produced it. */ -export interface TerminalOutputEvent { - terminalId: string - data: string -} - /** * Command lifecycle, used by the panel to attribute rows to the agent and to * show a running indicator. Emitted for user-typed commands too (no diff --git a/packages/testing/src/mocks/billing-plan-logic.ts b/packages/testing/src/mocks/billing-plan-logic.ts index 67b9d09e299..6130d316b8b 100644 --- a/packages/testing/src/mocks/billing-plan-logic.ts +++ b/packages/testing/src/mocks/billing-plan-logic.ts @@ -26,7 +26,7 @@ export function isEnterprise(plan: Plan): boolean { return plan === 'enterprise' } -export function isFree(plan: Plan): boolean { +function isFree(plan: Plan): boolean { return !plan || plan === 'free' } diff --git a/packages/testing/src/mocks/workflow-authz.mock.ts b/packages/testing/src/mocks/workflow-authz.mock.ts index dd829164858..355e4e98ce5 100644 --- a/packages/testing/src/mocks/workflow-authz.mock.ts +++ b/packages/testing/src/mocks/workflow-authz.mock.ts @@ -42,14 +42,6 @@ class MockFolderNotFoundError extends Error { } } -const unlockedStatus = { - locked: false, - directLocked: false, - inheritedLocked: false, - lockedBy: null as 'workflow' | 'folder' | null, - lockedFolderId: null as string | null, -} - /** * Controllable mocks for the `@sim/platform-authz/workflow` entry. * @@ -72,9 +64,6 @@ export const workflowAuthzMockFns = { mockAuthorizeWorkflowByWorkspacePermission: vi.fn(), mockGetActiveWorkflowContext: vi.fn(), mockGetActiveWorkflowRecord: vi.fn(), - mockAssertActiveWorkflowContext: vi.fn(), - mockGetFolderLockStatus: vi.fn().mockResolvedValue(unlockedStatus), - mockGetWorkflowLockStatus: vi.fn().mockResolvedValue(unlockedStatus), mockAssertWorkflowMutable: vi.fn().mockResolvedValue(undefined), mockAssertFolderMutable: vi.fn().mockResolvedValue(undefined), mockIsFolderInWorkspace: vi.fn().mockResolvedValue(true), @@ -94,9 +83,6 @@ export const workflowAuthzMock = { workflowAuthzMockFns.mockAuthorizeWorkflowByWorkspacePermission, getActiveWorkflowContext: workflowAuthzMockFns.mockGetActiveWorkflowContext, getActiveWorkflowRecord: workflowAuthzMockFns.mockGetActiveWorkflowRecord, - assertActiveWorkflowContext: workflowAuthzMockFns.mockAssertActiveWorkflowContext, - getFolderLockStatus: workflowAuthzMockFns.mockGetFolderLockStatus, - getWorkflowLockStatus: workflowAuthzMockFns.mockGetWorkflowLockStatus, assertWorkflowMutable: workflowAuthzMockFns.mockAssertWorkflowMutable, assertFolderMutable: workflowAuthzMockFns.mockAssertFolderMutable, isFolderInWorkspace: workflowAuthzMockFns.mockIsFolderInWorkspace, diff --git a/packages/utils/package.json b/packages/utils/package.json index cfb2304bc18..497cad35e92 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -6,10 +6,6 @@ "type": "module", "license": "Apache-2.0", "exports": { - ".": { - "types": "./src/index.ts", - "default": "./src/index.ts" - }, "./id": { "types": "./src/id.ts", "default": "./src/id.ts" diff --git a/packages/utils/src/client-info.ts b/packages/utils/src/client-info.ts index e623d49d6ae..8e747a6ac4a 100644 --- a/packages/utils/src/client-info.ts +++ b/packages/utils/src/client-info.ts @@ -31,9 +31,9 @@ export const CLIENT_INFO_HEADER = 'x-sim-client-info' * The official Sim clients, as they name themselves on the wire. `mcp` is the * Sim MCP server, which declares itself on each v2 request it dispatches. */ -export const SIM_SURFACES = ['web', 'desktop', 'cli', 'sdk-js', 'sdk-python', 'mcp'] as const +const SIM_SURFACES = ['web', 'desktop', 'cli', 'sdk-js', 'sdk-python', 'mcp'] as const -export type SimSurface = (typeof SIM_SURFACES)[number] +type SimSurface = (typeof SIM_SURFACES)[number] export interface ClientInfo { surface: SimSurface @@ -64,15 +64,15 @@ export interface ClientInfo { * - `webhook`, `schedule`: a run a trigger started rather than a client. * - `unknown`: none of the above, such as an unauthenticated webhook delivery. */ -export const UNDECLARED_SURFACES = ['api', 'internal', 'webhook', 'schedule', 'unknown'] as const +const UNDECLARED_SURFACES = ['api', 'internal', 'webhook', 'schedule', 'unknown'] as const -export type UndeclaredSurface = (typeof UNDECLARED_SURFACES)[number] +type UndeclaredSurface = (typeof UNDECLARED_SURFACES)[number] /** Every surface a request or run can be attributed to. */ -export type RequestSurface = SimSurface | UndeclaredSurface +type RequestSurface = SimSurface | UndeclaredSurface /** How the server established a request's client. */ -export type ClientInfoSource = +type ClientInfoSource = | 'header' | 'user_agent' | 'fetch_metadata' diff --git a/packages/utils/src/formatting.ts b/packages/utils/src/formatting.ts index ccaffa37e85..051bceb13bb 100644 --- a/packages/utils/src/formatting.ts +++ b/packages/utils/src/formatting.ts @@ -97,19 +97,6 @@ export function formatDate(date: Date): string { }) } -/** - * Format a time into a short format - * @param date - The date to format - * @returns A formatted time string in the format "h:mm A" - */ -export function formatTime(date: Date): string { - return date.toLocaleString('en-US', { - hour: 'numeric', - minute: '2-digit', - hour12: true, - }) -} - /** * Format a duration to a human-readable format * @param duration - Duration in milliseconds (number) or as string (e.g., "500ms") diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts deleted file mode 100644 index 639a27acd7d..00000000000 --- a/packages/utils/src/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -export { getErrorMessage, getPostgresErrorCode, toError } from './errors' -export { - formatDate, - formatDateTime, - formatDuration, - formatRelativeTime, - formatTime, - getTimezoneAbbreviation, -} from './formatting' -export { chunkArray, noop, sleep } from './helpers' -export { generateId, generateShortId, isValidUuid } from './id' -export type { EmbedInfo } from './media-embed' -export { getEmbedInfo } from './media-embed' -export { - filterUndefined, - getValueAtPath, - isPlainRecord, - isRecordLike, - omit, - sortObjectKeysDeep, - toRecord, - toRecordOrNull, -} from './object' -export { - assessTextPaste, - countPasteRows, - formatPasteLimit, - PASTE_LIMITS, - type TextPasteAdmission, - type TextPasteAdmissionInput, - type TextPasteRejectionReason, - utf8ByteLength, - utf8ByteLengthRange, -} from './paste' -export { - generateRandomBytes, - generateRandomHex, - generateRandomString, - LOWERCASE_ALPHANUMERIC_ALPHABET, - randomFloat, - randomInt, - randomItem, -} from './random' -export type { BackoffOptions } from './retry' -export { backoffWithJitter, parseRetryAfter } from './retry' -export { normalizeSSODomain } from './sso-domain' -export { - isValidEmailSyntax, - normalizeEmail, - sanitizeForJsonb, - sanitizeValueForJsonb, - truncate, -} from './string' -export { - findWorkflowReferenceTokens, - isLikelyWorkflowReferenceSegment, - splitWorkflowReferenceSegment, - type WorkflowReferenceToken, - type WorkflowReferenceTokenKind, -} from './workflow-references' diff --git a/packages/utils/src/paste.ts b/packages/utils/src/paste.ts index b2d38d4bd07..0f2f6783272 100644 --- a/packages/utils/src/paste.ts +++ b/packages/utils/src/paste.ts @@ -37,7 +37,7 @@ export interface TextPasteAdmissionInput { maxResultCharacters?: number } -export type TextPasteRejectionReason = +type TextPasteRejectionReason = | 'pasted-bytes' | 'pasted-characters' | 'result-bytes' diff --git a/packages/utils/src/random.ts b/packages/utils/src/random.ts index 9beae841c82..c7ff666cbd8 100644 --- a/packages/utils/src/random.ts +++ b/packages/utils/src/random.ts @@ -3,9 +3,6 @@ * Works in all contexts including non-secure (HTTP) browser environments. */ -/** Lowercase alphanumeric characters used as the default alphabet for random strings. */ -export const LOWERCASE_ALPHANUMERIC_ALPHABET = 'abcdefghijklmnopqrstuvwxyz0123456789' - const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' const UINT32_SAMPLE_SPACE_SIZE = 0x100000000 @@ -14,6 +11,7 @@ const UINT32_SAMPLE_SPACE_SIZE = 0x100000000 * Generates cryptographically secure random bytes. * @param length - Number of bytes to generate * @returns Uint8Array of random bytes + * @public check:utils names this as the replacement for `crypto.randomBytes()`. */ export function generateRandomBytes(length: number): Uint8Array { return crypto.getRandomValues(new Uint8Array(length)) diff --git a/packages/utils/src/sandbox-references.ts b/packages/utils/src/sandbox-references.ts index 89d3117c1d2..f12ffeccdc6 100644 --- a/packages/utils/src/sandbox-references.ts +++ b/packages/utils/src/sandbox-references.ts @@ -9,10 +9,9 @@ export const IMMUTABLE_DAYTONA_SNAPSHOT_REF_ERROR = export const SANDBOX_RELEASE_GENERATION_ERROR = 'must be a positive safe integer release generation' export const SANDBOX_PROVIDER_IDS = ['e2b', 'daytona'] as const -export type SandboxProviderName = (typeof SANDBOX_PROVIDER_IDS)[number] /** Leaves three decimal digits for a materializer revision in one safe integer. */ -export const MAX_SANDBOX_RELEASE_GENERATION = Math.floor((Number.MAX_SAFE_INTEGER - 999) / 1000) +const MAX_SANDBOX_RELEASE_GENERATION = Math.floor((Number.MAX_SAFE_INTEGER - 999) / 1000) const E2B_TEMPLATE_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,62}$/ const E2B_TEMPLATE_REFERENCE_NAME_PATTERN = @@ -24,7 +23,7 @@ export function isValidE2BTemplateName(value: string): boolean { } /** Exact E2B refs may include one documented lowercase namespace segment. */ -export function isValidE2BTemplateReferenceName(value: string): boolean { +function isValidE2BTemplateReferenceName(value: string): boolean { return E2B_TEMPLATE_REFERENCE_NAME_PATTERN.test(value) } diff --git a/packages/utils/src/workflow-references.ts b/packages/utils/src/workflow-references.ts index 64bc63b76ab..d5163b06a18 100644 --- a/packages/utils/src/workflow-references.ts +++ b/packages/utils/src/workflow-references.ts @@ -5,7 +5,7 @@ const INVALID_REFERENCE_CHARS = /[+*/=<>!&|]/ const LEADING_REFERENCE_PATTERN = /^[<>=!\s]*$/ const ENV_REFERENCE_PATTERN = /\{\{[^{}\r\n]+\}\}/g -export type WorkflowReferenceTokenKind = 'environment' | 'workflow' +type WorkflowReferenceTokenKind = 'environment' | 'workflow' export interface WorkflowReferenceToken { kind: WorkflowReferenceTokenKind diff --git a/packages/workflow-persistence/package.json b/packages/workflow-persistence/package.json index d439e653307..712da721ea6 100644 --- a/packages/workflow-persistence/package.json +++ b/packages/workflow-persistence/package.json @@ -10,10 +10,6 @@ "node": ">=20.0.0" }, "exports": { - ".": { - "types": "./src/index.ts", - "default": "./src/index.ts" - }, "./load": { "types": "./src/load.ts", "default": "./src/load.ts" diff --git a/packages/workflow-persistence/src/index.ts b/packages/workflow-persistence/src/index.ts deleted file mode 100644 index ad0b35248c1..00000000000 --- a/packages/workflow-persistence/src/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -export { - loadWorkflowFromNormalizedTablesRaw, - persistMigratedBlocks, - type RawNormalizedWorkflow, -} from './load' -export { saveWorkflowToNormalizedTables } from './save' -export { - DEFAULT_SUBBLOCK_TYPE, - mergeSubBlockValues, - mergeSubblockStateWithValues, -} from './subblocks' -export { - convertLoopBlockToLoop, - convertParallelBlockToParallel, - findChildNodes, - generateLoopBlocks, - generateParallelBlocks, -} from './subflow-helpers' -export type { DbOrTx, NormalizedWorkflowData } from './types' diff --git a/packages/workflow-persistence/src/subflow-helpers.ts b/packages/workflow-persistence/src/subflow-helpers.ts index fb44c8c12d2..d9541445b5a 100644 --- a/packages/workflow-persistence/src/subflow-helpers.ts +++ b/packages/workflow-persistence/src/subflow-helpers.ts @@ -20,7 +20,7 @@ export function clampParallelBatchSize(batchSize: unknown): number { * @param blocks - Record of all blocks in the workflow * @returns IDs of the blocks whose parent is this container */ -export function findChildNodes(containerId: string, blocks: Record): string[] { +function findChildNodes(containerId: string, blocks: Record): string[] { return Object.values(blocks) .filter((block) => block.data?.parentId === containerId) .map((block) => block.id) @@ -64,7 +64,7 @@ export function convertLoopBlockToLoop( * @param blocks - Record of all blocks in the workflow * @returns The parallel, or undefined when the block is missing or not a parallel */ -export function convertParallelBlockToParallel( +function convertParallelBlockToParallel( parallelBlockId: string, blocks: Record ): Parallel | undefined { diff --git a/packages/workflow-renderer/src/dimensions.ts b/packages/workflow-renderer/src/dimensions.ts index e35fb5cb08f..c7c1711f2f3 100644 --- a/packages/workflow-renderer/src/dimensions.ts +++ b/packages/workflow-renderer/src/dimensions.ts @@ -52,11 +52,11 @@ export const BLOCK_DIMENSIONS = { * host, the border SVG viewBox (`preserveAspectRatio='none'`, so a mismatch * paints the outline stretched), and autolayout all resolve through them. */ -export const NOTE_BLOCK_MIN_HEIGHT = +const NOTE_BLOCK_MIN_HEIGHT = BLOCK_DIMENSIONS.HEADER_HEIGHT + BLOCK_DIMENSIONS.NOTE_CONTENT_PADDING + BLOCK_DIMENSIONS.NOTE_MIN_CONTENT_HEIGHT -export const NOTE_BLOCK_MAX_HEIGHT = +const NOTE_BLOCK_MAX_HEIGHT = BLOCK_DIMENSIONS.HEADER_HEIGHT + BLOCK_DIMENSIONS.NOTE_CONTENT_VIEWPORT_HEIGHT /** Clamps a note's total height to the bounds the card itself honours. */ diff --git a/packages/workflow-renderer/src/edge/workflow-edge-view.tsx b/packages/workflow-renderer/src/edge/workflow-edge-view.tsx index d842f0fd497..de6206e46a0 100644 --- a/packages/workflow-renderer/src/edge/workflow-edge-view.tsx +++ b/packages/workflow-renderer/src/edge/workflow-edge-view.tsx @@ -50,7 +50,7 @@ function getExecutionPulseMotion(length: number) { * otherwise be read from stores — diff status, run status, and whether the run * status originated from a preview — is resolved by the container and passed in. */ -export interface WorkflowEdgeData extends Record { +interface WorkflowEdgeData extends Record { isSelected?: boolean onDelete?: (edgeId: string) => void } diff --git a/packages/workflow-renderer/src/index.ts b/packages/workflow-renderer/src/index.ts index 416bef3552c..e8e377db950 100644 --- a/packages/workflow-renderer/src/index.ts +++ b/packages/workflow-renderer/src/index.ts @@ -1,14 +1,9 @@ export { BlockTileView, type BlockTileViewProps, - getWorkflowTypeAccent, - getWorkflowTypeRole, hasWorkflowTypeRole, WorkflowTypeIcon, - type WorkflowTypeIconProps, - type WorkflowTypeRole, WorkflowTypeTag, - type WorkflowTypeTagProps, } from '@sim/workflow-renderer/workflow-type' export { BLOCK_Z_BASE, @@ -24,27 +19,21 @@ export { export * from './dimensions' export { type WorkflowEdge, - type WorkflowEdgeData, WorkflowEdgeView, - type WorkflowEdgeViewProps, } from './edge/workflow-edge-view' export { humanizeBlockName } from './lib/humanize-block-name' export { sortNodesParentsFirst } from './node-order' export { - NOTE_MARKDOWN_FLOW, NoteBlockView, - type NoteBlockViewProps, type NoteContentEditorProps, } from './note/note-block-view' export { DEFAULT_NOTE_COLOR, - getNoteColorOption, isNoteColor, NOTE_COLOR_OPTIONS, type NoteColor, - type NoteColorOption, } from './note/note-colors' -export { getNoteStringValue, isNoteContentEmpty } from './note/note-content' +export { getNoteStringValue } from './note/note-content' export { countNoteSearchOccurrencesBefore, forEachNoteSourceOccurrence, @@ -54,46 +43,23 @@ export { export { type SubflowNodeData, SubflowNodeView, - type SubflowNodeViewProps, - SubflowStartView, } from './subflow/subflow-node-view' export type { - BlockRunStatus, CodePreview, CodePreviewLanguage, - DiffStatus, EdgeDiffStatus, - EdgeRunStatus, } from './types' export { useCanvasColorMode } from './use-canvas-color-mode' export { type CanvasSentenceSegment, CanvasSentenceView, - type CanvasSentenceViewProps, } from './workflow-block/canvas-sentence-view' -export { InlineChip, type InlineChipProps } from './workflow-block/inline-chip' -export { - CURSOR_SOURCE_HANDLE_ID, - getCursorBranchSourceHandleId, - getCursorSourceHandleId, - getCursorSourceHandlePosition, - normalizeCursorSourceHandleId, -} from './workflow-block/source-handle' -export { SubBlockRowView, type SubBlockRowViewProps } from './workflow-block/sub-block-row-view' +export { InlineChip } from './workflow-block/inline-chip' +export { normalizeCursorSourceHandleId } from './workflow-block/source-handle' +export { SubBlockRowView } from './workflow-block/sub-block-row-view' export { CONNECTION_KNOB_PEAK_PX, - CURSOR_SWELL_LENGTH_PX, - getWorkflowBorderFrameDeltaSeconds, - isActionMenuSwellReady, WorkflowBlockBorder, - type WorkflowBorderCursorHandle, type WorkflowBorderPort, } from './workflow-block/workflow-block-border' -export { - ERROR_SOURCE_HANDLE_POSITION, - getErrorBorderPort, - getErrorSourceHandleStyle, - getNearestBranchCursorHandleId, - WorkflowBlockView, - type WorkflowBlockViewProps, -} from './workflow-block/workflow-block-view' +export { WorkflowBlockView } from './workflow-block/workflow-block-view' diff --git a/packages/workflow-renderer/src/note/note-block-view.tsx b/packages/workflow-renderer/src/note/note-block-view.tsx index d47a556d391..5060d25374a 100644 --- a/packages/workflow-renderer/src/note/note-block-view.tsx +++ b/packages/workflow-renderer/src/note/note-block-view.tsx @@ -373,7 +373,7 @@ const NOTE_COMPONENTS = { * move the read view out from under the editor, which is what made every block * after the first jump the moment editing opened. */ -export const NOTE_MARKDOWN_FLOW = 'space-y-4 [&>*:first-child]:mt-0 [&>*:last-child]:mb-0' +const NOTE_MARKDOWN_FLOW = 'space-y-4 [&>*:first-child]:mt-0 [&>*:last-child]:mb-0' interface NoteMarkdownProps { content: string diff --git a/packages/workflow-renderer/src/subflow/subflow-node-view.tsx b/packages/workflow-renderer/src/subflow/subflow-node-view.tsx index d085d99272d..30793eff5e7 100644 --- a/packages/workflow-renderer/src/subflow/subflow-node-view.tsx +++ b/packages/workflow-renderer/src/subflow/subflow-node-view.tsx @@ -155,7 +155,7 @@ interface SubflowStartViewProps { } /** Start control shared by editable and preview subflow containers. */ -export function SubflowStartView({ +function SubflowStartView({ parentId, kind, isPreview = false, diff --git a/packages/workflow-renderer/src/workflow-block/source-handle.ts b/packages/workflow-renderer/src/workflow-block/source-handle.ts index fe1897765ef..42ffb4e3f1c 100644 --- a/packages/workflow-renderer/src/workflow-block/source-handle.ts +++ b/packages/workflow-renderer/src/workflow-block/source-handle.ts @@ -5,7 +5,7 @@ import { } from '@sim/workflow-types/workflow' import { Position } from '@xyflow/react' -export const CURSOR_SOURCE_HANDLE_ID = 'source-cursor' +const CURSOR_SOURCE_HANDLE_ID = 'source-cursor' const CURSOR_BRANCH_SOURCE_HANDLE_PREFIX = `${CURSOR_SOURCE_HANDLE_ID}-branch-` /** Returns the temporary React Flow handle ID under the cursor swell. */ diff --git a/packages/workflow-renderer/src/workflow-block/workflow-block-border.tsx b/packages/workflow-renderer/src/workflow-block/workflow-block-border.tsx index c654247b25d..d337f950a32 100644 --- a/packages/workflow-renderer/src/workflow-block/workflow-block-border.tsx +++ b/packages/workflow-renderer/src/workflow-block/workflow-block-border.tsx @@ -109,10 +109,7 @@ const MAX_FRAME_DELTA_SECONDS = 1 / 30 * Returns a monotonic, capped animation step. Synchronous repaints can occur * between requested frames, so a later callback may carry an older timestamp. */ -export const getWorkflowBorderFrameDeltaSeconds = ( - timestamp: number, - previousTimestamp: number -) => { +const getWorkflowBorderFrameDeltaSeconds = (timestamp: number, previousTimestamp: number) => { if (!Number.isFinite(timestamp)) return 0 if (previousTimestamp === 0) return 1 / 60 const elapsed = (timestamp - previousTimestamp) / 1000 @@ -120,7 +117,7 @@ export const getWorkflowBorderFrameDeltaSeconds = ( return Math.min(MAX_FRAME_DELTA_SECONDS, Math.max(0, elapsed)) } -export const isActionMenuSwellReady = (target: number, value: number) => +const isActionMenuSwellReady = (target: number, value: number) => target === 1 && value >= ACTION_MENU_CONTENT_READY_THRESHOLD export interface WorkflowBorderPort { diff --git a/packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx b/packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx index 3e4ab248ff2..a16edfbe192 100644 --- a/packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx +++ b/packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx @@ -81,7 +81,7 @@ interface WorkflowCursorSourceHandle extends WorkflowBorderCursorHandle { } /** Resolves a moving branch-card swell to the nearest visible branch row. */ -export function getNearestBranchCursorHandleId( +function getNearestBranchCursorHandleId( rows: BranchCursorRow[], cursorY: number, firstRowY: number, @@ -163,10 +163,10 @@ const invisibleHandleSize = ( } /** Error is the only persisted source that leaves from a vertical card edge. */ -export const ERROR_SOURCE_HANDLE_POSITION = Position.Bottom +const ERROR_SOURCE_HANDLE_POSITION = Position.Bottom /** Keeps the Error hit target centered on the painted bottom-right knob. */ -export const getErrorSourceHandleStyle = (): CSSProperties => ({ +const getErrorSourceHandleStyle = (): CSSProperties => ({ right: 'auto', top: 'auto', bottom: -HANDLE_OUTSET_PX, @@ -177,7 +177,7 @@ export const getErrorSourceHandleStyle = (): CSSProperties => ({ }) /** Builds the fixed Error knob painted into the card's bottom edge. */ -export const getErrorBorderPort = (color?: string): WorkflowBorderPort => ({ +const getErrorBorderPort = (color?: string): WorkflowBorderPort => ({ id: 'error', side: 'bottom', position: { fromEnd: HANDLE_POSITIONS.ERROR_RIGHT_OFFSET }, diff --git a/packages/workflow-renderer/src/workflow-type.tsx b/packages/workflow-renderer/src/workflow-type.tsx index 234c70bddc2..d72874821e0 100644 --- a/packages/workflow-renderer/src/workflow-type.tsx +++ b/packages/workflow-renderer/src/workflow-type.tsx @@ -83,7 +83,7 @@ const DEFAULT_WORKFLOW_TYPE_ROLE: WorkflowTypeRole = 'neutral' export const hasWorkflowTypeRole = (type: string): type is keyof typeof WORKFLOW_TYPE_ROLES => Object.hasOwn(WORKFLOW_TYPE_ROLES, type) -export const getWorkflowTypeRole = (type: string): WorkflowTypeRole => +const getWorkflowTypeRole = (type: string): WorkflowTypeRole => WORKFLOW_TYPE_ROLES[type as keyof typeof WORKFLOW_TYPE_ROLES] ?? DEFAULT_WORKFLOW_TYPE_ROLE export const getWorkflowTypeAccent = (type: string) => diff --git a/packages/workflow-types/src/workflow.ts b/packages/workflow-types/src/workflow.ts index 3ef13aef486..742e4e7c52b 100644 --- a/packages/workflow-types/src/workflow.ts +++ b/packages/workflow-types/src/workflow.ts @@ -8,10 +8,6 @@ export const SUBFLOW_TYPES = { export type SubflowType = (typeof SUBFLOW_TYPES)[keyof typeof SUBFLOW_TYPES] -export function isValidSubflowType(type: string): type is SubflowType { - return Object.values(SUBFLOW_TYPES).includes(type as SubflowType) -} - export interface LoopConfig { nodes: string[] iterations: number @@ -207,7 +203,7 @@ export interface WorkflowLockBlock { /** * Reads a workflow block's parent ID from runtime block data. */ -export function getWorkflowBlockParentId(block?: WorkflowLockBlock): string | undefined { +function getWorkflowBlockParentId(block?: WorkflowLockBlock): string | undefined { const data = block?.data if (typeof data !== 'object' || data === null || !('parentId' in data)) return undefined @@ -331,11 +327,11 @@ export interface WorkflowEdgeHandles extends WorkflowEdgeEndpoints { targetHandle?: string | null } -export const WORKFLOW_CARD_SIDES = ['top', 'right', 'bottom', 'left'] as const +const WORKFLOW_CARD_SIDES = ['top', 'right', 'bottom', 'left'] as const export type WorkflowCardSide = (typeof WORKFLOW_CARD_SIDES)[number] /** The two card sides a connection line can attach to. Purely visual. */ -export const WORKFLOW_CONNECTION_SIDES = ['left', 'right'] as const +const WORKFLOW_CONNECTION_SIDES = ['left', 'right'] as const export type WorkflowConnectionSide = (typeof WORKFLOW_CONNECTION_SIDES)[number] /** The one output handle every non-branching block exposes. */ diff --git a/scripts/check-unused-exports.baseline.json b/scripts/check-unused-exports.baseline.json index ceaac73e6ae..f238aa01c30 100644 --- a/scripts/check-unused-exports.baseline.json +++ b/scripts/check-unused-exports.baseline.json @@ -5515,7 +5515,6 @@ "apps/sim/stores/workflows/workflow/types.ts#SUBFLOW_TYPES", "apps/sim/stores/workflows/workflow/types.ts#Subflow", "apps/sim/stores/workflows/workflow/types.ts#WorkflowActions", - "apps/sim/stores/workflows/workflow/types.ts#isValidSubflowType", "apps/sim/tools/affinity/utils.ts#AFFINITY_MAX_BATCH_FIELD_UPDATES", "apps/sim/tools/affinity/utils.ts#parseOptionalJsonArray", "apps/sim/tools/arxiv/utils.ts#cleanText", diff --git a/scripts/check-unused-exports.ts b/scripts/check-unused-exports.ts index 7957e68df49..bed43a8dd9d 100644 --- a/scripts/check-unused-exports.ts +++ b/scripts/check-unused-exports.ts @@ -16,10 +16,12 @@ * `scripts/check-unused-exports.baseline.json`. A new entry fails; so does a baseline entry that * no longer occurs, so the baseline only shrinks. Regenerate with `--update`. * - * Public package surface is not baselined: knip treats every workspace's `exports`/`main`/`bin` - * targets as entry files and, with `includeEntryExports: false` (set explicitly in knip.jsonc), - * never reports their exports. Exports used only by tests count as used because knip's Vitest - * plugin makes test files entries. + * Entry exports are reported (`includeEntryExports: true` in knip.jsonc): a private package's + * `exports` map serves only this monorepo, so an entry export nothing imports is dead. The apps, + * the published packages, db, and the root turn it off there, since their entries are public or + * standalone. Exports used only by tests count as used because knip's Vitest plugin makes test + * files entries. An export whose only consumer knip cannot see (a path-based `import()`, or a + * helper an audit names as the replacement) carries a `@public` TSDoc tag saying why. * * Knip is slow, so `run-audits.ts` runs this script and skips `check:dead-code`, which stays * available as the human-readable report. @@ -165,8 +167,10 @@ if (added.length) { } for (const kind of kinds) console.error(` ${kind}: ${HOW_TO_FIX[kind]}`) console.error( - ' If it is deliberate public API of a package, expose it through that package.json `exports` ' + - 'map (or add an `ignore` rule in knip.jsonc with a comment saying why). Never add it to the baseline.' + ' If it is deliberate public API of a published package, expose it through that package.json ' + + '`exports` map (or add an `ignore` rule in knip.jsonc with a comment saying why). A private ' + + "package's entry exports are checked too: delete them once nothing imports them. Never add " + + 'it to the baseline.' ) }