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

@justdeploy/sdk

v0.2.2

Published

Official server-side JavaScript and TypeScript SDK for JustDeploy

Readme

@justdeploy/sdk

The official JustDeploy SDK for server-side Node.js 22, 24 and 26. The package includes ESM, CommonJS, and TypeScript declarations.

Production supports local Credential authentication and automatic identity in deployed web, API, and cron applications. Development SDK access remains limited to Playground.

Install

npm install @justdeploy/[email protected]

Client

Create one client and reuse it. It accepts no arguments.

import { JustDeploy } from '@justdeploy/sdk';

const justdeploy = new JustDeploy();

For CommonJS:

const { JustDeploy } = require('@justdeploy/sdk');

const justdeploy = new JustDeploy();

For local development, set both JUSTDEPLOY_ACCESS_KEY and JUSTDEPLOY_SECRET_KEY in the process environment, using a Production Credential and resource IDs from the same organization. Deployed JustDeploy applications need no SDK configuration. A local client cannot use Development Credentials; test a Development organization in its deployed Playground app. If a deployed application explicitly keeps both variables, the SDK accepts and prioritizes them; build feedback recommends the simpler automatic deployment identity without blocking the build.

Database

const databases = await justdeploy.databases.list();
const result = await justdeploy.databases.query(databaseId,
  'SELECT * FROM orders WHERE customer = ?', { params: [customer] });

const tables = await justdeploy.databases.listTables(databaseId);
const table = await justdeploy.databases.createTable(databaseId, {
  name: 'orders',
  columns: [{ name: 'customer', type: 'string', nullable: false }],
});
await justdeploy.databases.updateTable(databaseId, 'orders', {
  add: [{ name: 'paid', type: 'boolean', default: false }],
});
await justdeploy.databases.deleteTable(databaseId, 'orders');

query accepts only the data statements allowed by the JustDeploy API. Use the table methods for schema changes.

Prepare schema once before starting the application. A read returns { rows }; a write returns { id }, not affectedRows. Separate calls do not share a transaction.

Pass input values in params, using one unquoted ? per value. Strings, finite numbers, booleans and null are supported. Send integers outside ±9,007,199,254,740,991 and exact decimals as strings; serialize dates and JSON explicitly. Objects, nested arrays and undefined are rejected. Never interpolate user input or quote the placeholders yourself.

Placeholders cannot replace table/column names or SQL fragments. Keep identifiers fixed or use an app-owned allowlist. LIMIT ? is not supported; validate a bounded integer before placing a LIMIT number in SQL. Calls without parameters and the existing signal option remain supported.

Storage

Browser files: direct upload

On your app server, authenticate the user and check upload permission before calling:

const upload = await justdeploy.storages.createUploadUrl(storageId, {
  name: 'image.jpg', mime: 'image/jpeg',
});
// Return only upload to that browser, with Cache-Control: no-store.

It returns { fileId, url, method: 'PUT', headers, expiresAt }. In the browser:

const response = await fetch(upload.url, {
  method: upload.method, headers: upload.headers, body: selectedFile,
  credentials: 'omit', redirect: 'error',
});
if (!response.ok) throw new Error(`Upload failed (${response.status}).`);
// Save upload.fileId through your app API. No active-state wait is needed.

File bytes go directly to Storage. Do not install the SDK in the browser or send it a Credential/session token. Do not add Authorization or Content-Length. The platform manages browser access; no bucket/origin configuration is required.

The URL is temporary bearer permission: do not log, cache or persist it. expiresAt is the latest permitted expiry and revocation can invalidate it earlier. It is not one-time and can overwrite the same file while valid. App-side size checks are not an enforced upload-size limit.

Every call prepares a new file and is never automatically retried. A lost response may already have created a file; do not blindly create another. For explicit cancellation, delete the file if its ID is known. Platform cleanup covers abandoned pending files; this method cannot observe browser failures or clean them up immediately.

Server files: upload bytes or a stream

const storages = await justdeploy.storages.list();

const file = await justdeploy.storages.upload(storageId, {
  name: 'hello.txt',
  mime: 'text/plain',
  data: new TextEncoder().encode('hello'),
});

const page = await justdeploy.storages.listFiles(storageId, { limit: 50 });
const info = await justdeploy.storages.getFile(storageId, file.id);

const download = await justdeploy.storages.download(storageId, file.id);
for await (const chunk of download.stream) {
  // Process each Uint8Array chunk without buffering the whole file.
}

await justdeploy.storages.deleteFile(storageId, file.id);

upload accepts a string, Blob, byte array, web stream, or async byte iterable. Upload and download bytes stream directly to the signed Storage URL without a JustDeploy authentication header. For a web stream or async iterable, also pass the exact byte length as size; sized values such as strings, blobs, and byte arrays are measured automatically. If a download races with a still-finishing upload, retry after the SDK's clear pending-upload error.

Upload results have no signed URL. file.size is the number of bytes successfully transferred. After PUT succeeds, the file can be read without waiting for active; metadata may still be pending. Before PUT succeeds, pending alone does not prove bytes exist. Use getFile again only when final metadata is needed. Save the file ID, not the expiring URL. When redirecting a browser, use (await justdeploy.storages.getFile(storageId, fileId)).url without buffering the download.

For pagination, pass page.nextCursor as the next call's cursor until it is null.

Transfer failures are safe SDK errors, not unchanged exceptions from your byte source. Failed uploads try to remove the pending record; cleanup failure does not replace the transfer error or cancellation.

A successful delete accepts the deletion. GET/list metadata may update later; an immediate stale read does not make the delete a failure. For cleanup verification, recheck the same ID after a short delay.

Mail

const mail = await justdeploy.mail.send({
  sender: '[email protected]',
  to: '[email protected]',
  subject: 'Welcome',
  text: 'Thanks for joining.',
  idempotencyKey: 'welcome-user-123',
});

const page = await justdeploy.mail.list({ limit: 50 });
const current = await justdeploy.mail.get(mail.id);

Use one idempotencyKey per operation. A retry keeps its key and content; each new password reset needs a new key. The same key with different content is rejected with 409. SDK input uses sender; REST input and returned records use from. delivered means the receiving server accepted the message, not inbox placement. See the shared Mail and tracking rules.

Errors and cancellation

Handle SDK failures with JustDeployError. API errors expose status, retryAfter, requestId, and details. For diagnostics, record only status and requestId, not the whole error, request, SQL, file contents, or credentials. Cancellation does not prove a write was rolled back. Authentication and API time limits are separate; see request behavior.

Authentication and API errors prefer valid JSON diagnostics and fall back to Retry-After and X-Request-Id headers. retryAfter is a positive safe integer in seconds, or null; HTTP-date values are not used. requestId is a validated identifier, or null. Non-JSON errors keep valid header diagnostics without exposing the response body. A delay does not trigger an automatic retry.

Methods that accept request options support an AbortSignal:

const controller = new AbortController();
const databases = await justdeploy.databases.list({ signal: controller.signal });

The SDK may refresh authentication and repeat one failed GET once. It never automatically repeats a mutation.