Download
Downloading an asset means ordering one of its services and then fetching the data through a one-time URL.
The short version
const { } = await .({ : 'did:ope:1234abcd...' })
const = await ()
const = await .()One call covers everything: satisfying any credential policy, asking the node for provider fees, reusing or placing an order, and building the URL.
Credentials are resolved before anything is ordered, so a policy you cannot satisfy costs nothing.
What you get back
const { , , , } = await .({
: 'did:ope:1234abcd...'
})reusedOrder is worth checking: true means no datatoken was bought, because an order from
a previous access was still inside the service's timeout. That is the difference between a
free download and a paid one. The node does not report that order, so nautilus finds it in
the datatoken's events; see
the order on chain.
One URL at a time
Fetch each URL before you request the next one for the same consumer and node. Two URLs
requested before either is fetched carry the same one-time number: the first fetched works,
and the other answers HTTP 401 nonce: … is not a valid nonce. If that happens, call
access() again and fetch the new URL right away; it reuses the order you hold when it finds
it. For a paid service, wait until at least 2 more blocks are mined after the purchase before
you call access() again: sooner, it does not find the order yet and pays again, and an RPC
that lags behind extends that wait. See
known limitations
for this and the other limits of this release.
Why access() can stop before paying
Finding no previous order is normal: nautilus buys one. But when the lookup itself fails
(the RPC rate-limits it, does not answer, answers with an error, or answers without the data the check needs) or stops short (it
cannot read back over the whole order window), nautilus cannot tell whether you already
hold a valid order. Buying anyway could make you pay twice, so for a
service that costs anything access() stops before paying and throws an
OrderCheckError. Nothing was ordered or paid,
and the message names the price, the cause and what to do:
access() stopped before paying for service "Download (JSON)" of asset "Weather" (did:ope:59a18b63…): it could not check whether 0x4C84…4A52 already holds a valid order, and buying without that check could make you pay twice (1.002 devEURAU). Nothing was ordered or paid; it is safe to retry. Cause: the RPC rate-limited the check (HTTP 429). Retry in a minute or use another RPC. To buy anyway, pass `orderOnLookupFailure: true`.error.retryable is true and error.reason says why ('rate-limited', 'unreachable',
'incomplete' or 'rpc-error'). Retry after a pause or with another RPC; to accept the
risk of a second payment, pass orderOnLookupFailure: true. An incomplete lookup stopped
by the lookup's depth (a service whose orders never expire, or whose timeout is longer than
about 100 000 blocks) ends the same way on every retry, and the message says so: if you
have not bought the service in that window, buying with orderOnLookupFailure: true is
safe. A free service is ordered anyway,
with one warning, since a second order costs only gas. To see the RPC's unredacted answer,
run with NAUTILUS_DEBUG=sensitive (topic order; see debugging).
Choosing a service
An asset can offer several services. By default nautilus takes the first access service;
name one explicitly when there is more than one. access() downloads from access
services only and refuses a compute service before calling the node: run a job on it with
compute() or freeCompute().
const = await .('did:ope:1234abcd...')
const = ()
const { } = await .({
: .,
: [0].
})Read the asset through the exported helpers — getServices, getMetadata and friends —
rather than indexing into credentialSubject. They go through a version-aware manager, so
your code survives a future DDO version moving fields.
Consumer parameters
If a service declares consumer parameters, pass values through userdata:
const { } = await .({
: 'did:ope:1234abcd...',
: {
: 'eu',
: 1000
}
})The values are checked against the service's declaration before anything is sent: a
missing required parameter, a value of the wrong type, a select value outside its options
(or for a select that declares none) or an undeclared key throws a
ConsumerParameterError. Keys set to undefined or null are left out of the download
URL, and the rest is encoded as one query parameter, so values holding &, #, + or =
reach the node intact. See
validation, and the
ConsumerParameterBuilder for the publishing side.
Selecting a file
A service can serve several files. fileIndex defaults to 0:
const { } = await .({
: 'did:ope:1234abcd...',
: 1
})Credential-gated assets
If the service requires a verifiable credential, configure a credential provider on the instance and nothing changes here — nautilus resolves the policy before ordering, so a policy you cannot satisfy costs nothing. See Credential-gated assets.
What it costs
Pricing is read from chain rather than from a subgraph, which v1 depended on and the current stack no longer runs. To inspect a price before committing:
const = await .('did:ope:1234abcd...')
const = ()[0].
const = (, ) as string
const = await (
.(),
,
.()
)
const = await (
.(),
,
.()
)
.(., .)pricing.schema is 'fixed', 'free', or 'none' when the datatoken has neither a
fixed-rate exchange nor a dispenser and so cannot be ordered at all.
On top of the price, the order pays the provider fee the service's node asks for. That
node is the service's serviceEndpoint, which the publisher chooses, so nautilus pays a
non-zero fee only within the maxProviderFee you set, or with your confirmProviderFees
callback. See what the node charges on top.
Try it
Runnable versions of everything on this page live in examples/:
npm start -- access:price did:ope:… # what it costs, before you buy
npm start -- access:download did:ope:… # order and fetch
npm start -- access:service did:ope:… # pick a specific service
npm start -- access:userdata did:ope:… # pass consumer parameters