chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,254 @@
import type { SubBlockType } from '@sim/workflow-types/blocks'
import type {
WorkflowSearchRange,
WorkflowSearchValuePath,
} from '@/lib/workflows/search-replace/types'
import { getValueAtPath, setValueAtPath } from '@/lib/workflows/search-replace/value-walker'
const SEARCHABLE_JSON_ARRAY_VALUE_FIELDS: Partial<Record<SubBlockType, Record<string, string>>> = {
'condition-input': {
value: 'Condition',
},
'router-input': {
value: 'Route',
},
'knowledge-tag-filters': {
tagValue: 'Value',
valueTo: 'Value To',
},
'document-tag-entry': {
value: 'Value',
},
'variables-input': {
value: 'Value',
},
}
const SEARCHABLE_JSON_OBJECT_VALUE_FIELDS: Partial<Record<SubBlockType, string>> = {
'input-mapping': 'Value',
'workflow-input-mapper': 'Value',
}
const SERIALIZED_SUBBLOCK_VALUE_TYPES = new Set<SubBlockType>([
'file-upload',
'grouped-checkbox-list',
'table',
])
export interface SearchableJsonStringLeaf {
path: WorkflowSearchValuePath
value: string
originalValue: string
fieldTitle: string
}
export interface JsonStringLeafReplacementResult {
handled: boolean
success: boolean
nextValue?: unknown
reason?: string
}
function parseJsonValue(value: string): unknown | null {
try {
return JSON.parse(value)
} catch {
return null
}
}
function getParsedValue(value: unknown): { parsed: unknown; stringify: boolean } | null {
if (typeof value === 'string') {
const parsed = parseJsonValue(value)
return parsed === null ? null : { parsed, stringify: true }
}
if (value && typeof value === 'object') {
return { parsed: value, stringify: false }
}
return null
}
function getObjectStringLeaves({
value,
path = [],
fieldTitle,
}: {
value: unknown
path?: WorkflowSearchValuePath
fieldTitle: string
}): SearchableJsonStringLeaf[] {
if (typeof value === 'string' && value.length > 0) {
return [{ path, value, originalValue: value, fieldTitle }]
}
if (Array.isArray(value)) {
return value.flatMap((item, index) =>
getObjectStringLeaves({ value: item, path: [...path, index], fieldTitle })
)
}
if (!value || typeof value !== 'object') return []
return Object.entries(value).flatMap(([fieldKey, fieldValue]) =>
getObjectStringLeaves({ value: fieldValue, path: [...path, fieldKey], fieldTitle })
)
}
export function isSearchableJsonValueSubBlock(
subBlockType: SubBlockType | undefined
): subBlockType is
| 'condition-input'
| 'router-input'
| 'knowledge-tag-filters'
| 'document-tag-entry'
| 'variables-input'
| 'input-mapping'
| 'workflow-input-mapper'
| 'table' {
return Boolean(
subBlockType &&
(subBlockType === 'table' ||
SEARCHABLE_JSON_ARRAY_VALUE_FIELDS[subBlockType] ||
SEARCHABLE_JSON_OBJECT_VALUE_FIELDS[subBlockType])
)
}
export function shouldParseSerializedSubBlockValue(
subBlockType: SubBlockType | undefined
): subBlockType is SubBlockType {
return Boolean(
subBlockType &&
(isSearchableJsonValueSubBlock(subBlockType) ||
SERIALIZED_SUBBLOCK_VALUE_TYPES.has(subBlockType))
)
}
export function getSearchableJsonStringLeaves(
value: unknown,
subBlockType: SubBlockType | undefined
): SearchableJsonStringLeaf[] {
const parsedValue = getParsedValue(value)
if (!parsedValue) return []
const { parsed } = parsedValue
if (subBlockType === 'table') {
if (!Array.isArray(parsed)) return []
return parsed.flatMap((row, rowIndex) => {
if (!row || typeof row !== 'object' || Array.isArray(row)) return []
const cells = (row as Record<string, unknown>).cells
if (!cells || typeof cells !== 'object' || Array.isArray(cells)) return []
return Object.entries(cells).flatMap(([column, cellValue]) =>
typeof cellValue === 'string' && cellValue.length > 0
? [
{
path: [rowIndex, 'cells', column],
value: cellValue,
originalValue: cellValue,
fieldTitle: column,
},
]
: []
)
})
}
const arrayFieldTitles = subBlockType
? SEARCHABLE_JSON_ARRAY_VALUE_FIELDS[subBlockType]
: undefined
if (arrayFieldTitles) {
if (!Array.isArray(parsed)) return []
return parsed.flatMap((row, index) => {
if (!row || typeof row !== 'object' || Array.isArray(row)) return []
return Object.entries(arrayFieldTitles).flatMap(([fieldKey, fieldTitle]) => {
const fieldValue = (row as Record<string, unknown>)[fieldKey]
return typeof fieldValue === 'string' && fieldValue.length > 0
? [{ path: [index, fieldKey], value: fieldValue, originalValue: fieldValue, fieldTitle }]
: []
})
})
}
const objectFieldTitle = subBlockType
? SEARCHABLE_JSON_OBJECT_VALUE_FIELDS[subBlockType]
: undefined
if (objectFieldTitle) {
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return []
return getObjectStringLeaves({ value: parsed, fieldTitle: objectFieldTitle })
}
return []
}
export function replaceJsonStringLeafRange({
value,
subBlockType,
path,
range,
rawValue,
replacement,
}: {
value: unknown
subBlockType: SubBlockType | undefined
path: WorkflowSearchValuePath
range: WorkflowSearchRange
rawValue: string
replacement: string
}): JsonStringLeafReplacementResult {
if (!isSearchableJsonValueSubBlock(subBlockType)) {
return { handled: false, success: false }
}
const parsedValue = getParsedValue(value)
if (!parsedValue) {
return { handled: true, success: false, reason: 'Target JSON is no longer valid' }
}
const { parsed, stringify } = parsedValue
const currentLeaf = getValueAtPath(parsed, path)
if (typeof currentLeaf !== 'string') {
for (let prefixLength = path.length - 1; prefixLength > 0; prefixLength -= 1) {
const valuePrefix = path.slice(0, prefixLength)
const nestedValue = getValueAtPath(parsed, valuePrefix)
if (typeof nestedValue !== 'string') continue
const nestedResult = replaceJsonStringLeafRange({
value: nestedValue,
subBlockType,
path: path.slice(prefixLength),
range,
rawValue,
replacement,
})
if (!nestedResult.handled || !nestedResult.success) return nestedResult
return {
handled: true,
success: true,
nextValue: stringify
? JSON.stringify(setValueAtPath(parsed, valuePrefix, nestedResult.nextValue))
: setValueAtPath(parsed, valuePrefix, nestedResult.nextValue),
}
}
}
if (typeof currentLeaf !== 'string') {
return { handled: true, success: false, reason: 'Target value is no longer text' }
}
const currentRawValue = currentLeaf.slice(range.start, range.end)
if (currentRawValue !== rawValue) {
return { handled: true, success: false, reason: 'Target text changed since search' }
}
const nextLeaf = `${currentLeaf.slice(0, range.start)}${replacement}${currentLeaf.slice(range.end)}`
return {
handled: true,
success: true,
nextValue: stringify
? JSON.stringify(setValueAtPath(parsed, path, nextLeaf))
: setValueAtPath(parsed, path, nextLeaf),
}
}