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

@cloudgate/sdk

v1.1.1

Published

Official TypeScript/JavaScript client for the CloudGate public API (v1): subscriptions, resources, billing, reports, support and organization administration.

Readme

@cloudgate/sdk

Official TypeScript/JavaScript client for the CloudGate public API v1. Node.js 18+, no runtime dependencies, ESM + CommonJS + type definitions.

Full API documentation: https://<your CloudGate domain>/public-api-docs.

npm install @cloudgate/sdk

Get a key

Sign in to CloudGate, open Profile → API keys, create a key. Choose Read and write to order or change services. A key can do only what you can do in CloudGate.

Environments

One package works with every CloudGate environment and tenant: you choose the server with baseUrl and a key from that same environment (a dev key works only on dev, a production key only on production). Each tenant has its own address.

# dev
export CLOUDGATE_BASE_URL=https://cloudgate-dev.obelion.ai
export CLOUDGATE_API_KEY=cg_test_...
# production — same code, different values
export CLOUDGATE_BASE_URL=https://<your CloudGate address>
export CLOUDGATE_API_KEY=cg_live_...
const cg = new CloudGate(); // reads CLOUDGATE_BASE_URL and CLOUDGATE_API_KEY

Use

import { CloudGate } from "@cloudgate/sdk";

const cg = new CloudGate({
  baseUrl: "https://cloudgate.example.com", // or CLOUDGATE_BASE_URL
  apiKey: process.env.CLOUDGATE_API_KEY,    // or CLOUDGATE_API_KEY
});

const me = await cg.me();                 // key, user, organization, tenant
if (!me.access.can_write) throw new Error("this key's owner is a viewer");

for await (const service of cg.services.list()) console.log(service.slug, service.name);

const offering = await cg.services.offerings("cs-linux-vm", { billing_cycle: "hourly" });
const price = await cg.services.quote("cs-linux-vm", { zone_id: 12, billing_cycle: "hourly", selections: [{ type_id: 3, item_id: 41 }] });

const vm = await cg.subscriptions.create({
  service: "cs-linux-vm",
  name: "ci-runner-1",
  zone_id: 12,
  billing_cycle: "hourly",
  selections: [{ type_id: 3, item_id: 41 }],
  service_key_id: 21,
  sub_username: "",
  sub_password: "",
  eula_accepted: true,
});
await cg.subscriptions.waitFor(vm.id, "active", { timeoutMs: 20 * 60_000 });

await cg.subscriptions.stop(vm.id);
await cg.subscriptions.waitFor(vm.id, "stopped");

const actions = await cg.subscriptions.actions(vm.id);       // each with an input_schema
await cg.subscriptions.runAction(vm.id, actions[0].action, { /* per input_schema */ });

await cg.subscriptions.delete(vm.id);
await cg.subscriptions.waitFor(vm.id, "deleted");

Resources: me(), providers (list, regions), regions.zones, services (list, offerings, quote), subscriptions (list, get, resources, create, start, stop, delete, actions, runAction, waitFor), projects, departments, serviceKeys, keyPairs (list, create), invoices (list, get), usage.get, wallet.get, activity.list, resources (summary, list(type), search, get, metrics, delete), errorLogs.list, notifications (list, markRead, markAllRead), tickets (list, get, create, reply, close), costs (subscriptions, resources). Every list() is an async iterator over all pages; collect() turns one into an array.

for (const t of await cg.resources.summary()) console.log(t.type, t.count);
for await (const vm of cg.resources.list("VirtualMachine")) console.log(vm.name, vm.cloud_id);
for await (const e of cg.errorLogs.list({ severity: "high", status: "open" })) console.log(e.at, e.title);
const ticket = await cg.tickets.create({ title: "VM unreachable", details: "…", category: 2, subscription_id: vm.id });

Management

The rest of what the website does, with the website's fields in and its answer out (typed Json; same permissions as the key's owner):

