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

@gsb-core/cli

v0.1.3

Published

CLI tool for syncing GSB serverless functions and libraries

Readme

GSB CLI Tool

A command-line interface for syncing GSB serverless functions and libraries to the GSB backend.

Features

  • 🚀 Push TypeScript/JavaScript files to GSB backend
  • 📄 Pull/Push document templates with multilingual support
  • 🧪 Test functions without saving them
  • 📋 Dry-run mode to preview changes
  • 🔧 Auto-detection of function vs library types
  • 📖 Support for metadata files
  • 📁 Organized folder structure for document templates
  • ⚙️ Configuration from existing MCP setup

Installation

Node.js 20 or newer and pnpm are supported.

Local Development

pnpm install
pnpm --filter @gsb-core/cli build

Global Installation (NPX)

npm install -g @gsb-core/cli

The installed gsb --version value is read from the published package metadata.

Configuration

Credential precedence is explicit environment variables, then the OS-native credential keyring referenced by .gsb/<tenantCode>/credentials.json, then a mode-0600 token in that file when no keyring is available, and finally the legacy .cursor/mcp.json entry. This allows CI credentials to override a developer's saved login. Conflicting tenant selectors, token aliases, or API URL aliases fail before any request.

Use GSB_TOKEN, GSB_TENANT_CODE, and GSB_BASE_URL for CI. GSB_API_KEY and GSB_API_URL remain supported aliases. Do not commit credentials; the MCP form below is retained only for existing installations.

Sign in interactively with gsb init --tenant dev1. For non-interactive setup, put the password in a temporary environment variable and name that variable rather than passing the secret as a command argument:

gsb init --tenant dev1 --email [email protected] \
  --password-env GSB_LOGIN_PASSWORD --force --json

Non-interactive initialization never prompts. Missing inputs use the same stable JSON error envelope and exit codes as other automated commands.

Expected structure:

{
  "mcpServers": {
    "GSB Back End": {
      "env": {
        "GSB_API_KEY": "your-api-key",
        "GSB_TENANT_CODE": "your-tenant-code"
      }
    }
  }
}

Usage

Shell Completion

Generate completion candidates directly from the installed CLI command tree:

# Bash
source <(gsb completion bash)

# Zsh
source <(gsb completion zsh)

# Fish
gsb completion fish | source

Add the matching command to the shell profile to enable it for future sessions. The generated script includes nested commands and options from the installed CLI version, so it stays aligned with the published command surface.

Automation Output

Migrated commands support --json. Successful envelopes are written to stdout, while progress and error envelopes are written to stderr. Errors include a stable error.code, and commands never prompt when required approval is absent.

gsb call query --json --input '{"queryParams":{"entDefName":"Order"}}'
gsb call save --json --yes --input-file ./request.json
gsb tools --read-only --json
gsb backup list --status completed --json
gsb backup show <backup-id-or-code> --json

gsb call --raw remains available for scripts that expect the legacy unwrapped result. New automation should use --json. gsb tools --json returns the local MCP registry without requiring tenant credentials; --read-only filters the structured result to tools classified as read. backup list --json validates filters before authentication, while backup show --json returns one backup record. Both use the same stable result or error envelope.

Backup mutations require approval bound to the selected tenant. Generic --yes does not authorize restore or deletion:

gsb backup add "Before release" --confirm-tenant dev1 --json
gsb backup restore <backup-id-or-code> \
  --confirm-tenant dev1 --json
gsb backup delete <backup-id-or-code> \
  --confirm-tenant dev1 --json

Interactive use prompts for the tenant code. Non-interactive use never prompts and fails with APPROVAL_REQUIRED unless --confirm-tenant exactly matches the verified target. If backup creation succeeds but starting it fails, the error is PARTIAL_APPLICATION and includes the created backup record for recovery.

gsb config --json reports the resolved tenant, effective API URL, credential source, and backend-verified user id. Operational commands call /api/auth/verifyToken while resolving their execution context and reject an invalid identity or a verified tenant that differs from the selected tenant. The CLI does not decode and trust JWT claims.

