Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/desktop/src/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
type TerminalToolArgs,
} from '@sim/terminal-protocol'
import { getErrorMessage } from '@sim/utils/errors'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import { PASTE_LIMITS, utf8ByteLength } from '@sim/utils/paste'
import type { BrowserWindow, IpcMainEvent, IpcMainInvokeEvent, WebContents } from 'electron'
import { clipboard, ipcMain, shell } from 'electron'
Expand Down Expand Up @@ -856,7 +856,7 @@ export function registerIpcHandlers(deps: IpcDeps): void {
) {
return { ok: false, error: `Unknown browser tool: ${String(tool)}` }
}
const toolParams = isRecordLike(params) ? params : {}
const toolParams = toRecord(params)
return executeTool(
scope,
tool,
Expand Down Expand Up @@ -1532,7 +1532,7 @@ export function registerIpcHandlers(deps: IpcDeps): void {
) {
return { ok: false, error: `Unknown terminal tool: ${String(tool)}` }
}
const call = isRecordLike(params) ? params : {}
const call = toRecord(params)
if (!isTerminalOperation(call.operation)) {
return { ok: false, error: `Unknown terminal operation: ${String(call.operation)}` }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useState } from 'react'
import { isBrowserToolName } from '@sim/browser-protocol'
import { cn } from '@sim/emcn'
import { Globe } from '@sim/emcn/icons'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecordOrNull } from '@sim/utils/object'
import { isBrowserAgentAvailable } from '@/lib/browser-agent/transport'
import { useChatSurface } from '@/app/workspace/[workspaceId]/home/components/chat-surface-context'
import type { AgentGroupItem } from '@/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/agent-group-view'
Expand Down Expand Up @@ -40,7 +40,7 @@ export function getBrowserAgentFaviconUrl(items: AgentGroupItem[]): string | nul
return typeof params?.url === 'string' ? pageFaviconUrl(params.url) : null
}

const output = result?.success && isRecordLike(result.output) ? result.output : null
const output = result?.success ? toRecordOrNull(result.output) : null
if (output) {
if (isRecordLike(output.activeTab) && typeof output.activeTab.url === 'string') {
return pageFaviconUrl(output.activeTab.url)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import { resolveStreamToolOutcome } from '@/lib/copilot/chat/stream-tool-outcome'
import {
MothershipStreamV1CompletionStatus,
Expand Down Expand Up @@ -230,7 +230,7 @@ function rebindResolvedIntegrationCall(node: ToolNode, toolName: string): void {
* through the `unknown`-typed {@link isRecordLike} guard rather than a double cast.
*/
function payloadRecord(payload: unknown): Record<string, unknown> {
return isRecordLike(payload) ? payload : {}
return toRecord(payload)
}

/** Parses a wire `ts` to epoch ms, or undefined when absent/unparseable. */
Expand Down
6 changes: 2 additions & 4 deletions apps/sim/background/webhook-execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { createLogger, type RequestContext, runWithRequestContext } from '@sim/l
import { toError } from '@sim/utils/errors'
import { interruptibleSleep } from '@sim/utils/helpers'
import { generateId } from '@sim/utils/id'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import { backoffWithJitter } from '@sim/utils/retry'
import { task, timeout } from '@trigger.dev/sdk'
import { eq } from 'drizzle-orm'
Expand Down Expand Up @@ -1091,9 +1091,7 @@ async function executeWebhookJobInternal(
})
}

const persistedProviderConfig = isRecordLike(resolvedWebhookRecord.providerConfig)
? resolvedWebhookRecord.providerConfig
: {}
const persistedProviderConfig = toRecord(resolvedWebhookRecord.providerConfig)
const slackStreamConfig =
payload.provider === 'slack' || payload.provider === 'slack_app'
? readSlackStreamResponseConfig(persistedProviderConfig)
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/ee/scim/lib/protocol/user-patch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ScimUserAttributes, ScimUserEmail } from '@sim/db/schema'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import type { ScimPatchOperation } from '@/lib/api/contracts/scim'
import { invalidPath, invalidValue, mutability, noTarget } from '@/ee/scim/lib/protocol/errors'
import {
Expand Down Expand Up @@ -331,7 +331,7 @@ function applyExtraOperation(
else {
if (!isRecordLike(value)) throw invalidValue(`${path} requires an object value`)
const current = user.extra[extension.schema]
user.extra[extension.schema] = { ...(isRecordLike(current) ? current : {}), ...value }
user.extra[extension.schema] = { ...toRecord(current), ...value }
}
return
}
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/executor/execution/block-executor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createLogger, type Logger } from '@sim/logger'
import { describeError } from '@sim/utils/errors'
import { sleep } from '@sim/utils/helpers'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import { DrizzleQueryError } from 'drizzle-orm/errors'
import { isTimeoutAbortReason } from '@/lib/core/execution-limits/types'
import { redactApiKeys } from '@/lib/core/security/redaction'
Expand Down Expand Up @@ -970,7 +970,7 @@ export class BlockExecutor {
}
})()
: mapping
inputs = isRecordLike(parsed) ? parsed : {}
inputs = toRecord(parsed)
}

