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:
type | shape |
|---|---|
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.