Context
There is no Harbor client today; storage is Tatum-only and plaintext (packages/walrus/src/storage.ts). Harbor's model is SPACES > BUCKETS > FILES, and bucket creation is a RESERVE → SIGN → FINALIZE handshake (an Enoki-sponsored Sui tx — no SUI balance needed). We need a pure-fetch, runtime-agnostic client that works in both the Worker and Node (the seal Worker spike decides which runtime actually signs/uploads).
Goal / user story
As ContextMEM, I want a HarborClient that can create a bucket (reserve→sign→finalize), upload a file (multipart ciphertext), poll its status to ready, and download it — so private namespaces can store encrypted blobs on Walrus via Sui.
Acceptance criteria
Implementation notes
- Auth:
Authorization: Bearer hbr_.... Inject config (apiKey, serviceKey, spaceId, baseUrl, optional fetch) the same way TatumStorageConfig is injected in storage.ts:21.
- Sign with
@mysten/sui/keypairs/ed25519 + decodeSuiPrivateKey from @mysten/sui/cryptography; build/execute the sponsored tx (Enoki sponsors gas). Sponsor sig expires fast — RESERVE and FINALIZE must be back-to-back with no awaiting of unrelated work between them.
- Add
@mysten/seal + @mysten/sui to packages/walrus/package.json (currently only fast-xml-parser + p-limit) and re-export from packages/walrus/src/index.ts.
- This client takes ciphertext only — encryption lives in
seal.ts (StorageProvider + SEAL issue). Mirror the polling/receipt shape already in storage.ts so the StorageProvider seam can wrap it.
Sui Overflow angle
The reserve→sign→finalize handshake is the FIRST time ContextMEM signs a real Sui tx. The resulting Bucket + Seal-policy objects are genuine on-chain artifacts (Enoki-sponsored, zero SUI), giving a concrete "where is the Sui contract" answer to show judges — with no custom Move authored yet.
Dependencies
The seal Worker spike decides whether sign/upload runs in Worker or Node. The namespace→Space/Bucket/Seal mapping issue supplies the service key + space id config this client consumes.
Part of the ContextMEM roadmap (#4) • Sui Overflow build.
Context
There is no Harbor client today; storage is Tatum-only and plaintext (
packages/walrus/src/storage.ts). Harbor's model is SPACES > BUCKETS > FILES, and bucket creation is a RESERVE → SIGN → FINALIZE handshake (an Enoki-sponsored Sui tx — no SUI balance needed). We need a pure-fetch, runtime-agnostic client that works in both the Worker and Node (the seal Worker spike decides which runtime actually signs/uploads).Goal / user story
As ContextMEM, I want a
HarborClientthat can create a bucket (reserve→sign→finalize), upload a file (multipart ciphertext), poll its status to ready, and download it — so private namespaces can store encrypted blobs on Walrus via Sui.Acceptance criteria
packages/walrus/src/harbor.tsexports aHarborClient(class or factory) with NOnode:fs/node:child_process/node:osimports (runs in Worker + Node).createBucket(spaceId, name)performs RESERVE → sign the sponsored tx withEd25519KeypairfromdecodeSuiPrivateKey(serviceKey)→ FINALIZE as one tight back-to-back sequence; returns{ bucketId, sealPolicyId }.uploadFile(bucketId, { name, data, contentType })does the multipart upload and returns afileId;getFileStatus(fileId)polls to a terminal/ready state mirroringwaitForWalrusStorageCertified(storage.ts:160).403 mirror_missing_grantis retried with backoff over the ~3s mirror window before surfacing an error.download(fileId)returns ciphertext bytes.fetchcovers reserve→sign→finalize ordering, themirror_missing_grantretry, and an upload+poll happy path.Implementation notes
Authorization: Bearer hbr_.... Inject config (apiKey,serviceKey,spaceId,baseUrl, optionalfetch) the same wayTatumStorageConfigis injected instorage.ts:21.@mysten/sui/keypairs/ed25519+decodeSuiPrivateKeyfrom@mysten/sui/cryptography; build/execute the sponsored tx (Enoki sponsors gas). Sponsor sig expires fast — RESERVE and FINALIZE must be back-to-back with no awaiting of unrelated work between them.@mysten/seal+@mysten/suitopackages/walrus/package.json(currently onlyfast-xml-parser+p-limit) and re-export frompackages/walrus/src/index.ts.seal.ts(StorageProvider + SEAL issue). Mirror the polling/receipt shape already instorage.tsso theStorageProviderseam can wrap it.Sui Overflow angle
The reserve→sign→finalize handshake is the FIRST time ContextMEM signs a real Sui tx. The resulting Bucket + Seal-policy objects are genuine on-chain artifacts (Enoki-sponsored, zero SUI), giving a concrete "where is the Sui contract" answer to show judges — with no custom Move authored yet.
Dependencies
The seal Worker spike decides whether sign/upload runs in Worker or Node. The namespace→Space/Bucket/Seal mapping issue supplies the service key + space id config this client consumes.
Part of the ContextMEM roadmap (#4) • Sui Overflow build.