@misofm/sdk 0.4.0 → 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 (48) hide show
  1. package/dist/catalog.d.ts +4 -17
  2. package/dist/catalog.d.ts.map +1 -1
  3. package/dist/catalog.js +46 -58
  4. package/dist/catalog.js.map +1 -1
  5. package/dist/cover.d.ts +10 -0
  6. package/dist/cover.d.ts.map +1 -1
  7. package/dist/cover.js +66 -19
  8. package/dist/cover.js.map +1 -1
  9. package/dist/credits.d.ts +10 -0
  10. package/dist/credits.d.ts.map +1 -1
  11. package/dist/credits.js +149 -39
  12. package/dist/credits.js.map +1 -1
  13. package/dist/drop.d.ts +7 -0
  14. package/dist/drop.d.ts.map +1 -1
  15. package/dist/drop.js +84 -34
  16. package/dist/drop.js.map +1 -1
  17. package/dist/pressing.d.ts.map +1 -1
  18. package/dist/pressing.js +59 -16
  19. package/dist/pressing.js.map +1 -1
  20. package/dist/read/artist.d.ts +1 -6
  21. package/dist/read/artist.d.ts.map +1 -1
  22. package/dist/read/artist.js +39 -22
  23. package/dist/read/artist.js.map +1 -1
  24. package/dist/read/catalog.d.ts +24 -3
  25. package/dist/read/catalog.d.ts.map +1 -1
  26. package/dist/read/catalog.js +190 -89
  27. package/dist/read/catalog.js.map +1 -1
  28. package/dist/read/index.d.ts +5 -3
  29. package/dist/read/index.d.ts.map +1 -1
  30. package/dist/read/index.js +2 -2
  31. package/dist/read/index.js.map +1 -1
  32. package/dist/read/types.d.ts +12 -1
  33. package/dist/read/types.d.ts.map +1 -1
  34. package/dist/read/works.d.ts +3 -2
  35. package/dist/read/works.d.ts.map +1 -1
  36. package/dist/read/works.js +158 -48
  37. package/dist/read/works.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/catalog.ts +71 -77
  40. package/src/cover.ts +107 -26
  41. package/src/credits.ts +353 -89
  42. package/src/drop.ts +150 -40
  43. package/src/pressing.ts +146 -36
  44. package/src/read/artist.ts +73 -34
  45. package/src/read/catalog.ts +324 -89
  46. package/src/read/index.ts +23 -2
  47. package/src/read/types.ts +16 -2
  48. package/src/read/works.ts +224 -59
package/src/drop.ts CHANGED
@@ -12,11 +12,13 @@ import type { ClientWithCoreApi } from "@mysten/sui/client";
12
12
  import { deriveDynamicFieldID } from "@mysten/sui/utils";
13
13
  import { bcs } from "@mysten/sui/bcs";
14
14
  import type { TxThunk } from "./transactions.ts";
15
- import { isNotFound } from "./queries.ts";
16
15
  import * as drop from "./contracts/miso_drop/drop.ts";
17
16
 
18
17
  /** Pricing policy: pay exactly `amount` (fixed) or at least `amount` (floor). */
19
- export type DropPrice = { kind: "fixed" | "floor"; amount: bigint | number | string };
18
+ export type DropPrice = {
19
+ kind: "fixed" | "floor";
20
+ amount: bigint | number | string;
21
+ };
20
22
 
