Skip to content
LogoLogo

RemoteStore

The interface every remote store implements. One required method, put, and three optional ones: check, verify and remove.

class  implements RemoteStore {
  async (: string, : { : string }): <> { 
    const  = await (, `${.}.json`)
 
    return { : 'url', , : 'GET' } as 
  }
}
 
declare function (: string, : string): <string>

put

Parameters

payload

  • Type: string

The encrypted DDO envelope, a JSON string {"encryptedData":"0x…"} whose value is node ciphertext. It is not the signed DDO: nothing readable reaches the store.

Store it unchanged. Its sha256 is the on-chain metaDataHash, and the node recomputes that hash over what it fetches (after JSON.parse and JSON.stringify, so added whitespace is harmless). Wrapping the payload, re-encoding it or adding fields breaks indexing. See what is stored.

hint

  • Type: { did: string }

A stable name derived from the DID, for stores that need a key.

Returns

  • Type: Promise<StorageObject>

A pointer the node can dereference:

typeshape
ipfs{ type, hash }
url{ type, url, method }
arweave{ type, transactionId }
s3{ type, s3Access }
ftp{ type, url }

nautilus wraps it in { remote: … } and has the node encrypt it before writing it on chain. The wrapper must carry exactly one key or the node will not treat it as a remote DDO.

nautilus validates the pointer before anything goes on chain, for every store (the type is matched case-insensitively). It rejects a nodePersistentStorage pointer — ocean-node 4.2 cannot read a remote DDO from its own bucket storage, see NodePersistentRemoteStore — any other type not in the table, an ipfs pointer whose hash is not a CIDv0 (Qm…) or a base32/base36 CIDv1 (b…/k…), a pointer missing what its type's storage class needs (a url without an absolute http(s) url or a GET/POST method, or with non-string headers; an s3 without non-empty bucket, objectKey, endpoint, accessKeyId and secretAccessKey; an arweave transactionId that is a URL or path; an ftp url that is not ftp:///ftps://), and a pointer that is not a plain JSON object or is already wrapped in { remote }. See storage options for what each type needs on the node.

check (optional)

  • Type: () => Promise<void>

A preflight that publish, completePublish and edit call before their first transaction. The NFT has to exist before the DDO can be stored, because the DID derives from its address, so a store that fails only at put leaves an NFT without metadata (or, on an edit, datatokens minted for nothing). Throw here if you can tell up front that put will fail: bad credentials, missing scopes, an unreachable endpoint. It runs on every one of those calls, edits included, so keep it cheap: whatever it writes (IpfsRemoteStore's probe: 'upload', S3RemoteStore's probe objects) is written again each time.

class  implements RemoteStore {
  async (: string, : { : string }): <> {
    const  = await (, `${.}.json`)
 
    return { : 'url', , : 'GET' } as 
  }
 
  async (): <void> { 
    if (!(await ())) throw new ('store unreachable') 
  } 
}

verify (optional)

  • Type: (pointer: StorageObject, expectedHash: string) => Promise<void>

A read-back that publish, completePublish and edit call after put() and right before the metadata transaction, with the pointer exactly as put() returned it (not redacted). Read the object behind pointer the way the node will — with the credentials the pointer carries — and throw unless "0x" + sha256(JSON.stringify(JSON.parse(body))) equals expectedHash, which is exactly the node's check.

nautilus cannot repair a MetadataCreated the node could not index — completePublish refuses an NFT that has metadata, and edit needs the indexed asset — so catching a store that alters bytes, or a key the node cannot read with, before the transaction is worth the round trip. Resolve only after that read: a store with no way to read back should throw, and say so in check(), unless its user opted out explicitly. Stores without verify are not verified. S3RemoteStore implements it with the read key; IpfsRemoteStore through its gatewayUrl, or a Kubo node's /api/v0/cat (see verify).

remove (optional)

  • Type: (pointer: StorageObject) => Promise<void>

Deletes what a pointer from put() refers to, for cleanup. It must work with the redacted pointer from PublishResponse.stored, whose secrets read '<redacted>': in a url, the user info, every query value and the fragment (scheme, host and path stay). S3RemoteStore deletes the object; IpfsRemoteStore unpins the CID.

nautilus calls it in one case only: publish, completePublish or edit stored the envelope and then failed before the metadata transaction was sent (a failed verify, a pointer the node would not encrypt, a transaction that could not be built), or the transaction was rejected or mined and reverted. Nothing can point at that object, so it is removed, best effort; the outcome is on error.stored. Once the transaction may have been mined, nautilus never removes anything. Cleaning up is up to you, and an asset that should stay indexed needs two envelopes for good: the creation one (from publish()), because a node reindex replays the asset from its creation event and drops it from the index when that envelope is gone, and the current one. Intermediate versions and those of assets retired for good can go; see cleaning up.