@donezone/client 0.1.50 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +542 -71
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/done.d.ts +20 -8
- package/dist/done.d.ts.map +1 -1
- package/dist/{envelope.d.ts → envelope-builder.d.ts} +1 -4
- package/dist/envelope-builder.d.ts.map +1 -0
- package/dist/envelope-crypto.d.ts +6 -0
- package/dist/envelope-crypto.d.ts.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1219 -6
- package/package.json +6 -5
- package/dist/auth.js +0 -112
- package/dist/client.js +0 -140
- package/dist/done.js +0 -484
- package/dist/envelope.d.ts.map +0 -1
- package/dist/envelope.js +0 -113
- package/dist/messages.js +0 -46
- package/dist/types.js +0 -1
package/README.md
CHANGED
|
@@ -1,128 +1,599 @@
|
|
|
1
1
|
# @donezone/client
|
|
2
2
|
|
|
3
|
-
Client
|
|
3
|
+
Client library for interacting with Done contracts from JavaScript/TypeScript (browser, Node, Bun). Handles envelope construction, signing, transport to the Done HTTP gateway, and SSE event subscriptions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Done HTTP-aware transport via `DoneBackendClient` for `/query`, `/tx`, and quota inspection.
|
|
9
|
-
- Contract helpers for building `WasmMsg::Execute` payloads from HTTP-like routes, reusing the ergonomics of the `Done` runtime.
|
|
7
|
+
## Table of Contents
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
1. [Concepts](#concepts)
|
|
10
|
+
2. [Installation](#installation)
|
|
11
|
+
3. [The `Done` Facade](#the-done-facade)
|
|
12
|
+
4. [DoneContractClient](#donecontractclient)
|
|
13
|
+
5. [DoneBackendClient](#donebackendclient)
|
|
14
|
+
6. [Envelope Builders](#envelope-builders)
|
|
15
|
+
7. [Low-Level Primitives](#low-level-primitives)
|
|
16
|
+
8. [Message Builders](#message-builders)
|
|
17
|
+
9. [Types Reference](#types-reference)
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Concepts
|
|
22
|
+
|
|
23
|
+
Every write operation on a Done contract requires an **auth envelope** — a signed payload that wraps one or more CosmWasm messages with identity, nonce, expiry, and signatures. This package handles building those envelopes, signing them (via pluggable signer callbacks), and submitting them to `POST /tx` on the Done HTTP gateway. Read operations are plain `GET /query/{contract}?msg=...` calls with no signing required.
|
|
24
|
+
|
|
25
|
+
**Call flow for a transaction:**
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Done.run(url, opts)
|
|
29
|
+
→ buildTransactionMessage (produces WasmMsg::Execute)
|
|
30
|
+
→ EnvelopeBuilder callback (user provides signing logic)
|
|
31
|
+
→ backend.executeEnvelope (POST /tx)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Call flow for a query:**
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Done.query(url, opts)
|
|
38
|
+
→ buildQueryMessage (serialises path/body/query)
|
|
39
|
+
→ GET /query/{contract}?msg=...
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Call flow for events:**
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Done.subscribe(eventsUrl, topic, handler)
|
|
46
|
+
→ EventSource SSE connection
|
|
47
|
+
→ JSON-parsed events forwarded to handler
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bun add @donezone/client
|
|
56
|
+
# or
|
|
57
|
+
npm install @donezone/client
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## The `Done` Facade
|
|
63
|
+
|
|
64
|
+
`Done` is a pre-configured singleton exported from the package. Most applications only need this.
|
|
14
65
|
|
|
15
66
|
```ts
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
67
|
+
import { Done, signDocDigest } from "@donezone/client";
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `Done.config(options)`
|
|
71
|
+
|
|
72
|
+
Mutates the global `Done` instance. Call once at app startup. Omitted fields keep their existing values.
|
|
21
73
|
|
|
74
|
+
```ts
|
|
22
75
|
Done.config({
|
|
23
|
-
doneHttp: "https://doneHttp.done.zone",
|
|
24
|
-
doneEvents: "https://doneEvents.done.zone",
|
|
25
|
-
signer:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
expiresAt: () => Math.floor(Date.now() / 1000) + 300,
|
|
29
|
-
publicKey: () => storedPasskey.publicKey,
|
|
30
|
-
sign: async (signDoc) => {
|
|
31
|
-
const digest = signDocDigest(signDoc);
|
|
32
|
-
return await signWithPasskeyHardware(digest); // returns Uint8Array or base64
|
|
33
|
-
},
|
|
34
|
-
}),
|
|
76
|
+
doneHttp: "https://doneHttp.done.zone", // Done HTTP gateway base URL
|
|
77
|
+
doneEvents: "https://doneEvents.done.zone", // Done Events SSE base URL
|
|
78
|
+
signer: myEnvelopeBuilder, // EnvelopeBuilder (see Envelope Builders)
|
|
79
|
+
fetch: customFetch, // optional custom fetch implementation
|
|
80
|
+
eventSource: customEventSourceFactory, // optional custom EventSource factory
|
|
35
81
|
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `Done.run(url, options?)`
|
|
85
|
+
|
|
86
|
+
Executes an authenticated transaction. Returns `Promise<ExecuteResponse>`.
|
|
87
|
+
|
|
88
|
+
`url` is resolved against `doneHttp`. The first path segment after the base must be the contract address, followed by the route path:
|
|
36
89
|
|
|
37
|
-
|
|
90
|
+
```ts
|
|
91
|
+
const result = await Done.run("/done1contract.../buy", {
|
|
38
92
|
body: { minAmountOut: "1" },
|
|
39
|
-
funds: { uusd: "100" },
|
|
40
|
-
memo: "
|
|
93
|
+
funds: { uusd: "100" }, // or [{ denom: "uusd", amount: "100" }]
|
|
94
|
+
memo: "optional memo",
|
|
95
|
+
gasLimit: 500_000,
|
|
96
|
+
traceId: "abc-123",
|
|
97
|
+
signal: abortController.signal,
|
|
41
98
|
});
|
|
99
|
+
// result: { transactionHash, height, gasUsed }
|
|
100
|
+
```
|
|
42
101
|
|
|
43
|
-
|
|
102
|
+
Requires `signer` to be configured on the `Done` instance.
|
|
103
|
+
|
|
104
|
+
### `Done.query<T>(url, options?)`
|
|
105
|
+
|
|
106
|
+
Issues a read-only query. Returns `Promise<T>`.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const price = await Done.query<{ amount: string }>("/done1contract.../price");
|
|
44
110
|
|
|
111
|
+
const orders = await Done.query("/done1contract.../orders", {
|
|
112
|
+
search: { limit: 10, offset: 0 }, // merged into querystring
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### `Done.subscribe(eventsUrl, topic, handler, options?)`
|
|
117
|
+
|
|
118
|
+
Opens an SSE stream. Returns an `() => void` cleanup function.
|
|
119
|
+
|
|
120
|
+
`eventsUrl` is resolved against `doneEvents`. The path must include the contract address (e.g. `/done1contract.../events` or just the address segment the events server expects).
|
|
121
|
+
|
|
122
|
+
```ts
|
|
45
123
|
const stop = Done.subscribe(
|
|
46
|
-
"/
|
|
47
|
-
"PriceChange",
|
|
124
|
+
"/done1contract.../events",
|
|
125
|
+
"PriceChange", // topic string; also accepts string[] for nested paths
|
|
48
126
|
(event) => {
|
|
49
|
-
console.log(
|
|
50
|
-
}
|
|
127
|
+
console.log(event); // parsed JSON; raw string if parsing fails
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
rawEvent: true, // forward the raw MessageEvent instead of parsing
|
|
131
|
+
signal: ac.signal, // AbortSignal closes the subscription automatically
|
|
132
|
+
onError: (e) => {}, // called on EventSource error events
|
|
133
|
+
},
|
|
51
134
|
);
|
|
52
135
|
|
|
53
|
-
// later
|
|
136
|
+
// later:
|
|
54
137
|
stop();
|
|
55
|
-
|
|
56
|
-
// Contract-specific helper using just the address
|
|
57
|
-
const sale = Done.contract("done1contract123");
|
|
58
|
-
await sale.run("/buy", { body: { minAmountOut: "1" }, funds: { uusd: "100" } });
|
|
59
|
-
const priceAgain = await sale.query("/price");
|
|
60
138
|
```
|
|
61
139
|
|
|
62
|
-
|
|
140
|
+
### `Done.create(options?)`
|
|
141
|
+
|
|
142
|
+
Returns a new isolated `DoneInstance` with its own settings, inheriting from the current `Done` configuration. Useful for multi-tenant dashboards or per-request contexts.
|
|
63
143
|
|
|
64
144
|
```ts
|
|
65
145
|
const staging = Done.create({
|
|
66
146
|
doneHttp: "https://doneHttp.staging.zone",
|
|
67
147
|
doneEvents: "https://doneEvents.staging.zone",
|
|
68
|
-
signer:
|
|
148
|
+
signer: stagingSigner,
|
|
69
149
|
});
|
|
70
150
|
|
|
71
|
-
await staging.run("/
|
|
151
|
+
await staging.run("/done1contract.../buy", { body: { minAmountOut: "5" } });
|
|
72
152
|
```
|
|
73
153
|
|
|
74
|
-
|
|
154
|
+
The returned instance has the same `run`, `query`, `subscribe`, `config`, `create`, and `contract` methods as the global `Done`.
|
|
155
|
+
|
|
156
|
+
### `Done.contract(address)` / `Done.contract(config)`
|
|
157
|
+
|
|
158
|
+
Returns a `DoneContractClient` (or `DoneContractHandle`) scoped to a specific contract. The instance inherits `signer`, `fetch`, and `eventSource` from the `Done` configuration.
|
|
75
159
|
|
|
76
160
|
```ts
|
|
161
|
+
// Simple: address string — inherits everything from Done config
|
|
162
|
+
const sale = Done.contract("done1contract123");
|
|
163
|
+
await sale.run("/buy", { body: { minAmountOut: "1" } });
|
|
164
|
+
const price = await sale.query<{ amount: string }>("/price");
|
|
165
|
+
|
|
166
|
+
// Advanced: full config object
|
|
77
167
|
const sale = Done.contract({
|
|
78
168
|
baseUrl: "https://doneHttp.done.zone",
|
|
79
169
|
address: "done1contract123",
|
|
170
|
+
buildEnvelope: customSigner,
|
|
171
|
+
eventsPath: "/events",
|
|
80
172
|
});
|
|
173
|
+
```
|
|
81
174
|
|
|
82
|
-
|
|
175
|
+
### `Done.buildEnvelope(draft)` / `Done.signDocDigest(envelope)` / `Done.toSignDoc(envelope)`
|
|
176
|
+
|
|
177
|
+
Convenience re-exports of the low-level primitives (see [Low-Level Primitives](#low-level-primitives)).
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## DoneContractClient
|
|
182
|
+
|
|
183
|
+
A strongly typed, contract-scoped client. Instantiate directly when you need per-contract configuration (e.g. a different signer or events URL).
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { DoneContractClient } from "@donezone/client";
|
|
187
|
+
|
|
188
|
+
const client = new DoneContractClient({
|
|
189
|
+
baseUrl: "https://doneHttp.done.zone",
|
|
190
|
+
address: "done1contract123",
|
|
191
|
+
buildEnvelope: myEnvelopeBuilder, // required to call execute/run/post
|
|
192
|
+
eventsPath: "/events", // default: "/events"
|
|
193
|
+
eventSource: myEventSourceFactory,
|
|
194
|
+
fetch: customFetch,
|
|
195
|
+
defaultMetadata: { gas_limit: 500_000 },
|
|
196
|
+
});
|
|
83
197
|
```
|
|
84
198
|
|
|
85
|
-
###
|
|
199
|
+
### Type Safety for Transactions
|
|
200
|
+
|
|
201
|
+
`execute`, `run`, and `post` require `buildEnvelope` to be present in the config. If it is absent, TypeScript will give a compile-time error (`Argument of type 'string' is not assignable to parameter of type 'never'`) rather than a runtime throw. Clients without `buildEnvelope` are limited to `query`, `get`, `subscribe`, and `transaction`.
|
|
202
|
+
|
|
203
|
+
### Methods
|
|
204
|
+
|
|
205
|
+
#### `client.query<T>(path, request?, init?)`
|
|
206
|
+
|
|
207
|
+
Read-only query. Returns `Promise<T>`.
|
|
86
208
|
|
|
87
209
|
```ts
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
210
|
+
const state = await client.query<{ count: number }>("/state");
|
|
211
|
+
const orders = await client.query("/orders", { query: { limit: "10" } });
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### `client.get(path, request?, init?)`
|
|
215
|
+
|
|
216
|
+
Same as `query` but returns a `DoneRequest` (a `PromiseLike<Response>` with convenience `.json<T>()`, `.text()`, `.arrayBuffer()` methods). Useful when you need the raw `Response`.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
const res = await client.get("/orders", { query: { limit: "10" } });
|
|
220
|
+
const data = await res.json<Order[]>();
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### `client.execute(path, request?, init?)` / `.run(...)` / `.post(...)`
|
|
224
|
+
|
|
225
|
+
Execute a transaction. All three are identical. Requires `buildEnvelope` in config (compile-time enforced). Returns `Promise<ExecuteResponse>`.
|
|
94
226
|
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
const call = contract.transaction("/buy", {
|
|
227
|
+
```ts
|
|
228
|
+
const result = await client.execute("/buy", {
|
|
98
229
|
body: { minAmountOut: "1" },
|
|
99
|
-
|
|
230
|
+
funds: { uusd: "100" },
|
|
231
|
+
memo: "purchase",
|
|
232
|
+
gasLimit: 300_000,
|
|
233
|
+
traceId: "trace-xyz",
|
|
234
|
+
signal: ac.signal,
|
|
100
235
|
});
|
|
236
|
+
// result: { transactionHash, height, gasUsed }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### `client.transaction(path, request?)`
|
|
240
|
+
|
|
241
|
+
Builds a `PreparedTransaction` (the `CosmosMsg` + optional metadata) without submitting it. Use this to batch multiple contract calls into a single envelope manually.
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
const tx = client.transaction("/buy", { body: { minAmountOut: "1" } });
|
|
245
|
+
// tx: { msg: CosmosMsg, metadata?: EnvelopeMetadata }
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### `client.subscribe(topic, handler, options?)`
|
|
249
|
+
|
|
250
|
+
Opens an SSE subscription to `{baseUrl}{eventsPath}/{address}?topic={topic}`. Returns `() => void`.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
const stop = client.subscribe("Pinged", (payload) => {
|
|
254
|
+
console.log(payload); // parsed JSON
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// With options:
|
|
258
|
+
const stop = client.subscribe(
|
|
259
|
+
["namespace", "event"], // string[] encodes as JSON topic
|
|
260
|
+
handler,
|
|
261
|
+
{ onError: console.error, signal: ac.signal },
|
|
262
|
+
);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### `client.publishCode(request, init?)`
|
|
266
|
+
|
|
267
|
+
Publishes or updates contract code. Returns `Promise<PublishCodeResponse>`.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
await client.publishCode({ script: contractSourceCode, msg: initMsg });
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### `client.buildEnvelope(draft)` / `client.signDocDigest(envelope)`
|
|
274
|
+
|
|
275
|
+
See [Low-Level Primitives](#low-level-primitives).
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## DoneBackendClient
|
|
280
|
+
|
|
281
|
+
The raw transport layer. Use this when you need full control over envelope construction and submission.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
import { DoneBackendClient } from "@donezone/client";
|
|
285
|
+
|
|
286
|
+
const backend = new DoneBackendClient({
|
|
287
|
+
baseUrl: "https://doneHttp.done.zone",
|
|
288
|
+
fetch: customFetch, // optional
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Methods
|
|
293
|
+
|
|
294
|
+
#### `backend.contract(address)`
|
|
295
|
+
|
|
296
|
+
Returns a `DoneContractHandle` with `transaction`, `query`, `get`, and `publishCode` helpers. Does **not** include `execute`/`run` — use `backend.executeEnvelope` for submission.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
const handle = backend.contract("done1contract123");
|
|
300
|
+
const tx = handle.transaction("/buy", { body: { minAmountOut: "1" } });
|
|
301
|
+
// tx: PreparedTransaction — pass tx.msg into buildEnvelope
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### `backend.executeEnvelope(envelope, options?, init?)`
|
|
305
|
+
|
|
306
|
+
Submit a fully-built `AuthEnvelope` to `POST /tx`. Returns `Promise<ExecuteResponse>`.
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
await backend.executeEnvelope(envelope, {
|
|
310
|
+
passkey: { publicKey: "base64-encoded-public-key" },
|
|
311
|
+
memo: "tx memo",
|
|
312
|
+
signal: ac.signal,
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### `backend.queryContract<T>(address, call, init?)`
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
const result = await backend.queryContract<{ price: string }>(
|
|
320
|
+
"done1contract123",
|
|
321
|
+
{ path: "/price" },
|
|
322
|
+
);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### `backend.queryContractRaw(address, call, init?)`
|
|
326
|
+
|
|
327
|
+
Same as `queryContract` but returns the raw `Response`.
|
|
328
|
+
|
|
329
|
+
#### `backend.publishCode(request, init?)`
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
await backend.publishCode({
|
|
333
|
+
contract: "js", // or "wasm"
|
|
334
|
+
script: contractSource,
|
|
335
|
+
msg: optionalInitMsg,
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
#### `backend.getAgentQuota(userId, agent)` / `backend.getForwarderQuota(address)`
|
|
340
|
+
|
|
341
|
+
Inspect quota usage for agent/forwarder authorization.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Envelope Builders
|
|
346
|
+
|
|
347
|
+
Envelope builders are functions with the signature `(ctx: EnvelopeBuildContext) => Promise<EnvelopeBuildResult> | EnvelopeBuildResult`. Pass them as `signer` to `Done.config()` or `buildEnvelope` to `DoneContractClient`.
|
|
348
|
+
|
|
349
|
+
### `createPasskeyEnvelopeBuilder(options)`
|
|
350
|
+
|
|
351
|
+
For WebAuthn / hardware passkey signing.
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
import { createPasskeyEnvelopeBuilder, signDocDigest } from "@donezone/client";
|
|
355
|
+
|
|
356
|
+
const builder = createPasskeyEnvelopeBuilder({
|
|
357
|
+
userId: "user-abc", // or (ctx) => resolveUserId(ctx)
|
|
358
|
+
nonce: () => Date.now(),
|
|
359
|
+
expiresAt: () => Math.floor(Date.now() / 1000) + 300,
|
|
360
|
+
publicKey: () => storedPublicKey, // base64 string
|
|
361
|
+
sign: async (signDoc, ctx) => {
|
|
362
|
+
const digest = signDocDigest(signDoc); // SHA-256 Uint8Array
|
|
363
|
+
return await signWithHardware(digest); // return Uint8Array or base64 string
|
|
364
|
+
},
|
|
365
|
+
// Optional:
|
|
366
|
+
agent: "done1agent...",
|
|
367
|
+
forwarder: "done1forwarder...",
|
|
368
|
+
metadata: { gas_limit: 500_000 },
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
Done.config({ signer: builder });
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
All option fields except `sign` can be a plain value **or** a `(ctx: EnvelopeBuildContext) => MaybePromise<T>` factory, giving per-call control.
|
|
375
|
+
|
|
376
|
+
### `createSessionEnvelopeBuilder(options)`
|
|
377
|
+
|
|
378
|
+
For session key signing (e.g. a server-side HSM or stored keypair).
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
import { createSessionEnvelopeBuilder } from "@donezone/client";
|
|
382
|
+
|
|
383
|
+
const builder = createSessionEnvelopeBuilder({
|
|
384
|
+
userId: "user-abc",
|
|
385
|
+
sessionId: "session-xyz",
|
|
386
|
+
nonce: () => Date.now(),
|
|
387
|
+
expiresAt: () => Math.floor(Date.now() / 1000) + 300,
|
|
388
|
+
sign: async (signDoc) => {
|
|
389
|
+
const digest = signDocDigest(signDoc);
|
|
390
|
+
return await signWithSessionKey(digest); // Uint8Array or base64
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### `createDevEnvelopeBuilder(options?)`
|
|
396
|
+
|
|
397
|
+
Produces **unsigned** envelopes for local development and testing. Never use in production.
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
import { createDevEnvelopeBuilder } from "@donezone/client";
|
|
401
|
+
|
|
402
|
+
const builder = createDevEnvelopeBuilder({
|
|
403
|
+
userId: "dev", // default: "dev"
|
|
404
|
+
ttlSeconds: 300, // default: 300
|
|
405
|
+
});
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## Low-Level Primitives
|
|
411
|
+
|
|
412
|
+
These are useful when implementing a custom envelope builder or doing manual envelope manipulation.
|
|
413
|
+
|
|
414
|
+
### `buildEnvelope(draft)`
|
|
415
|
+
|
|
416
|
+
Constructs and validates an `AuthEnvelope` from a draft. Throws if `msgs` is empty.
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
import { buildEnvelope } from "@donezone/client";
|
|
101
420
|
|
|
102
421
|
const envelope = buildEnvelope({
|
|
103
|
-
user_id: "user-
|
|
104
|
-
msgs: [
|
|
105
|
-
nonce:
|
|
422
|
+
user_id: "user-abc",
|
|
423
|
+
msgs: [cosmosMsg],
|
|
424
|
+
nonce: Date.now(),
|
|
106
425
|
expires_at: Math.floor(Date.now() / 1000) + 300,
|
|
107
|
-
role: "Passkey",
|
|
108
|
-
|
|
426
|
+
role: "Passkey", // or "Session"
|
|
427
|
+
signatures: { passkey: "base64sig" },
|
|
428
|
+
// Optional:
|
|
429
|
+
session_id: "...",
|
|
430
|
+
agent: "done1agent...",
|
|
431
|
+
forwarder: "done1forwarder...",
|
|
432
|
+
metadata: { trace_id: "...", memo: "...", gas_limit: 500_000 },
|
|
109
433
|
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### `toSignDoc(envelope)`
|
|
437
|
+
|
|
438
|
+
Strips signatures from an envelope (or draft) to produce the canonical `AuthEnvelopeSignDoc` that is actually signed.
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
import { toSignDoc } from "@donezone/client";
|
|
110
442
|
|
|
111
443
|
const signDoc = toSignDoc(envelope);
|
|
112
|
-
|
|
113
|
-
// sign digest with passkey/session key, then attach to envelope.signatures
|
|
444
|
+
```
|
|
114
445
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
446
|
+
### `signDocBytes(signDoc)`
|
|
447
|
+
|
|
448
|
+
Produces the canonical UTF-8 JSON bytes (keys sorted, no extra whitespace) of the sign doc. This is what gets hashed.
|
|
449
|
+
|
|
450
|
+
```ts
|
|
451
|
+
import { signDocBytes } from "@donezone/client";
|
|
452
|
+
|
|
453
|
+
const bytes = signDocBytes(signDoc); // Uint8Array
|
|
119
454
|
```
|
|
120
455
|
|
|
121
|
-
###
|
|
456
|
+
### `signDocDigest(signDoc)`
|
|
122
457
|
|
|
123
|
-
|
|
124
|
-
signing callbacks, so they work in Node, Bun, or browsers alike—the caller decides how to obtain
|
|
125
|
-
signatures (WebAuthn, HSM, remote service, etc.). The helpers return the envelope plus any metadata
|
|
126
|
-
the Done HTTP transport expects, keeping public/private key plumbing outside of the library.
|
|
458
|
+
SHA-256 of the canonical sign doc bytes. This is what passkey/session hardware actually signs.
|
|
127
459
|
|
|
128
|
-
|
|
460
|
+
```ts
|
|
461
|
+
import { signDocDigest } from "@donezone/client";
|
|
462
|
+
|
|
463
|
+
const digest = signDocDigest(signDoc); // Uint8Array (32 bytes)
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### `encodeSignature(bytes)` / `decodeSignature(base64)`
|
|
467
|
+
|
|
468
|
+
Convert between raw signature bytes and the base64 strings stored in `AuthEnvelope.signatures`.
|
|
469
|
+
|
|
470
|
+
```ts
|
|
471
|
+
import { encodeSignature, decodeSignature } from "@donezone/client";
|
|
472
|
+
|
|
473
|
+
const b64 = encodeSignature(rawSigBytes); // Uint8Array → base64 string
|
|
474
|
+
const raw = decodeSignature(b64); // base64 string → Uint8Array
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Message Builders
|
|
480
|
+
|
|
481
|
+
These build the wire format for contract calls. Useful when constructing multi-message envelopes manually.
|
|
482
|
+
|
|
483
|
+
### `buildTransactionMessage(contractAddr, call, options?)`
|
|
484
|
+
|
|
485
|
+
Builds a `WasmMsg::Execute` `CosmosMsg` in the shape the Done HTTP gateway expects.
|
|
486
|
+
|
|
487
|
+
```ts
|
|
488
|
+
import { buildTransactionMessage } from "@donezone/client";
|
|
489
|
+
|
|
490
|
+
const msg = buildTransactionMessage(
|
|
491
|
+
"done1contract123",
|
|
492
|
+
{ path: "/buy", body: { minAmountOut: "1" }, query: { mode: "fast" } },
|
|
493
|
+
{ funds: { uusd: "100" } },
|
|
494
|
+
);
|
|
495
|
+
// { wasm: { execute: { contract_addr, msg: { msg: { path, body, query } }, funds } } }
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
The `call.path` must start with `/`.
|
|
499
|
+
|
|
500
|
+
### `buildQueryMessage(call)`
|
|
501
|
+
|
|
502
|
+
Builds the query message object that goes into `GET /query/{contract}?msg=...`.
|
|
503
|
+
|
|
504
|
+
```ts
|
|
505
|
+
import { buildQueryMessage } from "@donezone/client";
|
|
506
|
+
|
|
507
|
+
const queryMsg = buildQueryMessage({ path: "/price", query: { verbose: "1" } });
|
|
508
|
+
// { msg: { path: "/price", query: { verbose: "1" } } }
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Types Reference
|
|
514
|
+
|
|
515
|
+
Key types exported from the package:
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
// Envelope core
|
|
519
|
+
AuthEnvelope // complete signed envelope sent to /tx
|
|
520
|
+
AuthEnvelopeSignDoc // envelope minus signatures — the thing that gets signed
|
|
521
|
+
EnvelopeDraft // input to buildEnvelope (signatures optional)
|
|
522
|
+
EnvelopeRole // "Passkey" | "Session"
|
|
523
|
+
EnvelopeSignatures // { passkey?: string; session?: string }
|
|
524
|
+
EnvelopeMetadata // { trace_id?: string; memo?: string; gas_limit?: number }
|
|
525
|
+
|
|
526
|
+
// Messages
|
|
527
|
+
CosmosMsg // WasmExecuteMsg | BankSendMsg | Record<string, unknown>
|
|
528
|
+
WasmExecuteMsg // { wasm: { execute: { contract_addr, msg, funds? } } }
|
|
529
|
+
BankSendMsg // { bank: { send: { to_address, amount } } }
|
|
530
|
+
Coin // { denom: string; amount: string }
|
|
531
|
+
FundsInput // Coin[] | Record<string, string | number> | undefined
|
|
532
|
+
|
|
533
|
+
// Client config
|
|
534
|
+
DoneContractConfig // config for DoneContractClient constructor
|
|
535
|
+
DoneClientConfig // config for DoneBackendClient constructor
|
|
536
|
+
DoneConfigOptions // config for Done.config() / Done.create()
|
|
537
|
+
|
|
538
|
+
// Request/response
|
|
539
|
+
ExecuteResponse // { transactionHash: string; height: number; gasUsed: number }
|
|
540
|
+
TransactionRequest // options for execute/run/post (body, query, funds, memo, etc.)
|
|
541
|
+
QueryRequest // options for query/get (body, query)
|
|
542
|
+
PreparedTransaction // { msg: CosmosMsg; metadata?: EnvelopeMetadata }
|
|
543
|
+
SubscriptionOptions // { onError?, signal?, rawEvent? }
|
|
544
|
+
|
|
545
|
+
// Builders
|
|
546
|
+
EnvelopeBuilder // (ctx: EnvelopeBuildContext) => Promise<EnvelopeBuildResult> | EnvelopeBuildResult
|
|
547
|
+
EnvelopeBuildContext // { msg, metadata?, path, request }
|
|
548
|
+
EnvelopeBuildResult // { envelope: AuthEnvelope; options?: ExecuteEnvelopeOptions }
|
|
549
|
+
EventSourceFactory // (url: string) => EventSource-compatible object
|
|
550
|
+
|
|
551
|
+
// Passkey/session builder options
|
|
552
|
+
PasskeyEnvelopeBuilderOptions
|
|
553
|
+
SessionEnvelopeBuilderOptions
|
|
554
|
+
DevEnvelopeBuilderOptions
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Complete Example
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
import {
|
|
563
|
+
Done,
|
|
564
|
+
createPasskeyEnvelopeBuilder,
|
|
565
|
+
signDocDigest,
|
|
566
|
+
} from "@donezone/client";
|
|
567
|
+
|
|
568
|
+
// Configure once at startup
|
|
569
|
+
Done.config({
|
|
570
|
+
doneHttp: "https://doneHttp.done.zone",
|
|
571
|
+
doneEvents: "https://doneEvents.done.zone",
|
|
572
|
+
signer: createPasskeyEnvelopeBuilder({
|
|
573
|
+
userId: () => currentUser.id,
|
|
574
|
+
nonce: () => Date.now(),
|
|
575
|
+
expiresAt: () => Math.floor(Date.now() / 1000) + 300,
|
|
576
|
+
publicKey: () => currentUser.passkeyPublicKey,
|
|
577
|
+
sign: async (signDoc) => {
|
|
578
|
+
const digest = signDocDigest(signDoc);
|
|
579
|
+
return await navigator.credentials.get(/* WebAuthn options using digest */);
|
|
580
|
+
},
|
|
581
|
+
}),
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
// Transaction
|
|
585
|
+
const { transactionHash } = await Done.run("/done1abc.../buy", {
|
|
586
|
+
body: { minAmountOut: "100" },
|
|
587
|
+
funds: { uusd: "1000" },
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
// Query
|
|
591
|
+
const price = await Done.query<{ amount: string }>("/done1abc.../price");
|
|
592
|
+
|
|
593
|
+
// Subscription
|
|
594
|
+
const stop = Done.subscribe(
|
|
595
|
+
"/done1abc.../events",
|
|
596
|
+
"PriceChange",
|
|
597
|
+
(event) => console.log("price changed:", event),
|
|
598
|
+
);
|
|
599
|
+
```
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toSignDoc } from "./envelope";
|
|
1
|
+
import { toSignDoc } from "./envelope-builder";
|
|
2
2
|
import type { EnvelopeBuildContext, EnvelopeBuilder, EnvelopeMetadata, EnvelopeRole } from "./types";
|
|
3
3
|
type MaybePromise<T> = T | Promise<T>;
|
|
4
4
|
type ValueOrFactory<T> = T | ((ctx: EnvelopeBuildContext) => MaybePromise<T>);
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EAEV,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAEV,oBAAoB,EAEpB,eAAe,EACf,gBAAgB,EAChB,YAAY,EAGb,MAAM,SAAS,CAAC;AAEjB,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AACtC,KAAK,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,oBAAoB,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9E,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,cAAc,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,6BAA8B,SAAQ,oBAAoB;IACzE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC9B,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAClC,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,EAAE,CACJ,OAAO,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,EACrC,GAAG,EAAE,oBAAoB,KACtB,YAAY,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,6BAA8B,SAAQ,oBAAoB;IACzE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC/B,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAClC,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC9B,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,EAAE,CACJ,OAAO,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,EACrC,GAAG,EAAE,oBAAoB,KACtB,YAAY,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;CACzC;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,eAAe,CA6CjB;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,eAAe,CA2CjB"}
|