Use the standalone diagnostic to inspect authenticated or public identity details:

gsb verify-token --json
gsb verify-token --anonymous --json

Both forms make exactly one POST /api/auth/verifyToken request with {"variation":{"tenantCode":"..."}}. The first sends the configured JWT and returns its verified email, role IDs, groups, and positions. The backend wire field is auth.roles, but its values are immutable role IDs, not names. --anonymous omits the JWT and requires no saved credential; it returns the tenant's public user identity and role IDs with a successful response.

Generate checked TypeScript interfaces from pulled entity schemas and verify the committed output has not drifted:

gsb schema-types --out .gsb/dev1/schema/entities.d.ts
gsb schema-types --out .gsb/dev1/schema/entities.d.ts --check

Use gsb inspect workflow <instanceId> --json or gsb inspect task <jobId> --json for the unified read-only inspection surface. Run pnpm --dir packages/public/platform/cli docs:generate to regenerate COMMANDS.md from the installed Commander tree and deprecation registry.

Local Change Status

gsb status
gsb status --all
gsb status --json

status compares local resources with their last successful pull or verified push. It reports clean, modified, or legacy-untracked; human output hides clean resources unless --all is set, while JSON always includes every resource and its current and baseline hashes. The report states remoteComparison: "not-requested" until three-way remote comparison is implemented.

gsb diff
gsb diff --remote
gsb diff --json

diff reports canonical resource-level hash changes. Modified resources include their baseline and current hashes. Resources created before content-hash tracking are reported as unavailable instead of presenting timestamp evidence as a content diff. Add --remote to authenticate against the selected tenant and compare each resource's immutable identity and saved cloud lastUpdateDate with the live row. This detects cloud-only updates, deletions, and name conflicts even when local files are clean. It is a cloud revision comparison, not a remote payload hash or field diff.

gsb plan --output change-plan.json
gsb plan --output change-plan.json --allow-create NewLibrary
gsb plan --output change-plan.json --allow-renames --json
gsb apply change-plan.json --output apply-result.json --json
gsb verify apply-result.json --json

plan reads live asset identities without mutating them and writes a versioned, content-addressed artifact. Existing updates require a content-hash baseline. New resources require exact-name approval, renames require --allow-renames, and an existing output file is never overwritten. Plans bind remote identity and lastUpdateDate; apply rechecks every precondition before each operation, performs the normal GSB save only when the revision matches, and reads every write back. It stops with applied, failed, and remaining operations if an operation fails. verify accepts either a plan or an apply-result artifact. Backend revision strings are preserved exactly, including values without a timezone, so comparison uses the byte-for-byte value returned by the API. A missing or changed revision stops the save: pull and reevaluate the edits before creating a replacement plan. Per-operation failures are reported as precondition-failed; neither the cloud revision nor the local edit baseline is advanced by the check. There is no claim write, deployment lock, or automatic stale plan retry.

For schema changes, pull immediately before editing, record a migration, then create the deployment plan:

gsb pull Order --schema
gsb migration plan .gsb/dev1/schema/Order \
  --recovery forward-repair \
  --recovery-instructions "Revert with a reviewed follow-up migration"
gsb migration check --json
gsb plan --output change-plan.json

Schema plans require the latest tenant migration artifact to match the schema identity and authoritative remote/local definition fingerprints. Existing-schema chains bind IDs into every fingerprint. Chains that create a schema use authored-content fingerprints throughout so server-assigned schema and property IDs do not invalidate the reviewed migration. Migration sequence, artifact checksum, transformation checksum, and recovery policy are checked again before apply. Apply-result verification checks the recorded migration binding and authoritative fingerprint rather than the server-normalized schema file hash. Additive and compatible migrations can be applied. Migrations requiring data transformation can be recorded for review but are rejected by plan until a typed transformation runtime exists. Migration artifact writes take an exclusive per-tenant filesystem lock so concurrent CLI processes cannot claim the same global sequence with different filenames.

To reverse the latest compatible migration for one schema, prepare a compensating migration, review it, and deploy it through the normal immutable lifecycle:

