@misofm/sdk 0.9.0 → 0.11.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 (265) hide show
  1. package/README.md +88 -56
  2. package/dist/client.d.ts +121 -18
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +200 -44
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts/composition_routed_stake/composition_routed_stake.d.ts +205 -0
  7. package/dist/contracts/composition_routed_stake/composition_routed_stake.d.ts.map +1 -0
  8. package/dist/contracts/composition_routed_stake/composition_routed_stake.js +184 -0
  9. package/dist/contracts/composition_routed_stake/composition_routed_stake.js.map +1 -0
  10. package/dist/contracts/composition_routed_stake/witness.d.ts +7 -0
  11. package/dist/contracts/composition_routed_stake/witness.d.ts.map +1 -0
  12. package/dist/contracts/composition_routed_stake/witness.js +9 -0
  13. package/dist/contracts/composition_routed_stake/witness.js.map +1 -0
  14. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.d.ts +89 -28
  15. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.d.ts.map +1 -1
  16. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.js +84 -23
  17. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.js.map +1 -1
  18. package/dist/contracts/composition_royalty_pool/witness.d.ts +6 -0
  19. package/dist/contracts/composition_royalty_pool/witness.d.ts.map +1 -0
  20. package/dist/contracts/composition_royalty_pool/witness.js +8 -0
  21. package/dist/contracts/composition_royalty_pool/witness.js.map +1 -0
  22. package/dist/contracts/genre/genre.d.ts +96 -0
  23. package/dist/contracts/genre/genre.d.ts.map +1 -0
  24. package/dist/contracts/genre/genre.js +107 -0
  25. package/dist/contracts/genre/genre.js.map +1 -0
  26. package/dist/contracts/recording_advisory/recording_advisory.d.ts +194 -0
  27. package/dist/contracts/recording_advisory/recording_advisory.d.ts.map +1 -0
  28. package/dist/contracts/recording_advisory/recording_advisory.js +204 -0
  29. package/dist/contracts/recording_advisory/recording_advisory.js.map +1 -0
  30. package/dist/contracts/recording_language/deps/language_code/language_code.d.ts +6 -0
  31. package/dist/contracts/recording_language/deps/language_code/language_code.d.ts.map +1 -0
  32. package/dist/contracts/recording_language/deps/language_code/language_code.js +8 -0
  33. package/dist/contracts/recording_language/deps/language_code/language_code.js.map +1 -0
  34. package/dist/contracts/recording_language/recording_language.d.ts +152 -0
  35. package/dist/contracts/recording_language/recording_language.d.ts.map +1 -0
  36. package/dist/contracts/recording_language/recording_language.js +149 -0
  37. package/dist/contracts/recording_language/recording_language.js.map +1 -0
  38. package/dist/contracts/recording_master_reference/deps/ori/walrus_data.d.ts +52 -0
  39. package/dist/contracts/recording_master_reference/deps/ori/walrus_data.d.ts.map +1 -0
  40. package/dist/contracts/recording_master_reference/deps/ori/walrus_data.js +37 -0
  41. package/dist/contracts/recording_master_reference/deps/ori/walrus_data.js.map +1 -0
  42. package/dist/contracts/recording_master_reference/recording_master_reference.d.ts +131 -0
  43. package/dist/contracts/recording_master_reference/recording_master_reference.d.ts.map +1 -0
  44. package/dist/contracts/recording_master_reference/recording_master_reference.js +121 -0
  45. package/dist/contracts/recording_master_reference/recording_master_reference.js.map +1 -0
  46. package/dist/contracts/recording_preview/deps/ori/walrus_data.d.ts +52 -0
  47. package/dist/contracts/recording_preview/deps/ori/walrus_data.d.ts.map +1 -0
  48. package/dist/contracts/recording_preview/deps/ori/walrus_data.js +37 -0
  49. package/dist/contracts/recording_preview/deps/ori/walrus_data.js.map +1 -0
  50. package/dist/contracts/recording_preview/recording_preview.d.ts +104 -0
  51. package/dist/contracts/recording_preview/recording_preview.d.ts.map +1 -0
  52. package/dist/contracts/recording_preview/recording_preview.js +94 -0
  53. package/dist/contracts/recording_preview/recording_preview.js.map +1 -0
  54. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.d.ts +90 -28
  55. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.d.ts.map +1 -1
  56. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.js +84 -23
  57. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.js.map +1 -1
  58. package/dist/contracts/recording_royalty_pool/witness.d.ts +6 -0
  59. package/dist/contracts/recording_royalty_pool/witness.d.ts.map +1 -0
  60. package/dist/contracts/recording_royalty_pool/witness.js +8 -0
  61. package/dist/contracts/recording_royalty_pool/witness.js.map +1 -0
  62. package/dist/contracts/release_description/release_description.d.ts +112 -0
  63. package/dist/contracts/release_description/release_description.d.ts.map +1 -0
  64. package/dist/contracts/release_description/release_description.js +123 -0
  65. package/dist/contracts/release_description/release_description.js.map +1 -0
  66. package/dist/contracts/release_dsp_link/release_dsp_link.d.ts +644 -0
  67. package/dist/contracts/release_dsp_link/release_dsp_link.d.ts.map +1 -0
  68. package/dist/contracts/release_dsp_link/release_dsp_link.js +556 -0
  69. package/dist/contracts/release_dsp_link/release_dsp_link.js.map +1 -0
  70. package/dist/contracts/release_genre/deps/per_track/per_track.d.ts +33 -0
  71. package/dist/contracts/release_genre/deps/per_track/per_track.d.ts.map +1 -0
  72. package/dist/contracts/release_genre/deps/per_track/per_track.js +32 -0
  73. package/dist/contracts/release_genre/deps/per_track/per_track.js.map +1 -0
  74. package/dist/contracts/release_genre/release_genre.d.ts +193 -0
  75. package/dist/contracts/release_genre/release_genre.d.ts.map +1 -0
  76. package/dist/contracts/release_genre/release_genre.js +207 -0
  77. package/dist/contracts/release_genre/release_genre.js.map +1 -0
  78. package/dist/contracts/release_kind/release_kind.d.ts +98 -0
  79. package/dist/contracts/release_kind/release_kind.d.ts.map +1 -0
  80. package/dist/contracts/release_kind/release_kind.js +109 -0
  81. package/dist/contracts/release_kind/release_kind.js.map +1 -0
  82. package/dist/contracts/release_revenue_distributor/release_revenue_distributor.d.ts +106 -0
  83. package/dist/contracts/release_revenue_distributor/release_revenue_distributor.d.ts.map +1 -0
  84. package/dist/contracts/release_revenue_distributor/release_revenue_distributor.js +113 -0
  85. package/dist/contracts/release_revenue_distributor/release_revenue_distributor.js.map +1 -0
  86. package/dist/contracts/release_revenue_distributor/witness.d.ts +7 -0
  87. package/dist/contracts/release_revenue_distributor/witness.d.ts.map +1 -0
  88. package/dist/contracts/release_revenue_distributor/witness.js +9 -0
  89. package/dist/contracts/release_revenue_distributor/witness.js.map +1 -0
  90. package/dist/contracts/routed_stake/deps/royalty_pool/stake.d.ts +54 -0
  91. package/dist/contracts/routed_stake/deps/royalty_pool/stake.d.ts.map +1 -0
  92. package/dist/contracts/routed_stake/deps/royalty_pool/stake.js +37 -0
  93. package/dist/contracts/routed_stake/deps/royalty_pool/stake.js.map +1 -0
  94. package/dist/contracts/routed_stake/deps/std/type_name.d.ts +18 -0
  95. package/dist/contracts/routed_stake/deps/std/type_name.d.ts.map +1 -0
  96. package/dist/contracts/routed_stake/deps/std/type_name.js +20 -0
  97. package/dist/contracts/routed_stake/deps/std/type_name.js.map +1 -0
  98. package/dist/contracts/routed_stake/deps/sui/balance.d.ts +13 -0
  99. package/dist/contracts/routed_stake/deps/sui/balance.d.ts.map +1 -0
  100. package/dist/contracts/routed_stake/deps/sui/balance.js +15 -0
  101. package/dist/contracts/routed_stake/deps/sui/balance.js.map +1 -0
  102. package/dist/contracts/routed_stake/deps/sui/vec_map.d.ts +37 -0
  103. package/dist/contracts/routed_stake/deps/sui/vec_map.d.ts.map +1 -0
  104. package/dist/contracts/routed_stake/deps/sui/vec_map.js +28 -0
  105. package/dist/contracts/routed_stake/deps/sui/vec_map.js.map +1 -0
  106. package/dist/contracts/routed_stake/routed_stake.d.ts +356 -0
  107. package/dist/contracts/routed_stake/routed_stake.d.ts.map +1 -0
  108. package/dist/contracts/routed_stake/routed_stake.js +311 -0
  109. package/dist/contracts/routed_stake/routed_stake.js.map +1 -0
  110. package/dist/contracts/royalty_pool/pool.d.ts +27 -17
  111. package/dist/contracts/royalty_pool/pool.d.ts.map +1 -1
  112. package/dist/contracts/royalty_pool/pool.js +26 -17
  113. package/dist/contracts/royalty_pool/pool.js.map +1 -1
  114. package/dist/contracts/vault/deps/sui/bag.d.ts +35 -0
  115. package/dist/contracts/vault/deps/sui/bag.d.ts.map +1 -0
  116. package/dist/contracts/vault/deps/sui/bag.js +37 -0
  117. package/dist/contracts/vault/deps/sui/bag.js.map +1 -0
  118. package/dist/contracts/vault/deps/sui/borrow.d.ts +20 -0
  119. package/dist/contracts/vault/deps/sui/borrow.d.ts.map +1 -0
  120. package/dist/contracts/vault/deps/sui/borrow.js +21 -0
  121. package/dist/contracts/vault/deps/sui/borrow.js.map +1 -0
  122. package/dist/contracts/vault/vault.d.ts +276 -0
  123. package/dist/contracts/vault/vault.d.ts.map +1 -0
  124. package/dist/contracts/vault/vault.js +274 -0
  125. package/dist/contracts/vault/vault.js.map +1 -0
  126. package/dist/contracts.d.ts +13 -2
  127. package/dist/contracts.d.ts.map +1 -1
  128. package/dist/contracts.js +15 -7
  129. package/dist/contracts.js.map +1 -1
  130. package/dist/cover.d.ts +17 -3
  131. package/dist/cover.d.ts.map +1 -1
  132. package/dist/cover.js +43 -20
  133. package/dist/cover.js.map +1 -1
  134. package/dist/credits.d.ts +31 -12
  135. package/dist/credits.d.ts.map +1 -1
  136. package/dist/credits.js +41 -25
  137. package/dist/credits.js.map +1 -1
  138. package/dist/deployments.d.ts +30 -57
  139. package/dist/deployments.d.ts.map +1 -1
  140. package/dist/deployments.js +5 -53
  141. package/dist/deployments.js.map +1 -1
  142. package/dist/index.d.ts +4 -2
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.js +6 -5
  145. package/dist/index.js.map +1 -1
  146. package/dist/pressing.d.ts +8 -7
  147. package/dist/pressing.d.ts.map +1 -1
  148. package/dist/pressing.js +91 -32
  149. package/dist/pressing.js.map +1 -1
  150. package/dist/read/artist.js +3 -3
  151. package/dist/read/artist.js.map +1 -1
  152. package/dist/read/catalog.d.ts +14 -9
  153. package/dist/read/catalog.d.ts.map +1 -1
  154. package/dist/read/catalog.js +71 -37
  155. package/dist/read/catalog.js.map +1 -1
  156. package/dist/read/client.d.ts +4 -2
  157. package/dist/read/client.d.ts.map +1 -1
  158. package/dist/read/client.js +15 -4
  159. package/dist/read/client.js.map +1 -1
  160. package/dist/read/config.d.ts +14 -11
  161. package/dist/read/config.d.ts.map +1 -1
  162. package/dist/read/config.js +10 -37
  163. package/dist/read/config.js.map +1 -1
  164. package/dist/read/index.d.ts +2 -2
  165. package/dist/read/index.d.ts.map +1 -1
  166. package/dist/read/index.js +1 -1
  167. package/dist/read/index.js.map +1 -1
  168. package/dist/read/receipts.d.ts +24 -7
  169. package/dist/read/receipts.d.ts.map +1 -1
  170. package/dist/read/receipts.js +78 -25
  171. package/dist/read/receipts.js.map +1 -1
  172. package/dist/read/types.d.ts +43 -25
  173. package/dist/read/types.d.ts.map +1 -1
  174. package/dist/read/types.js +2 -2
  175. package/dist/read/types.js.map +1 -1
  176. package/dist/recording-extensions.d.ts +37 -0
  177. package/dist/recording-extensions.d.ts.map +1 -0
  178. package/dist/recording-extensions.js +61 -0
  179. package/dist/recording-extensions.js.map +1 -0
  180. package/dist/release-extensions.d.ts +84 -0
  181. package/dist/release-extensions.d.ts.map +1 -0
  182. package/dist/release-extensions.js +160 -0
  183. package/dist/release-extensions.js.map +1 -0
  184. package/dist/release-graph.d.ts +17 -26
  185. package/dist/release-graph.d.ts.map +1 -1
  186. package/dist/release-graph.js +55 -49
  187. package/dist/release-graph.js.map +1 -1
  188. package/dist/transactions.d.ts +43 -24
  189. package/dist/transactions.d.ts.map +1 -1
  190. package/dist/transactions.js +48 -27
  191. package/dist/transactions.js.map +1 -1
  192. package/dist/vault.d.ts +268 -0
  193. package/dist/vault.d.ts.map +1 -0
  194. package/dist/vault.js +389 -0
  195. package/dist/vault.js.map +1 -0
  196. package/package.json +17 -11
  197. package/src/client.ts +399 -61
  198. package/src/contracts/composition_routed_stake/composition_routed_stake.ts +346 -0
  199. package/src/contracts/composition_routed_stake/witness.ts +11 -0
  200. package/src/contracts/composition_royalty_pool/composition_royalty_pool.ts +151 -35
  201. package/src/contracts/composition_royalty_pool/witness.ts +7 -0
  202. package/src/contracts/genre/genre.ts +151 -0
  203. package/src/contracts/recording_advisory/recording_advisory.ts +315 -0
  204. package/src/contracts/recording_language/deps/language_code/language_code.ts +7 -0
  205. package/src/contracts/recording_language/recording_language.ts +237 -0
  206. package/src/contracts/recording_master_reference/deps/ori/walrus_data.ts +36 -0
  207. package/src/contracts/recording_master_reference/recording_master_reference.ts +181 -0
  208. package/src/contracts/recording_preview/deps/ori/walrus_data.ts +36 -0
  209. package/src/contracts/recording_preview/recording_preview.ts +154 -0
  210. package/src/contracts/recording_royalty_pool/recording_royalty_pool.ts +152 -35
  211. package/src/contracts/recording_royalty_pool/witness.ts +7 -0
  212. package/src/contracts/release_description/release_description.ts +167 -0
  213. package/src/contracts/release_dsp_link/release_dsp_link.ts +813 -0
  214. package/src/contracts/release_genre/deps/per_track/per_track.ts +36 -0
  215. package/src/contracts/release_genre/release_genre.ts +314 -0
  216. package/src/contracts/release_kind/release_kind.ts +153 -0
  217. package/src/contracts/release_revenue_distributor/release_revenue_distributor.ts +178 -0
  218. package/src/contracts/release_revenue_distributor/witness.ts +11 -0
  219. package/src/contracts/routed_stake/deps/royalty_pool/stake.ts +39 -0
  220. package/src/contracts/routed_stake/deps/std/type_name.ts +22 -0
  221. package/src/contracts/routed_stake/deps/sui/balance.ts +17 -0
  222. package/src/contracts/routed_stake/deps/sui/vec_map.ts +33 -0
  223. package/src/contracts/routed_stake/routed_stake.ts +508 -0
  224. package/src/contracts/royalty_pool/pool.ts +34 -24
  225. package/src/contracts/vault/deps/sui/bag.ts +39 -0
  226. package/src/contracts/vault/deps/sui/borrow.ts +25 -0
  227. package/src/contracts/vault/vault.ts +454 -0
  228. package/src/contracts.ts +16 -9
  229. package/src/cover.ts +62 -37
  230. package/src/credits.ts +64 -51
  231. package/src/deployments.ts +35 -97
  232. package/src/index.ts +11 -5
  233. package/src/pressing.ts +135 -39
  234. package/src/read/artist.ts +3 -3
  235. package/src/read/catalog.ts +99 -44
  236. package/src/read/client.ts +20 -4
  237. package/src/read/config.ts +23 -49
  238. package/src/read/index.ts +3 -1
  239. package/src/read/receipts.ts +103 -26
  240. package/src/read/types.ts +44 -27
  241. package/src/recording-extensions.ts +102 -0
  242. package/src/release-extensions.ts +261 -0
  243. package/src/release-graph.ts +68 -81
  244. package/src/transactions.ts +79 -53
  245. package/src/vault.ts +777 -0
  246. package/dist/contracts/miso_drop/drop.d.ts +0 -550
  247. package/dist/contracts/miso_drop/drop.d.ts.map +0 -1
  248. package/dist/contracts/miso_drop/drop.js +0 -523
  249. package/dist/contracts/miso_drop/drop.js.map +0 -1
  250. package/dist/contracts/release_registry/release_registry.d.ts +0 -114
  251. package/dist/contracts/release_registry/release_registry.d.ts.map +0 -1
  252. package/dist/contracts/release_registry/release_registry.js +0 -119
  253. package/dist/contracts/release_registry/release_registry.js.map +0 -1
  254. package/dist/drop.d.ts +0 -127
  255. package/dist/drop.d.ts.map +0 -1
  256. package/dist/drop.js +0 -202
  257. package/dist/drop.js.map +0 -1
  258. package/dist/extensions/royalty-pool.d.ts +0 -32
  259. package/dist/extensions/royalty-pool.d.ts.map +0 -1
  260. package/dist/extensions/royalty-pool.js +0 -33
  261. package/dist/extensions/royalty-pool.js.map +0 -1
  262. package/src/contracts/miso_drop/drop.ts +0 -798
  263. package/src/contracts/release_registry/release_registry.ts +0 -160
  264. package/src/drop.ts +0 -376
  265. package/src/extensions/royalty-pool.ts +0 -90
