mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
chore(utils): migrate to shared random/ID utilities and add enforcement linting (#4623)
* chore(utils): migrate to shared random/ID utilities and add enforcement linting - Replace all Math.random(), crypto.randomUUID(), crypto.randomBytes(), nanoid, and uuid usages with shared @sim/utils/random and @sim/utils/id helpers across 72 files - Add new @sim/utils exports: deepClone, omit, filterUndefined (object), truncate (string), backoffWithJitter, parseRetryAfter (retry), getErrorMessage (errors) - Sweep all getErrorMessage, sleep, deepClone callsites across 500+ files to use shared utilities - Add Biome noRestrictedImports rule to catch nanoid, uuid, and crypto named imports at lint time - Add scripts/check-utils-enforcement.ts to catch Math.random and crypto.* global property access - Add check:utils script to package.json * chore(utils): replace deepClone wrapper with structuredClone built-in deepClone() was a one-line wrapper around structuredClone(), which is universally available in Node 17+ and all modern browsers. Removing the abstraction reduces indirection and means contributors don't need to learn a project-specific name for a well-known built-in. - Remove deepClone from packages/utils/src/object.ts and index.ts - Replace all 17 call sites with structuredClone() directly - Update check:utils script suggestion text - Update CLAUDE.md and global.md docs * fix(utils): add missing biome noRestrictedImports rule and correct truncate docs - Add noRestrictedImports to biome.json under style — bans nanoid and uuid package imports at lint time (crypto.randomUUID/randomBytes are caught by the check:utils grep script which handles global property access) - Correct truncate() TSDoc and parameter name: sliceLength makes it clear that total output length is sliceLength + suffix.length, matching the behavior all callers were already written to expect * fix(utils): add missing getErrorMessage imports at 4 call sites The sweep agents added getErrorMessage calls without the corresponding import in 4 files, causing test failures. Added the missing imports. * fix(utils): fix build errors from getErrorMessage sweep and retry.ts Turbopack issue - Fix retry.ts cross-file import: Turbopack cannot resolve './random.js' for internal package imports; inline the jitter crypto call directly - Add missing getErrorMessage imports to 32 files where the sweep added calls without the corresponding import (caught by type-check and test runs) - Remove accidental getErrorMessage import from crowdstrike/query/route.ts which has its own domain-specific getErrorMessage for parsing CrowdStrike's JSON error format - Fix use-sub-block-value.ts type error from structuredClone narrowing: add 'as T' cast at emitValue callsite (safe — valueCopy is always a structural copy of newValue) * fix(tools): use toError in crowdstrike catch block instead of local getErrorMessage The catch block was calling the local getErrorMessage function which parses CrowdStrike API JSON responses, not JavaScript Error objects. Use toError(error).message to correctly extract the message from a caught value in this context.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import type { ExecutionContext } from '../types'
|
||||
|
||||
/**
|
||||
@@ -18,7 +19,7 @@ import type { ExecutionContext } from '../types'
|
||||
*/
|
||||
export class ExecutionContextBuilder {
|
||||
private workflowId = 'test-workflow'
|
||||
private executionId = `exec-${Math.random().toString(36).substring(2, 10)}`
|
||||
private executionId = `exec-${generateRandomString(8)}`
|
||||
private blockStates = new Map<string, any>()
|
||||
private executedBlocks = new Set<string>()
|
||||
private blockLogs: any[] = []
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import {
|
||||
createAgentBlock,
|
||||
createBlock,
|
||||
@@ -229,7 +230,7 @@ export class WorkflowBuilder {
|
||||
value: any
|
||||
): this {
|
||||
this.variables?.push({
|
||||
id: `var-${Math.random().toString(36).substring(2, 8)}`,
|
||||
id: `var-${generateRandomString(6)}`,
|
||||
name,
|
||||
type,
|
||||
value,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import type { BlockData, BlockOutput, Position } from '../types'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
@@ -28,7 +29,7 @@ export interface BlockFactoryOptions {
|
||||
* Generates a unique block ID.
|
||||
*/
|
||||
function generateBlockId(prefix = 'block'): string {
|
||||
return `${prefix}-${Math.random().toString(36).substring(2, 10)}`
|
||||
return `${prefix}-${generateRandomString(8)}`
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* These are used in executor tests for DAG construction and edge management
|
||||
*/
|
||||
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import { createSerializedBlock, type SerializedBlock } from './serialized-block.factory'
|
||||
|
||||
/**
|
||||
@@ -62,7 +63,7 @@ export interface DAGNodeFactoryOptions {
|
||||
* ```
|
||||
*/
|
||||
export function createDAGNode(options: DAGNodeFactoryOptions = {}): DAGNode {
|
||||
const id = options.id ?? `node-${Math.random().toString(36).substring(2, 8)}`
|
||||
const id = options.id ?? `node-${generateRandomString(6)}`
|
||||
const block =
|
||||
options.block ??
|
||||
createSerializedBlock({
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
|
||||
/**
|
||||
* Options for creating a mock edge.
|
||||
*/
|
||||
@@ -17,7 +19,7 @@ export interface EdgeFactoryOptions {
|
||||
* Generates an edge ID from source and target.
|
||||
*/
|
||||
function generateEdgeId(source: string, target: string): string {
|
||||
return `${source}-${target}-${Math.random().toString(36).substring(2, 6)}`
|
||||
return `${source}-${target}-${generateRandomString(4)}`
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import type { ExecutionContext } from '../types'
|
||||
|
||||
/**
|
||||
@@ -38,7 +39,7 @@ export function createExecutionContext(
|
||||
): ExecutionContext {
|
||||
return {
|
||||
workflowId: options.workflowId ?? 'test-workflow',
|
||||
executionId: options.executionId ?? `exec-${Math.random().toString(36).substring(2, 10)}`,
|
||||
executionId: options.executionId ?? `exec-${generateRandomString(8)}`,
|
||||
blockStates: options.blockStates ?? new Map(),
|
||||
executedBlocks: options.executedBlocks ?? new Set(),
|
||||
blockLogs: options.blockLogs ?? [],
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* This file contains mock data samples to be used in tool unit tests.
|
||||
*/
|
||||
|
||||
import { randomFloat } from '@sim/utils/random'
|
||||
|
||||
/**
|
||||
* HTTP Request mock responses for different scenarios.
|
||||
*/
|
||||
@@ -147,7 +149,7 @@ export const mockPineconeResponses = {
|
||||
embedding: {
|
||||
embedding: Array(1536)
|
||||
.fill(0)
|
||||
.map(() => Math.random() * 2 - 1),
|
||||
.map(() => randomFloat() * 2 - 1),
|
||||
metadata: { text: 'Sample text for embedding', id: 'embed-123' },
|
||||
},
|
||||
searchResults: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import type { User, Workflow, WorkflowState, Workspace } from '../types'
|
||||
import { createWorkflowState } from './workflow.factory'
|
||||
|
||||
@@ -20,7 +21,7 @@ export interface UserFactoryOptions {
|
||||
* ```
|
||||
*/
|
||||
export function createUser(options: UserFactoryOptions = {}): User {
|
||||
const id = options.id ?? `user-${Math.random().toString(36).substring(2, 10)}`
|
||||
const id = options.id ?? `user-${generateRandomString(8)}`
|
||||
return {
|
||||
id,
|
||||
email: options.email ?? `${id}@test.example.com`,
|
||||
@@ -51,9 +52,9 @@ export interface WorkspaceFactoryOptions {
|
||||
export function createWorkspace(options: WorkspaceFactoryOptions = {}): Workspace {
|
||||
const now = new Date()
|
||||
return {
|
||||
id: options.id ?? `ws-${Math.random().toString(36).substring(2, 10)}`,
|
||||
id: options.id ?? `ws-${generateRandomString(8)}`,
|
||||
name: options.name ?? 'Test Workspace',
|
||||
ownerId: options.ownerId ?? `user-${Math.random().toString(36).substring(2, 10)}`,
|
||||
ownerId: options.ownerId ?? `user-${generateRandomString(8)}`,
|
||||
createdAt: options.createdAt ?? now,
|
||||
updatedAt: options.updatedAt ?? now,
|
||||
}
|
||||
@@ -83,9 +84,9 @@ export interface WorkflowObjectFactoryOptions {
|
||||
export function createWorkflow(options: WorkflowObjectFactoryOptions = {}): Workflow {
|
||||
const now = new Date()
|
||||
return {
|
||||
id: options.id ?? `wf-${Math.random().toString(36).substring(2, 10)}`,
|
||||
id: options.id ?? `wf-${generateRandomString(8)}`,
|
||||
name: options.name ?? 'Test Workflow',
|
||||
workspaceId: options.workspaceId ?? `ws-${Math.random().toString(36).substring(2, 10)}`,
|
||||
workspaceId: options.workspaceId ?? `ws-${generateRandomString(8)}`,
|
||||
state: options.state ?? createWorkflowState(),
|
||||
createdAt: options.createdAt ?? now,
|
||||
updatedAt: options.updatedAt ?? now,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import { type Mock, vi } from 'vitest'
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,7 @@ export function createMockSocket(): IMockSocket {
|
||||
const eventHandlers: Record<string, ((...args: any[]) => any)[]> = {}
|
||||
|
||||
const socket = {
|
||||
id: `socket-${Math.random().toString(36).substring(2, 10)}`,
|
||||
id: `socket-${generateRandomString(8)}`,
|
||||
connected: true,
|
||||
disconnected: false,
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { generateRandomString } from '@sim/utils/random'
|
||||
import { vi } from 'vitest'
|
||||
|
||||
interface ConsoleEntryLike {
|
||||
@@ -16,7 +17,7 @@ const entriesByWorkflow: Record<string, ConsoleEntryLike[]> = {}
|
||||
const mockGetWorkflowEntries = vi.fn((workflowId: string) => entriesByWorkflow[workflowId] ?? [])
|
||||
|
||||
const mockAddConsole = vi.fn((entry: ConsoleEntryLike) => {
|
||||
const stored = { ...entry, id: entry.id ?? `mock-${Math.random().toString(36).slice(2)}` }
|
||||
const stored = { ...entry, id: entry.id ?? `mock-${generateRandomString(16)}` }
|
||||
if (!entriesByWorkflow[entry.workflowId]) entriesByWorkflow[entry.workflowId] = []
|
||||
entriesByWorkflow[entry.workflowId].push(stored)
|
||||
return stored
|
||||
|
||||
Reference in New Issue
Block a user