Official Cosmoner SDKs for JavaScript, Python, and PHP, and the cosmoner
command line tool.
| Language | Package | Install |
|---|---|---|
| JavaScript | @cosmoner/sdk |
npm install @cosmoner/sdk |
| Python | cosmoner-sdk |
pip install cosmoner-sdk |
| PHP | cosmoner/sdk |
composer require cosmoner/sdk |
| CLI | @cosmoner/cli |
npx @cosmoner/cli |
The Terraform provider lives in its own repository,
datablock-dev/terraform-provider-cosmoner,
because the Terraform Registry only publishes providers from a repository with
that name. It uses the same API keys and COSMONER_* environment variables as
the CLI.
Each SDK provides a Cosmoner client with service namespaces. Currently supports
client.email, client.webhooks, client.apps, client.hosting,
client.secrets and client.variables.
All three share the same behaviour: automatic retries with jittered backoff, a
configurable timeout, a typed error hierarchy, and an optional project id that
can be set on the client or passed per call. Python additionally ships an
AsyncCosmoner client.
import { Cosmoner } from "@cosmoner/sdk";
const client = new Cosmoner({
apiKey: "your-api-key",
projectId: "your-project-id",
});
await client.email.send({
credentialId: "your-credential-id",
to: ["alice@example.com", "bob@example.com"],
subject: "Hello from Cosmoner",
html: "<h1>Hello!</h1>",
});from cosmoner import Cosmoner
client = Cosmoner(api_key="your-api-key", project_id="your-project-id")
client.email.send(
credential_id="your-credential-id",
to=["alice@example.com", "bob@example.com"],
subject="Hello from Cosmoner",
html="<h1>Hello!</h1>",
)use Cosmoner\Sdk\Cosmoner;
$client = new Cosmoner(apiKey: 'your-api-key', projectId: 'your-project-id');
$client->email->send(
credentialId: 'your-credential-id',
to: ['alice@example.com', 'bob@example.com'],
subject: 'Hello from Cosmoner',
html: '<h1>Hello!</h1>',
);All three SDKs validate a .cosmoner/deployment.yaml — the file you commit to
describe how a repository deploys — with no API key and no network call. The
CLI does the same from a terminal or a CI job, and does not care what language
the repository it is checking is written in:
npx @cosmoner/cli validate --strict.cosmoner/deployment.yaml
2:11 error Service names must be lowercase letters, numbers, or hyphens, and start with a letter or number services.0.name
4:18 error Static sites cannot define a run_command services.0.run_command
5:11 warning Unknown field "prot" — it will be ignored services.0.prot
2 errors, 1 warning
The four give the same answer to the same file. conformance/ holds the
fixtures and the exact output all of them are held to, and schemas/ holds the
platform's published JSON Schema, which each language's tests compare their
field table against. See the README in either directory.
client.apps.deploy() rolls an app that runs an image from a Cosmoner registry
onto a tag or digest, and client.apps.waitForDeployment() waits for it to go
live. The CLI wraps both for CI:
COSMONER_API_KEY=... COSMONER_PROJECT_ID=... npx @cosmoner/cli deploy web --tag v2It exits 0 once the app is live and 1 if the rollout fails or times out. See
cli/README.md for every option.
client.secrets and client.variables manage the values a deployment file
refers to with from_secret and from_variable. The CLI wraps both:
echo "$DB_PASSWORD" | npx @cosmoner/cli secrets set DB_PASSWORD --environment production
npx @cosmoner/cli variables set LOG_LEVEL --value debugThe two resources differ in one way that shapes the whole API: a variable's
value is returned on every read, and a secret's is returned exactly once, by
the call that sets it. Nothing decrypts a secret afterwards, so a lost value is
replaced rather than recovered — and cosmoner secrets never prints one.
Writing either needs an owner or admin role on top of the secrets:write /
variables:write scope: a project key's service account must hold one, or the
holder of a personal access token.
See the README in each language directory for full API reference:
Every pull request runs lint, type checks and tests for each language directory it touches. To run the same checks locally:
# JavaScript
cd javascript && npm ci && npm run lint && npm run typecheck && npm test
# Python
cd python && pip install -e ".[test,lint]" && ruff check . && ruff format --check . && mypy && pytest
# PHP
cd php && composer install && composer run lint && composer run analyse && composer run test
# CLI (the type check reads the SDK's source, so install that first)
cd javascript && npm ci && cd ../cli && npm ci && npm run lint && npm run typecheck && npm testThe CLI bundles the JavaScript SDK's source rather than depending on the
published package, so a change under javascript/ runs the CLI's checks too and
releases a new CLI. cli/README.md explains why.
npm run lint uses oxlint; composer run lint:fix
and ruff check --fix apply the auto-fixable subset.