21
23
  export interface CreateDropParams {
22
24
  /** The `Release` object the drop sells copies of — also the drop's derivation
@@ -48,7 +50,13 @@ export function createDrop(p: CreateDropParams): TxThunk {
48
50
  tx.add(
49
51
  drop._new({
50
52
  package: p.misoDropPackageId,
51
- arguments: [p.releaseId, p.releaseAdminCapId, terms.price, terms.supply, terms.window],
53
+ arguments: [
54
+ p.releaseId,
55
+ p.releaseAdminCapId,
56
+ terms.price,
57
+ terms.supply,
58
+ terms.window,
59
+ ],
52
60
  typeArguments: [p.currencyType],
53
61
  }),
54
62
  );
@@ -88,7 +96,14 @@ export function newEdition(p: NewEditionParams): TxThunk {
88
96
  tx.add(
89
97
  drop.newEdition({
90
98
  package: p.misoDropPackageId,
91
- arguments: [p.releaseId, p.oldDropId, p.releaseAdminCapId, terms.price, terms.supply, terms.window],
99
+ arguments: [
100
+ p.releaseId,
101
+ p.oldDropId,
102
+ p.releaseAdminCapId,
103
+ terms.price,
104
+ terms.supply,
105
+ terms.window,
106
+ ],
92
107
  typeArguments: [p.oldCurrencyType, p.currencyType],
93
108
  }),
94
109
  );
@@ -99,20 +114,37 @@ export function newEdition(p: NewEditionParams): TxThunk {
99
114
  * facade params — the flat shape stays the public API; the enums are a wire detail. */
100
115
  function buildTerms(
101
116
  tx: Parameters<TxThunk>[0],
102
- p: Pick<CreateDropParams, "price" | "maxSupply" | "startTimestampMs" | "endTimestampMs" | "misoDropPackageId">,
117
+ p: Pick<
118
+ CreateDropParams,
119
+ | "price"
120
+ | "maxSupply"
121
+ | "startTimestampMs"
122
+ | "endTimestampMs"
123
+ | "misoDropPackageId"
124
+ >,
103
125
  ) {
104
126
  const pkg = { package: p.misoDropPackageId };
105
- const makePrice = p.price.kind === "fixed" ? drop.newFixedPrice : drop.newFloorPrice;
106
- const price = tx.add(makePrice({ ...pkg, arguments: [BigInt(p.price.amount)] }));
127
+ const makePrice =
128
+ p.price.kind === "fixed" ? drop.newFixedPrice : drop.newFloorPrice;
129
+ const price = tx.add(
130
+ makePrice({ ...pkg, arguments: [BigInt(p.price.amount)] }),
131
+ );
107
132
  const supply =
108
133
  p.maxSupply == null
109
134
  ? tx.add(drop.newUncappedSupply({ ...pkg, arguments: [] }))
110
- : tx.add(drop.newCappedSupply({ ...pkg, arguments: [BigInt(p.maxSupply)] }));
135
+ : tx.add(
136
+ drop.newCappedSupply({ ...pkg, arguments: [BigInt(p.maxSupply)] }),
137
+ );
111
138
  const start = BigInt(p.startTimestampMs ?? 0);
112
139
  const window =
113
140
  p.endTimestampMs == null
114
141
  ? tx.add(drop.newUnboundedWindow({ ...pkg, arguments: [start] }))
115
- : tx.add(drop.newBoundedWindow({ ...pkg, arguments: [start, BigInt(p.endTimestampMs)] }));
142
+ : tx.add(
143
+ drop.newBoundedWindow({
144
+ ...pkg,
145
+ arguments: [start, BigInt(p.endTimestampMs)],
146
+ }),
147
+ );
116
148
  return { price, supply, window };
117
149
  }
118
150
 
@@ -143,7 +175,11 @@ export function buyRecord(p: BuyRecordParams): TxThunk {
143
175
  const [first, ...rest] = p.paymentCoinIds;
144
176
  if (!first) throw new Error("buyRecord: no payment coins provided");
145
177
  const primary = tx.object(first);
146
- if (rest.length > 0) tx.mergeCoins(primary, rest.map((id) => tx.object(id)));
178
+ if (rest.length > 0)
179
+ tx.mergeCoins(
180
+ primary,
181
+ rest.map((id) => tx.object(id)),
182
+ );
147
183
  const [payment] = tx.splitCoins(primary, [tx.pure.u64(BigInt(p.amount))]);
148
184
  const record = tx.add(
149
185
  drop.buy({
@@ -187,21 +223,24 @@ function currencyFromType(type: string | null | undefined): string | null {
187
223
  * drop ids — a party's featured drop, a superseded edition — where "no such
188
224
  * drop" is a normal state, so absence is `null` and only transport failures throw.
189
225
  */
190
- export async function getDrop(client: ClientWithCoreApi, dropId: string): Promise<DropView | null> {
191
- let content: Uint8Array | null | undefined;
192
- let type: string | undefined;
193
- try {
194
- const { object } = await client.core.getObject({ objectId: dropId, include: { content: true } });
195
- content = object?.content;
196
- type = object?.type;
197
- } catch (e) {
198
- if (isNotFound(e)) return null;
199
- throw e;
200
- }
201
- if (!content) return null;
226
+ export async function getDrop(
227
+ client: ClientWithCoreApi,
228
+ dropId: string,
229
+ ): Promise<DropView | null> {
230
+ return (await getDropsByIds(client, [dropId]))[dropId] ?? null;
231
+ }
202
232
 
233
+ function parseDrop(
234
+ dropId: string,
235
+ content: Uint8Array,
236
+ type?: string,
237
+ ): DropView {
203
238
  const d = drop.Drop.parse(content);
204
- const price = d.price as { $kind?: string; Fixed?: { amount: string }; Floor?: { amount: string } };
239
+ const price = d.price as {
240
+ $kind?: string;
241
+ Fixed?: { amount: string };
242
+ Floor?: { amount: string };
243
+ };
205
244
  const isFixed = price.$kind === "Fixed" || price.Fixed != null;
206
245
  const amount = (isFixed ? price.Fixed?.amount : price.Floor?.amount) ?? "0";
207
246
  const supply = d.supply as { $kind?: string; Capped?: { max: string } };
@@ -221,16 +260,51 @@ export async function getDrop(client: ClientWithCoreApi, dropId: string): Promis
221
260
  maxSupply: capped ? BigInt(supply.Capped?.max ?? "0") : null,
222
261
  quantitySold: BigInt(d.quantity_sold),
223
262
  startTimestampMs: BigInt(
224
- (bounded ? window.Bounded?.start_timestamp_ms : window.Unbounded?.start_timestamp_ms) ?? "0",
263
+ (bounded
264
+ ? window.Bounded?.start_timestamp_ms
265
+ : window.Unbounded?.start_timestamp_ms) ?? "0",
225
266
  ),
226
- endTimestampMs: bounded ? BigInt(window.Bounded?.end_timestamp_ms ?? "0") : null,
267
+ endTimestampMs: bounded
268
+ ? BigInt(window.Bounded?.end_timestamp_ms ?? "0")
269
+ : null,
227
270
  currencyType: currencyFromType(type),
228
271
  };
229
272
  }
230
273
 
274
+ /** Fetch and parse many Drop objects through one Core bulk request. */
275
+ export async function getDropsByIds(
276
+ client: ClientWithCoreApi,
277
+ dropIdsInput: readonly string[],
278
+ ): Promise<Partial<Record<string, DropView>>> {
279
+ const dropIds = [...new Set(dropIdsInput)];
280
+ if (dropIds.length === 0) return {};
281
+ const { objects } = await client.core.getObjects({
282
+ objectIds: dropIds,
283
+ include: { content: true },
284
+ });
285
+ const out: Partial<Record<string, DropView>> = {};
286
+ objects.forEach((object, index) => {
287
+ const dropId = dropIds[index];
288
+ if (
289
+ !dropId ||
290
+ object instanceof Error ||
291
+ !object.content ||
292
+ !/::drop::Drop</.test(object.type ?? "")
293
+ ) {
294
+ return;
295
+ }
296
+ out[dropId] = parseDrop(dropId, object.content, object.type);
297
+ });
298
+ return out;
299
+ }
300
+
231
301
  // The release's `CurrentDropKey` dynamic field holds a bare `ID`; the field object
232
302
  // serializes as `Field { id, name: CurrentDropKey (unit), value: ID }`.
233
- const CurrentDropField = bcs.struct("Field", { id: bcs.Address, name: bcs.bool(), value: bcs.Address });
303
+ const CurrentDropField = bcs.struct("Field", {
304
+ id: bcs.Address,
305
+ name: bcs.bool(),
306
+ value: bcs.Address,
307
+ });
234
308
 
235
309
  // Unit-struct key bytes (single `0x00` for the dummy bool field).
236
310
  const CURRENT_DROP_KEY_BYTES = drop.CurrentDropKey.serialize([false]).toBytes();
@@ -247,20 +321,56 @@ export interface GetCurrentDropParams {
247
321
  * destroyed, so this — not derived-address probing — is how the current edition is
248
322
  * found.
249
323
  */
250
- export async function getCurrentDrop(client: ClientWithCoreApi, p: GetCurrentDropParams): Promise<DropView | null> {
251
- const fieldId = deriveDynamicFieldID(
252
- p.releaseId,
253
- `${p.misoDropPackageId}::drop::CurrentDropKey`,
254
- CURRENT_DROP_KEY_BYTES,
324
+ export async function getCurrentDrop(
325
+ client: ClientWithCoreApi,
326
+ p: GetCurrentDropParams,
327
+ ): Promise<DropView | null> {
328
+ return (
329
+ (await getCurrentDrops(client, [p.releaseId], p.misoDropPackageId))[
330
+ p.releaseId
331
+ ] ?? null
332
+ );
333
+ }
334
+
335
+ /**
336
+ * Resolve the live drops for many releases in two Core bulk requests: all
337
+ * CurrentDrop pointer fields, then all pointed-to Drop objects.
338
+ */
339
+ export async function getCurrentDrops(
340
+ client: ClientWithCoreApi,
341
+ releaseIdsInput: readonly string[],
342
+ misoDropPackageId: string,
343
+ ): Promise<Partial<Record<string, DropView>>> {
344
+ const releaseIds = [...new Set(releaseIdsInput)];
345
+ if (releaseIds.length === 0) return {};
346
+ const fieldIds = releaseIds.map((releaseId) =>
347
+ deriveDynamicFieldID(
348
+ releaseId,
349
+ `${misoDropPackageId}::drop::CurrentDropKey`,
350
+ CURRENT_DROP_KEY_BYTES,
351
+ ),
352
+ );
353
+ const { objects } = await client.core.getObjects({
354
+ objectIds: fieldIds,
355
+ include: { content: true },
356
+ });
357
+ const dropIdByRelease: Partial<Record<string, string>> = {};
358
+ objects.forEach((object, index) => {
359
+ const releaseId = releaseIds[index];
360
+ if (!releaseId || object instanceof Error || !object.content) return;
361
+ dropIdByRelease[releaseId] = CurrentDropField.parse(object.content).value;
362
+ });
363
+
364
+ const drops = await getDropsByIds(
365
+ client,
366
+ Object.values(dropIdByRelease).filter(
367
+ (id): id is string => id !== undefined,
368
+ ),
255
369
  );
256
- let content: Uint8Array | null | undefined;
257
- try {
258
- const { object } = await client.core.getObject({ objectId: fieldId, include: { content: true } });
259
- content = object?.content;
260
- } catch (e) {
261
- if (isNotFound(e)) return null;
262
- throw e;
370
+ const out: Partial<Record<string, DropView>> = {};
371
+ for (const [releaseId, dropId] of Object.entries(dropIdByRelease)) {
372
+ const dropView = dropId ? drops[dropId] : undefined;
373
+ if (dropView) out[releaseId] = dropView;
263
374
  }
264
- if (!content) return null;
265
- return getDrop(client, CurrentDropField.parse(content).value);
375
+ return out;
266
376
  }
package/src/pressing.ts CHANGED
@@ -22,7 +22,10 @@ import * as listing from "./contracts/miso_pressing/listing.ts";
22
22
  import * as pressing from "./contracts/miso_pressing/pressing.ts";
23
23
 
24
24
  /** Pricing policy: pay exactly `amount` (fixed) or at least `amount` (floor). */
25
- export type ListingPrice = { kind: "fixed" | "floor"; amount: bigint | number | string };
25
+ export type ListingPrice = {
26
+ kind: "fixed" | "floor";
27
+ amount: bigint | number | string;
28
+ };
26
29
 
27
30
  /** Whether a currency's listing takes payment. Below the pressing's own run state. */
28
31
  export type ListingSwitch = "enabled" | "disabled";
@@ -54,15 +57,25 @@ const UNIT_STRUCT_KEY_BYTES = new Uint8Array([0x00]);
54
57
  * that is the address a Move type tag canonicalises to. `miso_pressing` is published
55
58
  * immutable, so its original and current ids are the same.
56
59
  */
57
- export function derivePressingId(releaseId: string, misoPressingPackageId: string): string {
58
- return deriveObjectID(releaseId, `${misoPressingPackageId}::pressing::PressingKey`, UNIT_STRUCT_KEY_BYTES);
60
+ export function derivePressingId(
61
+ releaseId: string,
62
+ misoPressingPackageId: string,
63
+ ): string {
64
+ return deriveObjectID(
65
+ releaseId,
66
+ `${misoPressingPackageId}::pressing::PressingKey`,
67
+ UNIT_STRUCT_KEY_BYTES,
68
+ );
59
69
  }
60
70
 
61
71
  /**
62
72
  * Where `pressingId`'s admin cap was minted. The cap is transferable, so this is not
63
73
  * where it lives — only where it came from.
64
74
  */
65
- export function derivePressingAdminCapId(pressingId: string, misoPressingPackageId: string): string {
75
+ export function derivePressingAdminCapId(
76
+ pressingId: string,
77
+ misoPressingPackageId: string,
78
+ ): string {
66
79
  return deriveObjectID(
67
80
  pressingId,
68
81
  `${misoPressingPackageId}::pressing::PressingAdminCapKey`,
@@ -93,7 +106,10 @@ export function deriveSaleIds(
93
106
  misoPressingPackageId: string,
94
107
  ): { pressingId: string; listingId: string } {
95
108
  const pressingId = derivePressingId(releaseId, misoPressingPackageId);
96
- return { pressingId, listingId: deriveListingId(pressingId, currencyType, misoPressingPackageId) };
109
+ return {
110
+ pressingId,
111
+ listingId: deriveListingId(pressingId, currencyType, misoPressingPackageId),
112
+ };
97
113
  }
98
114
 
99
115
  // ============================================================================
@@ -103,20 +119,37 @@ export function deriveSaleIds(
103
119
  type Tx = Parameters<TxThunk>[0];
104
120
 
105
121
  function priceArg(tx: Tx, misoPressingPackageId: string, price: ListingPrice) {
106
- const make = price.kind === "fixed" ? listing.newFixedPrice : listing.newFloorPrice;
107
- return tx.add(make({ package: misoPressingPackageId, arguments: [BigInt(price.amount)] }));
122
+ const make =
123
+ price.kind === "fixed" ? listing.newFixedPrice : listing.newFloorPrice;
124
+ return tx.add(
125
+ make({ package: misoPressingPackageId, arguments: [BigInt(price.amount)] }),
126
+ );
108
127
  }
109
128
 
110
- function switchArg(tx: Tx, misoPressingPackageId: string, state: ListingSwitch) {
111
- const make = state === "enabled" ? listing.newEnabledState : listing.newDisabledState;
129
+ function switchArg(
130
+ tx: Tx,
131
+ misoPressingPackageId: string,
132
+ state: ListingSwitch,
133
+ ) {
134
+ const make =
135
+ state === "enabled" ? listing.newEnabledState : listing.newDisabledState;
112
136
  return tx.add(make({ package: misoPressingPackageId }));
113
137
  }
114
138
 
115
- function runStateArg(tx: Tx, misoPressingPackageId: string, state: PressingRunState) {
139
+ function runStateArg(
140
+ tx: Tx,
141
+ misoPressingPackageId: string,
142
+ state: PressingRunState,
143
+ ) {
116
144
  const pkg = { package: misoPressingPackageId };
117
145
  switch (state.kind) {
118
146
  case "scheduled":
119
- return tx.add(pressing.newScheduledState({ ...pkg, arguments: [BigInt(state.startTimestampMs)] }));
147
+ return tx.add(
148
+ pressing.newScheduledState({
149
+ ...pkg,
150
+ arguments: [BigInt(state.startTimestampMs)],
151
+ }),
152
+ );
120
153
  case "active":
121
154
  return tx.add(pressing.newActiveState(pkg));
122
155
  case "paused":
@@ -169,7 +202,11 @@ export function openPressing(p: OpenPressingParams): TxThunk {
169
202
  const [run, adminCap] = tx.add(
170
203
  pressing._new({
171
204
  package: pkg,
172
- arguments: [p.releaseId, p.releaseAdminCapId, runStateArg(tx, pkg, p.state ?? { kind: "active" })],
205
+ arguments: [
206
+ p.releaseId,
207
+ p.releaseAdminCapId,
208
+ runStateArg(tx, pkg, p.state ?? { kind: "active" }),
209
+ ],
173
210
  }),
174
211
  );
175
212
  for (const terms of p.listings) {
@@ -246,7 +283,11 @@ export function setListingPrice(p: SetListingPriceParams): TxThunk {
246
283
  tx.add(
247
284
  listing.setPrice({
248
285
  package: pkg,
249
- arguments: [listingId, p.pressingAdminCapId, priceArg(tx, pkg, p.price)],
286
+ arguments: [
287
+ listingId,
288
+ p.pressingAdminCapId,
289
+ priceArg(tx, pkg, p.price),
290
+ ],
250
291
  typeArguments: [p.currencyType],
251
292
  }),
252
293
  );
@@ -269,7 +310,11 @@ export function setListingState(p: SetListingStateParams): TxThunk {
269
310
  tx.add(
270
311
  listing.setState({
271
312
  package: pkg,
272
- arguments: [listingId, p.pressingAdminCapId, switchArg(tx, pkg, p.state)],
313
+ arguments: [
314
+ listingId,
315
+ p.pressingAdminCapId,
316
+ switchArg(tx, pkg, p.state),
317
+ ],
273
318
  typeArguments: [p.currencyType],
274
319
  }),
275
320
  );
@@ -352,7 +397,11 @@ export interface BuyRecordParams {
352
397
  export function buyRecord(p: BuyRecordParams): TxThunk {
353
398
  return (tx) => {
354
399
  const pkg = p.misoPressingPackageId;
355
- const { pressingId, listingId } = deriveSaleIds(p.releaseId, p.currencyType, pkg);
400
+ const { pressingId, listingId } = deriveSaleIds(
401
+ p.releaseId,
402
+ p.currencyType,
403
+ pkg,
404
+ );
356
405
  const payment = tx.balance({
357
406
  type: p.currencyType,
358
407
  balance: BigInt(p.amount),
@@ -407,8 +456,13 @@ async function fetch(
407
456
  objectId: string,
408
457
  ): Promise<{ content: Uint8Array; type?: string } | null> {
409
458
  try {
410
- const { object } = await client.core.getObject({ objectId, include: { content: true } });
411
- return object?.content ? { content: object.content, type: object.type } : null;
459
+ const { object } = await client.core.getObject({
460
+ objectId,
461
+ include: { content: true },
462
+ });
463
+ return object?.content
464
+ ? { content: object.content, type: object.type }
465
+ : null;
412
466
  } catch (e) {
413
467
  if (isNotFound(e)) return null;
414
468
  throw e;
@@ -417,8 +471,12 @@ async function fetch(
417
471
 
418
472
  // The generated `MoveEnum` parsers emit `{ $kind, <Variant>: … }`; older ones omitted
419
473
  // `$kind`. Both shapes are accepted so a codegen bump cannot silently mis-read a price.
420
- function variant<T extends string>(v: { $kind?: string } & Record<string, unknown>, ...names: T[]): T {
421
- for (const name of names) if (v.$kind === name || v[name] != null) return name;
474
+ function variant<T extends string>(
475
+ v: { $kind?: string } & Record<string, unknown>,
476
+ ...names: T[]
477
+ ): T {
478
+ for (const name of names)
479
+ if (v.$kind === name || v[name] != null) return name;
422
480
  return names[0]!;
423
481
  }
424
482
 
@@ -430,18 +488,31 @@ function variant<T extends string>(v: { $kind?: string } & Record<string, unknow
430
488
  * computable for ANY release, so probing one that was never opened is a normal state,
431
489
  * not a broken reference — absence is `null` and only transport failures throw.
432
490
  */
433
- export async function getPressing(client: ClientWithCoreApi, pressingId: string): Promise<PressingView | null> {
491
+ export async function getPressing(
492
+ client: ClientWithCoreApi,
493
+ pressingId: string,
494
+ ): Promise<PressingView | null> {
434
495
  const got = await fetch(client, pressingId);
435
496
  if (!got) return null;
436
- const parsed = pressing.Pressing.parse(got.content);
437
- const s = parsed.state as { $kind?: string; Scheduled?: { start_timestamp_ms: string } };
497
+ return parsePressing(pressingId, got.content);
498
+ }
499
+
500
+ function parsePressing(pressingId: string, content: Uint8Array): PressingView {
501
+ const parsed = pressing.Pressing.parse(content);
502
+ const s = parsed.state as {
503
+ $kind?: string;
504
+ Scheduled?: { start_timestamp_ms: string };
505
+ };
438
506
  const kind = variant(s, "Scheduled", "Active", "Paused");
439
507
  return {
440
508
  id: pressingId,
441
509
  releaseId: parsed.release_id,
442
510
  state:
443
511
  kind === "Scheduled"
444
- ? { kind: "scheduled", startTimestampMs: BigInt(s.Scheduled?.start_timestamp_ms ?? "0") }
512
+ ? {
513
+ kind: "scheduled",
514
+ startTimestampMs: BigInt(s.Scheduled?.start_timestamp_ms ?? "0"),
515
+ }
445
516
  : kind === "Paused"
446
517
  ? { kind: "paused" }
447
518
  : { kind: "active" },
@@ -450,23 +521,45 @@ export async function getPressing(client: ClientWithCoreApi, pressingId: string)
450
521
  }
451
522
 
452
523
  /** Fetches and parses a `Listing<Currency>`, or `null` if that currency is not listed. */
453
- export async function getListing(client: ClientWithCoreApi, listingId: string): Promise<ListingView | null> {
524
+ export async function getListing(
525
+ client: ClientWithCoreApi,
526
+ listingId: string,
527
+ ): Promise<ListingView | null> {
454
528
  const got = await fetch(client, listingId);
455
529
  if (!got) return null;
456
- const parsed = listing.Listing.parse(got.content);
457
- const p = parsed.price as { $kind?: string; Fixed?: { amount: string }; Floor?: { amount: string } };
530
+ return parseListing(listingId, got.content, got.type);
531
+ }
532
+
533
+ function parseListing(
534
+ listingId: string,
535
+ content: Uint8Array,
536
+ type?: string,
537
+ ): ListingView {
538
+ const parsed = listing.Listing.parse(content);
539
+ const p = parsed.price as {
540
+ $kind?: string;
541
+ Fixed?: { amount: string };
542
+ Floor?: { amount: string };
543
+ };
458
544
  const priceKind = variant(p, "Fixed", "Floor");
459
- const st = parsed.state as { $kind?: string; Enabled?: unknown; Disabled?: unknown };
545
+ const st = parsed.state as {
546
+ $kind?: string;
547
+ Enabled?: unknown;
548
+ Disabled?: unknown;
549
+ };
460
550
  return {
461
551
  id: listingId,
462
552
  releaseId: parsed.release_id,
463
553
  pressingId: parsed.pressing_id,
464
554
  price: {
465
555
  kind: priceKind === "Fixed" ? "fixed" : "floor",
466
- amount: BigInt((priceKind === "Fixed" ? p.Fixed?.amount : p.Floor?.amount) ?? "0"),
556
+ amount: BigInt(
557
+ (priceKind === "Fixed" ? p.Fixed?.amount : p.Floor?.amount) ?? "0",
558
+ ),
467
559
  },
468
- state: variant(st, "Enabled", "Disabled") === "Enabled" ? "enabled" : "disabled",
469
- currencyType: currencyFromType(got.type),
560
+ state:
561
+ variant(st, "Enabled", "Disabled") === "Enabled" ? "enabled" : "disabled",
562
+ currencyType: currencyFromType(type),
470
563
  };
471
564
  }
472
565
 
@@ -488,10 +581,27 @@ export async function getSale(
488
581
  client: ClientWithCoreApi,
489
582
  p: GetSaleParams,
490
583
  ): Promise<{ pressing: PressingView | null; listing: ListingView | null }> {
491
- const { pressingId, listingId } = deriveSaleIds(p.releaseId, p.currencyType, p.misoPressingPackageId);
492
- const [pressingView, listingView] = await Promise.all([
493
- getPressing(client, pressingId),
494
- getListing(client, listingId),
495
- ]);
496
- return { pressing: pressingView, listing: listingView };
584
+ const { pressingId, listingId } = deriveSaleIds(
585
+ p.releaseId,
586
+ p.currencyType,
587
+ p.misoPressingPackageId,
588
+ );
589
+ const { objects } = await client.core.getObjects({
590
+ objectIds: [pressingId, listingId],
591
+ include: { content: true },
592
+ });
593
+ const pressingObject = objects[0];
594
+ const listingObject = objects[1];
595
+ return {
596
+ pressing:
597
+ !pressingObject ||
598
+ pressingObject instanceof Error ||
599
+ !pressingObject.content
600
+ ? null
601
+ : parsePressing(pressingId, pressingObject.content),
602
+ listing:
603
+ !listingObject || listingObject instanceof Error || !listingObject.content
604
+ ? null
605
+ : parseListing(listingId, listingObject.content, listingObject.type),
606
+ };
497
607
  }