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

@terella/data-plane

v0.1.0

Published

Portable S3-compatible data-plane SDK for Bun and Cloudflare Workers.

Downloads

90

Readme

@terella/data-plane

Portable S3-compatible data-plane SDK for Bun and Cloudflare Workers. The SDK uses only fetch and Web Crypto APIs, signs requests with AWS Signature V4, and provides typed access to shared Terella data contracts.

Installation

bun add @terella/data-plane

The package is also compatible with npm-compatible package managers and can be bundled for Cloudflare Workers.

Using the package directly from Git

The SDK is maintained as the packages/terella-sdk/data-plane submodule of Terella and has its own repository. Add it directly as a Git dependency:

bun add git+https://github.com/terella-project/terella-data-plane.git

This adds a dependency similar to:

{
  "dependencies": {
    "@terella/data-plane": "git+https://github.com/terella-project/terella-data-plane.git"
  }
}

Pin a branch, tag, or commit when reproducibility is important:

{
  "dependencies": {
    "@terella/data-plane": "git+https://github.com/terella-project/terella-data-plane.git#main"
  }
}

To work on the package through the Terella repository, initialize submodules:

git clone --recurse-submodules https://github.com/terella-project/terella.git
# or, from an existing checkout:
git submodule update --init packages/terella-sdk/data-plane

Configuration

Create a client with an endpoint, bucket, and S3 credentials:

import { createDataPlaneClient } from "@terella/data-plane";

const dataPlane = createDataPlaneClient({
  endpoint: "https://account-id.r2.cloudflarestorage.com",
  bucket: "terella-shared",
  accessKey: env.S3_ACCESS_KEY,
  secretKey: env.S3_SECRET_KEY,
  region: "auto", // default
});

The endpoint may include the bucket as its first path segment. Both forms are equivalent:

{ endpoint: "https://account-id.r2.cloudflarestorage.com/terella-shared", accessKey, secretKey }
{ endpoint: "https://account-id.r2.cloudflarestorage.com", bucket: "terella-shared", accessKey, secretKey }

For existing deployments, configuration can be read from environment-style values without exposing credentials in logs:

import { createDataPlaneClient, s3ConfigurationFromEnv } from "@terella/data-plane";

const config = s3ConfigurationFromEnv({
  S3_API_URL: process.env.S3_API_URL,
  S3_BUCKET: process.env.S3_BUCKET,
  ACCESS_KEY: process.env.ACCESS_KEY,
  SECRET_ACCESS_KEY: process.env.SECRET_ACCESS_KEY,
  S3_REGION: process.env.S3_REGION,
});

const dataPlane = config ? createDataPlaneClient(config) : null;

Supported environment names are:

| Purpose | Preferred names | Compatibility names | | --- | --- | --- | | Endpoint | DATA_PLANE_S3_ENDPOINT | S3_API_URL | | Bucket | DATA_PLANE_S3_BUCKET | S3_BUCKET | | Access key | DATA_PLANE_S3_ACCESS_KEY | S3_ACCESS_KEY, ACCESS_KEY | | Secret key | DATA_PLANE_S3_SECRET_KEY | S3_SECRET_KEY, SECRET_ACCESS_KEY | | Region | DATA_PLANE_S3_REGION | S3_REGION |

s3ConfigurationFromEnv returns null when the endpoint or credentials are incomplete. It does not print or validate live credentials until a client is created.

Ion steering exports

Publish a validated steering export. The SDK writes the immutable object and then advances the current pointer:

const contentId = await dataPlane.ion.steering.v1.publish(steeringExport);

const current = await dataPlane.ion.steering.v1.getCurrent();
const historical = await dataPlane.ion.steering.v1.getByContentId(contentId);

publish validates the ion.steering.v1 contract. Invalid payloads throw a DataPlaneError. Use parseIonSteeringExport or safeParseIonSteeringExport when validation is needed before publication. Waypoint entries may include title, narrative, and rationale. These fields are optional so previously published ion.steering.v1 objects remain valid. During the Helios-to-Ion migration window, reads try ion/steering/v1 first and then fall back to helios/steering/v1; publishes write both prefixes so older consumers continue to work. Legacy payloads are normalized to the Ion schema when returned by the client.

Geodynamo project contexts

Project contexts are isolated by project segment:

const contentId = await dataPlane.geodynamo.projectContext.v1.publish(
  "midi-vibe",
  projectContext,
);

const current = await dataPlane.geodynamo.projectContext.v1.getCurrent("midi-vibe");

Project identifiers must be a single safe object-key segment. The context must use the geodynamo.project-context.v1 schema and include at least:

{
  schema: "geodynamo.project-context.v1",
  generatedAt: "2026-07-10T12:00:00.000Z",
  scope: "terella-factory-cycle-only",
  source: "geodynamo",
  repo: "owner/midi-vibe",
  projectName: "midi-vibe",
  context: "Prioritized factory-cycle direction..."
}

External integration records

Integration records are addressed by provider, scope, and record ID:

await dataPlane.integrations.v1.publish(
  "github",
  "owner",
  "midi-vibe",
  {
    schema: "terella.integration-record.v1",
    provider: "github",
    scope: "owner",
    record: "midi-vibe",
    updatedAt: new Date().toISOString(),
    status: "active",
  },
);

const record = await dataPlane.integrations.v1.getCurrent(
  "github",
  "owner",
  "midi-vibe",
);

Object layout and content addressing

Published values are stored as immutable JSON objects, with a mutable pointer identifying the current content:

ion/steering/v1/objects/<contentId>.json
ion/steering/v1/current.json

# Compatibility copy while Helios consumers are being migrated.
helios/steering/v1/objects/<contentId>.json
helios/steering/v1/current.json

geodynamo/contexts/v1/<project>/objects/<contentId>.json
geodynamo/contexts/v1/<project>/current.json

integrations/v1/<provider>/<scope>/<record>/objects/<contentId>.json
integrations/v1/<provider>/<scope>/<record>/current.json

The SDK computes SHA-256 content IDs from canonical JSON for project contexts and integration records. Ion steering exports retain their contract-defined contentId.

Low-level client and helpers

Use S3Client for arbitrary JSON objects within the configured bucket:

import { S3Client, objectKey } from "@terella/data-plane";

const s3 = new S3Client(config);
const key = objectKey("reports", "v1", "latest.json");

await s3.putJson(key, { generatedAt: new Date().toISOString() });
const report = await s3.getJson<{ generatedAt: string }>(key);

objectKey rejects empty, traversal, slash-containing, and control-character segments. This prevents callers from escaping a domain prefix or accidentally overwriting another domain's pointer.

The package also exports canonicalJson, contentId, parseS3Configuration, awsSignatureV4, and the shared contract types and schema constants.

Errors and optional mirroring

All SDK failures use DataPlaneError. Error messages redact authorization headers, signatures, secret-bearing URLs, and secret-key-like values. A missing object is returned as null by getJson, getCurrent, and getByContentId.

Applications that treat shared storage as an additive mirror should catch DataPlaneError around reads and writes. Native Ion R2 publication and Geodynamo Pages output should remain the canonical paths when shared S3 is unavailable.

Testing and verification

Run the package checks from this directory:

bun run check
bun test
bun run build

The live S3 test is read-only and runs only when endpoint, bucket, access-key, and secret-key environment variables are configured. It never prints object payloads or credentials. Unit tests use a fake fetch implementation and do not require S3 access.