package/src/pressing.ts CHANGED
@@ -9,22 +9,24 @@
9
9
  // permanent, edited in place rather than replaced. A sale needs both switches open.
10
10
  //
11
11
  // EVERYTHING IS ADDRESS MATH. The pressing's UID derives off its release's, each
12
- // listing's off the pressing's. So there is no registry and no pointer to follow:
12
+ // listing's off the pressing's. The core `ReleaseRegistry` owns release creation,
13
+ // but there is no pressing registry or pointer to follow:
13
14
  // `derivePressingId`/`deriveListingId` answer "where is it" offline, which is why the
14
15
  // builders here take a RELEASE id and compute the rest. A caller cannot pass a
15
16
  // listing that belongs to some other pressing, because it never picks one.
16
17
 
17
18
  import type { ClientWithCoreApi } from "@mysten/sui/client";
18
- import { deriveObjectID, normalizeStructTag } from "@mysten/sui/utils";
19
+ import { deriveObjectID, normalizeStructTag, normalizeSuiAddress, parseStructTag } from "@mysten/sui/utils";
19
20
  import type { TxThunk } from "./transactions.ts";
20
21
  import { isNotFound } from "./queries.ts";
22
+ import { asU64, type U64Input } from "./vault.ts";
21
23
  import * as listing from "./contracts/miso_pressing/listing.ts";