gsb migration rollback <sequence> \
  --recovery-instructions "Reapply the reviewed change if compensation must be reversed"
gsb status --json
gsb plan --output rollback-plan.json --json
gsb verify rollback-plan.json --json
gsb apply rollback-plan.json --output rollback-result.json --json
gsb verify rollback-result.json --json
gsb migration check --json

migration rollback never writes to the backend. It restores the checksummed pre-change schema into the checkout and records a new forward migration whose hashes reverse the target migration. Only the latest migration for that schema is eligible, and local and live fingerprints must still match its toHash. The command fails closed for old artifacts without snapshots, schema creation, property removal, type/data reversals, stale state, and any reverse classified as destructive or requiring data transformation. Adding a property is safe forward but cannot currently be rolled back automatically because the reverse operation deletes that property. Schema definitions are not entity-version-enabled. Tenant backup restore is a separate, destructive disaster-recovery operation and requires migration-chain reconciliation; it is not routine schema rollback.

When upgrading from the former app-local checkout layout, move the complete directory atomically with the shipped codemod. It refuses an existing destination instead of merging potentially unrelated tenant state:

node node_modules/@gsb-core/cli/codemods/move-tenant-checkout.mjs \
  apps/my-app/.gsb dev1 .

Deployment uses ordinary GSB saves and does not block unrelated operations. The read-then-save revision check is intentionally not atomic: a concurrent save between the check and the write, or brief cross-asset misalignment, remains possible. Tenant-wide locks are not required. gsb migration check still reports backend ledger and lock availability, but these are not deployment prerequisites.

CI/CD, Automated Deployment, and Seeds

See the delivery and resource-pack guide or the published guide for CI credentials, a protected GitHub Actions example, workflow-based deployment, seed mechanisms, query-selected data promotion, and installation conflict policies.

  • Build one resource pack and promote its exact packId from staging to production.
  • Templates select module resources, definition data, and saved-query subsets through dataDefinitions and dataQueries; build-time moduleFields selects asset families.
  • Choose skipUserModified: true to preserve supported target edits or false to allow overwrites. Verify schema/property behavior and skipped dependencies before release.
  • Pack build/install are Application Service APIs, not currently gsb call tools.
  • gsb bulk save supports reviewed entity seeds; gsb assistant seed handles assistant configuration. Assistant seeding requires exact --confirm-tenant <code> approval and supports stable --json envelopes. Explicit manifests are validated before authentication; a failed later write reports PARTIAL_APPLICATION with applied, failed, and remaining configuration keys. Neither seed path implies universal idempotency or a general gsb seed command.
  • Use pnpm exec gsb for parsed output. Inspect business results and terminal job state, not just a successful CLI envelope. Use plan -> apply -> verify for mutations.

Query Entities

The CLI uses the same QueryParams model as @gsb-core/core. TypeScript callers use the fluent builder; gsb call receives its serialized fields:

gsb call query --input '{
  "queryParams": {
    "entDefName": "Order",
    "filters": [{
      "col": { "name": "status" },
      "val": { "value": "open" },
      "function": 0
    }],
    "selectCols": [{ "name": "id" }, { "name": "status" }],
    "startIndex": 0,
    "count": 25,
    "calcTotalCount": true
  }
}' --raw

The query-shaped read tools normalize this JSON into a real QueryParams instance. Legacy GSB code-library payloads using query, propVal, or colName remain readable, but new scripts should use filters, col / val, and name. Only filters is sent over the wire; the server honors it directly.

Every property referenced by a query must have effective Read permission. This applies even when the property is used only in a filter, sort, group, aggregate, include, subquery, or permission queryStr and is not returned in selectCols. Dotted paths require Read access to the relationship and traversed property. Entity-level Read/Query permission does not bypass property permissions; the backend rejects inaccessible references with an error such as User does not have access right for property. GsbTenant-partner_id : Read.

