npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@salesforce/graphiti

v10.19.1

Published

Progressive GraphQL query builder CLI for Salesforce orgs

Readme

graphiti

Progressive GraphQL query builder CLI for Salesforce orgs. Treats a query as a projection of the schema — navigate the schema like a filesystem, select leaf fields, set arguments, and compose queries without ever writing raw GraphQL.

Install

npm install
npm run build

Run via node dist/cli.js (built) or npx tsx src/cli.ts (dev).

Prerequisites

  • Salesforce CLI installed and authenticated (sf org login web --alias myorg)

Quick Start

# 1. Connect to an org (downloads GraphQL schema once)
graphiti connect myorg

# 2. Start a new query session
graphiti query new myorg
# → prints Session: s_xxxx and root fields

# 3. Navigate the schema like a directory
graphiti query s_xxxx ls                       # list available fields
graphiti query s_xxxx ls -l                    # long listing (type, args, selections)
graphiti query s_xxxx ls --search Account      # filter by name
graphiti query s_xxxx cd accounts             # enter a field directory
graphiti query s_xxxx cd accounts/edges/node  # multi-level nav
graphiti query s_xxxx pwd                      # print current path
graphiti query s_xxxx cd ..                   # go up one level
graphiti query s_xxxx cd /                    # go back to root

# 4. Select leaf fields (parent path added automatically)
graphiti query s_xxxx select Id
graphiti query s_xxxx select Name --as accountName

# 5. Remove a selection
graphiti query s_xxxx rm Id

# 6. Navigate union/interface fragment directories
graphiti query s_xxxx cd search               # field of union type
graphiti query s_xxxx cd [Account]            # inline fragment directory
graphiti query s_xxxx select name

# 7. Set field arguments
graphiti query s_xxxx cd accounts
graphiti query s_xxxx args set first 10
graphiti query s_xxxx args set where '{"Status":{"eq":"Open"}}'
graphiti query s_xxxx args ls
graphiti query s_xxxx args rm first

# 8. Bind arguments to query variables
graphiti query s_xxxx vars set \$whereInput AccountWhere
graphiti query s_xxxx bind set where \$whereInput

# 9. Set directory-scoped default argument values
graphiti query s_xxxx defaults set first 20

# 10. Preview and execute
graphiti query s_xxxx show
graphiti query s_xxxx validate
graphiti query s_xxxx execute

Interactive Mode

Start an interactive REPL session for faster iteration — same commands, no need to repeat the session ID each time. Bare commands like select, cd, and args set show guided pick-lists.

graphiti query s_xxxx interactive

REPL prompt: graphiti [s_xxxx] /accounts >

Inside the REPL:

  • Type any subcommand (ls, cd edges, select Id, etc.) without the graphiti query s_xxxx prefix.
  • select with no argument → guided pick-list of available leaf fields.
  • cd with no argument → guided pick-list of navigable directories.
  • args set with no argument → guided pick-list of available field arguments.
  • vars set with just set → guided prompts for name, type, and default value.
  • exit or Ctrl-C to quit.

Commands Reference

Setup

| Command | Description | | ------------------------------------------- | ---------------------------------------------------------------------- | | graphiti connect <org> | Connect to a Salesforce org and download its GraphQL schema | | graphiti connect <org> --refresh | Re-download the schema and clear all caches (after deploying metadata) | | graphiti type <org> <TypeName> | Inspect a named GraphQL type | | graphiti validate <org> <TypeName> <json> | Validate a JSON value against an input type |

Session lifecycle

| Command | Description | | ----------------------------------------------------- | -------------------------------------------------- | | graphiti query new <org> [--mutation] [--aggregate] | Create a new query, mutation, or aggregate session | | graphiti query help [topic] | Show command help, optionally scoped to a topic |

Navigation

| Command | Description | | --------------------------------------------- | ----------------------------------------------------------- | | graphiti query <sid> pwd | Print current schema navigation path | | graphiti query <sid> ls [-l] [--search pat] | List schema entries at current path | | graphiti query <sid> cd <path> | Navigate to a schema path (supports .., /, multi-level) |

Projection

| Command | Description | | ------------------------------------------------- | ---------------------------------------- | | graphiti query <sid> select <leaf> [--as alias] | Select a leaf field (parents auto-added) | | graphiti query <sid> rm <field-or-alias> | Remove a leaf selection |

Multiple instances & aliases