22
24
  import * as pressing from "./contracts/miso_pressing/pressing.ts";
23
25
 
24
26
  /** Pricing policy: pay exactly `amount` (fixed) or at least `amount` (floor). */
25
27
  export type ListingPrice = {
26
28
  kind: "fixed" | "floor";
27
- amount: bigint | number | string;
29
+ amount: U64Input;
28
30
  };
29
31
 
30
32
  /** Whether a currency's listing takes payment. Below the pressing's own run state. */
@@ -38,7 +40,7 @@ export type ListingSwitch = "enabled" | "disabled";
38
40
  * this run scheduled for" is an event-log question once a run has sold anything.
39
41
  */
40
42
  export type PressingRunState =
41
- | { kind: "scheduled"; startTimestampMs: bigint | number }
43
+ | { kind: "scheduled"; startTimestampMs: U64Input }
42
44
  | { kind: "active" }
43
45
  | { kind: "paused" };
44
46
 
@@ -122,7 +124,7 @@ function priceArg(tx: Tx, misoPressingPackageId: string, price: ListingPrice) {
122
124
  const make =
123
125
  price.kind === "fixed" ? listing.newFixedPrice : listing.newFloorPrice;
124
126
  return tx.add(
125
- make({ package: misoPressingPackageId, arguments: [BigInt(price.amount)] }),
127
+ make({ package: misoPressingPackageId, arguments: [asU64("listing price", price.amount)] }),
126
128
  );
127
129
  }
