Skip to content

refactor(sim): consolidate record guards + pure utils into @sim/utils#5061

Merged
waleedlatif1 merged 2 commits into
stagingfrom
refactor/consolidate-record-utils
Jun 15, 2026
Merged

refactor(sim): consolidate record guards + pure utils into @sim/utils#5061
waleedlatif1 merged 2 commits into
stagingfrom
refactor/consolidate-record-utils

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Add canonical record guards + pure helpers to @sim/utils: isRecordLike (loose), sortObjectKeysDeep; relocate isPlainRecord (strict) and normalizeEmail so they're reusable across apps and packages.
  • Replace ~55 re-implemented loose record guards (typeof === 'object' && !== null && !Array.isArray) across tools/providers/lib/workflows/copilot/triggers/contracts with the single isRecordLike; one strict site → isPlainRecord.
  • Dedupe three true-duplicate normalize* clusters: sortObjectKeysDeep (sanitization + copilot builders), normalizeToken (salesforce + servicenow triggers), normalizeEmail.
  • Intentionally left untouched: array-allowing guards (different predicate) and all domain-specific normalizers (comparison/normalize.ts, copilot persisted-message, vanta, SSO/domain) — migrating those would change behavior.

Type of Change

  • Refactor (no functional change)

Testing

  • New @sim/utils unit tests: loose-vs-strict guard distinction (Date/class-instance → loose true, strict false), deep key sort, email normalization.
  • Typecheck clean (apps + package), biome clean, check:api-validation:strict + monorepo-boundary checks pass.
  • Behavior audited line-by-line by independent adversarial reviewers against origin/staging — every migrated predicate/transform is an exact semantic no-op; the one risky union-narrowing site (lib/table/sql.ts) was deliberately skipped.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Add isRecordLike (loose, non-prototype-checked record guard) and
sortObjectKeysDeep; relocate isPlainRecord (strict) and normalizeEmail
into @sim/utils so they are reusable across apps and packages. Unit tests
cover the loose-vs-strict distinction, deep key sorting, and email
normalization.
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 15, 2026 6:55pm

Request Review

@cursor

cursor Bot commented Jun 15, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Mechanical refactor to shared utilities with intended semantic parity; touches auth/invitation email normalization but behavior matches prior trim+lowercase.

Overview
Centralizes shared pure helpers in @sim/utils and rewires apps/sim to import them instead of redefining the same logic locally.

@sim/utils/object: isRecordLike (loose non-array object guard), isPlainRecord (strict plain-object guard), and sortObjectKeysDeep replace dozens of copy-pasted isRecord / isJsonRecord / isPlainObject checks across API tool routes, Zod contracts, copilot stream parsing, executor start-block handling, webhooks, and UI hooks. lib/core/utils/records now delegates strict checks to isPlainRecord and drops its local isPlainRecord implementation (and related unit tests).

@sim/utils/string: normalizeEmail replaces email.trim().toLowerCase() and invitation-local normalizers in auth verification, access control, and invitation/credential-set API routes.

Other: Copilot workflow JSON formatting uses shared sortObjectKeysDeep instead of an inline recursive sorter; stream/index no longer re-exports a local isRecord helper.

Domain-specific normalizers and array-allowing guards called out in the PR description are intentionally unchanged.

Reviewed by Cursor Bugbot for commit 3cbf4c7. Configure here.

@waleedlatif1 waleedlatif1 changed the title refactor(sim): consolidate record guards + pure utils into @sim/utils (no behavior change) refactor(sim): consolidate record guards + pure utils into @sim/utils Jun 15, 2026
@greptile-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR consolidates a widespread pattern of locally-duplicated record guard predicates and pure utility functions into the @sim/utils package, replacing ~55 inline isRecord/isPlainObject/isJsonRecord checks across tools, providers, copilot, and trigger code with canonical isRecordLike and isPlainRecord helpers exported from @sim/utils/object.

  • Record guards: isRecordLike (loose — accepts class instances, Date) and isPlainRecord (strict — plain-object only) are now shared via packages/utils/src/object.ts; all local variants were verified to be semantically equivalent before replacement.
  • Key-sort dedup: Two independent sortKeysRecursively/sortKeys implementations in json-sanitizer.ts and copilot builders are replaced by the new sortObjectKeysDeep export.
  • Token/email normalization: normalizeToken (salesforce + servicenow triggers) and normalizeEmail (auth + invitations) are consolidated into triggers/utils/tokens.ts and @sim/utils/string respectively.

Confidence Score: 5/5

This is a mechanical deduplication refactor with no functional changes — every replaced predicate and transform is semantically identical to its canonical equivalent.

