@misofm/sdk 0.2.1 → 0.3.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 (82) hide show
  1. package/README.md +37 -5
  2. package/dist/contracts/miso_drop/drop.d.ts +550 -0
  3. package/dist/contracts/miso_drop/drop.d.ts.map +1 -0
  4. package/dist/contracts/miso_drop/drop.js +523 -0
  5. package/dist/contracts/miso_drop/drop.js.map +1 -0
  6. package/dist/contracts.d.ts +1 -0
  7. package/dist/contracts.d.ts.map +1 -1
  8. package/dist/contracts.js +3 -0
  9. package/dist/contracts.js.map +1 -1
  10. package/dist/drop.d.ts +120 -0
  11. package/dist/drop.d.ts.map +1 -0
  12. package/dist/drop.js +152 -0
  13. package/dist/drop.js.map +1 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +4 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/read/artist.d.ts +24 -0
  19. package/dist/read/artist.d.ts.map +1 -0
  20. package/dist/read/artist.js +114 -0
  21. package/dist/read/artist.js.map +1 -0
  22. package/dist/read/catalog.d.ts +63 -0
  23. package/dist/read/catalog.d.ts.map +1 -0
  24. package/dist/read/catalog.js +252 -0
  25. package/dist/read/catalog.js.map +1 -0
  26. package/dist/read/client.d.ts +36 -0
  27. package/dist/read/client.d.ts.map +1 -0
  28. package/dist/read/client.js +46 -0
  29. package/dist/read/client.js.map +1 -0
  30. package/dist/read/config.d.ts +83 -0
  31. package/dist/read/config.d.ts.map +1 -0
  32. package/dist/read/config.js +76 -0
  33. package/dist/read/config.js.map +1 -0
  34. package/dist/read/genres.d.ts +7 -0
  35. package/dist/read/genres.d.ts.map +1 -0
  36. package/dist/read/genres.js +38 -0
  37. package/dist/read/genres.js.map +1 -0
  38. package/dist/read/index.d.ts +12 -0
  39. package/dist/read/index.d.ts.map +1 -0
  40. package/dist/read/index.js +23 -0
  41. package/dist/read/index.js.map +1 -0
  42. package/dist/read/internal/scalars.d.ts +23 -0
  43. package/dist/read/internal/scalars.d.ts.map +1 -0
  44. package/dist/read/internal/scalars.js +56 -0
  45. package/dist/read/internal/scalars.js.map +1 -0
  46. package/dist/read/internal/walrus.d.ts +4 -0
  47. package/dist/read/internal/walrus.d.ts.map +1 -0
  48. package/dist/read/internal/walrus.js +23 -0
  49. package/dist/read/internal/walrus.js.map +1 -0
  50. package/dist/read/receipts.d.ts +22 -0
  51. package/dist/read/receipts.d.ts.map +1 -0
  52. package/dist/read/receipts.js +233 -0
  53. package/dist/read/receipts.js.map +1 -0
  54. package/dist/read/types.d.ts +279 -0
  55. package/dist/read/types.d.ts.map +1 -0
  56. package/dist/read/types.js +21 -0
  57. package/dist/read/types.js.map +1 -0
  58. package/dist/read/wallet.d.ts +58 -0
  59. package/dist/read/wallet.d.ts.map +1 -0
  60. package/dist/read/wallet.js +325 -0
  61. package/dist/read/wallet.js.map +1 -0
  62. package/dist/read/works.d.ts +31 -0
  63. package/dist/read/works.d.ts.map +1 -0
  64. package/dist/read/works.js +106 -0
  65. package/dist/read/works.js.map +1 -0
  66. package/package.json +15 -2
  67. package/src/contracts/miso_drop/drop.ts +798 -0
  68. package/src/contracts.ts +4 -0
  69. package/src/drop.ts +266 -0
  70. package/src/index.ts +5 -0
  71. package/src/read/artist.ts +136 -0
  72. package/src/read/catalog.ts +293 -0
  73. package/src/read/client.ts +79 -0
  74. package/src/read/config.ts +164 -0
  75. package/src/read/genres.ts +37 -0
  76. package/src/read/index.ts +53 -0
  77. package/src/read/internal/scalars.ts +57 -0
  78. package/src/read/internal/walrus.ts +32 -0
  79. package/src/read/receipts.ts +266 -0
  80. package/src/read/types.ts +361 -0
  81. package/src/read/wallet.ts +360 -0
  82. package/src/read/works.ts +164 -0
