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