const result: Record<string, any> = {}
Expand Down
6 changes: 3 additions & 3 deletions apps/sim/hooks/queries/custom-tools.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createLogger } from '@sim/logger'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { requestJson } from '@/lib/api/client/request'
import {
Expand Down Expand Up @@ -125,8 +125,8 @@ async function fetchCustomTools(
}

const functionSchema = tool.schema.function
const parameters = isRecordLike(functionSchema.parameters) ? functionSchema.parameters : {}
const properties = isRecordLike(parameters.properties) ? parameters.properties : {}
const parameters = toRecord(functionSchema.parameters)
const properties = toRecord(parameters.properties)
const required = Array.isArray(parameters.required)
? parameters.required.filter((value): value is string => typeof value === 'string')
: undefined
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/hooks/queries/organization.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createLogger } from '@sim/logger'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import {
queryOptions,
type UseQueryResult,
Expand Down Expand Up @@ -269,7 +269,7 @@ export function useUpdateOrganizationUsageLimit() {
organizationKeys.billing(organizationId),
(old: unknown) => {
if (!isRecordLike(old) || !isRecordLike(old.data)) return old
const usage = isRecordLike(old.data.usage) ? old.data.usage : {}
const usage = toRecord(old.data.usage)
const currentUsage =
readNumber(old.data.currentUsage) ??
readNumber(usage.current) ??
Expand Down
14 changes: 7 additions & 7 deletions apps/sim/lib/auth/connectors/managed-oauth.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createHash } from 'node:crypto'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import type { OAuth2Tokens } from 'better-auth/oauth2'
import type { GenericOAuthConfig } from 'better-auth/plugins'
import { OAuth2Client, type TokenPayload } from 'google-auth-library'
Expand Down Expand Up @@ -830,7 +830,7 @@ const USER_INFO_MANAGED_OAUTH_CONNECTORS = new Map<string, () => ManagedOAuthCon
},
parse: (profile) => {
const account = asProfileRecord(profile, 'Dropbox')
const name = isRecordLike(account.name) ? account.name : {}
const name = toRecord(account.name)
return withOptionalIdentityFields(
{
providerSubjectId: requireIdentityField(account.account_id, 'Dropbox account id'),
Expand Down Expand Up @@ -889,15 +889,15 @@ const USER_INFO_MANAGED_OAUTH_CONNECTORS = new Map<string, () => ManagedOAuthCon
* `bot.owner.user`. A workspace-owned internal integration reports
* `{ type: 'workspace' }` and identifies nobody, which cannot be bound to an invitation.
*/
const bot = isRecordLike(self.bot) ? self.bot : {}
const owner = isRecordLike(bot.owner) ? bot.owner : {}
const bot = toRecord(self.bot)
const owner = toRecord(bot.owner)
if (owner.type !== 'user') {
throw new Error(
'Notion returned a workspace-owned integration, which identifies no person to bind this invitation to'
)
}
const user = asProfileRecord(owner.user, 'Notion')
const person = isRecordLike(user.person) ? user.person : {}
const person = toRecord(user.person)
return withOptionalIdentityFields(
{
providerSubjectId: requireIdentityField(user.id, 'Notion user id'),
Expand Down Expand Up @@ -1004,7 +1004,7 @@ const USER_INFO_MANAGED_OAUTH_CONNECTORS = new Map<string, () => ManagedOAuthCon
scopes: {
from: 'profile',
read: (profile) => {
const metadata = isRecordLike(profile) ? profile : {}
const metadata = toRecord(profile)
if (Array.isArray(metadata.scopes)) {
return metadata.scopes.filter((scope): scope is string => typeof scope === 'string')
}
Expand Down Expand Up @@ -1135,7 +1135,7 @@ const USER_INFO_MANAGED_OAUTH_CONNECTORS = new Map<string, () => ManagedOAuthCon
parse: (profile) => {
const envelope = asProfileRecord(profile, 'Asana')
const user = asProfileRecord(envelope.data, 'Asana')
const photo = isRecordLike(user.photo) ? user.photo : {}
const photo = toRecord(user.photo)
return withOptionalIdentityFields(
{
providerSubjectId: requireIdentityField(user.gid, 'Asana user id'),
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/lib/billing/core/reporting-period.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isRecordLike } from '@sim/utils/object'
import { toRecord } from '@sim/utils/object'
import { defaultBillingPeriod } from '@/lib/billing/core/billing-period'
import { isEnterprise } from '@/lib/billing/plan-helpers'

Expand Down Expand Up @@ -91,7 +91,7 @@ export function resolveSubscriptionUsagePeriod(
return subscription.usagePeriod
}
if (subscription && isEnterprise(subscription.plan)) {
const metadata = isRecordLike(subscription.metadata) ? subscription.metadata : {}
const metadata = toRecord(subscription.metadata)
const anchor = metadata[ENTERPRISE_REPORTING_PERIOD_ANCHOR_METADATA_KEY]
const interval =
parseBillingInterval(metadata[ENTERPRISE_REPORTING_PERIOD_INTERVAL_METADATA_KEY]) ??
Expand Down
6 changes: 2 additions & 4 deletions apps/sim/lib/billing/webhooks/enterprise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { db } from '@sim/db'
import { foldedEmail, organization, outboxEvent, session, subscription, user } from '@sim/db/schema'
import { createLogger } from '@sim/logger'
import { generateId } from '@sim/utils/id'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import { normalizeEmail } from '@sim/utils/string'
import { and, eq, inArray, sql } from 'drizzle-orm'
import type Stripe from 'stripe'
Expand Down Expand Up @@ -57,9 +57,7 @@ export async function handleManualEnterpriseSubscription(event: Stripe.Event) {
async function processManualEnterpriseSubscription(event: Stripe.Event) {
const eventSubscription = event.data.object as Stripe.Subscription
const rawPreviousAttributes: unknown = event.data.previous_attributes
const previousAttributes: Record<string, unknown> = isRecordLike(rawPreviousAttributes)
? rawPreviousAttributes
: {}
const previousAttributes: Record<string, unknown> = toRecord(rawPreviousAttributes)
return withEnterpriseReconciliationLease(eventSubscription.id, (lease) =>
reconcileManualEnterpriseSubscription(eventSubscription, lease, {
created: event.type === 'customer.subscription.created',
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/lib/copilot/chat/citation-evidence.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isRecordLike } from '@sim/utils/object'
import { toRecordOrNull } from '@sim/utils/object'

export interface RetrievalCitationBlock {
toolCall?: { name: string; status: string; result?: { success: boolean; output?: unknown } }
Expand All @@ -12,7 +12,7 @@ export function parseCitationRecord(value: unknown): Record<string, unknown> | n
return null
}
}
return isRecordLike(value) ? value : null
return toRecordOrNull(value)
}

/** Only successful retrieval tool results may supply source destinations. */
Expand Down
6 changes: 3 additions & 3 deletions apps/sim/lib/copilot/tools/client/browser-tool-execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import { type BrowserToolName, browserToolRendererTimeoutMs } from '@sim/browser-protocol'
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import { truncate } from '@sim/utils/string'
import {
cancelBrowserTool,
Expand Down Expand Up @@ -143,7 +143,7 @@ function compactCompletionForPageExit(
const serialized = JSON.stringify({ toolCallId, ...completion })
if (new Blob([serialized]).size <= PAGE_EXIT_COMPLETION_MAX_BYTES) return completion

const data = isRecordLike(completion.data) ? completion.data : {}
const data = toRecord(completion.data)
return {
status: completion.status,
message: truncate(completion.message, 1024),
Expand All @@ -164,7 +164,7 @@ function compactCompletionForRetry(
const serialized = JSON.stringify({ toolCallId, ...completion })
if (new Blob([serialized]).size <= RETAINED_COMPLETION_MAX_BYTES) return completion

const data = isRecordLike(completion.data) ? completion.data : {}
const data = toRecord(completion.data)
return {
status: completion.status,
message: truncate(completion.message, 1024),
Expand Down
6 changes: 3 additions & 3 deletions apps/sim/lib/copilot/tools/client/browser-tool-result.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { BrowserToolName } from '@sim/browser-protocol'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecordOrNull } from '@sim/utils/object'

function finiteNumber(value: unknown): value is number {
return typeof value === 'number' && Number.isFinite(value)
Expand Down Expand Up @@ -36,15 +36,15 @@ export function sanitizeBrowserToolResultForModel(
note: 'The screenshot could not be encoded. Use browser_snapshot or browser_read_text instead.',
}
}
const viewport = isRecordLike(rest.viewport) ? rest.viewport : null
const viewport = toRecordOrNull(rest.viewport)
const screenshotUrl =
typeof rest.url === 'string' && rest.url
? rest.url
: viewport && typeof viewport.url === 'string'
? viewport.url
: ''
const location = screenshotUrl ? ` of ${screenshotUrl}` : ''
const clip = isRecordLike(rest.clip) ? rest.clip : null
const clip = toRecordOrNull(rest.clip)
const cropSize = imageDimensions(clip)
const viewportSize = imageDimensions(viewport)
const imageSize = imageDimensions(rest.imageSize)
Expand Down
4 changes: 2 additions & 2 deletions apps/sim/lib/internal/buffer/operations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { isRecordLike } from '@sim/utils/object'
import { isRecordLike, toRecord } from '@sim/utils/object'
import type { EgressProfile } from '@/lib/core/security/egress/profiles'
import {
secureFetchWithPinnedIP,
Expand Down Expand Up @@ -166,7 +166,7 @@ async function executePostMutation(args: {
})
const data = await parseBufferGraphQLResponse(response)
const candidate = data.createPost ?? data.editPost
result = isRecordLike(candidate) ? candidate : {}
result = toRecord(candidate)
} catch (error) {
context.signal?.throwIfAborted()
const message = getErrorMessage(error, 'Buffer API request failed')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { toRecordOrNull } from '@sim/utils/object'
import type { InternalToolOperationImplementation } from '@/lib/internal/tool-operations/types'
import type { CbInsightsOrgParams } from '@/tools/cbinsights/types'
import {
asNumber,
asRecord,
asString,
cbInsightsRequest,
requireOrgId,
} from '@/tools/cbinsights/utils'
import { asNumber, asString, cbInsightsRequest, requireOrgId } from '@/tools/cbinsights/utils'

export const executeCbinsightsGetOrgFundingWindowOperation: InternalToolOperationImplementation<
CbInsightsOrgParams
Expand All @@ -25,8 +20,8 @@ export const executeCbinsightsGetOrgFundingWindowOperation: InternalToolOperatio
windowStart: asString(data.windowStart),
windowEnd: asString(data.windowEnd),
cohortNextRoundRate: asNumber(data.cohortNextRoundRate),
cohortCriteria: asRecord(data.cohortCriteria),
latestFunding: asRecord(data.latestFunding),
cohortCriteria: toRecordOrNull(data.cohortCriteria),
Comment thread
waleedlatif1 marked this conversation as resolved.
latestFunding: toRecordOrNull(data.latestFunding),
}),
signal
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toRecordOrNull } from '@sim/utils/object'
import type { InternalToolOperationImplementation } from '@/lib/internal/tool-operations/types'
import type { CbInsightsOrgParams } from '@/tools/cbinsights/types'
import { asRecord, cbInsightsRequest, requireOrgId } from '@/tools/cbinsights/utils'
import { cbInsightsRequest, requireOrgId } from '@/tools/cbinsights/utils'

export const executeCbinsightsGetOrgOutlookOperation: InternalToolOperationImplementation<
CbInsightsOrgParams
Expand All @@ -14,9 +15,9 @@ export const executeCbinsightsGetOrgOutlookOperation: InternalToolOperationImple
params,
{ path: `/v2/organizations/${orgId}/outlook` },
(data) => ({
mosaicScore: asRecord(data.mosaicScore),
commercialMaturity: asRecord(data.commercialMaturity),
exitProbability: asRecord(data.exitProbability),
mosaicScore: toRecordOrNull(data.mosaicScore),
commercialMaturity: toRecordOrNull(data.commercialMaturity),
exitProbability: toRecordOrNull(data.exitProbability),
}),
signal
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { toRecordOrNull } from '@sim/utils/object'
import type { InternalToolOperationImplementation } from '@/lib/internal/tool-operations/types'
import type { CbInsightsOrgParams } from '@/tools/cbinsights/types'
import {
asRecord,
asString,
cbInsightsRequest,
requireOrgId,
Expand All @@ -23,7 +23,7 @@ export const executeCbinsightsGetScoutingReportOperation: InternalToolOperationI
timeoutMs: SCOUTING_REPORT_TIMEOUT_MS,
},
(data) => ({
orgInfo: asRecord(data.orgInfo),
orgInfo: toRecordOrNull(data.orgInfo),
reportMarkdown: asString(data.reportMarkdown),
reportJson: asString(data.reportJson),
}),
Expand Down
3 changes: 2 additions & 1 deletion apps/sim/lib/internal/confluence/client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { toRecord } from '@sim/utils/object'
import { validateJiraCloudId } from '@/lib/core/security/input-validation'
import { MAX_JSON_API_RESPONSE_BYTES } from '@/lib/core/security/input-validation.server'
import {
Expand All @@ -17,7 +18,7 @@ export interface ConfluenceConnectionConfig {
export type JsonObject = Record<string, unknown>

export function asObject(value: unknown): JsonObject {
return value && typeof value === 'object' && !Array.isArray(value) ? (value as JsonObject) : {}
return toRecord(value)
}

export function asArray(value: unknown): unknown[] {
Expand Down
Loading
Loading