Skip to content

@kelphect/sdk-native (Node and Bun)

@kelphect/sdk-native 0.1.0 is the shared server-only TypeScript client for Lockwell Native Wire v1. It uses raw TLS 1.3, deterministic binary frames, bounded multiplexing, and the credential proof defined by the [LNW reference] (/reference/native-wire). It never sends HTTP, JSON, XML, or S3 on this transport and never silently falls back.

The package is source-shipped and test-qualified in this repository. Publication to a customer registry is a separate release decision; pin the exact package version and server commit together in an application lockfile.

Runtime and exports

RuntimeMinimumEntry
Node22.0.0@kelphect/sdk-native/node or the root node condition
Bun1.4.0@kelphect/sdk-native/bun or the root bun condition
Browser / default bundler conditionunsupportedthrows a credential-free denial

/protocol exposes append-only constants and registries. /testing exposes the codec and injectable socket boundary for conformance tests. Keep all client construction, credentials, and imports in server-only modules.

Install and connect

sh
npm install @kelphect/[email protected]
# or: bun add @kelphect/[email protected]
ts
import { createLockwellClient } from "@kelphect/sdk-native";

const lockwell = createLockwellClient({
  host: process.env.LOCKWELL_NATIVE_HOST ?? "lockwell.internal",
  port: Number(process.env.LOCKWELL_NATIVE_PORT ?? "9444"),
  tls: {
    // The issuing CA is public configuration, not a private key.
    ca: process.env.LOCKWELL_NATIVE_CA,
  },
  credentials: async () => ({
    accessKeyId: process.env.LOCKWELL_ACCESS_KEY_ID!,
    secretKey: process.env.LOCKWELL_SECRET_KEY!,
  }),
  pool: { min: 1, max: 4, acquireTimeoutMs: 5_000, idleTimeoutMs: 30_000 },
});

await lockwell.connect({ timeoutMs: 5_000 });
const result = await lockwell.putObject({
  bucket: "private",
  key: "a.bin",
  body: new Uint8Array([1, 2, 3]),
  contentLength: 3,
  options: { idempotencyKey: crypto.randomUUID(), timeoutMs: 10_000 },
});
console.log(result.etag);
await lockwell.close();

Use tls.ca for a private PKI. Hostname verification and TLS 1.3 cannot be disabled. mTLS requires tls.cert and tls.key together. Credential providers run for every new connection, allowing rotation without rebuilding the client.

Operations and streaming

The typed client covers capabilities/readiness; bucket CRUD and versioning; object PUT/GET/HEAD/DELETE, ranges, conditions, ordered metadata, checksums, list/pagination and copy; versions/delete markers; multipart create, upload, list, completion/resume discovery, abort and upload listing; tags; retention and legal hold; batch delete; bucket CORS and webhook notifications; and signed GET/PUT capabilities. SSE-C and ADMIN are not advertised or implemented on this access-key wire.

getObject returns a ReadableStream<Uint8Array> and a completion promise. Consume the body to release a stream back to the pool. putObject and uploadPart accept Uint8Array, ArrayBuffer, Blob, ReadableStream, or an async iterable; provide the exact contentLength. Progress callbacks report transferred bytes. One-shot streams are never replayed implicitly.

ts
const download = await lockwell.getObject({
  bucket: "private",
  key: "a.bin",
  range: { start: 0, endInclusive: 1023 },
  onProgress: (transferred, total) => console.log({ transferred, total }),
});
for await (const chunk of download.body) consume(chunk);
await download.completed;

RequestOptions supports signal, an absolute deadline or timeoutMs, an idempotency key, and a validated traceparent. Diagnostics expose state, open/idle connections, active streams, and negotiated capabilities without returning credentials or TLS material.

Authentication, errors, and retries

Every connection performs HELLO/WELCOME and an access-key HMAC proof with a fresh timestamp and nonce. Duplicate AUTH_REPLAY is terminal. A bounded replay-capacity RATE_LIMITED response may be retried only by discarding the connection, resolving credentials again, and generating a fresh proof before the caller deadline. Application retries are limited to read-safe operations or writes with an idempotency key and replayable body; AUTH_REPLAY, scope denials, malformed hints, and streaming bodies are not retried. AbortSignal cancellation and deadlines stop the active stream.

The client reports stable LockwellError subclasses (ProtocolError, TransportError, AuthenticationError, AuthorizationError, ServiceError, CancelledError, DeadlineExceededError, and ClientClosedError). Error text is bounded and redacted; log sinks receive no secret, token, payload, or filesystem path.

Framework and browser boundaries

Framework adapters must own the lifecycle at a server/Nitro boundary. Use SolidStart for the tested SolidStart v2 integration. The browser condition and the package default export intentionally throw, and the package contains no browser socket or credential code. Do not import it from client components, static builds, Cloudflare Workers, or an unknown serverless target.

Verification

The source README, unit tests, byte fixtures, malformed-frame tests, packed consumer, and live Go TLS tests are the authority. Re-run the package checks from sdk/typescript-native before changing a capability claim:

sh
bun run typecheck
bun test --timeout 15000
bun run build
bun run pack:check

The capability index records which framework and base-SDK adapters are merged. Go's standalone LNW client, Node's primary-LNW transport, Java shared-core LNW client, and Nuxt remain pending source-owner PRs and are not claimed by this page. The merged Next.js adapter is documented separately in the Next.js guide.

Source-available under PolyForm Noncommercial 1.0.0; commercial use requires a written grant. License