@misonetwork/sdk 0.3.0 → 0.4.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/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +6 -0
- package/dist/client.js.map +1 -1
- package/dist/internal.d.ts +7 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +22 -0
- package/dist/internal.js.map +1 -1
- package/dist/queries.d.ts +37 -0
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +210 -28
- package/dist/queries.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +86 -18
- package/src/internal.ts +24 -0
- package/src/queries.ts +404 -55
package/src/queries.ts
CHANGED
|
@@ -22,13 +22,19 @@
|
|
|
22
22
|
import type { ClientWithCoreApi } from "@mysten/sui/client";
|
|
23
23
|
import type { SuiGraphQLClient } from "@mysten/sui/graphql";
|
|
24
24
|
import { graphql } from "@mysten/sui/graphql/schema";
|
|
25
|
-
import { deriveObjectID } from "@mysten/sui/utils";
|
|
25
|
+
import { deriveObjectID, normalizeSuiAddress } from "@mysten/sui/utils";
|
|
26
26
|
|
|
27
27
|
import { Composition as CompositionBcs } from "./contracts/miso/composition.ts";
|
|
28
28
|
import { Deal as DealBcs } from "./contracts/miso/deal.ts";
|
|
29
29
|
import { Recording as RecordingBcs } from "./contracts/miso/recording.ts";
|
|
30
30
|
import { Release as ReleaseBcs } from "./contracts/miso/release.ts";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
mapBps,
|
|
33
|
+
mapComposition,
|
|
34
|
+
mapDiscReleaseJson,
|
|
35
|
+
mapRecording,
|
|
36
|
+
mapRelease,
|
|
37
|
+
} from "./internal.ts";
|
|
32
38
|
import type {
|
|
33
39
|
Composition,
|
|
34
40
|
CompositionAdminCap,
|
|
@@ -50,7 +56,8 @@ import type {
|
|
|
50
56
|
*/
|
|
51
57
|
export function extractTypeParam(objectType: string): string {
|
|
52
58
|
const match = objectType.match(/<(.+)>$/);
|
|
53
|
-
if (!match?.[1])
|
|
59
|
+
if (!match?.[1])
|
|
60
|
+
throw new Error(`Could not extract type parameter from: ${objectType}`);
|
|
54
61
|
return match[1];
|
|
55
62
|
}
|
|
56
63
|
|
|
@@ -62,7 +69,8 @@ export function extractTypeParams2(objectType: string): [string, string] {
|
|
|
62
69
|
const ch = inner[i];
|
|
63
70
|
if (ch === "<") depth++;
|
|
64
71
|
else if (ch === ">") depth--;
|
|
65
|
-
else if (ch === "," && depth === 0)
|
|
72
|
+
else if (ch === "," && depth === 0)
|
|
73
|
+
return [inner.slice(0, i).trim(), inner.slice(i + 1).trim()];
|
|
66
74
|
}
|
|
67
75
|
throw new Error(`Expected two type parameters in: ${objectType}`);
|
|
68
76
|
}
|
|
@@ -90,13 +98,20 @@ export function extractTypeParams2(objectType: string): [string, string] {
|
|
|
90
98
|
export function isNotFound(e: unknown): boolean {
|
|
91
99
|
if (typeof e === "object" && e !== null && "code" in e) {
|
|
92
100
|
const code = (e as { code: unknown }).code;
|
|
93
|
-
if (
|
|
101
|
+
if (
|
|
102
|
+
code === "notExists" ||
|
|
103
|
+
code === "deleted" ||
|
|
104
|
+
code === "dynamicFieldNotFound" ||
|
|
105
|
+
code === "notFound"
|
|
106
|
+
) {
|
|
94
107
|
return true;
|
|
95
108
|
}
|
|
96
109
|
}
|
|
97
110
|
const msg = e instanceof Error ? e.message : String(e);
|
|
98
111
|
return (
|
|
99
|
-
/\bobject\b[\s\S]*\b(?:not\s?found|does not exist|has been deleted)\b/i.test(
|
|
112
|
+
/\bobject\b[\s\S]*\b(?:not\s?found|does not exist|has been deleted)\b/i.test(
|
|
113
|
+
msg,
|
|
114
|
+
) ||
|
|
100
115
|
/\bdynamic field\b[\s\S]*\bnot\s?found\b/i.test(msg) ||
|
|
101
116
|
/\bno object\b/i.test(msg)
|
|
102
117
|
);
|
|
@@ -106,8 +121,14 @@ export function isNotFound(e: unknown): boolean {
|
|
|
106
121
|
const UNIT_STRUCT_KEY_BYTES = new Uint8Array([0x00]);
|
|
107
122
|
|
|
108
123
|
/** Fetches one object's BCS content bytes (or null if absent). */
|
|
109
|
-
async function getContent(
|
|
110
|
-
|
|
124
|
+
async function getContent(
|
|
125
|
+
client: ClientWithCoreApi,
|
|
126
|
+
objectId: string,
|
|
127
|
+
): Promise<Uint8Array | null> {
|
|
128
|
+
const { object } = await client.core.getObject({
|
|
129
|
+
objectId,
|
|
130
|
+
include: { content: true },
|
|
131
|
+
});
|
|
111
132
|
return object.content ?? null;
|
|
112
133
|
}
|
|
113
134
|
|
|
@@ -119,7 +140,9 @@ async function getContent(client: ClientWithCoreApi, objectId: string): Promise<
|
|
|
119
140
|
const AddressesByTypeQuery = graphql(`
|
|
120
141
|
query AddressesByType($type: String!) {
|
|
121
142
|
objects(filter: { type: $type }) {
|
|
122
|
-
nodes {
|
|
143
|
+
nodes {
|
|
144
|
+
address
|
|
145
|
+
}
|
|
123
146
|
}
|
|
124
147
|
}
|
|
125
148
|
`);
|
|
@@ -136,11 +159,217 @@ const AddressesByTypeQuery = graphql(`
|
|
|
136
159
|
const AddressesAndTypesByTypeQuery = graphql(`
|
|
137
160
|
query AddressesAndTypesByType($type: String!) {
|
|
138
161
|
objects(filter: { type: $type }) {
|
|
139
|
-
nodes {
|
|
162
|
+
nodes {
|
|
163
|
+
address
|
|
164
|
+
asMoveObject {
|
|
165
|
+
contents {
|
|
166
|
+
type {
|
|
167
|
+
repr
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
140
172
|
}
|
|
141
173
|
}
|
|
142
174
|
`);
|
|
143
175
|
|
|
176
|
+
export interface WorkShareTypes {
|
|
177
|
+
compositions: readonly string[];
|
|
178
|
+
recordings: readonly string[];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface WorkAddressesByShareType {
|
|
182
|
+
compositions: Partial<Record<string, string>>;
|
|
183
|
+
recordings: Partial<Record<string, string>>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
interface WorkAddressConnection {
|
|
187
|
+
nodes: Array<{
|
|
188
|
+
address: string;
|
|
189
|
+
asMoveObject?: {
|
|
190
|
+
contents?: { type?: { repr?: string } | null } | null;
|
|
191
|
+
} | null;
|
|
192
|
+
}>;
|
|
193
|
+
pageInfo?: { hasNextPage: boolean; endCursor: string | null };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Resolve many work share types in one GraphQL request.
|
|
198
|
+
*
|
|
199
|
+
* Compositions can be queried by their exact one-parameter type. Recordings
|
|
200
|
+
* carry both RecordingShare and CompositionShare, while an admin cap only
|
|
201
|
+
* exposes the first, so one bare Recording scan is shared by every requested
|
|
202
|
+
* recording type and filtered client-side.
|
|
203
|
+
*/
|
|
204
|
+
export async function getWorkAddressesByShareTypes(
|
|
205
|
+
client: SuiGraphQLClient,
|
|
206
|
+
shareTypes: WorkShareTypes,
|
|
207
|
+
misoPackageId: string,
|
|
208
|
+
): Promise<WorkAddressesByShareType> {
|
|
209
|
+
const compositions = [...new Set(shareTypes.compositions)];
|
|
210
|
+
const recordings = new Set(shareTypes.recordings);
|
|
211
|
+
const out: WorkAddressesByShareType = { compositions: {}, recordings: {} };
|
|
212
|
+
if (compositions.length === 0 && recordings.size === 0) return out;
|
|
213
|
+
|
|
214
|
+
const declarations: string[] = [];
|
|
215
|
+
const selections: string[] = [];
|
|
216
|
+
const variables: Record<string, string> = {};
|
|
217
|
+
|
|
218
|
+
compositions.forEach((shareType, index) => {
|
|
219
|
+
const variable = `compositionType${index}`;
|
|
220
|
+
declarations.push(`$${variable}: String!`);
|
|
221
|
+
selections.push(
|
|
222
|
+
`composition${index}: objects(first: 1, filter: { type: $${variable} }) { nodes { address } }`,
|
|
223
|
+
);
|
|
224
|
+
variables[variable] =
|
|
225
|
+
`${misoPackageId}::composition::Composition<${shareType}>`;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
if (recordings.size > 0) {
|
|
229
|
+
declarations.push("$recordingType: String!");
|
|
230
|
+
selections.push(`recordings: objects(first: 50, filter: { type: $recordingType }) {
|
|
231
|
+
pageInfo { hasNextPage endCursor }
|
|
232
|
+
nodes { address asMoveObject { contents { type { repr } } } }
|
|
233
|
+
}`);
|
|
234
|
+
variables.recordingType = `${misoPackageId}::recording::Recording`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const result = await client.query<
|
|
238
|
+
Record<string, WorkAddressConnection | null>,
|
|
239
|
+
Record<string, string>
|
|
240
|
+
>({
|
|
241
|
+
query: `query WorkAddressesByShareTypes(${declarations.join(", ")}) {
|
|
242
|
+
${selections.join("\n")}
|
|
243
|
+
}`,
|
|
244
|
+
variables,
|
|
245
|
+
});
|
|
246
|
+
if (result.errors?.length) {
|
|
247
|
+
throw new AggregateError(
|
|
248
|
+
result.errors.map((error) => new Error(error.message)),
|
|
249
|
+
"Work type discovery failed",
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
compositions.forEach((shareType, index) => {
|
|
254
|
+
const address = result.data?.[`composition${index}`]?.nodes[0]?.address;
|
|
255
|
+
if (address) out.compositions[shareType] = address;
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const readRecordingPage = (
|
|
259
|
+
page: WorkAddressConnection | null | undefined,
|
|
260
|
+
) => {
|
|
261
|
+
for (const node of page?.nodes ?? []) {
|
|
262
|
+
const repr = node.asMoveObject?.contents?.type?.repr;
|
|
263
|
+
if (!repr) continue;
|
|
264
|
+
try {
|
|
265
|
+
const [recordingShareType] = extractTypeParams2(repr);
|
|
266
|
+
if (recordings.has(recordingShareType)) {
|
|
267
|
+
out.recordings[recordingShareType] = node.address;
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
// Ignore a live object whose type does not match the deployed Recording ABI.
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
let recordingPage = result.data?.recordings;
|
|
276
|
+
readRecordingPage(recordingPage);
|
|
277
|
+
while (
|
|
278
|
+
recordingPage?.pageInfo?.hasNextPage &&
|
|
279
|
+
recordingPage.pageInfo.endCursor &&
|
|
280
|
+
Object.keys(out.recordings).length < recordings.size
|
|
281
|
+
) {
|
|
282
|
+
const next = await client.query<
|
|
283
|
+
{ recordings: WorkAddressConnection | null },
|
|
284
|
+
{ recordingType: string; cursor: string }
|
|
285
|
+
>({
|
|
286
|
+
query: `query RecordingWorkAddresses($recordingType: String!, $cursor: String!) {
|
|
287
|
+
recordings: objects(first: 50, after: $cursor, filter: { type: $recordingType }) {
|
|
288
|
+
pageInfo { hasNextPage endCursor }
|
|
289
|
+
nodes { address asMoveObject { contents { type { repr } } } }
|
|
290
|
+
}
|
|
291
|
+
}`,
|
|
292
|
+
variables: {
|
|
293
|
+
recordingType: variables.recordingType!,
|
|
294
|
+
cursor: recordingPage.pageInfo.endCursor,
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
if (next.errors?.length) {
|
|
298
|
+
throw new AggregateError(
|
|
299
|
+
next.errors.map((error) => new Error(error.message)),
|
|
300
|
+
"Recording type discovery failed",
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
recordingPage = next.data?.recordings;
|
|
304
|
+
readRecordingPage(recordingPage);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return out;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface WorkIds {
|
|
311
|
+
compositions: readonly string[];
|
|
312
|
+
recordings: readonly string[];
|
|
313
|
+
releases: readonly string[];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export interface WorksById {
|
|
317
|
+
compositions: Partial<Record<string, Composition>>;
|
|
318
|
+
recordings: Partial<Record<string, Recording>>;
|
|
319
|
+
releases: Partial<Record<string, Release>>;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Fetch and parse heterogeneous work objects through one Core bulk request. */
|
|
323
|
+
export async function getWorksByIds(
|
|
324
|
+
client: ClientWithCoreApi,
|
|
325
|
+
ids: WorkIds,
|
|
326
|
+
): Promise<WorksById> {
|
|
327
|
+
const kinds = new Map<string, keyof WorksById>();
|
|
328
|
+
for (const [kind, objectIds] of Object.entries(ids) as Array<
|
|
329
|
+
[keyof WorksById, readonly string[]]
|
|
330
|
+
>) {
|
|
331
|
+
for (const objectId of objectIds) {
|
|
332
|
+
const normalized = normalizeSuiAddress(objectId);
|
|
333
|
+
const previous = kinds.get(normalized);
|
|
334
|
+
if (previous && previous !== kind) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
`Work ${normalized} was requested as both ${previous} and ${kind}`,
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
kinds.set(normalized, kind);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const out: WorksById = { compositions: {}, recordings: {}, releases: {} };
|
|
344
|
+
if (kinds.size === 0) return out;
|
|
345
|
+
|
|
346
|
+
const { objects } = await client.core.getObjects({
|
|
347
|
+
objectIds: [...kinds.keys()],
|
|
348
|
+
include: { content: true, json: true },
|
|
349
|
+
});
|
|
350
|
+
for (const obj of objects) {
|
|
351
|
+
if (obj instanceof Error || !obj.content) continue;
|
|
352
|
+
const kind = kinds.get(normalizeSuiAddress(obj.objectId));
|
|
353
|
+
if (kind === "compositions") {
|
|
354
|
+
out.compositions[obj.objectId] = mapComposition(
|
|
355
|
+
obj.objectId,
|
|
356
|
+
CompositionBcs.parse(obj.content),
|
|
357
|
+
);
|
|
358
|
+
} else if (kind === "recordings") {
|
|
359
|
+
out.recordings[obj.objectId] = mapRecording(
|
|
360
|
+
obj.objectId,
|
|
361
|
+
RecordingBcs.parse(obj.content),
|
|
362
|
+
);
|
|
363
|
+
} else if (kind === "releases") {
|
|
364
|
+
const json = obj.json as { discs?: unknown[] } | null;
|
|
365
|
+
out.releases[obj.objectId] = json?.discs
|
|
366
|
+
? mapDiscReleaseJson(obj.objectId, json)
|
|
367
|
+
: mapRelease(obj.objectId, ReleaseBcs.parse(obj.content));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return out;
|
|
371
|
+
}
|
|
372
|
+
|
|
144
373
|
// ============================================================================
|
|
145
374
|
// Composition
|
|
146
375
|
// ============================================================================
|
|
@@ -151,24 +380,36 @@ export async function getCompositionsByIds(
|
|
|
151
380
|
compositionIds: string[],
|
|
152
381
|
): Promise<Record<string, Composition>> {
|
|
153
382
|
if (compositionIds.length === 0) return {};
|
|
154
|
-
const { objects } = await client.core.getObjects({
|
|
383
|
+
const { objects } = await client.core.getObjects({
|
|
384
|
+
objectIds: compositionIds,
|
|
385
|
+
include: { content: true },
|
|
386
|
+
});
|
|
155
387
|
const out: Record<string, Composition> = {};
|
|
156
388
|
for (const obj of objects) {
|
|
157
389
|
if (obj instanceof Error || !obj.content) continue;
|
|
158
|
-
out[obj.objectId] = mapComposition(
|
|
390
|
+
out[obj.objectId] = mapComposition(
|
|
391
|
+
obj.objectId,
|
|
392
|
+
CompositionBcs.parse(obj.content),
|
|
393
|
+
);
|
|
159
394
|
}
|
|
160
395
|
return out;
|
|
161
396
|
}
|
|
162
397
|
|
|
163
398
|
/** Fetches a composition by its object ID. */
|
|
164
|
-
export async function getCompositionById(
|
|
399
|
+
export async function getCompositionById(
|
|
400
|
+
client: ClientWithCoreApi,
|
|
401
|
+
compositionId: string,
|
|
402
|
+
): Promise<Composition> {
|
|
165
403
|
const content = await getContent(client, compositionId);
|
|
166
404
|
if (!content) throw new Error(`Composition not found: ${compositionId}`);
|
|
167
405
|
return mapComposition(compositionId, CompositionBcs.parse(content));
|
|
168
406
|
}
|
|
169
407
|
|
|
170
408
|
/** Extracts the share type `T` from a `Composition<T>` object. */
|
|
171
|
-
export async function getCompositionShareType(
|
|
409
|
+
export async function getCompositionShareType(
|
|
410
|
+
client: ClientWithCoreApi,
|
|
411
|
+
compositionId: string,
|
|
412
|
+
): Promise<string> {
|
|
172
413
|
const { object } = await client.core.getObject({ objectId: compositionId });
|
|
173
414
|
return extractTypeParam(object.type);
|
|
174
415
|
}
|
|
@@ -180,12 +421,32 @@ export async function getCompositionByShareType(
|
|
|
180
421
|
shareType: string,
|
|
181
422
|
misoPackageId: string,
|
|
182
423
|
): Promise<Composition> {
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
424
|
+
const address = await getCompositionAddressByShareType(
|
|
425
|
+
graphqlClient,
|
|
426
|
+
shareType,
|
|
427
|
+
misoPackageId,
|
|
428
|
+
);
|
|
429
|
+
if (!address)
|
|
430
|
+
throw new Error(`Composition not found for share type: ${shareType}`);
|
|
186
431
|
return getCompositionById(client, address);
|
|
187
432
|
}
|
|
188
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Resolves a composition share type to its object address.
|
|
436
|
+
*
|
|
437
|
+
* This is the lightweight discovery primitive for callers that need the
|
|
438
|
+
* composition's identity but will read extension fields rather than the core
|
|
439
|
+
* Composition contents.
|
|
440
|
+
*/
|
|
441
|
+
export async function getCompositionAddressByShareType(
|
|
442
|
+
graphqlClient: SuiGraphQLClient,
|
|
443
|
+
shareType: string,
|
|
444
|
+
misoPackageId: string,
|
|
445
|
+
): Promise<string | null> {
|
|
446
|
+
const type = `${misoPackageId}::composition::Composition<${shareType}>`;
|
|
447
|
+
return firstAddressOfType(graphqlClient, type);
|
|
448
|
+
}
|
|
449
|
+
|
|
189
450
|
export async function getCompositionAdminCapById(
|
|
190
451
|
client: ClientWithCoreApi,
|
|
191
452
|
adminCapId: string,
|
|
@@ -207,7 +468,10 @@ export async function getOwnedCompositionAdminCaps(
|
|
|
207
468
|
misoPackageId: string,
|
|
208
469
|
): Promise<CompositionAdminCap[]> {
|
|
209
470
|
const capType = `${misoPackageId}::composition::CompositionAdminCap`;
|
|
210
|
-
const { objects } = await client.core.listOwnedObjects({
|
|
471
|
+
const { objects } = await client.core.listOwnedObjects({
|
|
472
|
+
owner,
|
|
473
|
+
type: capType,
|
|
474
|
+
});
|
|
211
475
|
const caps: CompositionAdminCap[] = [];
|
|
212
476
|
for (const obj of objects) {
|
|
213
477
|
const match = obj.type?.match(/<(.+)>$/);
|
|
@@ -216,8 +480,15 @@ export async function getOwnedCompositionAdminCaps(
|
|
|
216
480
|
return caps;
|
|
217
481
|
}
|
|
218
482
|
|
|
219
|
-
export function deriveCompositionAdminCapId(
|
|
220
|
-
|
|
483
|
+
export function deriveCompositionAdminCapId(
|
|
484
|
+
compositionId: string,
|
|
485
|
+
misoPackageId: string,
|
|
486
|
+
): string {
|
|
487
|
+
return deriveObjectID(
|
|
488
|
+
compositionId,
|
|
489
|
+
`${misoPackageId}::composition::CompositionAdminCapKey`,
|
|
490
|
+
UNIT_STRUCT_KEY_BYTES,
|
|
491
|
+
);
|
|
221
492
|
}
|
|
222
493
|
|
|
223
494
|
// ============================================================================
|
|
@@ -229,16 +500,25 @@ export async function getRecordingsByIds(
|
|
|
229
500
|
recordingIds: string[],
|
|
230
501
|
): Promise<Record<string, Recording>> {
|
|
231
502
|
if (recordingIds.length === 0) return {};
|
|
232
|
-
const { objects } = await client.core.getObjects({
|
|
503
|
+
const { objects } = await client.core.getObjects({
|
|
504
|
+
objectIds: recordingIds,
|
|
505
|
+
include: { content: true },
|
|
506
|
+
});
|
|
233
507
|
const out: Record<string, Recording> = {};
|
|
234
508
|
for (const obj of objects) {
|
|
235
509
|
if (obj instanceof Error || !obj.content) continue;
|
|
236
|
-
out[obj.objectId] = mapRecording(
|
|
510
|
+
out[obj.objectId] = mapRecording(
|
|
511
|
+
obj.objectId,
|
|
512
|
+
RecordingBcs.parse(obj.content),
|
|
513
|
+
);
|
|
237
514
|
}
|
|
238
515
|
return out;
|
|
239
516
|
}
|
|
240
517
|
|
|
241
|
-
export async function getRecordingById(
|
|
518
|
+
export async function getRecordingById(
|
|
519
|
+
client: ClientWithCoreApi,
|
|
520
|
+
recordingId: string,
|
|
521
|
+
): Promise<Recording> {
|
|
242
522
|
const content = await getContent(client, recordingId);
|
|
243
523
|
if (!content) throw new Error(`Recording not found: ${recordingId}`);
|
|
244
524
|
return mapRecording(recordingId, RecordingBcs.parse(content));
|
|
@@ -250,8 +530,14 @@ export async function getRecordingById(client: ClientWithCoreApi, recordingId: s
|
|
|
250
530
|
* them and returns the first; use {@link getRecordingShareTypes} when the
|
|
251
531
|
* parent composition's share type is needed too.
|
|
252
532
|
*/
|
|
253
|
-
export async function getRecordingShareType(
|
|
254
|
-
|
|
533
|
+
export async function getRecordingShareType(
|
|
534
|
+
client: ClientWithCoreApi,
|
|
535
|
+
recordingId: string,
|
|
536
|
+
): Promise<string> {
|
|
537
|
+
const [recordingShareType] = await getRecordingShareTypes(
|
|
538
|
+
client,
|
|
539
|
+
recordingId,
|
|
540
|
+
);
|
|
255
541
|
return recordingShareType;
|
|
256
542
|
}
|
|
257
543
|
|
|
@@ -275,8 +561,13 @@ export async function getRecordingByShareType(
|
|
|
275
561
|
shareType: string,
|
|
276
562
|
misoPackageId: string,
|
|
277
563
|
): Promise<Recording> {
|
|
278
|
-
const address = await addressOfRecordingWithShareType(
|
|
279
|
-
|
|
564
|
+
const address = await addressOfRecordingWithShareType(
|
|
565
|
+
graphqlClient,
|
|
566
|
+
misoPackageId,
|
|
567
|
+
shareType,
|
|
568
|
+
);
|
|
569
|
+
if (!address)
|
|
570
|
+
throw new Error(`Recording not found for share type: ${shareType}`);
|
|
280
571
|
return getRecordingById(client, address);
|
|
281
572
|
}
|
|
282
573
|
|
|
@@ -302,7 +593,10 @@ export async function getOwnedRecordingAdminCaps(
|
|
|
302
593
|
misoPackageId: string,
|
|
303
594
|
): Promise<RecordingAdminCap[]> {
|
|
304
595
|
const capType = `${misoPackageId}::recording::RecordingAdminCap`;
|
|
305
|
-
const { objects } = await client.core.listOwnedObjects({
|
|
596
|
+
const { objects } = await client.core.listOwnedObjects({
|
|
597
|
+
owner,
|
|
598
|
+
type: capType,
|
|
599
|
+
});
|
|
306
600
|
const caps: RecordingAdminCap[] = [];
|
|
307
601
|
for (const obj of objects) {
|
|
308
602
|
const match = obj.type?.match(/<(.+)>$/);
|
|
@@ -311,8 +605,15 @@ export async function getOwnedRecordingAdminCaps(
|
|
|
311
605
|
return caps;
|
|
312
606
|
}
|
|
313
607
|
|
|
314
|
-
export function deriveRecordingAdminCapId(
|
|
315
|
-
|
|
608
|
+
export function deriveRecordingAdminCapId(
|
|
609
|
+
recordingId: string,
|
|
610
|
+
misoPackageId: string,
|
|
611
|
+
): string {
|
|
612
|
+
return deriveObjectID(
|
|
613
|
+
recordingId,
|
|
614
|
+
`${misoPackageId}::recording::RecordingAdminCapKey`,
|
|
615
|
+
UNIT_STRUCT_KEY_BYTES,
|
|
616
|
+
);
|
|
316
617
|
}
|
|
317
618
|
|
|
318
619
|
// ============================================================================
|
|
@@ -320,11 +621,19 @@ export function deriveRecordingAdminCapId(recordingId: string, misoPackageId: st
|
|
|
320
621
|
// ============================================================================
|
|
321
622
|
|
|
322
623
|
/** Fetches a deal by its object ID (share types read from the type parameters). */
|
|
323
|
-
export async function getDealById(
|
|
324
|
-
|
|
624
|
+
export async function getDealById(
|
|
625
|
+
client: ClientWithCoreApi,
|
|
626
|
+
dealId: string,
|
|
627
|
+
): Promise<Deal> {
|
|
628
|
+
const { object } = await client.core.getObject({
|
|
629
|
+
objectId: dealId,
|
|
630
|
+
include: { content: true },
|
|
631
|
+
});
|
|
325
632
|
if (!object.content) throw new Error(`Deal not found: ${dealId}`);
|
|
326
633
|
const d = DealBcs.parse(object.content);
|
|
327
|
-
const [recordingShareType, compositionShareType] = extractTypeParams2(
|
|
634
|
+
const [recordingShareType, compositionShareType] = extractTypeParams2(
|
|
635
|
+
object.type,
|
|
636
|
+
);
|
|
328
637
|
return {
|
|
329
638
|
id: dealId,
|
|
330
639
|
releaseId: d.release_id,
|
|
@@ -343,23 +652,44 @@ export async function getReleasesByIds(
|
|
|
343
652
|
releaseIds: string[],
|
|
344
653
|
): Promise<Record<string, Release>> {
|
|
345
654
|
if (releaseIds.length === 0) return {};
|
|
346
|
-
const { objects } = await client.core.getObjects({
|
|
655
|
+
const { objects } = await client.core.getObjects({
|
|
656
|
+
objectIds: releaseIds,
|
|
657
|
+
include: { content: true, json: true },
|
|
658
|
+
});
|
|
347
659
|
const out: Record<string, Release> = {};
|
|
348
660
|
for (const obj of objects) {
|
|
349
661
|
if (obj instanceof Error || !obj.content) continue;
|
|
350
|
-
|
|
662
|
+
const json = obj.json as { discs?: unknown[] } | null;
|
|
663
|
+
out[obj.objectId] = json?.discs
|
|
664
|
+
? mapDiscReleaseJson(obj.objectId, json)
|
|
665
|
+
: mapRelease(obj.objectId, ReleaseBcs.parse(obj.content));
|
|
351
666
|
}
|
|
352
667
|
return out;
|
|
353
668
|
}
|
|
354
669
|
|
|
355
|
-
export async function getReleaseById(
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
670
|
+
export async function getReleaseById(
|
|
671
|
+
client: ClientWithCoreApi,
|
|
672
|
+
releaseId: string,
|
|
673
|
+
): Promise<Release> {
|
|
674
|
+
const { object } = await client.core.getObject({
|
|
675
|
+
objectId: releaseId,
|
|
676
|
+
include: { content: true, json: true },
|
|
677
|
+
});
|
|
678
|
+
if (!object.content) throw new Error(`Release not found: ${releaseId}`);
|
|
679
|
+
const json = object.json as { discs?: unknown[] } | null;
|
|
680
|
+
return json?.discs
|
|
681
|
+
? mapDiscReleaseJson(releaseId, json)
|
|
682
|
+
: mapRelease(releaseId, ReleaseBcs.parse(object.content));
|
|
359
683
|
}
|
|
360
684
|
|
|
361
|
-
export async function getReleaseRegistry(
|
|
362
|
-
|
|
685
|
+
export async function getReleaseRegistry(
|
|
686
|
+
client: SuiGraphQLClient,
|
|
687
|
+
misoPackageId: string,
|
|
688
|
+
): Promise<string> {
|
|
689
|
+
const address = await firstAddressOfType(
|
|
690
|
+
client,
|
|
691
|
+
`${misoPackageId}::release::ReleaseRegistry`,
|
|
692
|
+
);
|
|
363
693
|
if (!address) throw new Error("ReleaseRegistry not found");
|
|
364
694
|
return address;
|
|
365
695
|
}
|
|
@@ -368,9 +698,13 @@ export async function getReleaseAdminCapById(
|
|
|
368
698
|
client: ClientWithCoreApi,
|
|
369
699
|
adminCapId: string,
|
|
370
700
|
): Promise<ReleaseAdminCap> {
|
|
371
|
-
const { object } = await client.core.getObject({
|
|
701
|
+
const { object } = await client.core.getObject({
|
|
702
|
+
objectId: adminCapId,
|
|
703
|
+
include: { json: true },
|
|
704
|
+
});
|
|
372
705
|
const json = object.json as { release_id: string } | null;
|
|
373
|
-
if (!json?.release_id)
|
|
706
|
+
if (!json?.release_id)
|
|
707
|
+
throw new Error(`ReleaseAdminCap not found: ${adminCapId}`);
|
|
374
708
|
return { id: adminCapId, releaseId: json.release_id };
|
|
375
709
|
}
|
|
376
710
|
|
|
@@ -380,23 +714,29 @@ export async function getOwnedReleaseAdminCaps(
|
|
|
380
714
|
misoPackageId: string,
|
|
381
715
|
): Promise<ReleaseAdminCap[]> {
|
|
382
716
|
const capType = `${misoPackageId}::release::ReleaseAdminCap`;
|
|
383
|
-
const { objects } = await client.core.listOwnedObjects({
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
objectIds: objects.map((o) => o.objectId),
|
|
717
|
+
const { objects } = await client.core.listOwnedObjects({
|
|
718
|
+
owner,
|
|
719
|
+
type: capType,
|
|
387
720
|
include: { json: true },
|
|
388
721
|
});
|
|
389
722
|
const caps: ReleaseAdminCap[] = [];
|
|
390
|
-
for (const obj of
|
|
391
|
-
if (obj instanceof Error) continue;
|
|
723
|
+
for (const obj of objects) {
|
|
392
724
|
const json = obj.json as { release_id: string } | null;
|
|
393
|
-
if (json?.release_id)
|
|
725
|
+
if (json?.release_id)
|
|
726
|
+
caps.push({ id: obj.objectId, releaseId: json.release_id });
|
|
394
727
|
}
|
|
395
728
|
return caps;
|
|
396
729
|
}
|
|
397
730
|
|
|
398
|
-
export function deriveReleaseAdminCapId(
|
|
399
|
-
|
|
731
|
+
export function deriveReleaseAdminCapId(
|
|
732
|
+
releaseId: string,
|
|
733
|
+
misoPackageId: string,
|
|
734
|
+
): string {
|
|
735
|
+
return deriveObjectID(
|
|
736
|
+
releaseId,
|
|
737
|
+
`${misoPackageId}::release::ReleaseAdminCapKey`,
|
|
738
|
+
UNIT_STRUCT_KEY_BYTES,
|
|
739
|
+
);
|
|
400
740
|
}
|
|
401
741
|
|
|
402
742
|
// ============================================================================
|
|
@@ -404,7 +744,10 @@ export function deriveReleaseAdminCapId(releaseId: string, misoPackageId: string
|
|
|
404
744
|
// ============================================================================
|
|
405
745
|
|
|
406
746
|
/** Extracts the share type `T` from a `Currency<T>` object. */
|
|
407
|
-
export async function getShareCurrencyType(
|
|
747
|
+
export async function getShareCurrencyType(
|
|
748
|
+
client: ClientWithCoreApi,
|
|
749
|
+
shareCurrencyId: string,
|
|
750
|
+
): Promise<string> {
|
|
408
751
|
const { object } = await client.core.getObject({ objectId: shareCurrencyId });
|
|
409
752
|
return extractTypeParam(object.type);
|
|
410
753
|
}
|
|
@@ -444,8 +787,14 @@ export async function getShareCurrencyTreasuryCap(
|
|
|
444
787
|
// ============================================================================
|
|
445
788
|
|
|
446
789
|
/** Returns the first object address of a fully-qualified type, or null. */
|
|
447
|
-
async function firstAddressOfType(
|
|
448
|
-
|
|
790
|
+
async function firstAddressOfType(
|
|
791
|
+
client: SuiGraphQLClient,
|
|
792
|
+
type: string,
|
|
793
|
+
): Promise<string | null> {
|
|
794
|
+
const result = await client.query({
|
|
795
|
+
query: AddressesByTypeQuery,
|
|
796
|
+
variables: { type },
|
|
797
|
+
});
|
|
449
798
|
return result.data?.objects?.nodes?.[0]?.address ?? null;
|
|
450
799
|
}
|
|
451
800
|
|