Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Cloud Standard slots

The standard module turns the Cloud Standard slots into a typed codec. CloudStandard encodes and seals each slot; CloudReader reads and decrypts them (see Reading); PrismManager orchestrates the high-level prism lifecycle.

Slot identifiers

SLOT_NAMES = {
  key: "dataprism.key", encryption: "dataprism.encryption",
  metadata: "dataprism.metadata", providers: "dataprism.providers",
}
SLOT_IDS = { key, encryption, metadata, providers }   // hash of each name
 
dataId(name: string): DataId          // hash of the name
fileDataId(filename: string): DataId  // legacy filename hash; not scoped addressing
isReservedSlot(id: DataId): boolean   // is it one of the dataprism.* slots?

CloudStandard

A codec bound to a DataPrismKey. new CloudStandard(key) retains legacy filename addressing. Pass a separate fileDataIdScopeKey to enable scoped file identifiers.

SlotbuildreadEncrypted?
dataprism.keykeySlot()readKey(payload)clear
dataprism.encryptionencryptionSlot()readEncryption(payload)clear
dataprism.metadatametadataSlot(meta)readMetadata(payload)sealed
dataprism.providersprovidersSlot(providers)readProviders(payload)sealed
filefileSlot(index)readFileIndex(payload)sealed

Each build method returns a SlotWrite = { dataId, payload }, ready to hand to the execution layer. The clear slots are JSON as hex; the sealed slots go through key.sealJson, except V3 file indexes, which seal canonical JSON bytes. The read* methods throw a clear "slot empty / does not exist" error on an empty payload instead of a cryptic crypto failure.

readFileIndex and CloudReader.fileIndex accept legacy, V2 and V3 indexes. The older readFile and CloudReader.file methods retain their legacy/V2 return types and reject V3 with guidance to use the union reader.

Other members:

  • initialSlots({ metadata?, providers? }) → SlotWrite[]: the provisioning slots. Always includes key plus encryption; adds metadata / providers only if provided.
  • fileId(filename) → DataId: applies this standard's legacy or scoped profile.
  • reader(source, cloudId) → CloudReader: build a decrypting reader.
const std = new CloudStandard(key);
const slots = std.initialSlots({ metadata, providers });
await (
  await client.execution.batchWriteData({
    cloudId,
    dataIds: slots.map((s) => s.dataId),
    payloads: slots.map((s) => s.payload),
  })
).wait();

Slot schemas

The file types below show the legacy index layout. V2 and V3 carry versioned chunk descriptors; use the union reader above when reading across versions.

interface MetadataSlot {
  name: string;
  description: string;
  addresses: Record<Address, string>; // owner / writer addresses → readable name
  fileDataIdProfile?: "dataprism.file-data-id.hmac-sha256.v1";
}
 
type ProviderId =
  | "aws_s3"
  | "gcp_storage"
  | "azure_blob"
  | "cloudflare_r2"
  | "scaleway_object_storage";
 
interface ProvidersSlot {
  aws_s3?: { service: "signed_url"; signerUrl; region; bucket };
  gcp_storage?: { service: "signed_url"; signerUrl; projectId; bucket };
  azure_blob?: { service: "signed_url"; signerUrl; accountName; container };
  cloudflare_r2?: {
    service: "signed_url";
    signerUrl;
    endpoint;
    bucket;
    region;
  };
  scaleway_object_storage?: {
    service: "signed_url";
    signerUrl;
    endpoint;
    region;
    bucket;
  };
}
 
interface Quorum {
  dataShards: number;
  parityShards: number;
}
interface ChunkDesc {
  hash: Hex;
  len: number;
  shards: Hex[];
} // shards = content hashes
interface BlobRef {
  level: number;
  size: number;
  chunks: ChunkDesc[];
}
interface FileIndex {
  name: string;
  size: number;
  chunkSize: number;
  quorum: Quorum;
  providers: string[]; // ordered provider-ID list, frozen at upload
  root: BlobRef; // compact Merkle root (≈ a few hundred bytes)
  meta?: Record<string, unknown>;
}
interface SlotWrite {
  dataId: Hex;
  payload: Hex;
}

Scoped file identifiers