| Client | Methods | | --- | --- | | subscriptionSettings | rename, placement, move, sync, architecture, preferences, setPreferences, notify, setNotify, bucketUsers, bucketPolicies, bucketLifecycle, bucketVersioning, harborInventory, linkedDatabases, linkableDatabases, linkedGpuVms, linkableGpuVms, replication, harborImages (all pages), harborInventory (one page + projects/users in meta) | | monitoring | get, enable, update, disable | | provisioning | addOns, addOnResourceGroups, addOnCompartments, addOnResources, replicate, replicationTargets, adoptUnmanagedResource, previewGpuVmConversion, convertGpuVm | | bundles, bundleSubscriptions | list, retrieve, tiers; list, create, details, update, delete, addTiers, rename, move, sync | | resourceOperations | syncStatus, sync, syncAllStatus, syncAll, bulkDelete, children, vpcs, vpcInventory | | projectAdmin, departmentAdmin | create, retrieve, details, update, delete, setStatus (+ hierarchy) | | users | list, create, retrieve, details, update, delete, setStatus, setFinancialAccess | | serviceKeyAdmin | create (FormData with the credential file), retrieve, update, delete, setStatus, setMonitoring, regions, vendors | | credentials (read_write keys) | kubeconfig, sshCertificate, rdpCredential, bucketUserSecretKey, backupBucket, backupBucketSecretKey, inference | | billing | vendorInvoices (all pages), vendorInvoicesPage (one page + meta.statistics), invoicePdf, creditActivity, creditReservations, creditCapacity, validateVoucher, redeemVoucher | | reports | list, retrieve (one page of rows + the report in meta.report), rows (all rows), delete, download, publish, preview(kind), create(kind), update(kind, id) | | inquiries | list, create, retrieve, delete, reply, ticketProviders | | profile | retrieve, update (FormData for the photo), notificationSettings, updateNotificationSettings |

Every list, management ones included (users.list(), reports.list(), inquiries.list(), billing.creditReservations()…), is an async iterator that follows next_cursor for you. The …Page() methods and reports.retrieve() return one page { data, next_cursor, total_count?, meta? } when you need what a list carries besides its rows. billing.creditActivity() returns the newest limit (1–100) entries only; narrow it by date.

Files (invoicePdf, reports.download, credentials.kubeconfig) come back as { data: Uint8Array, contentType, filename }. Password, MFA and API keys themselves are managed in the website only.

const kubeconfig = await cg.credentials.kubeconfig(21, "cluster-cloud-id");
await fs.writeFile(kubeconfig.filename ?? "kubeconfig.yaml", kubeconfig.data);

const form = new FormData();
form.set("key_name", "prod");
form.set("vendor", "5");
form.set("file", new Blob([await fs.readFile("creds.json")]), "creds.json");
await cg.serviceKeyAdmin.create(form);

Behaviour

  • Retries 429, 502, 503, 504 and network errors up to 3 times (exponential backoff with jitter, or the server's Retry-After).
  • Idempotency: every POST/DELETE carries an Idempotency-Key that is reused by its retries, so a retried order is never placed twice. Pass your own with { idempotencyKey } to make retries across process restarts safe. (Not for services.quote — it writes nothing — or keyPairs.create, whose private key is never stored.) Calls the server cannot replay — multipart bodies and anything under credentials — are retried only on 429.
  • Errors are typed: AuthenticationError (401), PermissionError (403), NotFoundError (404), ValidationError (400/402/422), ConflictError (409), RateLimitError (429, retryAfterSeconds), ApiError (5xx/network), WaitError (from waitFor). All extend CloudGateError with code, status, requestId.
  • waitFor(id, target, { timeoutMs, intervalMs, signal, onPoll }) polls until the status is target, and throws WaitError on failed, on an unexpected deleted, on timeout or when cancelled.

Reference

Every CloudGate serves the full API reference at https://<your CloudGate address>/public-api-docs and the machine-readable OpenAPI contract at https://<your CloudGate address>/api/public/v1/openapi.json.

Changes in 1.1.1

  • Ticket: status and category are typed as numbers (status 1 open, 2 in progress, 3 resolved, 4 closed, 5 pending; category 1 general, 2 billing, 3 technical, 4 other), and the new status_name gives the status as text.
  • MIT license.

No code changes are needed to upgrade.

Changes in 1.1.0

1.1.0 makes the management lists page like every other list (1.0.0 is deprecated). Code that read their website-shaped answers changes:

// 1.x
const { users } = await cg.users.list({ page: 1, limit: 50 });
// 1.1 — every user, page after page
for await (const user of cg.users.list()) console.log(user.email);

The same applies to reports.list, reports.preview, inquiries.list, billing.vendorInvoices, billing.creditReservations and profile.notificationSettings. reports.retrieve and the new …Page() methods return one page (limit, cursor) with meta. Nothing else changed.

Versioning

Semantic versioning: from 1.1.0 on, 1.x adds methods and fields without breaking existing code; a breaking change would be 2.0.0.

License

MIT — see LICENSE.