The full server wire model is accepted: selectCols with aggregateFunction, dateModifier, groupBy, distinct, and scripts; filters with every QueryFunction value, relation ("and" / "or"), relationLevel, negate, extra (the Between bounds, as { value1, value2 }), subqueries via val.valQuery, and nested children groups; includes with their own nested query fields; sortCols; searchText; queryType; and calcTotalCount. The fluent aliases take / limit (→ count) and skip (→ startIndex) are also honored, and a filter val may be a bare scalar as shorthand for { "value": … }.

Bulk Operations

A CLI or MCP call awaits its own response, so the core batching window never fills — those services run with useBulk: false and skip the 50ms wait. For mass operations use gsb bulk, which posts a chunk of calls to /api/entity/bulk as one request:

# One tool, many inputs
gsb bulk save --input-file rows.json --chunk-size 200 --yes

# Mixed tools
gsb bulk --yes --input '[
  { "tool": "save", "input": { "request": { "entDefName": "Order", "entity": { "title": "A" } } } },
  { "tool": "delete", "input": { "request": { "entDefName": "Order", "entityId": "…" } } }
]'

Accepted input shapes: an array of { tool, input }, a single { tool, inputs: [...] } fan-out, or a bare array of inputs when the tool name is given as the argument.

Bulk carries the entity endpoints only — query, queryMapped, save, saveMulti, saveMappedItems, removeMappedItems, delete, deleteQuery. Anything else is one round trip by nature and stays on gsb call.

Options

  • -i, --input <json> / --input-file <path>: the calls to run
  • --chunk-size <n>: calls per request (default 100)
  • --stop-on-error: stop after the first failing chunk
  • -y, --yes: approve write, destructive or side-effecting tools
  • --raw: JSON only, no progress or summary

Results are printed as an array of { index, tool, ok, result, error } in input order; the command exits non-zero if any call failed.

Push Command

Push a TypeScript/JavaScript file to GSB backend:

# Basic push
gsb push path/to/function.ts

# Push with type specification
gsb push path/to/library.ts --type library

# Dry run (preview without pushing)
gsb push path/to/function.ts --dry-run

# Push schemas, libraries, functions, workflows, and templates changed since sync
gsb push --all-changed
gsb push --all-changed --dry-run

# Verbose output
gsb push path/to/function.ts --verbose

Options

  • -t, --type <type>: Specify type: function, library, or auto (default: auto)
  • -d, --doc-template: Push document template from folder
  • --all-changed: Push changed or never-synced schemas, libraries, functions, workflows, and document templates
  • --allow-renames: Approve collision-free immutable-ID renames without an interactive prompt
  • --force: Explicitly approve a stale local cloud baseline while retaining the apply-time revision comparison
  • --dry-run: Show what would be pushed without actually pushing
  • -v, --verbose: Enable verbose output

Successful pulls and verified pushes record a canonical SHA-256 hash in serverSync.contentHash. --all-changed compares current payload content with that baseline, including file additions, removals, and renames. JSON key order, serverSync, line endings, and filesystem timestamps do not create false changes. Older metadata uses timestamp detection until its next successful pull or push.

Document Template Commands

The CLI supports pulling and pushing document templates with multilingual content.

Pull Document Templates

# Pull all document templates
gsb pull -d

# Pull specific template by name
gsb pull -d "My Template"

# Pull with verbose output
gsb pull -d --verbose

Schema Commands

Entity-definition schemas use .gsb/<tenantCode>/schema/<name>/<name>.json, with independently tracked property documents under properties/. Definition and property documents contain immutable identity, sync timestamps, and canonical content hashes.

gsb pull --schema
gsb pull Order --schema
gsb list --schema
gsb push .gsb/<tenantCode>/schema/Order --schema --dry-run
gsb push .gsb/<tenantCode>/schema/Order --schema

Routine additive schema work, such as creating one definition or adding a column, does not require a manual cache clean. The server updates the affected definition caches as part of the operation.

After a large migration or a mass update spanning many entity definitions, clean the tenant's server caches before validating the new schema:

gsb --tenant <tenantCode> cache clean --confirm-tenant <tenantCode>

