@donezone/client 0.1.0

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/dist/done.js ADDED
@@ -0,0 +1,473 @@
1
+ import { buildEnvelope as buildEnvelopeHelper, CURRENT_ENVELOPE_VERSION, signDocDigest, toSignDoc, } from "./envelope";
2
+ import { DoneBackendClient } from "./client";
3
+ import { buildTransactionMessage } from "./messages";
4
+ export class DoneContractClient {
5
+ backend;
6
+ address;
7
+ buildEnvelopeFn;
8
+ eventSourceFactory;
9
+ eventsPath;
10
+ defaultMetadata;
11
+ constructor(config) {
12
+ this.backend = new DoneBackendClient({ baseUrl: config.baseUrl, fetch: config.fetch });
13
+ this.address = config.address;
14
+ this.buildEnvelopeFn = config.buildEnvelope;
15
+ this.eventSourceFactory = config.eventSource;
16
+ this.eventsPath = config.eventsPath ?? "/events";
17
+ this.defaultMetadata = config.defaultMetadata;
18
+ }
19
+ get(path, request = {}, init = {}) {
20
+ const promise = this.fetchQuery(path, request, init);
21
+ return new DoneRequest(promise);
22
+ }
23
+ async query(path, request = {}, init = {}) {
24
+ const response = await this.fetchQuery(path, request, init);
25
+ return response.json();
26
+ }
27
+ async post(path, request = {}, init = {}) {
28
+ return this.execute(path, request, init);
29
+ }
30
+ async run(path, request = {}, init = {}) {
31
+ return this.execute(path, request, init);
32
+ }
33
+ async execute(path, request = {}, init = {}) {
34
+ if (!this.buildEnvelopeFn) {
35
+ throw new Error("execute requires a buildEnvelope function in contract config");
36
+ }
37
+ const normalizedCall = {
38
+ path,
39
+ query: request.query,
40
+ body: request.body,
41
+ };
42
+ const transactionMsg = buildTransactionMessage(this.address, normalizedCall, request);
43
+ const metadata = mergeMetadata(this.defaultMetadata, request.metadata, { trace_id: request.traceId, memo: request.memo, gas_limit: request.gasLimit });
44
+ const buildContext = {
45
+ msg: transactionMsg,
46
+ metadata,
47
+ path,
48
+ request,
49
+ };
50
+ const buildResult = await this.buildEnvelopeFn(buildContext);
51
+ if (metadata) {
52
+ buildResult.envelope.metadata = buildResult.envelope.metadata ?? metadata;
53
+ }
54
+ const executeOptions = mergeExecuteOptions(buildResult.options, {
55
+ memo: request.memo,
56
+ passkey: request.passkey,
57
+ signal: request.signal,
58
+ });
59
+ return this.backend.executeEnvelope(buildResult.envelope, executeOptions, init);
60
+ }
61
+ transaction(path, request = {}) {
62
+ const normalizedCall = {
63
+ path,
64
+ query: request.query,
65
+ body: request.body,
66
+ };
67
+ const msg = buildTransactionMessage(this.address, normalizedCall, request);
68
+ const metadata = mergeMetadata(this.defaultMetadata, request.metadata, {
69
+ trace_id: request.traceId,
70
+ memo: request.memo,
71
+ gas_limit: request.gasLimit,
72
+ });
73
+ return { msg, metadata };
74
+ }
75
+ subscribe(topic, handler, options = {}) {
76
+ const factory = this.eventSourceFactory ?? defaultEventSourceFactory;
77
+ const eventsBase = buildEventsUrl(this.backend.baseUrl, this.eventsPath);
78
+ const encodedTopic = Array.isArray(topic) ? JSON.stringify(topic) : topic;
79
+ const url = `${eventsBase}?topic=${encodeURIComponent(encodedTopic)}`;
80
+ const source = factory(url);
81
+ const messageListener = (event) => {
82
+ if (options.rawEvent) {
83
+ handler(event);
84
+ return;
85
+ }
86
+ const data = event.data;
87
+ try {
88
+ handler(JSON.parse(data));
89
+ }
90
+ catch {
91
+ handler(data);
92
+ }
93
+ };
94
+ if (typeof source.addEventListener === "function") {
95
+ source.addEventListener("message", messageListener);
96
+ }
97
+ else {
98
+ source.onmessage = messageListener;
99
+ }
100
+ if (options.onError) {
101
+ if (typeof source.addEventListener === "function") {
102
+ source.addEventListener("error", options.onError);
103
+ }
104
+ else {
105
+ source.onerror = options.onError;
106
+ }
107
+ }
108
+ const cleanup = () => {
109
+ if (typeof source.removeEventListener === "function") {
110
+ source.removeEventListener("message", messageListener);
111
+ if (options.onError) {
112
+ source.removeEventListener("error", options.onError);
113
+ }
114
+ }
115
+ source.close();
116
+ };
117
+ if (options.signal) {
118
+ if (options.signal.aborted) {
119
+ cleanup();
120
+ }
121
+ else {
122
+ options.signal.addEventListener("abort", cleanup, { once: true });
123
+ }
124
+ }
125
+ return cleanup;
126
+ }
127
+ buildEnvelope(draft) {
128
+ return buildEnvelopeHelper(draft);
129
+ }
130
+ signDocDigest(envelope) {
131
+ return signDocDigest(toSignDoc(envelope));
132
+ }
133
+ get baseUrl() {
134
+ return this.backend.baseUrl;
135
+ }
136
+ async fetchQuery(path, request, init = {}) {
137
+ const call = { path, query: request.query, body: request.body };
138
+ return this.backend.queryContractRaw(this.address, call, init);
139
+ }
140
+ }
141
+ export class DoneRequest {
142
+ promise;
143
+ constructor(promise) {
144
+ this.promise = promise;
145
+ }
146
+ then(onfulfilled, onrejected) {
147
+ return this.promise.then(onfulfilled, onrejected);
148
+ }
149
+ catch(onrejected) {
150
+ return this.promise.catch(onrejected);
151
+ }
152
+ finally(onfinally) {
153
+ return this.promise.finally(onfinally);
154
+ }
155
+ json() {
156
+ return this.promise.then((response) => response.json());
157
+ }
158
+ text() {
159
+ return this.promise.then((response) => response.text());
160
+ }
161
+ arrayBuffer() {
162
+ return this.promise.then((response) => response.arrayBuffer());
163
+ }
164
+ }
165
+ function mergeMetadata(...entries) {
166
+ const merged = {};
167
+ for (const entry of entries) {
168
+ if (!entry)
169
+ continue;
170
+ if (entry.trace_id)
171
+ merged.trace_id = entry.trace_id;
172
+ if (entry.memo)
173
+ merged.memo = entry.memo;
174
+ if (typeof entry.gas_limit === "number")
175
+ merged.gas_limit = entry.gas_limit;
176
+ }
177
+ return Object.keys(merged).length > 0 ? merged : undefined;
178
+ }
179
+ function mergeExecuteOptions(base, overrides) {
180
+ if (!base && !overrides.memo && !overrides.passkey && !overrides.signal) {
181
+ return undefined;
182
+ }
183
+ return {
184
+ memo: overrides.memo ?? base?.memo,
185
+ passkey: overrides.passkey ?? base?.passkey,
186
+ signal: overrides.signal ?? base?.signal,
187
+ };
188
+ }
189
+ function defaultEventSourceFactory(url) {
190
+ if (typeof EventSource === "undefined") {
191
+ throw new Error("EventSource is not available in this environment");
192
+ }
193
+ return new EventSource(url);
194
+ }
195
+ function buildEventsUrl(baseUrl, eventsPath) {
196
+ const normalized = eventsPath.startsWith("/") ? eventsPath : `/${eventsPath}`;
197
+ return `${baseUrl.replace(/\/$/, "")}${normalized}`;
198
+ }
199
+ function resolveFetch(fn) {
200
+ if (fn)
201
+ return fn;
202
+ if (typeof fetch === "function")
203
+ return fetch.bind(globalThis);
204
+ throw new Error("global fetch is not available; configure Done with a fetch implementation via Done.config");
205
+ }
206
+ function resolveEventSource(factory) {
207
+ if (factory)
208
+ return factory;
209
+ if (typeof EventSource === "function") {
210
+ return (url) => new EventSource(url);
211
+ }
212
+ return undefined;
213
+ }
214
+ function normalizeConfig(input = {}, base) {
215
+ const previous = base ?? {
216
+ doneHttp: "https://doneHttp.done.zone",
217
+ doneEvents: "https://doneEvents.done.zone",
218
+ fetch: resolveFetch(),
219
+ eventSource: resolveEventSource(),
220
+ envelopeBuilder: undefined,
221
+ };
222
+ return {
223
+ doneHttp: input.doneHttp ?? previous.doneHttp,
224
+ doneEvents: input.doneEvents ?? previous.doneEvents,
225
+ fetch: resolveFetch(input.fetch ?? previous.fetch),
226
+ eventSource: resolveEventSource(input.eventSource ?? previous.eventSource),
227
+ envelopeBuilder: input.envelopeBuilder ?? input.signer ?? previous.envelopeBuilder,
228
+ };
229
+ }
230
+ function resolveRoute(raw, base, extraSearch) {
231
+ const url = new URL(raw, base);
232
+ if (extraSearch) {
233
+ for (const [key, value] of Object.entries(extraSearch)) {
234
+ url.searchParams.set(key, String(value));
235
+ }
236
+ }
237
+ const pathSegments = url.pathname.replace(/^\/+/, "").split("/");
238
+ const contract = pathSegments.shift();
239
+ if (!contract) {
240
+ throw new Error("route must include contract address as first path segment");
241
+ }
242
+ const path = pathSegments.length > 0 ? `/${pathSegments.join("/")}` : "/";
243
+ const queryRecord = searchParamsToRecord(url.searchParams);
244
+ return {
245
+ url,
246
+ contract,
247
+ path,
248
+ query: Object.keys(queryRecord).length > 0 ? queryRecord : undefined,
249
+ };
250
+ }
251
+ function searchParamsToRecord(params) {
252
+ const record = {};
253
+ for (const [key, value] of params) {
254
+ const existing = record[key];
255
+ if (existing === undefined) {
256
+ record[key] = value;
257
+ }
258
+ else if (Array.isArray(existing)) {
259
+ existing.push(value);
260
+ }
261
+ else {
262
+ record[key] = [existing, value];
263
+ }
264
+ }
265
+ return record;
266
+ }
267
+ function normalizeContractBody(body) {
268
+ if (body === undefined || body === null) {
269
+ return body;
270
+ }
271
+ if (isPlainObject(body) || Array.isArray(body)) {
272
+ return body;
273
+ }
274
+ if (typeof body === "string") {
275
+ try {
276
+ return JSON.parse(body);
277
+ }
278
+ catch (err) {
279
+ throw new Error("string bodies must contain JSON payloads when invoking Done.run/query");
280
+ }
281
+ }
282
+ if (body instanceof URLSearchParams) {
283
+ return Object.fromEntries(Array.from(body));
284
+ }
285
+ throw new Error("unsupported body type for Done.run/query; provide a JSON-serialisable value");
286
+ }
287
+ function isPlainObject(value) {
288
+ if (value === null || typeof value !== "object")
289
+ return false;
290
+ const proto = Object.getPrototypeOf(value);
291
+ return proto === Object.prototype || proto === null;
292
+ }
293
+ function normalizeContractSegment(value) {
294
+ if (!value) {
295
+ throw new Error("contract identifier cannot be empty");
296
+ }
297
+ return value.replace(/^\/+/u, "").replace(/\/+$/u, "");
298
+ }
299
+ class DoneInstance {
300
+ settings;
301
+ backend;
302
+ CURRENT_ENVELOPE_VERSION = CURRENT_ENVELOPE_VERSION;
303
+ buildEnvelope = buildEnvelopeHelper;
304
+ signDocDigest = signDocDigest;
305
+ toSignDoc = toSignDoc;
306
+ constructor(input) {
307
+ this.settings = normalizeConfig(input);
308
+ this.backend = new DoneBackendClient({ baseUrl: this.settings.doneHttp, fetch: this.settings.fetch });
309
+ }
310
+ async run(url, init = {}) {
311
+ const { body: rawBody, funds, memo, traceId, gasLimit, passkey, metadata, search, ...rest } = init;
312
+ const fetchInit = { ...rest };
313
+ const resolved = resolveRoute(url, this.settings.doneHttp, search);
314
+ const contractBody = normalizeContractBody(rawBody);
315
+ const call = {
316
+ path: resolved.path,
317
+ query: resolved.query,
318
+ body: contractBody,
319
+ };
320
+ const msg = buildTransactionMessage(resolved.contract, call, { funds });
321
+ const mergedMetadata = mergeMetadata(metadata, {
322
+ trace_id: traceId,
323
+ memo,
324
+ gas_limit: gasLimit,
325
+ });
326
+ const builder = this.requireEnvelopeBuilder();
327
+ const request = {
328
+ body: contractBody,
329
+ query: resolved.query,
330
+ funds,
331
+ memo,
332
+ traceId,
333
+ gasLimit,
334
+ metadata: mergedMetadata,
335
+ passkey,
336
+ signal: fetchInit.signal,
337
+ };
338
+ const result = await Promise.resolve(builder({
339
+ msg,
340
+ metadata: mergedMetadata,
341
+ path: resolved.path,
342
+ request,
343
+ }));
344
+ if (mergedMetadata) {
345
+ result.envelope.metadata = result.envelope.metadata ?? mergedMetadata;
346
+ }
347
+ const executeOptions = mergeExecuteOptions(result.options, {
348
+ memo,
349
+ passkey,
350
+ signal: fetchInit.signal,
351
+ });
352
+ return this.backend.executeEnvelope(result.envelope, executeOptions ?? {}, fetchInit);
353
+ }
354
+ async query(url, init = {}) {
355
+ const { body: rawBody, search, ...rest } = init;
356
+ const fetchInit = { ...rest };
357
+ const resolved = resolveRoute(url, this.settings.doneHttp, search);
358
+ const contractBody = normalizeContractBody(rawBody);
359
+ const call = {
360
+ path: resolved.path,
361
+ query: resolved.query,
362
+ body: contractBody,
363
+ };
364
+ return this.backend.queryContract(resolved.contract, call, fetchInit);
365
+ }
366
+ subscribe(eventsUrl, topic, handler, options = {}) {
367
+ const factory = this.settings.eventSource ?? defaultEventSourceFactory;
368
+ if (!factory) {
369
+ throw new Error("EventSource is not available; configure Done with an eventSource factory");
370
+ }
371
+ const url = new URL(eventsUrl, this.settings.doneEvents);
372
+ const topicValue = Array.isArray(topic) ? JSON.stringify(topic) : topic;
373
+ url.searchParams.set("topic", topicValue);
374
+ const source = factory(url.toString());
375
+ const messageListener = (event) => {
376
+ if (options.rawEvent) {
377
+ handler(event);
378
+ return;
379
+ }
380
+ try {
381
+ handler(JSON.parse(event.data));
382
+ }
383
+ catch {
384
+ handler(event.data);
385
+ }
386
+ };
387
+ if (typeof source.addEventListener === "function") {
388
+ source.addEventListener("message", messageListener);
389
+ }
390
+ else {
391
+ source.onmessage = messageListener;
392
+ }
393
+ if (options.onError) {
394
+ if (typeof source.addEventListener === "function") {
395
+ source.addEventListener("error", options.onError);
396
+ }
397
+ else {
398
+ source.onerror = options.onError;
399
+ }
400
+ }
401
+ const cleanup = () => {
402
+ if (typeof source.removeEventListener === "function") {
403
+ source.removeEventListener("message", messageListener);
404
+ if (options.onError) {
405
+ source.removeEventListener("error", options.onError);
406
+ }
407
+ }
408
+ source.close();
409
+ };
410
+ if (options.signal) {
411
+ if (options.signal.aborted) {
412
+ cleanup();
413
+ }
414
+ else {
415
+ options.signal.addEventListener("abort", cleanup, { once: true });
416
+ }
417
+ }
418
+ return cleanup;
419
+ }
420
+ config(update) {
421
+ this.settings = normalizeConfig(update, this.settings);
422
+ this.backend = new DoneBackendClient({ baseUrl: this.settings.doneHttp, fetch: this.settings.fetch });
423
+ }
424
+ create(update = {}) {
425
+ const merged = normalizeConfig(update, this.settings);
426
+ return new DoneInstance({
427
+ doneHttp: merged.doneHttp,
428
+ doneEvents: merged.doneEvents,
429
+ fetch: merged.fetch,
430
+ eventSource: merged.eventSource,
431
+ envelopeBuilder: merged.envelopeBuilder,
432
+ });
433
+ }
434
+ contract(config, maybeConfig) {
435
+ if (typeof config === "string") {
436
+ if (!maybeConfig) {
437
+ return this.buildContractHandle(config);
438
+ }
439
+ return new DoneContractClient({
440
+ baseUrl: config,
441
+ ...maybeConfig,
442
+ buildEnvelope: maybeConfig.buildEnvelope ?? this.settings.envelopeBuilder,
443
+ fetch: maybeConfig.fetch ?? this.settings.fetch,
444
+ eventSource: maybeConfig.eventSource ?? this.settings.eventSource,
445
+ });
446
+ }
447
+ return new DoneContractClient({
448
+ ...config,
449
+ baseUrl: config.baseUrl,
450
+ buildEnvelope: config.buildEnvelope ?? this.settings.envelopeBuilder,
451
+ fetch: config.fetch ?? this.settings.fetch,
452
+ eventSource: config.eventSource ?? this.settings.eventSource,
453
+ });
454
+ }
455
+ requireEnvelopeBuilder() {
456
+ if (!this.settings.envelopeBuilder) {
457
+ throw new Error("Done.run requires an envelope builder; configure Done.config({ signer: ... }) first");
458
+ }
459
+ return this.settings.envelopeBuilder;
460
+ }
461
+ buildContractHandle(contract) {
462
+ const address = normalizeContractSegment(contract);
463
+ const client = new DoneContractClient({
464
+ baseUrl: this.settings.doneHttp,
465
+ address,
466
+ buildEnvelope: this.settings.envelopeBuilder,
467
+ fetch: this.settings.fetch,
468
+ eventSource: this.settings.eventSource,
469
+ });
470
+ return client;
471
+ }
472
+ }
473
+ export const Done = new DoneInstance();
@@ -0,0 +1,29 @@
1
+ import type { AuthEnvelope, AuthEnvelopeSignDoc, Coin, CosmosMsg, EnvelopeMetadata, EnvelopeRole, EnvelopeSignatures } from "./types";
2
+ export declare const CURRENT_ENVELOPE_VERSION = 1;
3
+ export interface EnvelopeDraft {
4
+ version?: number;
5
+ user_id: string;
6
+ session_id?: string;
7
+ msgs: CosmosMsg[];
8
+ nonce: number;
9
+ expires_at: number;
10
+ role: EnvelopeRole;
11
+ agent?: string;
12
+ forwarder?: string;
13
+ metadata?: EnvelopeMetadata;
14
+ signatures?: EnvelopeSignatures;
15
+ }
16
+ export interface TransactionCall {
17
+ contract: string;
18
+ path: string;
19
+ body?: unknown;
20
+ query?: Record<string, unknown>;
21
+ funds?: Coin[];
22
+ }
23
+ export declare function toSignDoc(envelope: AuthEnvelope | EnvelopeDraft): AuthEnvelopeSignDoc;
24
+ export declare function buildEnvelope(draft: EnvelopeDraft): AuthEnvelope;
25
+ export declare function signDocBytes(signDoc: AuthEnvelopeSignDoc): Uint8Array;
26
+ export declare function signDocDigest(signDoc: AuthEnvelopeSignDoc): Uint8Array;
27
+ export declare function encodeSignature(signature: Uint8Array): string;
28
+ export declare function decodeSignature(signature: string): Uint8Array;
29
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,IAAI,EACJ,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CAChB;AAWD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa,GAAG,mBAAmB,CAcrF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CAmBhE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CAGrE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CAGtE;AAwBD,wBAAgB,eAAe,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAU7D;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAW7D"}
@@ -0,0 +1,98 @@
1
+ import { sha256 } from "@noble/hashes/sha256";
2
+ export const CURRENT_ENVELOPE_VERSION = 1;
3
+ function normalizeMetadata(metadata) {
4
+ if (!metadata)
5
+ return undefined;
6
+ const normalized = {};
7
+ if (metadata.trace_id)
8
+ normalized.trace_id = metadata.trace_id;
9
+ if (metadata.memo)
10
+ normalized.memo = metadata.memo;
11
+ if (typeof metadata.gas_limit === "number")
12
+ normalized.gas_limit = metadata.gas_limit;
13
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
14
+ }
15
+ export function toSignDoc(envelope) {
16
+ const metadata = normalizeMetadata(envelope.metadata);
17
+ return {
18
+ version: envelope.version ?? CURRENT_ENVELOPE_VERSION,
19
+ user_id: envelope.user_id,
20
+ session_id: envelope.session_id,
21
+ msgs: envelope.msgs.map((msg) => cloneMsg(msg)),
22
+ nonce: envelope.nonce,
23
+ expires_at: envelope.expires_at,
24
+ role: envelope.role,
25
+ agent: envelope.agent,
26
+ forwarder: envelope.forwarder,
27
+ metadata,
28
+ };
29
+ }
30
+ export function buildEnvelope(draft) {
31
+ if (!Array.isArray(draft.msgs) || draft.msgs.length === 0) {
32
+ throw new Error("envelope requires at least one message");
33
+ }
34
+ const version = draft.version ?? CURRENT_ENVELOPE_VERSION;
35
+ const metadata = normalizeMetadata(draft.metadata);
36
+ return {
37
+ version,
38
+ user_id: draft.user_id,
39
+ session_id: draft.session_id,
40
+ msgs: draft.msgs.map((msg) => cloneMsg(msg)),
41
+ nonce: draft.nonce,
42
+ expires_at: draft.expires_at,
43
+ role: draft.role,
44
+ agent: draft.agent,
45
+ forwarder: draft.forwarder,
46
+ signatures: draft.signatures ? { ...draft.signatures } : {},
47
+ metadata,
48
+ };
49
+ }
50
+ export function signDocBytes(signDoc) {
51
+ const json = canonicalStringify(signDoc);
52
+ return new TextEncoder().encode(json);
53
+ }
54
+ export function signDocDigest(signDoc) {
55
+ const bytes = signDocBytes(signDoc);
56
+ return sha256(bytes);
57
+ }
58
+ function cloneMsg(msg) {
59
+ return structuredClone(msg);
60
+ }
61
+ function canonicalStringify(value) {
62
+ return JSON.stringify(value, (_key, val) => {
63
+ if (val instanceof Map) {
64
+ return Object.fromEntries(Array.from(val.entries()).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));
65
+ }
66
+ if (val && typeof val === "object" && !Array.isArray(val)) {
67
+ const entries = Object.entries(val).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
68
+ return entries.reduce((acc, [key, entry]) => {
69
+ acc[key] = entry;
70
+ return acc;
71
+ }, {});
72
+ }
73
+ return val;
74
+ });
75
+ }
76
+ export function encodeSignature(signature) {
77
+ const nodeBuffer = globalThis.Buffer;
78
+ if (nodeBuffer) {
79
+ return nodeBuffer.from(signature).toString("base64");
80
+ }
81
+ let result = "";
82
+ for (const byte of signature) {
83
+ result += String.fromCharCode(byte);
84
+ }
85
+ return btoa(result);
86
+ }
87
+ export function decodeSignature(signature) {
88
+ const nodeBuffer = globalThis.Buffer;
89
+ if (nodeBuffer) {
90
+ return nodeBuffer.from(signature, "base64");
91
+ }
92
+ const binary = atob(signature);
93
+ const bytes = new Uint8Array(binary.length);
94
+ for (let i = 0; i < binary.length; i++) {
95
+ bytes[i] = binary.charCodeAt(i);
96
+ }
97
+ return bytes;
98
+ }
@@ -0,0 +1,10 @@
1
+ export * from "./types";
2
+ export { DoneBackendClient } from "./client";
3
+ export type { EnvelopeDraft } from "./envelope";
4
+ export type { TransactionOptions, QueryOptions } from "./client";
5
+ export { Done, DoneContractClient } from "./done";
6
+ export { DoneRequest } from "./done";
7
+ export { createPasskeyEnvelopeBuilder, createSessionEnvelopeBuilder, type PasskeyEnvelopeBuilderOptions, type SessionEnvelopeBuilderOptions, } from "./auth";
8
+ export { CURRENT_ENVELOPE_VERSION, buildEnvelope, decodeSignature, encodeSignature, signDocBytes, signDocDigest, toSignDoc, } from "./envelope";
9
+ export { buildQueryMessage, buildTransactionMessage } from "./messages";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EACL,4BAA4B,EAC5B,4BAA4B,EAC5B,KAAK,6BAA6B,EAClC,KAAK,6BAA6B,GACnC,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,eAAe,EACf,eAAe,EACf,YAAY,EACZ,aAAa,EACb,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from "./types";
2
+ export { DoneBackendClient } from "./client";
3
+ export { Done, DoneContractClient } from "./done";
4
+ export { DoneRequest } from "./done";
5
+ export { createPasskeyEnvelopeBuilder, createSessionEnvelopeBuilder, } from "./auth";
6
+ export { CURRENT_ENVELOPE_VERSION, buildEnvelope, decodeSignature, encodeSignature, signDocBytes, signDocDigest, toSignDoc, } from "./envelope";
7
+ export { buildQueryMessage, buildTransactionMessage } from "./messages";
@@ -0,0 +1,4 @@
1
+ import type { CosmosMsg, DoneContractCall, ExecuteCallOptions } from "./types";
2
+ export declare function buildTransactionMessage(contractAddr: string, call: DoneContractCall, options?: ExecuteCallOptions): CosmosMsg;
3
+ export declare function buildQueryMessage(call: DoneContractCall): Record<string, unknown>;
4
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,SAAS,CAAC;AAEjB,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,gBAAgB,EACtB,OAAO,GAAE,kBAAuB,GAC/B,SAAS,CAcX;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEjF"}
@@ -0,0 +1,46 @@
1
+ export function buildTransactionMessage(contractAddr, call, options = {}) {
2
+ const payload = normalizeCall(call);
3
+ const msg = { msg: payload };
4
+ const funds = normalizeFunds(options.funds);
5
+ return {
6
+ wasm: {
7
+ execute: {
8
+ contract_addr: contractAddr,
9
+ msg,
10
+ funds: funds && funds.length > 0 ? funds : undefined,
11
+ },
12
+ },
13
+ };
14
+ }
15
+ export function buildQueryMessage(call) {
16
+ return { msg: normalizeCall(call) };
17
+ }
18
+ function normalizeCall(call) {
19
+ if (!call.path || !call.path.startsWith("/")) {
20
+ throw new Error("contract call path must start with '/'");
21
+ }
22
+ const payload = { path: call.path };
23
+ if (call.query instanceof URLSearchParams) {
24
+ payload.query = Object.fromEntries(Array.from(call.query));
25
+ }
26
+ else if (call.query) {
27
+ payload.query = call.query;
28
+ }
29
+ if (call.body !== undefined) {
30
+ payload.body = call.body;
31
+ }
32
+ return payload;
33
+ }
34
+ function normalizeFunds(funds) {
35
+ if (!funds)
36
+ return undefined;
37
+ if (Array.isArray(funds)) {
38
+ if (funds.length === 0)
39
+ return undefined;
40
+ return funds.map((coin) => ({ denom: coin.denom, amount: coin.amount }));
41
+ }
42
+ const entries = Object.entries(funds);
43
+ if (entries.length === 0)
44
+ return undefined;
45
+ return entries.map(([denom, amount]) => ({ denom, amount: String(amount) }));
46
+ }