@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.
Files changed (60) hide show
  1. package/README.md +97 -503
  2. package/dist/client.d.ts +6 -55
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +7 -52
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts/miso/release.d.ts +34 -31
  7. package/dist/contracts/miso/release.d.ts.map +1 -1
  8. package/dist/contracts/miso/release.js +32 -29
  9. package/dist/contracts/miso/release.js.map +1 -1
  10. package/dist/contracts/miso/track.d.ts +66 -22
  11. package/dist/contracts/miso/track.d.ts.map +1 -1
  12. package/dist/contracts/miso/track.js +65 -20
  13. package/dist/contracts/miso/track.js.map +1 -1
  14. package/dist/contracts/utils/index.d.ts +44 -0
  15. package/dist/contracts/utils/index.d.ts.map +1 -1
  16. package/dist/contracts/utils/index.js +104 -2
  17. package/dist/contracts/utils/index.js.map +1 -1
  18. package/dist/contracts.d.ts +0 -1
  19. package/dist/contracts.d.ts.map +1 -1
  20. package/dist/contracts.js +0 -1
  21. package/dist/contracts.js.map +1 -1
  22. package/dist/internal.d.ts +0 -7
  23. package/dist/internal.d.ts.map +1 -1
  24. package/dist/internal.js +0 -22
  25. package/dist/internal.js.map +1 -1
  26. package/dist/parsers.d.ts +1 -4
  27. package/dist/parsers.d.ts.map +1 -1
  28. package/dist/parsers.js +0 -24
  29. package/dist/parsers.js.map +1 -1
  30. package/dist/queries.d.ts +31 -5
  31. package/dist/queries.d.ts.map +1 -1
  32. package/dist/queries.js +179 -56
  33. package/dist/queries.js.map +1 -1
  34. package/dist/transactions.d.ts +10 -71
  35. package/dist/transactions.d.ts.map +1 -1
  36. package/dist/transactions.js +15 -72
  37. package/dist/transactions.js.map +1 -1
  38. package/dist/types.d.ts +3 -40
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/view.d.ts +7 -7
  41. package/dist/view.d.ts.map +1 -1
  42. package/dist/view.js +9 -9
  43. package/dist/view.js.map +1 -1
  44. package/package.json +4 -4
  45. package/src/client.ts +82 -89
  46. package/src/contracts/miso/release.ts +39 -36
  47. package/src/contracts/miso/track.ts +81 -23
  48. package/src/contracts/utils/index.ts +156 -4
  49. package/src/contracts.ts +0 -1
  50. package/src/internal.ts +0 -24
  51. package/src/parsers.ts +0 -35
  52. package/src/queries.ts +357 -83
  53. package/src/transactions.ts +20 -112
  54. package/src/types.ts +3 -53
  55. package/src/view.ts +13 -13
  56. package/dist/contracts/miso/deal.d.ts +0 -184
  57. package/dist/contracts/miso/deal.d.ts.map +0 -1
  58. package/dist/contracts/miso/deal.js +0 -184
  59. package/dist/contracts/miso/deal.js.map +0 -1
  60. 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`, `getDealById`,
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 { mapBps, mapComposition, mapDiscReleaseJson, mapRecording, mapRelease } from "./internal.ts";
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]) throw new Error(`Could not extract type parameter from: ${objectType}`);
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) return [inner.slice(0, i).trim(), inner.slice(i + 1).trim()];
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 (code === "notExists" || code === "deleted" || code === "dynamicFieldNotFound" || code === "notFound") {
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(msg) ||
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(client: ClientWithCoreApi, objectId: string): Promise<Uint8Array | null> {
110
- const { object } = await client.core.getObject({ objectId, include: { content: true } });
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 { address }
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 { address asMoveObject { contents { type { repr } } } }
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({ objectIds: compositionIds, include: { content: true } });
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(obj.objectId, CompositionBcs.parse(obj.content));
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(client: ClientWithCoreApi, compositionId: string): Promise<Composition> {
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(client: ClientWithCoreApi, compositionId: string): Promise<string> {
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(graphqlClient, shareType, misoPackageId);
184
- if (!address) throw new Error(`Composition not found for share type: ${shareType}`);
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({ owner, type: capType });
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(compositionId: string, misoPackageId: string): string {
235
- return deriveObjectID(compositionId, `${misoPackageId}::composition::CompositionAdminCapKey`, UNIT_STRUCT_KEY_BYTES);
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({ objectIds: recordingIds, include: { content: true } });
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(obj.objectId, RecordingBcs.parse(obj.content));
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(client: ClientWithCoreApi, recordingId: string): Promise<Recording> {
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(client: ClientWithCoreApi, recordingId: string): Promise<string> {
269
- const [recordingShareType] = await getRecordingShareTypes(client, recordingId);
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 — `deal::new`, `track::new`, `recording::publish`
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(graphqlClient, misoPackageId, shareType);
294
- if (!address) throw new Error(`Recording not found for share type: ${shareType}`);
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({ owner, type: capType });
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(recordingId: string, misoPackageId: string): string {
330
- return deriveObjectID(recordingId, `${misoPackageId}::recording::RecordingAdminCapKey`, UNIT_STRUCT_KEY_BYTES);
331
- }
332
-
333
- // ============================================================================
334
- // Deal
335
- // ============================================================================
336
-
337
- /** Fetches a deal by its object ID (share types read from the type parameters). */
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, json: 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
- const json = obj.json as { discs?: unknown[] } | null;
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(client: ClientWithCoreApi, releaseId: string): Promise<Release> {
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, json: true },
643
+ include: { content: true },
380
644
  });
381
645
  if (!object.content) throw new Error(`Release not found: ${releaseId}`);
382
- const json = object.json as { discs?: unknown[] } | null;
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({ objectId: adminCapId, include: { json: true } });
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) throw new Error(`ReleaseAdminCap not found: ${adminCapId}`);
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({ owner, type: capType });
411
- if (objects.length === 0) return [];
412
- const { objects: details } = await client.core.getObjects({
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 details) {
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) caps.push({ id: obj.objectId, releaseId: 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(releaseId: string, misoPackageId: string): string {
426
- return deriveObjectID(releaseId, `${misoPackageId}::release::ReleaseAdminCapKey`, UNIT_STRUCT_KEY_BYTES);
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(client: ClientWithCoreApi, shareCurrencyId: string): Promise<string> {
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(client: SuiGraphQLClient, type: string): Promise<string | null> {
475
- const result = await client.query({ query: AddressesByTypeQuery, variables: { type } });
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