This is a safety step for stale or temporarily inconsistent caches across cluster nodes, not a command to run after every schema change. After cleaning, verify representative definitions and queries through the normal load-balanced endpoint; if nodes still disagree, repeat the clean or escalate the cluster synchronization issue. Cache clearing requires exact target-specific approval and returns a stable result or error envelope with --json.

Background task inspection also uses stable envelopes. Cancellation is target-bound and generic --yes cannot replace the exact tenant approval:

gsb task status <job-id> --json
gsb task cancel <job-id> --confirm-tenant <tenantCode> --json

Push Document Templates

# Push document template from folder
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d

# Push with dry run
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d --dry-run

# Push with verbose output
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d --verbose

List Document Templates

# List all local document template folders
gsb list -d

# List with verbose output
gsb list -d --verbose

Document Template Structure

Document templates are stored in a structured folder format:

.gsb/
  <tenantCode>/
    docTemplates/
      myTemplate/
        meta.json          # Template metadata
        en_us.html         # English content
        tr_tr.html         # Turkish content
        fr_fr.html         # French content
        ...                # Other language files
        content.html       # Non-multilingual content (if applicable)

Multilingual Templates

For multilingual templates, each language is stored as a separate HTML file:

  • en_us.html - English (US)
  • tr_tr.html - Turkish
  • ko_kr.html - Korean
  • hi_in.html - Hindi
  • ar_sa.html - Arabic
  • de_de.html - German
  • ja_jp.html - Japanese
  • fr_fr.html - French
  • ru_ru.html - Russian
  • zh_cn.html - Chinese
  • es_es.html - Spanish
  • pt_pt.html - Portuguese
  • it_it.html - Italian

Non-Multilingual Templates

For non-multilingual templates, the content is stored in content.html.

Template Metadata

The meta.json file contains template metadata:

{
  "id": "template-uuid",
  "name": "myTemplate",
  "title": "My Document Template",
  "fileName": "template.html",
  "isMultilingual": true,
  "languageScript": "latin",
  "module_id": "module-uuid",
  "tags": [{ "id": "tag-uuid", "name": "report" }],
  "defaultPrintOptions": "{}",
  "enableOverride": false,
  "createDate": "2024-01-01T00:00:00.000Z",
  "lastUpdateDate": "2024-01-01T00:00:00.000Z"
}

Test Command

Test a function without saving it to GSB backend:

# Basic test
gsb test path/to/function.ts

# Test with entity context
gsb test path/to/function.ts --entity '{"id":"123","name":"test"}'

# Test with parameters
gsb test path/to/function.ts --params '{"param1":"value1"}'

# Test with both entity and parameters
gsb test path/to/function.ts --entity '{"id":"123"}' --params '{"debug":true}'

Run Command

