
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
stainless-tools
Advanced tools
A TypeScript library and CLI tool for managing Stainless config and generated SDKs. This tool helps you generate, monitor, and sync SDK repositories as you update your OpenAPI / Stainless config files.
This src
files were entirely built using Cursor. It took an entire day with careful prompting to cover various use-cases and write the appropriate tests and documentation. No human wrote any part of the src
code, although the README has been hand-polished.
It has only been tested on MacOS under Node 22 (although built for 18). Other platforms may not be supported.
You must have at least Node 18 installed to use this tool.
npm install stainless-tools -g
Ensure you have:
https://github.com/stainless-sdks/<project_name>-<language>
Before using the tool, you need to set up your environment variables. You can do this in two ways:
.env
file (or .env.override
if you auto-generate your .env
file) in your project root:STAINLESS_API_KEY=your_api_key_here
export STAINLESS_API_KEY=your_api_key_here
The tool uses cosmiconfig for configuration management. You can define your configuration in any of these ways:
stainless-tools
property in package.json.stainless-toolsrc
file in JSON or YAML format.stainless-toolsrc.json
, .stainless-toolsrc.yaml
, .stainless-toolsrc.yml
, .stainless-toolsrc.js
, or .stainless-toolsrc.cjs
filestainless-tools.config.js
or stainless-tools.config.cjs
CommonJS moduleinterface StainlessConfig {
// Map of SDK names to their repository URLs
// Each SDK can have a staging and/or production URL
// By default, the staging URL is used, but you can use --prod to use the production URL
stainlessSdkRepos: {
[key: string]: {
// The staging URL is used by default
staging?: string;
// The production URL is used when --prod is specified
prod?: string;
};
};
// Optional lifecycle hooks for each SDK
// These commands are executed at specific points in the SDK lifecycle
lifecycle?: {
[key: string]: {
postClone: string;
postUpdate: string;
prePublishSpec: string;
};
};
defaults?: {
// Default branch name for all SDKs (optional)
// If not specified, will use existing branch in target directory or generate a new cli/ branch
// Typically use 'main' for production and '<username>/dev' for staging
// See: https://app.stainlessapi.com/docs/guides/branches
branch?: string;
// Default target directory for generated SDKs. Supports the following template variables:
// - {sdk}: The name of the SDK being generated
// - {env}: The environment (staging/prod) being used
// - {branch}: The git branch name (forward slashes converted to hyphens)
targetDir?: string;
// Default OpenAPI specification file location
openApiFile?: string;
// Default Stainless configuration file
stainlessConfigFile?: string;
// Whether to use the "Guess with AI" command from the Stainless Studio for the Stainless Config
guessConfig?: boolean;
// Default project name
projectName?: string;
};
}
The targetDir
configuration supports template variables that are dynamically replaced when generating SDKs:
{sdk}
: Replaced with the name of the SDK being generated{env}
: Replaced with the current environment (staging
or prod
){branch}
: Replaced with the git branch name (forward slashes are converted to hyphens for filesystem compatibility)This allows you to organize your SDKs in a structured way. For example:
{
defaults: {
targetDir: './sdks/{env}/{sdk}/{branch}'
}
}
Would generate directories like:
./sdks/staging/typescript/main
./sdks/prod/typescript/main
./sdks/staging/python/theogravity-dev
(from branch theogravity/dev
)This is particularly useful when working with multiple SDKs, environments, and branches simultaneously. Note that forward slashes in branch names are automatically converted to hyphens to ensure filesystem compatibility across different platforms.
// stainless-tools.config.js
module.exports = {
stainlessSdkRepos: {
typescript: {
// Used by default
staging: 'git@github.com:stainless-sdks/yourproject-typescript-staging.git',
// Used when --prod is specified
prod: 'git@github.com:stainless-sdks/yourproject-typescript.git',
},
},
defaults: {
branch: 'main',
// Organize SDKs by environment, name, and branch
targetDir: './sdks/{env}/{sdk}/{branch}',
openApiFile: './specs/openapi.yml',
stainlessConfigFile: './stainless-tools.config.yml',
projectName: 'my-project',
guessConfig: false
}
};
The tool supports lifecycle hooks that allow you to automate tasks after certain operations. Currently supported hooks:
The prePublishSpec
hook runs before:
This hook is useful for:
The postClone
hook runs after:
This hook is useful for:
The postUpdate
hook runs after:
This hook is useful for:
Hooks are configured in the lifecycle
section of your configuration file:
module.exports = {
stainlessSdkRepos: {
typescript: {
staging: 'git@github.com:stainless-sdks/test-typescript.git',
prod: 'git@github.com:test-org/test-typescript.git',
},
},
// Lifecycle hooks allow you to automate tasks at specific points in the SDK lifecycle
// Each SDK can have its own set of hooks with different commands
// All hooks have access to these environment variables:
// - STAINLESS_TOOLS_SDK_PATH: Full path to the SDK repository
// - STAINLESS_TOOLS_SDK_BRANCH: Current branch name
// - STAINLESS_TOOLS_SDK_REPO_NAME: Name of the SDK (e.g., 'typescript')
lifecycle: {
typescript: {
// Runs before publishing specs to Stainless
// Use this to validate or transform your OpenAPI spec
// Example: Run OpenAPI linter, validate against schema, etc.
prePublishSpec: 'npm run validate-spec',
// Runs after initial clone of the SDK repository
// Use this to set up the development environment
// Example: Install dependencies, configure git hooks, etc.
postClone: 'cd $STAINLESS_TOOLS_SDK_PATH && npm install && npm run build',
// Runs after pulling new changes from remote
// Use this to ensure the SDK is ready after updates
// Example: Rebuild, update dependencies, run migrations, etc.
postUpdate: 'npm run build',
},
python: {
// Run Python-specific validation before publishing
// Example: Validate against custom rules, check formatting, etc.
prePublishSpec: 'python scripts/validate_spec.py',
// Set up Python virtual environment and install package
// Example: Create venv, install dependencies, etc.
postClone: 'python -m venv venv && source venv/bin/activate && pip install -e .',
// Update dependencies and reinstall package after changes
// Example: Update pip packages, rebuild extensions, etc.
postUpdate: 'source venv/bin/activate && pip install -e .',
},
},
// Optional default configurations
defaults: {
branch: 'main',
targetDir: './sdks/{env}/{sdk}/{branch}',
openApiFile: './specs/openapi.yml',
stainlessConfigFile: './stainless-tools.config.yml',
guessConfig: false,
projectName: 'my-project'
}
};
The hook commands:
STAINLESS_TOOLS_SDK_PATH
: Full path to the cloned SDK repositorySTAINLESS_TOOLS_SDK_BRANCH
: Name of the current branchSTAINLESS_TOOLS_SDK_REPO_NAME
: Name of the SDK repository (e.g., "typescript", "python")Example using environment variables:
module.exports = {
lifecycle: {
typescript: {
// Use environment variables to avoid hardcoding paths
postClone: 'cd $STAINLESS_TOOLS_SDK_PATH && npm install && npm run build',
// Log the current branch during updates
postUpdate: 'echo "Updating SDK on branch $STAINLESS_TOOLS_SDK_BRANCH" && npm run build'
}
}
};
You can also use external scripts:
module.exports = {
lifecycle: {
typescript: {
postClone: './scripts/setup-sdk.sh', // Script has access to env vars
postUpdate: './scripts/update-sdk.sh'
}
}
};
Example setup script (setup-sdk.sh
):
#!/bin/bash
echo "Setting up $STAINLESS_TOOLS_SDK_REPO_NAME SDK in $STAINLESS_TOOLS_SDK_PATH"
cd "$STAINLESS_TOOLS_SDK_PATH"
# Install dependencies
npm install
# Run build
npm run build
# Additional setup steps...
The generate
command is the primary feature of Stainless Tools. It will clone (or update if exists) an SDK repository to a target directory, publish the OpenAPI file and Stainless Config file to the Stainless Config repo, and continuously monitor for changes to the SDK repository, pulling in new changes when detected.
stainless-tools generate [options] <sdk-name>
Arguments:
sdk-name Name of the SDK to generate
Options:
-b, --branch <name> Branch name to use (optional)
-t, --target-dir <dir> Target directory for the SDK (required if not in config)
-o, --open-api-file <file> OpenAPI specification file (required if not in config)
-c, --config <file> Configuration file path
-s, --stainless-config-file <file> Stainless configuration file (required if not in config)
-p, --project-name <name> Project name for Stainless API (required if not in config)
-g, --guess-config Uses the "Guess with AI" command from the Stainless Studio for the Stainless Config if enabled
--prod Use production URLs instead of staging URLs
-h, --help Display help for command
### Examples
```bash
# Using staging URL (default) with config file fully defined
# Will use branch from config, env var, existing directory, or generate new cli/ branch
stainless-tools generate typescript
# Using production URL with main branch
stainless-tools generate typescript \
--prod \
--branch main
# Minimal required options (when no defaults defined in config file)
stainless-tools generate \
--open-api-file ./api-spec.json \
--project-name my-project \
typescript
# Using all CLI options with production URL
stainless-tools generate \
--prod \
--branch main \
--target-dir ./sdks/typescript \
--open-api-file ./api-spec.json \
--project-name my-project \
--config ./stainless-tools.config.js \
--guess-config \
typescript
Each SDK supports two environments with separate repositories:
staging
: For development and testing, typically using yourusername/dev
branchprod
: For production releases, typically using main
branchThe branch name is completely optional and will be determined in this order:
--branch yourusername/dev
STAINLESS_SDK_BRANCH=yourusername/dev
defaults.branch
in your config filecli/<random-hex>
branchExample configuration:
{
"stainlessSdkRepos": {
"typescript": {
"staging": "git@github.com:stainless-sdks/my-api-typescript.git",
"prod": "git@github.com:my-org/my-api-typescript.git"
}
},
"defaults": {
"branch": "yourusername/dev" // Optional default branch
}
}
Basic usage:
# Development: Uses staging URL (default)
# Will use branch from config, env var, or generate a new cli/ branch
stainless-tools generate typescript
# Production: Uses prod URL with explicit branch
stainless-tools generate typescript \
--prod \
--branch main
# Using existing branch from target directory
# If ./sdks/typescript exists and is on branch 'feature/new-api',
# this will continue using that branch
stainless-tools generate typescript
When you run generate
:
Branch discovery:
--branch
)STAINLESS_SDK_BRANCH
)defaults.branch
)cli/<random-hex>
branchIf you provide an OpenAPI file (--open-api-file
) or Stainless config file (--stainless-config-file
):
Repository initialization:
Continuous monitoring:
postClone
after initial setuppostUpdate
after pulling changesHandles interruptions gracefully:
This workflow ensures:
The publish-specs
command allows you to publish your OpenAPI specification and Stainless configuration directly to Stainless, making it easy to update your SDK configuration without using the web interface.
stainless-tools publish-specs [options] <sdk-name>
Arguments:
sdk-name Name of the SDK to publish specifications for
Options:
-b, --branch <branch> Git branch to use (optional)
-t, --target-dir <dir> Directory where the SDK will be generated
-o, --open-api-file <file> Path to OpenAPI specification file
-c, --config <file> Path to configuration file
-s, --stainless-config-file <file> Path to Stainless-specific configuration
-p, --project-name <name> Name of the project in Stainless
-g, --guess-config Use AI to guess configuration
--prod Use production URLs instead of staging
# Basic usage - will use branch from config, env var, or generate new cli/ branch
stainless-tools publish-specs typescript
# With custom configuration and explicit branch
stainless-tools publish-specs typescript \
--branch main \
--open-api-file openapi.json \
--config config.json
# Minimal required options
stainless-tools publish-specs \
--project-name my-project \
--open-api-file openapi.json \
typescript
# With Stainless-specific configuration
stainless-tools publish-specs \
--stainless-config-file stainless.config.json \
--open-api-file openapi.json \
typescript
# Production use with explicit branch
stainless-tools publish-specs typescript \
--prod \
--branch main \
--open-api-file openapi.json
When you run publish-specs
:
The publish-specs command is particularly useful for:
3.5.2
2849c5a
Thanks @theogravity! - Fix an issue where publish runs in a loop after an initial spec / OAI file changeFAQs
Tools for use with the Stainless SDK service
The npm package stainless-tools receives a total of 0 weekly downloads. As such, stainless-tools popularity was classified as not popular.
We found that stainless-tools demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.