128
130
 
@@ -147,7 +149,7 @@ function runStateArg(
147
149
  return tx.add(
148
150
  pressing.newScheduledState({
149
151
  ...pkg,
150
- arguments: [BigInt(state.startTimestampMs)],
152
+ arguments: [asU64("pressing schedule timestamp", state.startTimestampMs)],
151
153
  }),
152
154
  );
153
155
  case "active":
@@ -360,7 +362,7 @@ export interface BuyRecordParams {
360
362
  */
361
363
  releaseId: string;
362
364
  /** Amount to pay in the currency's smallest unit (exact for `fixed`, ≥ for `floor`). */
363
- amount: bigint | number | string;
365
+ amount: U64Input;
364
366
  /** The listing's `Currency` type, e.g. `0x2::sui::SUI`. */
365
367
  currencyType: string;
366
368
  /** The `miso_record` `Settings` shared object — it must authorize `miso_pressing`'s
@@ -404,7 +406,7 @@ export function buyRecord(p: BuyRecordParams): TxThunk {
404
406
  );
405
407
  const payment = tx.balance({
406
408
  type: p.currencyType,
407
- balance: BigInt(p.amount),
409
+ balance: asU64("purchase amount", p.amount),
408
410
  useGasCoin: p.useGasCoin ?? false,
409
411
  });
410
412
  const record = tx.add(
@@ -439,36 +441,72 @@ export interface ListingView {
439
441
  pressingId: string;
440
442
  price: { kind: "fixed" | "floor"; amount: bigint };
441
443
  state: ListingSwitch;
442
- /** The `Currency` type, parsed from the object's type tag (`null` if unavailable). */
443
- currencyType: string | null;
444
- }
445
-
446
- /** Extracts `CURRENCY` from a `…::listing::Listing<CURRENCY>` type tag. */
447
- function currencyFromType(type: string | null | undefined): string | null {
448
- if (!type) return null;
449
- const lt = type.indexOf("<");
450
- return lt >= 0 && type.endsWith(">") ? type.slice(lt + 1, -1) : null;
444
+ /** The exact normalized `Currency` type from the validated outer type tag. */
445
+ currencyType: string;
451
446
  }
452
447
 
453
- /** Reads one object's BCS content + type, or `null` when it does not exist. */
448
+ /** Reads one object's BCS content + type, or `null` only when it does not exist. */
454
449
  async function fetch(
455
450
  client: ClientWithCoreApi,
456
451
  objectId: string,
457
- ): Promise<{ content: Uint8Array; type?: string } | null> {
452
+ ): Promise<{ content: Uint8Array; type: string } | null> {
458
453
  try {
459
454
  const { object } = await client.core.getObject({
460
455
  objectId,
461
456
  include: { content: true },
462
457
  });
463
- return object?.content
464
- ? { content: object.content, type: object.type }
465
- : null;
458
+ if (!object) return null;
459
+ if (!object.content || !object.type) {
460
+ throw new Error(`object ${objectId} has no BCS content or full type`);
461
+ }
462
+ return { content: object.content, type: object.type };
466
463
  } catch (e) {
467
464
  if (isNotFound(e)) return null;
468
465
  throw e;
469
466
  }
470
467
  }
471
468
 
469
+ function sameId(a: string, b: string): boolean {
470
+ return normalizeSuiAddress(a) === normalizeSuiAddress(b);
471
+ }
472
+
473
+ function requireId(label: string, actual: string, expected: string): void {
474
+ if (!sameId(actual, expected)) {
475
+ throw new Error(`${label} ${actual} does not match expected ${expected}`);
476
+ }
477
+ }
478
+
479
+ /** Require the exact configured package/module/struct outer tag. */
480
+ function requirePressingType(type: string, misoPressingPackageId: string): void {
481
+ const actual = normalizeStructTag(type);
482
+ const expected = normalizeStructTag(`${misoPressingPackageId}::pressing::Pressing`);
483
+ if (actual !== expected) {
484
+ throw new Error(`Pressing has type ${actual}, expected configured ${expected}`);
485
+ }
486
+ }
487
+
488
+ /** Validate the whole Listing<CURRENCY> tag and return its normalized Currency. */
489
+ function requireListingCurrency(type: string, misoPressingPackageId: string): string {
490
+ const actual = normalizeStructTag(type);
491
+ const tag = parseStructTag(actual);
492
+ if (
493
+ tag.address !== normalizeSuiAddress(misoPressingPackageId) ||
494
+ tag.module !== "listing" ||
495
+ tag.name !== "Listing" ||
496
+ tag.typeParams.length !== 1
497
+ ) {
498
+ throw new Error(`Listing has type ${actual}, not a configured miso_pressing::listing::Listing<CURRENCY>`);
499
+ }
500
+ const currencyType = normalizeStructTag(tag.typeParams[0]!);
501
+ const expected = normalizeStructTag(
502
+ `${misoPressingPackageId}::listing::Listing<${currencyType}>`,
503
+ );
504
+ if (actual !== expected) {
505
+ throw new Error(`Listing has non-canonical type ${actual}, expected ${expected}`);
506
+ }
507
+ return currencyType;
508
+ }
509
+
472
510
  // The generated `MoveEnum` parsers emit `{ $kind, <Variant>: … }`; older ones omitted
473
511
  // `$kind`. Both shapes are accepted so a codegen bump cannot silently mis-read a price.
474
512
  function variant<T extends string>(
@@ -491,14 +529,27 @@ function variant<T extends string>(
491
529
  export async function getPressing(
492
530
  client: ClientWithCoreApi,
493
531
  pressingId: string,
532
+ misoPressingPackageId: string,
494
533
  ): Promise<PressingView | null> {
495
534
  const got = await fetch(client, pressingId);
496
535
  if (!got) return null;
497
- return parsePressing(pressingId, got.content);
536
+ return parsePressing(pressingId, got.content, got.type, misoPressingPackageId);
498
537
  }
499
538
 
500
- function parsePressing(pressingId: string, content: Uint8Array): PressingView {
539
+ function parsePressing(
540
+ pressingId: string,
541
+ content: Uint8Array,
542
+ type: string,
543
+ misoPressingPackageId: string,
544
+ ): PressingView {
545
+ requirePressingType(type, misoPressingPackageId);
501
546
  const parsed = pressing.Pressing.parse(content);
547
+ requireId("Pressing UID", parsed.id, pressingId);
548
+ requireId(
549
+ "Pressing derived id",
550
+ pressingId,
551
+ derivePressingId(parsed.release_id, misoPressingPackageId),
552
+ );
502
553
  const s = parsed.state as {
503
554
  $kind?: string;
504
555
  Scheduled?: { start_timestamp_ms: string };
@@ -524,18 +575,32 @@ function parsePressing(pressingId: string, content: Uint8Array): PressingView {
524
575
  export async function getListing(
525
576
  client: ClientWithCoreApi,
526
577
  listingId: string,
578
+ misoPressingPackageId: string,
527
579
  ): Promise<ListingView | null> {
528
580
  const got = await fetch(client, listingId);
529
581
  if (!got) return null;
530
- return parseListing(listingId, got.content, got.type);
582
+ return parseListing(listingId, got.content, got.type, misoPressingPackageId);
531
583
  }
532
584
 
533
585
  function parseListing(
534
586
  listingId: string,
535
587
  content: Uint8Array,
536
- type?: string,
588
+ type: string,
589
+ misoPressingPackageId: string,
537
590
  ): ListingView {
591
+ const currencyType = requireListingCurrency(type, misoPressingPackageId);
538
592
  const parsed = listing.Listing.parse(content);
593
+ requireId("Listing UID", parsed.id, listingId);
594
+ requireId(
595
+ "Listing pressing",
596
+ parsed.pressing_id,
597
+ derivePressingId(parsed.release_id, misoPressingPackageId),
598
+ );
599
+ requireId(
600
+ "Listing derived id",
601
+ listingId,
602
+ deriveListingId(parsed.pressing_id, currencyType, misoPressingPackageId),
603
+ );
539
604
  const p = parsed.price as {
540
605
  $kind?: string;
541
606
  Fixed?: { amount: string };
@@ -559,7 +624,7 @@ function parseListing(
559
624
  },
560
625
  state:
561
626
  variant(st, "Enabled", "Disabled") === "Enabled" ? "enabled" : "disabled",
562
- currencyType: currencyFromType(type),
627
+ currencyType,
563
628
  };
564
629
  }
565
630
 
@@ -592,16 +657,47 @@ export async function getSale(
592
657
  });
593
658
  const pressingObject = objects[0];
594
659
  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
- };
660
+ if (pressingObject instanceof Error && !isNotFound(pressingObject)) {
661
+ throw pressingObject;
662
+ }
663
+ if (listingObject instanceof Error && !isNotFound(listingObject)) {
664
+ throw listingObject;
665
+ }
666
+ const parsedPressing =
667
+ !pressingObject || pressingObject instanceof Error
668
+ ? null
669
+ : parseBatchPressing(pressingId, pressingObject.content, pressingObject.type, p.misoPressingPackageId);
670
+ const parsedListing =
671
+ !listingObject || listingObject instanceof Error
672
+ ? null
673
+ : parseBatchListing(listingId, listingObject.content, listingObject.type, p.misoPressingPackageId);
674
+ if (parsedPressing) requireId("Sale pressing release", parsedPressing.releaseId, p.releaseId);
675
+ if (parsedListing) {
676
+ requireId("Sale listing release", parsedListing.releaseId, p.releaseId);
677
+ requireId("Sale listing pressing", parsedListing.pressingId, pressingId);
678
+ if (parsedListing.currencyType !== normalizeStructTag(p.currencyType)) {
679
+ throw new Error(`Sale listing currency ${parsedListing.currencyType} does not match requested ${normalizeStructTag(p.currencyType)}`);
680
+ }
681
+ }
682
+ return { pressing: parsedPressing, listing: parsedListing };
683
+ }
684
+
685
+ function parseBatchPressing(
686
+ pressingId: string,
687
+ content: Uint8Array | undefined,
688
+ type: string | undefined,
689
+ misoPressingPackageId: string,
690
+ ): PressingView {
691
+ if (!content || !type) throw new Error(`Pressing ${pressingId} has no BCS content or full type`);
692
+ return parsePressing(pressingId, content, type, misoPressingPackageId);
693
+ }
694
+
695
+ function parseBatchListing(
696
+ listingId: string,
697
+ content: Uint8Array | undefined,
698
+ type: string | undefined,
699
+ misoPressingPackageId: string,
700
+ ): ListingView {
701
+ if (!content || !type) throw new Error(`Listing ${listingId} has no BCS content or full type`);
702
+ return parseListing(listingId, content, type, misoPressingPackageId);
607
703
  }
@@ -13,7 +13,7 @@
13
13
 
14
14
  import { resolveGenreNames } from "./genres.ts";
15
15
  import { getReleaseResources } from "./catalog.ts";
16
- import { getDrop } from "../drop.ts";
16
+ import { getPressing } from "../pressing.ts";
17
17
  import type { MisoClient } from "./client.ts";
18
18
  import type {
19
19
  ArtistProfile,
@@ -128,7 +128,7 @@ export async function getPartySummaries(
128
128
  /**
129
129
  * The party's pinned pressing, resolved through to its release and cover.
130
130
  * `null` — a successful empty — when nothing is pinned or the pin is dangling
131
- * (the pressing it named has since been superseded and destroyed).
131
+ * (the pressing id was invalid or was never opened).
132
132
  */
133
133
  async function resolveFeaturedRelease(
134
134
  client: MisoClient,
@@ -138,7 +138,7 @@ async function resolveFeaturedRelease(
138
138
  const pressingId = await client.sui.party.getFeaturedDrop(partyId);
139
139
  if (!pressingId) return null;
140
140
 
141
- const pressing = await getDrop(client.protocol, pressingId);
141
+ const pressing = await getPressing(client.protocol, pressingId, client.config.protocol.pressing);
142
142
  if (!pressing) return null;
143
143
 
144
144
  const [resources, entity] = await Promise.all([
@@ -6,11 +6,16 @@
6
6
  // callers get different answers, which is what makes this layer edge-cacheable.
7
7
  //
8
8
  // The composition of these reads is the point. A pressing page used to cost the
9
- // browser five sequential round-trips to the chain (drop → release → cover →
9
+ // browser five sequential round-trips to the chain (pressing → release → cover →
10
10
  // credits → recordings); the same work happens once here, inside one datacenter,
11
11
  // and every subsequent visitor is served from cache.
12
12
 
13
- import { getCurrentDrops, getDrop, type DropView } from "../drop.ts";
13
+ import {
14
+ getPressing,
15
+ getSale,
16
+ type ListingView as ContractListingView,
17
+ type PressingView as ContractPressingView,
18
+ } from "../pressing.ts";
14
19
  import {
15
20
  getReleaseCoversByIds,
16
21
  parseReleaseCoverContent,
@@ -29,7 +34,7 @@ import { getReleaseById, getReleasesByIds, isNotFound } from "@misonetwork/sdk";
29
34
  import type { Release } from "@misonetwork/sdk";
30
35
  import type { MisoClient } from "./client.ts";
31
36
  import { getRecordingTitles, parseReleaseObject } from "./works.ts";
32
- import { gte, int, ms, msOrNull, u64, u64OrNull } from "./internal/scalars.ts";
37
+ import { int, u64 } from "./internal/scalars.ts";
33
38
  import { quiltPatchId, u256ToB64Url } from "./internal/walrus.ts";
34
39
  import type {
35
40
  Cover,
@@ -37,12 +42,15 @@ import type {
37
42
  Credit,
38
43
  Currency,
39
44
  DiscoverItem,
40
- DropPreview,
45
+ ListingView,
41
46
  PressingDetail,
47
+ PressingPreview,
42
48
  PressingView,
43
49
  Price,
44
50
  RecordAlbum,
45
51
  ReleaseDetail,
52
+ SaleDetail,
53
+ SaleView,
46
54
  TrackCredits,
47
55
  TrackView,
48
56
  WorkState,
@@ -100,27 +108,45 @@ export function currencyInfo(type: string | null): Currency {
100
108
 
101
109
  // ── Projections ──────────────────────────────────────────────────────────────
102
110
 
103
- function toPressingView(drop: DropView): PressingView {
104
- const quantitySold = u64(drop.quantitySold);
105
- const maxSupply = u64OrNull(drop.maxSupply);
111
+ function toPressingView(pressing: ContractPressingView): PressingView {
112
+ return {
113
+ id: pressing.id,
114
+ releaseId: pressing.releaseId,
115
+ state:
116
+ pressing.state.kind === "scheduled"
117
+ ? {
118
+ kind: "scheduled",
119
+ startTimestampMs: Number(pressing.state.startTimestampMs ?? 0n),
120
+ }
121
+ : pressing.state.kind === "paused"
122
+ ? { kind: "paused" }
123
+ : { kind: "active" },
124
+ supply: u64(pressing.supply),
125
+ };
126
+ }
127
+
128
+ function toListingView(listing: ContractListingView): ListingView {
106
129
  const price: Price = {
107
- kind: drop.price.kind,
108
- amount: u64(drop.price.amount),
130
+ kind: listing.price.kind,
131
+ amount: u64(listing.price.amount),
109
132
  };
110
133
  return {
111
- id: drop.id,
112
- releaseId: drop.releaseId,
113
- edition: int(drop.edition),
134
+ id: listing.id,
135
+ pressingId: listing.pressingId,
136
+ releaseId: listing.releaseId,
114
137
  price,
115
- currency: currencyInfo(drop.currencyType),
116
- quantitySold,
117
- maxSupply,
118
- startTimestampMs: ms(drop.startTimestampMs),
119
- endTimestampMs: msOrNull(drop.endTimestampMs),
120
- soldOut: maxSupply !== null && gte(quantitySold, maxSupply),
138
+ currency: currencyInfo(listing.currencyType),
139
+ state: listing.state,
121
140
  };
122
141
  }
123
142
 
143
+ function toSaleView(
144
+ pressing: ContractPressingView,
145
+ listing: ContractListingView,
146
+ ): SaleView {
147
+ return { pressing: toPressingView(pressing), listing: toListingView(listing) };
148
+ }
149
+
124
150
  function toWorkState(state: Release["state"]): WorkState {
125
151
  return state.type === "Published"
126
152
  ? { type: "Published", timestampMs: state.timestampMs }
@@ -265,7 +291,7 @@ export async function getReleaseResources(
265
291
  * Identity (the release object) is HARD — a failure here is a failed read.
266
292
  * Decoration (cover, credits) is SOFT: a release with no cover extension set is a
267
293
  * normal state, not a broken page, so those reads swallow their errors. That
268
- * split is inherited from `lib/drops.ts` and is what keeps a half-configured
294
+ * split keeps a half-configured
269
295
  * release renderable.
270
296
  */
271
297
  export type ReleaseInclude = "trackCredits";
@@ -361,13 +387,13 @@ export async function getTrackCredits(
361
387
 
362
388
  // ── Pressing ─────────────────────────────────────────────────────────────────
363
389
 
364
- /** Everything the pressing buy page renders. `null` when no such pressing exists. */
390
+ /** Everything a Pressing page renders. `null` when no such Pressing exists. */
365
391
  export async function getPressingDetail(
366
392
  client: MisoClient,
367
393
  pressingId: string,
368
394
  options: GetReleaseOptions = {},
369
395
  ): Promise<PressingDetail | null> {
370
- const pressing = await getDrop(client.protocol, pressingId);
396
+ const pressing = await getPressing(client.protocol, pressingId, client.config.protocol.pressing);
371
397
  if (!pressing) return null;
372
398
  const release = await getReleaseDetail(client, pressing.releaseId, options);
373
399
  return { pressing: toPressingView(pressing), release };
@@ -375,15 +401,15 @@ export async function getPressingDetail(
375
401
 
376
402
  /**
377
403
  * The confirmation preview behind "paste a pressing id to pin it". Verifies the
378
- * object really is a `Drop` before spending reads on it — a release id or a
404
+ * object really is a `Pressing` before spending reads on it — a release id or a
379
405
  * record id pasted by mistake must come back as `null`, not as a half-built card.
380
406
  */
381
- export async function getDropPreview(
407
+ export async function getPressingPreview(
382
408
  client: MisoClient,
383
- dropId: string,
384
- ): Promise<DropPreview | null> {
385
- const pressing = await getDrop(client.protocol, dropId);
386
- if (!pressing?.currencyType) return null;
409
+ pressingId: string,
410
+ ): Promise<PressingPreview | null> {
411
+ const pressing = await getPressing(client.protocol, pressingId, client.config.protocol.pressing);
412
+ if (!pressing) return null;
387
413
 
388
414
  const { release, cover } = await getReleaseResources(
389
415
  client,
@@ -392,36 +418,65 @@ export async function getDropPreview(
392
418
  );
393
419
 
394
420
  return {
395
- pressingId: dropId,
396
- currency: currencyInfo(pressing.currencyType),
421
+ pressingId,
397
422
  title: release.title,
398
423
  subtitle: null,
399
424
  coverUrl: cover?.still.url ?? null,
400
- price: { kind: pressing.price.kind, amount: u64(pressing.price.amount) },
425
+ state: toPressingView(pressing).state,
426
+ supply: u64(pressing.supply),
401
427
  trackCount: release.tracks.length,
402
428
  };
403
429
  }
404
430
 
431
+ /**
432
+ * Everything a currency-specific buy page renders. The Listing is derived from
433
+ * the release's Pressing and the requested currency, never found through an old
434
+ * drop pointer.
435
+ */
436
+ export async function getSaleDetail(
437
+ client: MisoClient,
438
+ releaseId: string,
439
+ currencyType: string,
440
+ options: GetReleaseOptions = {},
441
+ ): Promise<SaleDetail | null> {
442
+ const sale = await getSale(client.protocol, {
443
+ releaseId,
444
+ currencyType,
445
+ misoPressingPackageId: client.config.protocol.pressing,
446
+ });
447
+ if (!sale.pressing || !sale.listing) return null;
448
+ const release = await getReleaseDetail(client, sale.pressing.releaseId, options);
449
+ return { sale: toSaleView(sale.pressing, sale.listing), release };
450
+ }
451
+
405
452
  // ── Discover ─────────────────────────────────────────────────────────────────
406
453
 
407
454
  /**
408
455
  * The records currently on sale.
409
456
  *
410
- * Configured by RELEASE id, never by drop id: a release id is permanent, while a
411
- * drop is superseded (and the old `Drop` destroyed) whenever a new edition opens.
412
- * Following the release's `CurrentDropKey` pointer keeps this list pointing at the
413
- * live edition without anyone touching the config.
457
+ * Configured by release + currency: Pressing and Listing ids are deterministic,
458
+ * permanent derived addresses. There is no `CurrentDropKey` pointer or edition
459
+ * replacement in the current ABI.
414
460
  */
415
461
  export async function getDiscoverShelf(
416
462
  client: MisoClient,
417
463
  ): Promise<DiscoverItem[]> {
418
- const configuredIds = [...client.config.discoverReleaseIds];
419
- const drops = await getCurrentDrops(
420
- client.protocol,
421
- configuredIds,
422
- client.config.protocol.drop,
464
+ const configuredSales = [...client.config.discoverSales];
465
+ const settled = await Promise.all(
466
+ configuredSales.map(async (configured) => ({
467
+ configured,
468
+ result: await getSale(client.protocol, {
469
+ ...configured,
470
+ misoPressingPackageId: client.config.protocol.pressing,
471
+ }),
472
+ })),
473
+ );
474
+ const available = settled.filter(
475
+ (item): item is typeof item & {
476
+ result: { pressing: ContractPressingView; listing: ContractListingView };
477
+ } => item.result.pressing !== null && item.result.listing !== null,
423
478
  );
424
- const releaseIds = configuredIds.filter((releaseId) => drops[releaseId]);
479
+ const releaseIds = [...new Set(available.map((item) => item.result.pressing.releaseId))];
425
480
  if (releaseIds.length === 0) return [];
426
481
 
427
482
  const [releases, coverViews, credits] = await Promise.all([
@@ -434,17 +489,17 @@ export async function getDiscoverShelf(
434
489
  ).catch(() => ({}) as Partial<Record<string, CreditView[]>>),
435
490
  ]);
436
491
 
437
- return releaseIds.flatMap((releaseId) => {
438
- const drop = drops[releaseId];
492
+ return available.flatMap(({ result }) => {
493
+ const releaseId = result.pressing.releaseId;
439
494
  const release = releases[releaseId];
440
- if (!drop || !release) return [];
495
+ if (!release) return [];
441
496
  const cover = toCover(
442
497
  client.config.walrusAggregatorUrl,
443
498
  coverViews[releaseId] ?? null,
444
499
  );
445
500
  return [
446
501
  {
447
- pressing: toPressingView(drop),
502
+ sale: toSaleView(result.pressing, result.listing),
448
503
  releaseId,
449
504
  title: release.title,
450
505
  artist: primaryArtistNames(toCredits(credits[releaseId] ?? null)).join(
@@ -27,6 +27,10 @@ import type { SuiClientRegistration } from "@mysten/sui/client";
27
27
  import { party, type PartyClient } from "@misonetwork/miso-party/client";
28
28
  import { misoConfig, networkFrom, type MisoConfig, type MisoConfigOverrides, type Network } from "./config.ts";
29
29
 
30
+ function definedOverrides<T extends object>(value: T): Partial<T> {
31
+ return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined)) as Partial<T>;
32
+ }
33
+
30
34
  /**
31
35
  * The structural slice of a Sui client the protocol SDK's read helpers want. They
32
36
  * declare `ClientWithCoreApi` against their own @mysten/sui; this alias names the
@@ -53,15 +57,27 @@ export interface MisoClient {
53
57
  export interface CreateMisoClientOptions extends MisoConfigOverrides {
54
58
  /** "testnet" | "mainnet". A bare string (e.g. a Worker's `NETWORK` var) is accepted. */
55
59
  network?: Network | string;
60
+ /** Complete verified configuration; required until a deployment is bundled. */
61
+ config?: MisoConfig;
56
62
  }
57
63
 
58
64
  /**
59
- * Build the client for a network. Endpoint overrides let a deployment point at a
60
- * private fullnode or an indexer without forking the config.
65
+ * Build the client from a complete verified configuration. The network-only
66
+ * shortcut remains for a future bundled deployment, but currently fails closed.
61
67
  */
62
68
  export function createMisoClient(options: CreateMisoClientOptions = {}): MisoClient {
63
- const { network, ...overrides } = options;
64
- const config = misoConfig(networkFrom(network), overrides);
69
+ const { network, config: providedConfig, ...overrides } = options;
70
+ const requestedNetwork = networkFrom(network);
71
+ // A caller-supplied verified deployment may still override transport URLs or
72
+ // the discover shelf; undefined fields never erase verified config values.
73
+ const config = providedConfig
74
+ ? { ...providedConfig, ...definedOverrides(overrides) }
75
+ : misoConfig(requestedNetwork, overrides);
76
+ if (network !== undefined && config.network !== requestedNetwork) {
77
+ throw new Error(
78
+ `@misofm/sdk/read: provided config is for ${config.network}, not ${requestedNetwork}.`,
79
+ );
80
+ }
65
81
 
66
82
  const grpc = new SuiGrpcClient({ baseUrl: config.grpcUrl, network: config.network });
67
83
  const graphqlRaw = new SuiGraphQLClient({ url: config.graphqlUrl, network: config.network });