Without fileDataIdScopeKey, CloudStandard uses the legacy keccak256(UTF8(filename)) lookup rule and writes metadata without a fileDataIdProfile. Supplying scoped-profile metadata without the addressing key is rejected, as are unknown profile values.

const scoped = new CloudStandard(key, { fileDataIdScopeKey: addressingKey });
const dataId = scoped.fileId(filename);
const metadataSlot = scoped.metadataSlot(metadata);

addressingKey must be 32 bytes and kept by the customer. In this mode, metadataSlot() records dataprism.file-data-id.hmac-sha256.v1 automatically. File writes, reads, repairs and name-based deletes use the keyed identifier: domain-separated HMAC-SHA-256 over the canonical JSON of the NFC-normalized filename. Names remain case-sensitive. Use standard.fileId(filename), not the standalone legacy fileDataId(filename) helper, for these lookups.

Keep the addressing key stable across file-encryption key rotations. TenantScope.bindPrism retains a separate addressing key in a customer-owned binding store, and TenantPrism.standard(key) supplies it to CloudStandard. The Prism opening key is still supplied separately. See Three separate keys.

Scoped addressing does not itself turn on V3 writes or migrate existing entries. V3 uploads require an explicit publicIndex option; constructors without the addressing option and legacy/V2 reads remain supported.

See File storage & resilience for how FileIndex / BlobRef / ChunkDesc describe a file.

PrismManager

High-level lifecycle orchestration, on top of the execution layer plus the standard. Build via client.prism(standard, cloudId?) or new PrismManager({ standard, execution, source?, cloudId? }).

Creation

create(args: CreatePrismArgs): Promise<CreatePrismOutcome>

CreatePrismArgs = { fundAmount, salt, metadata?, providers?, relayerFee?, timestamp? }.

The key slot written during creation always contains the public key and an empty private member. The removed includePrivate property is rejected at runtime for JavaScript callers as well as absent from the TypeScript interface.

create provisions the prism and writes all four reserved slots (key, encryption, metadata, providers, with empty defaults if not supplied) in a single atomic operation: one signature, one confirmation. The fundAmount must cover the creation fee plus the per-entry data fees. It returns { cloudId, create, init }.

const manager = client.prism(new CloudStandard(key));
const { cloudId } = await manager.create({
  fundAmount,
  salt,
  metadata,
  providers,
});

Dedicated slot editors

These write reserved slots intentionally. Full replacements use modifyData; read-modify-write helpers use modifyDataIfCurrent with the observed evidence lineage and version:

MethodEffect
setMetadata(metadata, opts?)replace dataprism.metadata
setProviders(providers, opts?)replace all of dataprism.providers
setProvider(id, config, opts?)upsert one provider (reads current, merges, preserves others)
removeProvider(id, options)remove one provider after a matching safety preflight

setProvider / removeProvider require a source with getDataEvidence (the NetworkReader provides it). readMetadata() / readProviders() require a source with getData.

Provider removal is intentionally fail-closed. Build a preflight from the complete known file inventory and the caller-approved minimum margin, repair every affected index, then remove the registry entry:

const preflight = preflightProviderRemoval("aws_s3", knownFiles, {
  configuredProviders: await manager.readProviders(),
  inventoryComplete: true,
  minimumToleratedProviderLoss: approvedMinimum,
});
 
await manager.removeProvider("aws_s3", { preflight });

An incomplete inventory or any file that still maps a shard position to the provider blocks removal. A caller may pass riskAcceptance: { reason: "..." }, but that acceptance is explicit and is never selected by the SDK. A configuration change after the scan invalidates the preflight. The submitted removal is also bound to that exact registry snapshot on-chain; a concurrent update causes the transaction to revert rather than overwriting the newer configuration.

await manager.setProvider("aws_s3", {
  service: "signed_url",
  signerUrl: "https://storage.example.com/aws/sign",
  region,
  bucket,
});
await manager.setMetadata({ name: "Acme", description: "v2", addresses });

Guarded generic writes

writeData(dataId, payload, opts?)        // throws if dataId is reserved
modifyData(dataId, payload, opts?)       // throws if dataId is reserved
deleteData(dataId, opts?)                // throws if dataId is reserved
batchWriteData(dataIds, payloads, opts?) // throws if ANY dataId is reserved
Copyright © 2026 DataPrism.