| Command | Description | | ---------------------------------------------- | ---------------------------------------------- | | graphiti query <sid> alias ls | List all projection instances at current path | | graphiti query <sid> alias set <name> | Set alias on the focused instance | | graphiti query <sid> alias new <name> | Create a new projection instance with an alias | | graphiti query <sid> alias use <alias-or-id> | Switch focus to a different instance | | graphiti query <sid> alias clear | Remove alias from the focused instance |

Use alias new to select the same field multiple times with different arguments (e.g., two aliased versions of accounts with different where clauses).

Arguments

| Command | Description | | ---------------------------------------------- | -------------------------------------------- | | graphiti query <sid> args ls | List args on the focused projection instance | | graphiti query <sid> args set <name> <value> | Set an argument value | | graphiti query <sid> args rm <name> | Remove an argument |

Variable bindings

| Command | Description | | -------------------------------------------- | ---------------------------------------------- | | graphiti query <sid> bind ls | List variable bindings on the focused instance | | graphiti query <sid> bind set <arg> <$var> | Bind an argument to a query variable | | graphiti query <sid> bind rm <arg> | Remove a binding |

Directory-scoped defaults

Default argument values applied to all projection instances under the current path unless an instance overrides them.

| Command | Description | | -------------------------------------------------- | ----------------------------- | | graphiti query <sid> defaults ls | List defaults at current path | | graphiti query <sid> defaults set <name> <value> | Set a default | | graphiti query <sid> defaults rm <name> | Remove a default |

Variables

| Command | Description | | -------------------------------------------------------- | ------------------------ | | graphiti query <sid> vars ls | List all query variables | | graphiti query <sid> vars set <$name> <type> [default] | Define a variable | | graphiti query <sid> vars value <$name> <value> | Set the runtime value | | graphiti query <sid> vars rm <$name> | Remove a variable |

Query output

| Command | Description | | ------------------------------- | -------------------------------------------- | | graphiti query <sid> show | Print the current GraphQL query string | | graphiti query <sid> validate | Validate the query against the schema | | graphiti query <sid> execute | Execute the query against the Salesforce org |

Interactive

| Command | Description | | ---------------------------------- | --------------------------------- | | graphiti query <sid> interactive | Start an interactive REPL session |

Performance

Schema and auth data are cached aggressively to minimize cold-start overhead:

  • Auth memoizationsf org display is called at most once per process; the result is cached for the lifetime of the command or interactive session.
  • Session-stored instanceUrl — The Salesforce instance URL is resolved once at query new time and persisted in the session file. Subsequent commands use this URL to locate the cached schema file directly, completely bypassing sf org display.
  • SDL schema cache — After a schema is first built from the introspection JSON, it is serialized to a compact SDL file (~/.graphiti/schemas/<cacheKey>.graphql) next to the introspection JSON. Subsequent cold starts load the SDL file instead, which is faster than re-processing the raw introspection format.
  • In-process schema cache — Within a single interactive session, the parsed GraphQLSchema is kept in memory so every command after the first is near-instant.

Schema storage

Schemas are stored in ~/.graphiti/schemas/ keyed by a hash of the normalized Salesforce instance URL. This means:

  • Reusing an org alias for a different org will always pick up the correct schema.
  • The companion SDL file (<cacheKey>.graphql) is regenerated automatically whenever the introspection JSON is updated.

Refreshing after a deploy

graphiti caches three things per org: the on-disk introspection JSON, the in-memory parsed schema, and an ObjectInfo cache (picklists, filterable/sortable flags, required-on-create; 1-hour TTL on disk). When you deploy new metadata (fields, picklist values, objects), run a refresh to invalidate all three coherently:

  • graphiti connect <org> --refresh re-downloads the schema and clears all three caches.
  • In the MCP server, call the sf_gql_connect tool with forceRefresh: true — the long-lived server cannot otherwise pick up new metadata, since its in-memory caches outlive a single request.
  • Concurrent refreshes (a CLI --refresh and an MCP sf_gql_connect firing at once) coalesce into a single introspection via the on-disk schema lock, so you normally never pay for the (large, multi-second) introspection twice. Coalescing is best-effort: it keys off the cache file's modification time, so on filesystems with coarse mtime resolution two refreshes landing in the same tick may each download — never incorrect, just occasionally redundant.
  • If a refresh fails (network/5xx) it is retried once; on terminal failure the previously cached schema is kept and a staleness-aware message is surfaced — the cache stays usable.

ObjectInfo is keyed by org alias, not instance URL. Refreshing alias A does not invalidate ObjectInfo cached under a different alias B that points at the same org; refresh each alias you actively use, or let ObjectInfo's 1-hour TTL heal it.

Development

npm run build     # compile TypeScript
npm test          # build + run tests