@@ -0,0 +1,23 @@
1
+ /** A u64/u128 as it may arrive off the wire, in BCS, or from a JSON projection. */
2
+ export type NumericLike = bigint | number | string | null | undefined;
3
+ /**
4
+ * Base-unit scalar → decimal string. Returns `"0"` for anything unreadable, which
5
+ * is the honest projection of "the chain gave us no number" for quantities and
6
+ * amounts. Use {@link u64OrNull} where absent must stay distinguishable from zero.
7
+ */
8
+ export declare function u64(v: NumericLike): string;
9
+ /** Base-unit scalar → decimal string, or `null` when absent/unparseable. */
10
+ export declare function u64OrNull(v: NumericLike): string | null;
11
+ /**
12
+ * A millisecond timestamp → `number`. Milliseconds stay numbers (they are far
13
+ * inside Number.MAX_SAFE_INTEGER and `new Date()` wants one), unlike token
14
+ * amounts which must not lose precision.
15
+ */
16
+ export declare function msOrNull(v: NumericLike): number | null;
17
+ /** As {@link msOrNull}, defaulting to `0` (the epoch) when absent. */
18
+ export declare function ms(v: NumericLike): number;
19
+ /** A plain integer field (bps, edition, counts) → `number`, defaulting to `0`. */
20
+ export declare function int(v: NumericLike): number;
21
+ /** Integer comparison over two decimal strings — `a >= b` without going through Number. */
22
+ export declare function gte(a: string, b: string): boolean;
23
+ //# sourceMappingURL=scalars.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scalars.d.ts","sourceRoot":"","sources":["../../../src/read/internal/scalars.ts"],"names":[],"mappings":"AAOA,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEtE;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAE1C;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAMvD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAKtD;AAED,sEAAsE;AACtE,wBAAgB,EAAE,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAEzC;AAED,kFAAkF;AAClF,wBAAgB,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAK1C;AAED,2FAA2F;AAC3F,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,56 @@
1
+ // Copyright (c) Miso Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ //
4
+ // The bigint→JSON boundary. Every u64/u128 the protocol SDKs hand back arrives as
5
+ // a `bigint`, which `JSON.stringify` throws on; these convert once, here, so no
6
+ // view type can carry one out of the SDK (see the header of ../types.ts).
7
+ /**
8
+ * Base-unit scalar → decimal string. Returns `"0"` for anything unreadable, which
9
+ * is the honest projection of "the chain gave us no number" for quantities and
10
+ * amounts. Use {@link u64OrNull} where absent must stay distinguishable from zero.
11
+ */
12
+ export function u64(v) {
13
+ return u64OrNull(v) ?? "0";
14
+ }
15
+ /** Base-unit scalar → decimal string, or `null` when absent/unparseable. */
16
+ export function u64OrNull(v) {
17
+ if (v == null)
18
+ return null;
19
+ if (typeof v === "bigint")
20
+ return v.toString();
21
+ if (typeof v === "number")
22
+ return Number.isFinite(v) ? BigInt(Math.trunc(v)).toString() : null;
23
+ const s = v.trim();
24
+ return /^\d+$/.test(s) ? BigInt(s).toString() : null;
25
+ }
26
+ /**
27
+ * A millisecond timestamp → `number`. Milliseconds stay numbers (they are far
28
+ * inside Number.MAX_SAFE_INTEGER and `new Date()` wants one), unlike token
29
+ * amounts which must not lose precision.
30
+ */
31
+ export function msOrNull(v) {
32
+ const s = u64OrNull(v);
33
+ if (s === null)
34
+ return null;
35
+ const n = Number(s);
36
+ return Number.isSafeInteger(n) ? n : null;
37
+ }
38
+ /** As {@link msOrNull}, defaulting to `0` (the epoch) when absent. */
39
+ export function ms(v) {
40
+ return msOrNull(v) ?? 0;
41
+ }
42
+ /** A plain integer field (bps, edition, counts) → `number`, defaulting to `0`. */
43
+ export function int(v) {
44
+ if (typeof v === "number" && Number.isFinite(v))
45
+ return Math.trunc(v);
46
+ if (typeof v === "bigint")
47
+ return Number(v);
48
+ if (typeof v === "string" && /^-?\d+$/.test(v.trim()))
49
+ return Number(v.trim());
50
+ return 0;
51
+ }
52
+ /** Integer comparison over two decimal strings — `a >= b` without going through Number. */
53
+ export function gte(a, b) {
54
+ return BigInt(a) >= BigInt(b);
55
+ }
56
+ //# sourceMappingURL=scalars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scalars.js","sourceRoot":"","sources":["../../../src/read/internal/scalars.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,sCAAsC;AACtC,EAAE;AACF,kFAAkF;AAClF,gFAAgF;AAChF,0EAA0E;AAK1E;;;;GAIG;AACH,MAAM,UAAU,GAAG,CAAC,CAAc;IAChC,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;AAC7B,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,SAAS,CAAC,CAAc;IACtC,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/C,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/F,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,CAAc;IACrC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,EAAE,CAAC,CAAc;IAC/B,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,GAAG,CAAC,CAAc;IAChC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtE,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/E,OAAO,CAAC,CAAC;AACX,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,CAAS;IACtC,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function u256ToB64Url(value: bigint | string): string;
2
+ /** Build Walrus's 37-byte quilt-patch id. All fields use BCS little-endian. */
3
+ export declare function quiltPatchId(quiltId: bigint | string, version: number, startIndex: number, endIndex: number): string;
4
+ //# sourceMappingURL=walrus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walrus.d.ts","sourceRoot":"","sources":["../../../src/read/internal/walrus.ts"],"names":[],"mappings":"AAYA,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAE3D;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CASR"}
@@ -0,0 +1,23 @@
1
+ // Copyright (c) Miso Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { bcs } from "@mysten/sui/bcs";
4
+ import { toBase64 } from "@mysten/sui/utils";
5
+ const u256 = bcs.u256();
6
+ function toBase64Url(bytes) {
7
+ return toBase64(bytes).replace(/=*$/, "").replaceAll("+", "-").replaceAll("/", "_");
8
+ }
9
+ export function u256ToB64Url(value) {
10
+ return toBase64Url(u256.serialize(BigInt(value)).toBytes());
11
+ }
12
+ /** Build Walrus's 37-byte quilt-patch id. All fields use BCS little-endian. */
13
+ export function quiltPatchId(quiltId, version, startIndex, endIndex) {
14
+ const bytes = new Uint8Array(37);
15
+ bytes.set(u256.serialize(BigInt(quiltId)).toBytes(), 0);
16
+ bytes[32] = version;
17
+ bytes[33] = startIndex & 0xff;
18
+ bytes[34] = (startIndex >> 8) & 0xff;
19
+ bytes[35] = endIndex & 0xff;
20
+ bytes[36] = (endIndex >> 8) & 0xff;
21
+ return toBase64Url(bytes);
22
+ }
23
+ //# sourceMappingURL=walrus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walrus.js","sourceRoot":"","sources":["../../../src/read/internal/walrus.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,sCAAsC;AAEtC,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;AAExB,SAAS,WAAW,CAAC,KAAiB;IACpC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAsB;IACjD,OAAO,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAC1B,OAAwB,EACxB,OAAe,EACf,UAAkB,EAClB,QAAgB;IAEhB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IACxD,KAAK,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAE,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IACnC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { MisoClient } from "./client.ts";
2
+ import type { PressingDetail, PurchaseReceipt, TrackRoyalty } from "./types.ts";
3
+ /** Composition royalty rate (bps) per recording id. Sparse — an unresolved parent has no entry. */
4
+ type CompositionRates = Record<string, number | undefined>;
5
+ /**
6
+ * Split `paid` across the release's tracks by their `splitBps`, then split each
7
+ * track's share between its composition and its recording. All BigInt — the same
8
+ * truncating integer math the on-chain royalty layer does, so the numbers shown
9
+ * are the numbers paid.
10
+ */
11
+ export declare function breakdown(tracks: PressingDetail["release"]["tracks"], paid: string, compositionRates: CompositionRates): TrackRoyalty[];
12
+ /**
13
+ * The receipt for `txDigest`, a purchase from `pressingId`.
14
+ *
15
+ * The sale and the pressing detail are fetched together — arriving from the buy
16
+ * button costs one round of work, not two. `null` when the pressing no longer
17
+ * exists (a superseded edition), which the caller renders as "not found" rather
18
+ * than as an error.
19
+ */
20
+ export declare function getPurchaseReceipt(client: MisoClient, pressingId: string, txDigest: string): Promise<PurchaseReceipt | null>;
21
+ export {};
22
+ //# sourceMappingURL=receipts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipts.d.ts","sourceRoot":"","sources":["../../src/read/receipts.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAc,YAAY,EAAE,MAAM,YAAY,CAAC;AAe5F,mGAAmG;AACnG,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAgK3D;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,EAC3C,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,gBAAgB,GACjC,YAAY,EAAE,CAgBhB;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAmBjC"}
@@ -0,0 +1,233 @@
1
+ // Copyright (c) Miso Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ //
4
+ // What one record sale actually was, read back from its transaction.
5
+ //
6
+ // The transaction digest is the receipt's identity: everything shown is
7
+ // re-derived from chain state, so a receipt link survives a refresh, a deep link,
8
+ // or a share to another device. `drop::buy` emits ONE `RecordSoldEvent` carrying
9
+ // the copy that was minted, its number in the run, and what the buyer paid.
10
+ //
11
+ // Two reads, in order, because a receipt is opened at two very different ages:
12
+ // fullnode the fresh path — usually the instant the transaction lands, possibly
13
+ // before this node has it, hence `waitForTransaction`.
14
+ // indexer the old path — GraphQL keeps transactions the fullnode has pruned.
15
+ // This is what makes a months-old receipt link still open.
16
+ //
17
+ // Where the money goes is PRESENTATIONAL, not a second on-chain fact: `buy`
18
+ // forwards the whole payment to the release's funds accumulator (there is no
19
+ // platform fee), and the royalty layer splits it downstream by the same terms this
20
+ // read walks. We show the buyer that arithmetic, in the same truncating integer
21
+ // math the chain does.
22
+ import * as dropContract from "../contracts/miso_drop/drop.js";
23
+ import { extractTypeParams2, getCompositionsByIds, } from "@misonetwork/sdk";
24
+ import { getPressingDetail } from "./catalog.js";
25
+ import { int, u64 } from "./internal/scalars.js";
26
+ import { getWorkAddressesByShareTypes } from "./works.js";
27
+ const BPS = 10000n;
28
+ /** `…::drop::RecordSoldEvent<Currency>` — the one event `drop::buy` emits. */
29
+ const RECORD_SOLD_EVENT = "::drop::RecordSoldEvent";
30
+ /**
31
+ * How long to wait for the fullnode to have the transaction before falling back
32
+ * to the indexer. Propagation is p95 ~330ms, so this only ever runs long for a
33
+ * digest the node genuinely doesn't have.
34
+ */
35
+ const FULLNODE_WAIT_MS = 5_000;
36
+ function coerceBigInt(v) {
37
+ if (typeof v === "bigint")
38
+ return v;
39
+ if (typeof v === "number" && Number.isFinite(v))
40
+ return BigInt(Math.trunc(v));
41
+ if (typeof v === "string" && /^\d+$/.test(v))
42
+ return BigInt(v);
43
+ return null;
44
+ }
45
+ /**
46
+ * The event's JSON projection — the fallback for transports that surface `json`
47
+ * but no BCS. Field names are the Move ones (snake_case).
48
+ */
49
+ function saleFromJson(json) {
50
+ const number = coerceBigInt(json.number);
51
+ const paid = coerceBigInt(json.paid);
52
+ const recordId = json.record_id;
53
+ if (number == null || paid == null || typeof recordId !== "string")
54
+ return null;
55
+ return {
56
+ dropId: typeof json.drop_id === "string" ? json.drop_id : "",
57
+ releaseId: typeof json.release_id === "string" ? json.release_id : "",
58
+ edition: int(coerceBigInt(json.edition) ?? 0n),
59
+ recordId,
60
+ number: number.toString(),
61
+ paid: paid.toString(),
62
+ buyer: typeof json.buyer === "string" ? json.buyer : "",
63
+ };
64
+ }
65
+ /**
66
+ * The sale a transaction recorded, or null if it emitted none. BCS is the stable
67
+ * shape (a JSON projection's field names vary by transport), so it is tried first.
68
+ */
69
+ function findSale(events) {
70
+ for (const e of events) {
71
+ if (!e.eventType.includes(RECORD_SOLD_EVENT))
72
+ continue;
73
+ try {
74
+ // The generated struct decodes addresses to 0x-hex and u64s to decimal strings.
75
+ const s = dropContract.RecordSoldEvent.parse(e.bcs);
76
+ return {
77
+ dropId: s.drop_id,
78
+ releaseId: s.release_id,
79
+ edition: int(s.edition),
80
+ recordId: s.record_id,
81
+ number: u64(s.number),
82
+ paid: u64(s.paid),
83
+ buyer: s.buyer,
84
+ };
85
+ }
86
+ catch {
87
+ // Unparseable BCS (or none surfaced) — fall through to the JSON view.
88
+ }
89
+ const fromJson = e.json && saleFromJson(e.json);
90
+ if (fromJson)
91
+ return fromJson;
92
+ }
93
+ return null;
94
+ }
95
+ /** The sale, read from the fullnode. */
96
+ async function saleFromFullnode(client, txDigest) {
97
+ const result = await client.sui.waitForTransaction({
98
+ digest: txDigest,
99
+ include: { events: true },
100
+ timeout: FULLNODE_WAIT_MS,
101
+ });
102
+ if (result.$kind !== "Transaction" || !result.Transaction.status.success) {
103
+ throw new Error(`Transaction did not succeed: ${txDigest}`);
104
+ }
105
+ const sale = findSale(result.Transaction.events);
106
+ if (!sale)
107
+ throw new Error(`No record purchase in transaction ${txDigest}`);
108
+ return sale;
109
+ }
110
+ const TX_EVENTS_QUERY = `query TransactionEvents($digest: String!) {
111
+ transaction(digest: $digest) {
112
+ effects {
113
+ status
114
+ events { nodes { contents { type { repr } json } } }
115
+ }
116
+ }
117
+ }`;
118
+ /** The sale, read from the GraphQL indexer — the path for a pruned transaction. */
119
+ async function saleFromIndexer(client, txDigest) {
120
+ const { data, errors } = await client.graphqlRaw.query({
121
+ query: TX_EVENTS_QUERY,
122
+ variables: { digest: txDigest },
123
+ });
124
+ if (errors?.length)
125
+ throw new Error(errors[0].message);
126
+ const effects = data?.transaction?.effects;
127
+ if (!effects)
128
+ throw new Error(`Transaction not found: ${txDigest}`);
129
+ if (effects.status !== "SUCCESS")
130
+ throw new Error(`Transaction did not succeed: ${txDigest}`);
131
+ for (const node of effects.events?.nodes ?? []) {
132
+ const contents = node.contents;
133
+ if (!contents?.type.repr.includes(RECORD_SOLD_EVENT))
134
+ continue;
135
+ const sale = typeof contents.json === "object" && contents.json !== null
136
+ ? saleFromJson(contents.json)
137
+ : null;
138
+ if (sale)
139
+ return sale;
140
+ }
141
+ throw new Error(`No record purchase in transaction ${txDigest}`);
142
+ }
143
+ /**
144
+ * Each recording's parent composition royalty rate, in basis points, keyed by
145
+ * recording id.
146
+ *
147
+ * A `Recording<RecordingShare, CompositionShare>` names its parent by SHARE TYPE,
148
+ * not by id, so the hop is: recording type tag → composition share type →
149
+ * (GraphQL) composition id → (Core) the composition's `royaltyRate`.
150
+ *
151
+ * Best-effort by design: any failure returns the rates resolved so far, and the
152
+ * receipt drops to a track-level breakdown rather than failing the whole page.
153
+ */
154
+ async function compositionRatesByRecording(client, recordingIds) {
155
+ if (recordingIds.length === 0)
156
+ return {};
157
+ const shareTypeByRecording = {};
158
+ const { objects } = await client.protocol.core.getObjects({ objectIds: [...new Set(recordingIds)] });
159
+ for (const obj of objects) {
160
+ if (obj instanceof Error || !obj.type)
161
+ continue;
162
+ try {
163
+ const [, compositionShareType] = extractTypeParams2(obj.type);
164
+ shareTypeByRecording[obj.objectId] = compositionShareType;
165
+ }
166
+ catch {
167
+ // A recording type we can't read the parent off — skip this track.
168
+ }
169
+ }
170
+ const shareTypes = Object.values(shareTypeByRecording);
171
+ if (shareTypes.length === 0)
172
+ return {};
173
+ const addresses = await getWorkAddressesByShareTypes(client.graphql, { compositions: shareTypes, recordings: [] }, client.config.protocol.miso);
174
+ const compositionIds = Object.values(addresses.compositions).filter((id) => !!id);
175
+ const compositions = await getCompositionsByIds(client.protocol, compositionIds);
176
+ const rates = {};
177
+ for (const [recordingId, shareType] of Object.entries(shareTypeByRecording)) {
178
+ const compositionId = addresses.compositions[shareType];
179
+ const composition = compositionId ? compositions[compositionId] : undefined;
180
+ if (composition)
181
+ rates[recordingId] = int(composition.royaltyRate.value);
182
+ }
183
+ return rates;
184
+ }
185
+ /**
186
+ * Split `paid` across the release's tracks by their `splitBps`, then split each
187
+ * track's share between its composition and its recording. All BigInt — the same
188
+ * truncating integer math the on-chain royalty layer does, so the numbers shown
189
+ * are the numbers paid.
190
+ */
191
+ export function breakdown(tracks, paid, compositionRates) {
192
+ const paidUnits = BigInt(paid);
193
+ return tracks.map((track) => {
194
+ const amount = (paidUnits * BigInt(track.splitBps)) / BPS;
195
+ const rate = compositionRates[track.recordingId];
196
+ const base = {
197
+ no: track.no,
198
+ title: track.title,
199
+ recordingId: track.recordingId,
200
+ splitBps: track.splitBps,
201
+ amount: amount.toString(),
202
+ };
203
+ if (rate == null)
204
+ return { ...base, composition: null, recording: null };
205
+ const composition = (amount * BigInt(rate)) / BPS;
206
+ return { ...base, composition: composition.toString(), recording: (amount - composition).toString() };
207
+ });
208
+ }
209
+ /**
210
+ * The receipt for `txDigest`, a purchase from `pressingId`.
211
+ *
212
+ * The sale and the pressing detail are fetched together — arriving from the buy
213
+ * button costs one round of work, not two. `null` when the pressing no longer
214
+ * exists (a superseded edition), which the caller renders as "not found" rather
215
+ * than as an error.
216
+ */
217
+ export async function getPurchaseReceipt(client, pressingId, txDigest) {
218
+ const [sale, detail] = await Promise.all([
219
+ saleFromFullnode(client, txDigest).catch(() => saleFromIndexer(client, txDigest)),
220
+ getPressingDetail(client, pressingId),
221
+ ]);
222
+ if (!detail)
223
+ return null;
224
+ // Best-effort: a failed composition lookup costs the sub-rows, not the page.
225
+ const rates = await compositionRatesByRecording(client, detail.release.tracks.map((t) => t.recordingId)).catch(() => ({}));
226
+ return {
227
+ sale,
228
+ detail,
229
+ price: detail.pressing.price.amount,
230
+ tracks: breakdown(detail.release.tracks, sale.paid, rates),
231
+ };
232
+ }
233
+ //# sourceMappingURL=receipts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipts.js","sourceRoot":"","sources":["../../src/read/receipts.ts"],"names":[],"mappings":"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"}