gsb test covers a single function. gsb run covers a whole workflow: it starts a run and then tails the three tables GSB records it in — GsbWorkflowInstance (where the run is), GsbWfLog (the engine's step-by-step trace, prefixed sys) and GsbWfInstanceHistory (what people did on human tasks, prefixed user). Activity ids are resolved to their names, and the command exits non-zero when the run ends in Error or Cancelled.

# Start a workflow by name and follow it
gsb run registration --entity '{"email":"[email protected]","name":"Ada"}'

# Take the folder instead of the name, using its workflow.test.json for input
gsb run .gsb/<tenantCode>/workflows/OrderApproval

# Block on runWorkflow rather than startWorkflow
gsb run OrderApproval --sync --entity-id order-123

# Watch a run someone else started, without starting anything
gsb run --attach <instanceId>

GSB writes a GsbWfLog row only for workflows whose enableLog flag is on, so an otherwise healthy run can tail completely silent. gsb run says so before starting, and --enable-log turns the flag on first.

When the run settles, the summary prints result, responseStr and parentResult from the instance, plus the code, message and logId the run answered with. Potentially sensitive instance parameters are omitted. The last three fields matter: a function that sets instance.code / instance.message has those returned as the HTTP status and body, never stored on the instance, so the response is the only place a failure reason exists. --json emits the sanitized summary in the standard result envelope; validation and failed workflow outcomes use the standard error envelope on stderr.

❌ Run ended: Error
  Instance: 07f4b3fe-76db-45d3-b2a6-21d8f3dee8ff
  Code: 409
  Message: No tenant to register. Please provide tenant with a unique code
  Log id: d43bf17c-db6d-42d9-9245-01b0432374be

Options:

| Option | Description | | ----------------------- | ------------------------------------------------- | | --entity <json> | entity the run operates on | | --entity-id <id> | run against an existing entity row | | --entity-def <id> | GsbEntityDef id of that entity | | --params <json> | instance parameters | | --input-file <path> | read the whole request from a JSON file | | --sync | use runWorkflow instead of startWorkflow | | --attach <instanceId> | follow an existing instance, start nothing | | --enable-log | turn on the workflow's enableLog before running | | --no-follow | return as soon as the run is accepted | | --interval <ms> | poll interval, default 1000 | | --timeout <seconds> | stop following after this long, default 300 | | --json | print a stable sanitized result or error envelope |

Sample input lives in workflow.test.json next to workflow.meta.json, mirroring <name>.test.json for functions. It holds either the instance itself or a full request:

{ "entityDefinition_id": "8be90815-…", "entity": { "email": "[email protected]" } }

Command-line flags override the file, and workflow_id is always taken from the resolved workflow. A run that parks on a user task keeps polling until --timeout; advance it with gsb call iterateTask --yes.

Config Command

Show current GSB configuration:

gsb config

User Commands

Create a user, assign a role ID, and optionally update ignored test env files. Automation reads an existing password from an environment variable, or generates one only when an ignored env-file destination is provided.

gsb users roles --json
gsb users list --limit 50 --json
gsb users add [email protected] \
  --role-id <role-id> \
  --write-env apps/account/.env.local apps/workspace/.env.local \
  --confirm-tenant <tenantCode> --json
gsb users assign-role [email protected] <role-id> \
  --confirm-tenant <tenantCode> --json
GSB_NEW_PASSWORD='replace-me' \
  gsb users reset-password [email protected] \
    --password-env GSB_NEW_PASSWORD \
    --confirm-tenant <tenantCode> --json

Role and user listing return stable result or error envelopes with --json; user limits must be positive integers and are validated before authentication. Role assignment also returns a stable envelope, accepts only a role ID, and requires exact target-specific approval; generic --yes cannot authorize it. User creation has the same approval requirement and never prints or returns a password. Use --password-env <name> to supply one, or --write-env <path> to store a generated password without emitting it. Password reset follows the same secret-input and approval rules; if credential-file writing fails after the reset, the CLI returns PARTIAL_APPLICATION with the user and successfully written file paths, never the password.

File Structure

All pulled schemas/properties, workflows, functions/operations, libraries, and document templates can be committed alongside application code. Commit identity and sync metadata with their resources; never commit credentials or sensitive test inputs. The CLI writes source files but does not create Git commits or push a Git remote. gsb status compares local payloads with their sync baseline, not Git history or current remote content.

See Backend source control with Git for the complete layout, branch/PR workflow, safe refresh, and commit-to-release traceability.

Functions

gsb pull -f writes one folder per function. Pass a name to pull a specific function. Functions are shared many-to-many with workflow activities, so each row lives in exactly one folder, chosen by its standalone flag: standalone functions in serverless/functions-std/, workflow-only functions in serverless/functions-wf/. When the flag flips, the copy in the other folder is removed so a function is never duplicated on disk.

Operation-based functions keep their logic in operations, not code, so each operation gets its own file:

.gsb/
  <tenantCode>/
    serverless/
      functions-std/
        sendResetPasswordEmail/
          sendResetPasswordEmail.ts        # the function's `code` (empty for operation-only functions)
          sendResetPasswordEmail.meta.json # id, name, title, module_id, standalone, testInstance
          op-1.ts                          # RunScriptCode operation body
          op-1.json                        # that operation's config, minus scriptCode
          op-2.json                        # a non-script operation (email, notification, …)
      functions-wf/
        CalculateTotal/                    # same layout, referenced by workflow activities
      libraries/
        myLibrary.ts
        myLibrary.meta.json (optional)

op-N files are ordered numerically and pushed back in that order. Push and test take the folder:

gsb push .gsb/<tenantCode>/serverless/functions-std/sendResetPasswordEmail
gsb test .gsb/<tenantCode>/serverless/functions-std/sendResetPasswordEmail --params '{"email":"[email protected]"}'

Loose <name>.ts files from before the folder layout are still pushed and listed.

Workflows

gsb pull -w writes one folder per workflow. Activities reference functions by name, never by body, so pushing a workflow can never overwrite code shared with another workflow. Function bodies change only through a function push.

.gsb/
  <tenantCode>/
    workflows/
      OrderApproval/
        workflow.meta.json     # id, name, title, enableLog, enableUseExisting, module_id
        workflow.test.json     # optional sample input for `gsb run`
        design.json            # canvas positions, isolated so drags don't churn logic files
        activities/
          010-Start.json       # activity fields plus functions / afterFunctions / prevFunctions
          020-Approve.json
        transitions/
          010-StartToApprove.json  # `from` and `to` are activity names

Numeric prefixes keep the order stable; files are read back in numeric order. Push resolves every function name to its server id and fails before writing if a name is unknown:

gsb pull -w                                  # all workflows
gsb pull -w OrderApproval                    # one workflow
gsb push .gsb/<tenantCode>/workflows/OrderApproval --dry-run
gsb list -w --verbose

Because references key on function names, every function row needs a unique name. Report the functions that lack one, then apply the derived PascalCase names:

gsb normalize-functions            # report only
gsb normalize-functions --apply

Existing names are never changed, and duplicate names are reported as errors because they make a reference ambiguous.

Activities have the same problem in a worse form: GSB names every activity default. The real label lives in the workflow's designer payload, keyed by activity refId, so it can be lifted onto the rows:

gsb normalize-activities                          # report only
gsb normalize-activities --workflow registration  # one workflow
gsb normalize-activities --apply

Unlabelled Start/End/Timer nodes are named after their activity type. Re-run gsb pull -w afterwards so the local folders pick up the new names.

Document Template Files

Document templates are stored in the .gsb/<tenantCode>/docTemplates/ folder:

.gsb/
  <tenantCode>/
    docTemplates/
      template1/
        meta.json
        en_us.html
        tr_tr.html
        fr_fr.html
      template2/
        meta.json
        content.html (for non-multilingual)
      template3/
        meta.json
        en_us.html
        de_de.html
        es_es.html

Metadata Files

Optional .meta.json files can provide additional metadata:

{
  "id": "uuid-of-existing-function",
  "name": "functionName",
  "title": "Human Readable Title",
  "description": "Function description",
  "references": [{ "id": "service-dependency-id" }]
}

Metadata Properties

  • id: GSB function/library ID (for updates)
  • name: Function/library name (defaults to filename)
  • title: Display title (defaults to formatted name)
  • description: Optional description
  • references: Array of service dependency IDs

Examples

Push a Function

# Push a pulled function folder (code plus its operations)
gsb push .gsb/<tenantCode>/serverless/functions-std/myFunction

# Push a single loose file
gsb push .gsb/<tenantCode>/serverless/functions-std/myFunction.ts --verbose

Test a Function

# Test with sample data
gsb test .gsb/<tenantCode>/serverless/functions-std/calculateTotal \
  --entity '{"order":{"items":[{"price":10,"quantity":2}]}}' \
  --params '{"applyTax":true}'

Inspect the Serverless Runtime Contract

The CLI exposes the same canonical serverless guide as MCP and the documentation app:

gsb call getServerlessFunctionDocs --raw

Use this guide to inspect injected globals, _runtime fields, email delivery paths, task scheduling constraints, and current document-generation prerequisites. Runtime-provided modules such as nodemailer, bullmq, and ioredis are used directly; do not load them with require().

The guide also documents the native password contract used by Emotion Guru: POST /api/auth/changePassword accepts either oldPassword for a signed-in password change or email plus resetToken for reset-link confirmation, together with newPassword. Reset-link confirmation is delegated to the tenant's trusted sendResetPasswordEmail function; do not edit GsbUser.password directly. Inspect the tenant implementation and its metadata with:

gsb pull -f .gsb/<tenantCode>/serverless/functions-wf/Change-Password
gsb pull -f .gsb/<tenantCode>/serverless/functions-std/sendResetPasswordEmail

Version an Entity Before a Risky Change

Explicit snapshots are optional and apply to one version-enabled entity. Create one before a meaningful function, workflow, or configuration change; use a tenant backup for broad releases or disaster recovery. Schema definitions are not version-enabled and use reviewed compensating migrations where the reverse is supported.

# Snapshot the current function, then push the edit
gsb version add <function-id> \
  --definition GsbWfFunction \
  --note "Before registration validation rewrite" \
  --confirm-tenant <tenantCode>
gsb push .gsb/<tenantCode>/serverless/functions-wf/myFunction

# Inspect snapshots and automatic field-change audit rows
gsb version list <entity-id> --json
gsb version changes <entity-id> --json

# Restore by GsbEntityVersion row ID, not by live entity ID
gsb version restore <version-row-id> --confirm-tenant <tenantCode>

Snapshot creation and restore require exact target-specific approval; generic approval cannot authorize either mutation. GsbEntityDef.isVersioned enables explicit snapshots. GsbEntityDef.isTracked enables automatic GsbTrackVersion rows on every create/update. The systems are independent. The CLI decodes tracked values from Base64 JSON. Both read commands return stable result or error envelopes with decoded records and validate positive --limit values before authentication. Both snapshot mutations also return stable envelopes and never prompt during JSON execution. Run gsb call getEntityVersioningDocs --raw for endpoint payloads, MCP tool names, restore safeguards, and current version-number behavior.

Document Template Examples

# Pull all document templates from server
gsb pull -d

# Pull specific template
gsb pull -d "Invoice Template"

# List local templates
gsb list -d

# Push updated template
gsb push .gsb/<tenantCode>/docTemplates/invoiceTemplate -d

# Preview template push
gsb push .gsb/<tenantCode>/docTemplates/invoiceTemplate -d --dry-run

Dry Run

# Preview what would be pushed
gsb push .gsb/<tenantCode>/serverless/functions-std/newFunction.ts --dry-run

# Preview document template push
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d --dry-run

Type Detection

The CLI automatically detects whether a file is a function or library based on:

  1. File path (contains functions or libraries)
  2. Metadata type property
  3. Default to function if unclear

Error Handling

The CLI provides clear error messages for common issues:

  • Missing MCP configuration
  • Invalid file paths
  • Network/API errors
  • Invalid JSON in metadata
  • TypeScript/JavaScript file validation

Development

Building

npm run build

Development Mode

npm run dev -- push path/to/file.ts

Adding New Commands

  1. Add command definition in src/index.ts
  2. Implement logic in appropriate service files
  3. Add types to src/types.ts
  4. Update README documentation

File Structure

src/
  index.ts        # Main CLI entry point with all commands
  config.ts       # Configuration management
  gsbService.ts   # GSB backend service wrapper
  fileUtils.ts    # File reading, validation, and doc template utilities
  types.ts        # TypeScript type definitions

Troubleshooting

"MCP configuration not found"

Ensure your project has .cursor/mcp.json with GSB backend configuration.

"Invalid TypeScript file"

Only .ts and .js files are supported.

API Connection Issues

Check your GSB_API_KEY and GSB_TENANT_CODE in the MCP configuration.

Function Test Failures

Ensure your function code is compatible with GSB serverless environment.

Document Template Issues

"Pull functionality is not yet implemented"

The document template pull functionality requires proper API configuration. This will be available once the GSB backend API methods are properly configured.

"Document template folder not found"

Ensure the folder path exists and contains a valid meta.json file.

"meta.json not found in folder"

Each document template folder must contain a meta.json file with template metadata.

Contributing

  1. Fork the repository
  2. Create feature branch
  3. Add tests for new functionality
  4. Submit pull request

License

MIT License