All ~55 inline record-guard substitutions replace predicates logically equivalent to isRecordLike. Boolean(v) and v !== null produce identical results for objects. isPlainRecord is a straight move with unchanged prototype logic. sortObjectKeysDeep is byte-for-byte identical to the two local implementations it replaces. normalizeToken and normalizeEmail consolidations are exact copies. The package.json subpath exports for @sim/utils/object and @sim/utils/string are already in place.

No files require special attention — the most complex migration sites (copilot/request/session/contract.ts and executor/utils/start-block.ts) were audited and found to be clean substitutions.

Important Files Changed

Filename Overview
packages/utils/src/object.ts Adds isPlainRecord (strict prototype check), isRecordLike (loose non-null non-array check), and sortObjectKeysDeep (recursive key-sort). All implementations are correct and well-documented.
packages/utils/src/string.ts Adds normalizeEmail as a pure trim+lowercase helper. Identical to the function removed from invitations/core.ts.
packages/utils/src/index.ts Re-exports new canonical symbols (isPlainRecord, isRecordLike, sortObjectKeysDeep, normalizeEmail) from the package root barrel.
packages/utils/src/object.test.ts New test suite covering isPlainRecord, isRecordLike, and sortObjectKeysDeep with Date/class-instance/array/primitive cases. Coverage is complete for the public contract.
apps/sim/lib/core/utils/records.ts isPlainRecord removed from local definition; now imported from @sim/utils/object for internal use. All callers updated to import directly from @sim/utils/object rather than via this file.
apps/sim/triggers/utils/tokens.ts New file consolidating the duplicated normalizeToken function from salesforce and servicenow triggers. Implementation is identical to both originals.
apps/sim/lib/copilot/request/session/contract.ts Local isRecord (Boolean(value) && typeof === 'object' && !Array.isArray) replaced by isRecordLike across 13 call sites. Boolean(value) and value !== null are semantically equivalent for non-null objects, so no behavior change.
apps/sim/executor/utils/start-block.ts Local isPlainObject replaced by isRecordLike across 13 call sites; predicate is semantically identical.
apps/sim/lib/workflows/sanitization/json-sanitizer.ts Local sortKeysRecursively and isRecord replaced by sortObjectKeysDeep and isRecordLike from @sim/utils/object. Implementations are identical.
apps/sim/lib/uploads/utils/user-file-base64.server.ts Local isPlainObject (checked !value
apps/sim/tools/vanta/utils.ts Local isJsonRecord replaced by isRecordLike across 18 call sites. Predicate is identical.
apps/sim/lib/invitations/core.ts normalizeEmail removed from this file; callers updated to import from @sim/utils/string. normalizeEmail imported here from @sim/utils/string for continued local use.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["@sim/utils/object"] -->|isRecordLike| B["55+ call sites across\ntools / copilot / triggers / lib"]
    A -->|isPlainRecord| C["records.ts\nexecution-core.ts\nsubblocks.ts\nsubblock-migrations.ts\nuser-file-base64.server.ts"]
    A -->|sortObjectKeysDeep| D["json-sanitizer.ts\nbuilders.ts"]

    E["@sim/utils/string"] -->|normalizeEmail| F["invitations/core.ts\ninvitations/send.ts\nworkspace-invitations.ts\nroute handlers"]

    G["triggers/utils/tokens.ts"] -->|normalizeToken| H["salesforce/utils.ts\nservicenow/utils.ts"]

    style A fill:#4ade80,stroke:#16a34a
    style E fill:#4ade80,stroke:#16a34a
    style G fill:#86efac,stroke:#16a34a
Loading

Reviews (2): Last reviewed commit: "refactor(sim): consolidate record guards..." | Re-trigger Greptile

…sim/utils

Replace ~55 re-implemented loose record guards with the canonical
@sim/utils isRecordLike (and one strict site with isPlainRecord), and
dedupe three normalize clusters: sortObjectKeysDeep (sanitization +
copilot builders), normalizeToken (salesforce + servicenow triggers),
and normalizeEmail. Array-allowing guards and domain-specific normalizers
are intentionally left untouched. Pure refactor — identical predicates
and transforms, no behavior change.
@waleedlatif1 waleedlatif1 force-pushed the refactor/consolidate-record-utils branch from 69ad368 to 3cbf4c7 Compare June 15, 2026 18:55
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3cbf4c7. Configure here.

@waleedlatif1 waleedlatif1 merged commit 0673e3c into staging Jun 15, 2026
15 checks passed
@waleedlatif1 waleedlatif1 deleted the refactor/consolidate-record-utils branch June 15, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant