# `@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

| Runtime | Minimum | Entry |
| --- | --- | --- |
| Node | 22.0.0 | `@kelphect/sdk-native/node` or the root `node` condition |
| Bun | 1.4.0 | `@kelphect/sdk-native/bun` or the root `bun` condition |
| Browser / default bundler condition | unsupported | throws 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/sdk-native@0.1.0
# or: bun add @kelphect/sdk-native@0.1.0
```

```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 integrations must own the lifecycle at a server/Nitro boundary. 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 `typescript-native` in `lockwell-sdk-node` before changing a capability claim:

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

The [capability index](/reference/sdk-capabilities) records which framework and base-SDK adapters are merged.
Go's standalone LNW client, Node's primary-LNW transport, and the Java shared-core LNW client are the supported
consumers; framework-specific adapters are not claimed by this page.
