Skip to content

Commit 4c0ee74

Browse files
committed
improvement(utils): route the remaining record-coercion helpers through toRecord
The first pass matched one operand order, so six exact equivalents written `x !== null && typeof x === 'object'` survived — two of them beside a sibling the pass had already deleted. Domain-named wrappers keep their names and delegate, matching the microsoft-teams client that already did.
1 parent 5765543 commit 4c0ee74

13 files changed

Lines changed: 27 additions & 43 deletions

File tree

‎apps/sim/lib/internal/confluence/client.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { toRecord } from '@sim/utils/object'
12
import { validateJiraCloudId } from '@/lib/core/security/input-validation'
23
import { MAX_JSON_API_RESPONSE_BYTES } from '@/lib/core/security/input-validation.server'
34
import {
@@ -17,7 +18,7 @@ export interface ConfluenceConnectionConfig {
1718
export type JsonObject = Record<string, unknown>
1819

1920
export function asObject(value: unknown): JsonObject {
20-
return value && typeof value === 'object' && !Array.isArray(value) ? (value as JsonObject) : {}
21+
return toRecord(value)
2122
}
2223

2324
export function asArray(value: unknown): unknown[] {

‎apps/sim/lib/internal/google-drive/client.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { toRecord } from '@sim/utils/object'
12
import {
23
MAX_JSON_API_RESPONSE_BYTES,
34
type SecureFetchResponse,
@@ -54,9 +55,7 @@ export async function requestGoogleDrive(
5455
export type JsonObject = Record<string, unknown>
5556

5657
export function asObject(value: unknown): JsonObject {
57-
return value !== null && typeof value === 'object' && !Array.isArray(value)
58-
? (value as JsonObject)
59-
: {}
58+
return toRecord(value)
6059
}
6160

6261
export async function responseObject(response: SecureFetchResponse): Promise<JsonObject> {

‎apps/sim/lib/internal/google-drive/operations.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ const mocks = vi.hoisted(() => ({
99
}))
1010

1111
vi.mock('@/lib/internal/google-drive/client', () => ({
12-
asObject: (value: unknown) =>
13-
value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {},
12+
asObject: (value: unknown) => toRecord(value),
1413
googleApiErrorMessage: (data: { error?: { message?: string } }, fallback: string) =>
1514
data.error?.message || fallback,
1615
requestGoogleDrive: mocks.request,
@@ -21,6 +20,7 @@ vi.mock('@/lib/internal/google-drive/file-input', () => ({
2120
resolveGoogleDriveUploadFile: mocks.resolveFile,
2221
}))
2322

23+
import { toRecord } from '@sim/utils/object'
2424
import {
2525
executeGoogleDriveDownload,
2626
executeGoogleDriveExport,

‎apps/sim/lib/internal/jira/operations.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Logger } from '@sim/logger'
22
import { createLogger } from '@sim/logger'
3+
import { toRecord } from '@sim/utils/object'
34
import { validateAlphanumericId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
45
import { createJiraClient, type JiraClient } from '@/lib/internal/jira/client'
56
import { JiraOperationError } from '@/lib/internal/jira/errors'
@@ -26,9 +27,7 @@ export interface JiraOperationContext {
2627
type JsonObject = Record<string, unknown>
2728

2829
function asObject(value: unknown): JsonObject {
29-
return value !== null && typeof value === 'object' && !Array.isArray(value)
30-
? (value as JsonObject)
31-
: {}
30+
return toRecord(value)
3231
}
3332

3433
function parseObject(text: string): JsonObject {

‎apps/sim/lib/internal/microsoft-dataverse/client.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export async function uploadDataverseFile(
4141
return
4242
}
4343
const data = await response.json().catch(() => null)
44-
const error = isRecordLike(data) && toRecordOrNull(data.error)
44+
const error = isRecordLike(data) ? toRecordOrNull(data.error) : null
4545
const message =
4646
error && typeof error.message === 'string'
4747
? error.message

‎apps/sim/lib/internal/onepassword/client.ts‎

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {
1111
Website,
1212
} from '@1password/sdk'
1313
import { generateId } from '@sim/utils/id'
14+
import { toRecord } from '@sim/utils/object'
1415
import {
1516
MAX_JSON_API_RESPONSE_BYTES,
1617
type SecureFetchResponse,
@@ -449,12 +450,6 @@ export function findItemFileAttributes(item: Item, fileId: string): FileAttribut
449450
* category enum strings vs Connect's SCREAMING_SNAKE_CASE) and silently no-ops or
450451
* corrupts the write otherwise.
451452
*/
452-
function objectValue(value: unknown): Record<string, unknown> {
453-
return value !== null && typeof value === 'object' && !Array.isArray(value)
454-
? (value as Record<string, unknown>)
455-
: {}
456-
}
457-
458453
function optionalString(value: unknown): string | undefined {
459454
return typeof value === 'string' ? value : undefined
460455
}
@@ -465,8 +460,8 @@ export function connectItemToSdkItem(connectItem: Record<string, unknown>, exist
465460

466461
const fields = Array.isArray(connectItem.fields)
467462
? connectItem.fields.map((value) => {
468-
const field = objectValue(value)
469-
const section = objectValue(field.section)
463+
const field = toRecord(value)
464+
const section = toRecord(field.section)
470465
const id = optionalString(field.id)
471466
return {
472467
/** Preserve SDK-only metadata on fields that already existed. */
@@ -482,7 +477,7 @@ export function connectItemToSdkItem(connectItem: Record<string, unknown>, exist
482477

483478
const sections = Array.isArray(connectItem.sections)
484479
? connectItem.sections.map((value) => {
485-
const section = objectValue(value)
480+
const section = toRecord(value)
486481
const id = optionalString(section.id)
487482
return {
488483
...(id ? existingSectionsById.get(id) : undefined),
@@ -495,7 +490,7 @@ export function connectItemToSdkItem(connectItem: Record<string, unknown>, exist
495490
const websitesValue = connectItem.urls ?? connectItem.websites
496491
const websites = Array.isArray(websitesValue)
497492
? websitesValue.map((value) => {
498-
const website = objectValue(value)
493+
const website = toRecord(value)
499494
return {
500495
url: optionalString(website.href) || optionalString(website.url) || '',
501496
label: optionalString(website.label) || '',

‎apps/sim/lib/internal/servicenow/client.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export async function uploadServiceNowAttachment(
4545
)
4646
const data = await response.json().catch(() => null)
4747
if (!response.ok) {
48-
const error = isRecordLike(data) && toRecordOrNull(data.error)
48+
const error = isRecordLike(data) ? toRecordOrNull(data.error) : null
4949
const message =
5050
error && typeof error.message === 'string'
5151
? error.message

‎apps/sim/lib/internal/slack/operations.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createLogger } from '@sim/logger'
2+
import { toRecord } from '@sim/utils/object'
23
import type {
34
SlackDeleteMessageBody,
45
SlackDownloadBody,
@@ -49,9 +50,7 @@ function providerError(data: SlackJsonObject, status: number, fallback: string):
4950
}
5051

5152
function record(value: unknown): SlackJsonObject {
52-
return typeof value === 'object' && value !== null && !Array.isArray(value)
53-
? (value as SlackJsonObject)
54-
: {}
53+
return toRecord(value)
5554
}
5655

5756
function mapReaction(value: unknown) {

‎apps/sim/lib/webhooks/slack-custom-ingress.ts‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createLogger } from '@sim/logger'
2+
import { toRecord } from '@sim/utils/object'
23
import type { NextRequest } from 'next/server'
34
import { NextResponse } from 'next/server'
45
import { cancelWorkflowExecution } from '@/lib/execution/cancel-workflow-execution'
@@ -46,12 +47,7 @@ interface DispatchSlackCustomBotOptions {
4647
export function getLegacySlackCustomBotCredentialId(
4748
foundWebhook: LegacySlackPathWebhook
4849
): string | null {
49-
const providerConfig =
50-
foundWebhook.providerConfig !== null &&
51-
typeof foundWebhook.providerConfig === 'object' &&
52-
!Array.isArray(foundWebhook.providerConfig)
53-
? (foundWebhook.providerConfig as Record<string, unknown>)
54-
: {}
50+
const providerConfig = toRecord(foundWebhook.providerConfig)
5551

5652
if (providerConfig.ingressMode !== LEGACY_SLACK_CUSTOM_BOT_INGRESS_MODE) {
5753
return null

‎apps/sim/tools/bitbucket/get_merge_task_status.ts‎

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { toRecordOrNull } from '@sim/utils/object'
12
import {
23
BITBUCKET_PULL_REQUEST_OUTPUT_PROPERTIES,
34
type BitbucketGetMergeTaskStatusParams,
@@ -23,12 +24,6 @@ interface BitbucketMergeTaskOutput {
2324
mergeResult: BitbucketPullRequest | null
2425
}
2526

26-
function record(value: unknown): Record<string, unknown> | null {
27-
return typeof value === 'object' && value !== null && !Array.isArray(value)
28-
? (value as Record<string, unknown>)
29-
: null
30-
}
31-
3227
function stringField(value: unknown): string | null {
3328
return typeof value === 'string' ? value : null
3429
}
@@ -61,7 +56,7 @@ export const bitbucketGetMergeTaskStatusTool: ToolConfig<
6156
transformResponse: async (response) => {
6257
const data = await bitbucketJson(response)
6358
if (data.type === 'error') {
64-
const error = record(data.error)
59+
const error = toRecordOrNull(data.error)
6560
const message = stringField(error?.message)?.trim()
6661
if (!message) throw new Error('Bitbucket returned a malformed merge task error')
6762
const detail = stringField(error?.detail)?.trim()
@@ -73,11 +68,11 @@ export const bitbucketGetMergeTaskStatusTool: ToolConfig<
7368
throw new Error('Bitbucket merge task status must be PENDING or SUCCESS')
7469
}
7570

76-
const links = record(data.links)
77-
const self = record(links?.self)
71+
const links = toRecordOrNull(data.links)
72+
const self = toRecordOrNull(links?.self)
7873
let mergeResult: BitbucketPullRequest | null = null
7974
if (taskStatus === 'SUCCESS') {
80-
const result = record(data.merge_result)
75+
const result = toRecordOrNull(data.merge_result)
8176
if (!result) throw new Error('Bitbucket successful merge task omitted merge_result')
8277
mergeResult = normalizeBitbucketPullRequest(result)
8378
}

0 commit comments

Comments
 (0)