@misofm/sdk 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -9
- package/dist/client.d.ts +17 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +22 -3
- package/dist/client.js.map +1 -1
- package/dist/contracts/release_registry/release_registry.d.ts +114 -0
- package/dist/contracts/release_registry/release_registry.d.ts.map +1 -0
- package/dist/contracts/release_registry/release_registry.js +119 -0
- package/dist/contracts/release_registry/release_registry.js.map +1 -0
- package/dist/contracts/royalty_pool/pool.d.ts +28 -2
- package/dist/contracts/royalty_pool/pool.d.ts.map +1 -1
- package/dist/contracts/royalty_pool/pool.js +28 -2
- package/dist/contracts/royalty_pool/pool.js.map +1 -1
- package/dist/contracts/utils/index.d.ts +44 -0
- package/dist/contracts/utils/index.d.ts.map +1 -1
- package/dist/contracts/utils/index.js +104 -2
- package/dist/contracts/utils/index.js.map +1 -1
- package/dist/contracts.d.ts +1 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +4 -1
- package/dist/contracts.js.map +1 -1
- package/dist/cover.d.ts +3 -6
- package/dist/cover.d.ts.map +1 -1
- package/dist/cover.js +7 -16
- package/dist/cover.js.map +1 -1
- package/dist/credits.d.ts.map +1 -1
- package/dist/credits.js +17 -43
- package/dist/credits.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/read/catalog.d.ts +2 -12
- package/dist/read/catalog.d.ts.map +1 -1
- package/dist/read/catalog.js +9 -24
- package/dist/read/catalog.js.map +1 -1
- package/dist/read/config.d.ts +3 -8
- package/dist/read/config.d.ts.map +1 -1
- package/dist/read/config.js +15 -50
- package/dist/read/config.js.map +1 -1
- package/dist/read/index.d.ts +1 -1
- package/dist/read/index.d.ts.map +1 -1
- package/dist/read/index.js +1 -1
- package/dist/read/index.js.map +1 -1
- package/dist/read/types.d.ts +1 -1
- package/dist/read/types.d.ts.map +1 -1
- package/dist/read/wallet.d.ts +3 -7
- package/dist/read/wallet.d.ts.map +1 -1
- package/dist/read/wallet.js +11 -38
- package/dist/read/wallet.js.map +1 -1
- package/dist/read/works.d.ts +2 -5
- package/dist/read/works.d.ts.map +1 -1
- package/dist/read/works.js +7 -37
- package/dist/read/works.js.map +1 -1
- package/dist/release-graph.d.ts +6 -19
- package/dist/release-graph.d.ts.map +1 -1
- package/dist/release-graph.js +29 -43
- package/dist/release-graph.js.map +1 -1
- package/dist/transactions.d.ts +12 -28
- package/dist/transactions.d.ts.map +1 -1
- package/dist/transactions.js +23 -28
- package/dist/transactions.js.map +1 -1
- package/package.json +3 -3
- package/src/client.ts +33 -2
- package/src/contracts/release_registry/release_registry.ts +160 -0
- package/src/contracts/royalty_pool/pool.ts +28 -2
- package/src/contracts/utils/index.ts +156 -4
- package/src/contracts.ts +5 -1
- package/src/cover.ts +8 -19
- package/src/credits.ts +23 -63
- package/src/index.ts +3 -1
- package/src/read/catalog.ts +9 -29
- package/src/read/config.ts +18 -58
- package/src/read/index.ts +0 -1
- package/src/read/types.ts +1 -1
- package/src/read/wallet.ts +11 -37
- package/src/read/works.ts +5 -42
- package/src/release-graph.ts +40 -75
- package/src/transactions.ts +33 -62
package/src/credits.ts
CHANGED
|
@@ -605,9 +605,7 @@ const RELEASE_CREDITS_KEY_BYTES = releaseCredits.ExtensionKey.serialize([
|
|
|
605
605
|
|
|
606
606
|
type CreditFieldKind =
|
|
607
607
|
| "composition"
|
|
608
|
-
| "compositionLegacy"
|
|
609
608
|
| "recording"
|
|
610
|
-
| "recordingLegacy"
|
|
611
609
|
| "release";
|
|
612
610
|
|
|
613
611
|
interface CreditFieldTarget {
|
|
@@ -616,13 +614,7 @@ interface CreditFieldTarget {
|
|
|
616
614
|
fieldId: string;
|
|
617
615
|
}
|
|
618
616
|
|
|
619
|
-
/**
|
|
620
|
-
* Fetch many derived credit fields through one Core bulk request.
|
|
621
|
-
*
|
|
622
|
-
* Composition and recording extensions have one legacy key spelling. Both IDs
|
|
623
|
-
* ride in the same request, so fallback compatibility does not add a sequential
|
|
624
|
-
* round trip when the current key is absent.
|
|
625
|
-
*/
|
|
617
|
+
/** Fetch many derived credit fields through one Core bulk request. */
|
|
626
618
|
async function fetchCreditFields(
|
|
627
619
|
client: ClientWithCoreApi,
|
|
628
620
|
targets: readonly CreditFieldTarget[],
|
|
@@ -645,52 +637,30 @@ function compositionCreditTargets(
|
|
|
645
637
|
compositionIds: readonly string[],
|
|
646
638
|
packageId: string,
|
|
647
639
|
): CreditFieldTarget[] {
|
|
648
|
-
return compositionIds.
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
fieldId: deriveDynamicFieldID(
|
|
653
|
-
workId,
|
|
654
|
-
`${packageId}::composition_credits::ExtensionKey`,
|
|
655
|
-
COMPOSITION_CREDITS_KEY_BYTES,
|
|
656
|
-
),
|
|
657
|
-
},
|
|
658
|
-
{
|
|
640
|
+
return compositionIds.map((workId) => ({
|
|
641
|
+
workId,
|
|
642
|
+
kind: "composition" as const,
|
|
643
|
+
fieldId: deriveDynamicFieldID(
|
|
659
644
|
workId,
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
COMPOSITION_CREDITS_KEY_BYTES,
|
|
665
|
-
),
|
|
666
|
-
},
|
|
667
|
-
]);
|
|
645
|
+
`${packageId}::composition_credits::ExtensionKey`,
|
|
646
|
+
COMPOSITION_CREDITS_KEY_BYTES,
|
|
647
|
+
),
|
|
648
|
+
}));
|
|
668
649
|
}
|
|
669
650
|
|
|
670
651
|
function recordingCreditTargets(
|
|
671
652
|
recordingIds: readonly string[],
|
|
672
653
|
packageId: string,
|
|
673
654
|
): CreditFieldTarget[] {
|
|
674
|
-
return recordingIds.
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
fieldId: deriveDynamicFieldID(
|
|
679
|
-
workId,
|
|
680
|
-
`${packageId}::recording_credits::ExtensionKey`,
|
|
681
|
-
RECORDING_CREDITS_KEY_BYTES,
|
|
682
|
-
),
|
|
683
|
-
},
|
|
684
|
-
{
|
|
655
|
+
return recordingIds.map((workId) => ({
|
|
656
|
+
workId,
|
|
657
|
+
kind: "recording" as const,
|
|
658
|
+
fieldId: deriveDynamicFieldID(
|
|
685
659
|
workId,
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
RECORDING_CREDITS_KEY_BYTES,
|
|
691
|
-
),
|
|
692
|
-
},
|
|
693
|
-
]);
|
|
660
|
+
`${packageId}::recording_credits::ExtensionKey`,
|
|
661
|
+
RECORDING_CREDITS_KEY_BYTES,
|
|
662
|
+
),
|
|
663
|
+
}));
|
|
694
664
|
}
|
|
695
665
|
|
|
696
666
|
function releaseCreditTargets(
|
|
@@ -825,15 +795,10 @@ export async function getCompositionCreditsByIds(
|
|
|
825
795
|
);
|
|
826
796
|
const contents = await fetchCreditFields(client, targets);
|
|
827
797
|
const out: Partial<Record<string, CreditView[]>> = {};
|
|
828
|
-
for (const
|
|
829
|
-
const
|
|
830
|
-
(target) => target.workId === compositionId,
|
|
831
|
-
);
|
|
832
|
-
const content = candidates
|
|
833
|
-
.map((target) => contents.get(target.fieldId))
|
|
834
|
-
.find((value): value is Uint8Array => value !== undefined);
|
|
798
|
+
for (const target of targets) {
|
|
799
|
+
const content = contents.get(target.fieldId);
|
|
835
800
|
if (content) {
|
|
836
|
-
out[
|
|
801
|
+
out[target.workId] = creditViews(
|
|
837
802
|
CompositionCreditsField.parse(content).value.credits,
|
|
838
803
|
compositionRoleLabel,
|
|
839
804
|
);
|
|
@@ -875,16 +840,11 @@ export async function getRecordingCreditsByIds(
|
|
|
875
840
|
);
|
|
876
841
|
const contents = await fetchCreditFields(client, targets);
|
|
877
842
|
const out: Partial<Record<string, RecordingCreditsView>> = {};
|
|
878
|
-
for (const
|
|
879
|
-
const
|
|
880
|
-
(target) => target.workId === recordingId,
|
|
881
|
-
);
|
|
882
|
-
const content = candidates
|
|
883
|
-
.map((target) => contents.get(target.fieldId))
|
|
884
|
-
.find((value): value is Uint8Array => value !== undefined);
|
|
843
|
+
for (const target of targets) {
|
|
844
|
+
const content = contents.get(target.fieldId);
|
|
885
845
|
if (!content) continue;
|
|
886
846
|
const value = RecordingCreditsField.parse(content).value;
|
|
887
|
-
out[
|
|
847
|
+
out[target.workId] = {
|
|
888
848
|
credits: creditViews(value.credits, recordingRoleLabel),
|
|
889
849
|
primaryArtistIds: value.primary_artist_ids.contents,
|
|
890
850
|
featuredArtistIds: value.featured_artist_ids.contents,
|
package/src/index.ts
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
//
|
|
15
15
|
// A release is protocol. Pressing a record off it and selling that record is
|
|
16
16
|
// platform. Keeping the split at the package boundary is what stops the protocol
|
|
17
|
-
// from quietly growing a storefront.
|
|
17
|
+
// from quietly growing a storefront. Core's `release::new` is the sole practical
|
|
18
|
+
// exception: it needs `&mut UID`, which cannot cross a PTB command boundary, so
|
|
19
|
+
// the platform's `release_registry` extension owns the PTB-callable minting path.
|
|
18
20
|
//
|
|
19
21
|
// Extensions live on this side of the line for the same reason. An extension is
|
|
20
22
|
// not part of what a Composition or Recording IS — it is a choice Miso makes
|
package/src/read/catalog.ts
CHANGED
|
@@ -161,24 +161,16 @@ function toTracks(
|
|
|
161
161
|
|
|
162
162
|
// ── Cover ────────────────────────────────────────────────────────────────────
|
|
163
163
|
|
|
164
|
-
/**
|
|
165
|
-
* A release's cover, trying the current `release_cover_art` package and then each
|
|
166
|
-
* legacy one in turn.
|
|
167
|
-
*
|
|
168
|
-
* Covers set before the cover_art package split live under a different
|
|
169
|
-
* `CoverArtKey` TYPE (different package address), so a current-package read
|
|
170
|
-
* simply misses them rather than failing. Ported verbatim from miso-app's
|
|
171
|
-
* `lib/pressing.ts:readReleaseCover`.
|
|
172
|
-
*/
|
|
164
|
+
/** A release's cover from the configured `release_cover_art` package. */
|
|
173
165
|
export async function readReleaseCover(
|
|
174
166
|
client: MisoClient,
|
|
175
167
|
releaseId: string,
|
|
176
168
|
): Promise<Cover | null> {
|
|
177
|
-
const { releaseCoverArt
|
|
169
|
+
const { releaseCoverArt } = client.config.protocol;
|
|
178
170
|
const covers = await getReleaseCoversByIds(
|
|
179
171
|
client.protocol,
|
|
180
172
|
[releaseId],
|
|
181
|
-
|
|
173
|
+
releaseCoverArt,
|
|
182
174
|
).catch(() => ({}) as Partial<Record<string, ReleaseCoverView>>);
|
|
183
175
|
return toCover(client.config.walrusAggregatorUrl, covers[releaseId] ?? null);
|
|
184
176
|
}
|
|
@@ -203,15 +195,9 @@ export async function getReleaseResources(
|
|
|
203
195
|
): Promise<ReleaseResources> {
|
|
204
196
|
const wantsCover = include.includes("cover");
|
|
205
197
|
const wantsCredits = include.includes("credits");
|
|
206
|
-
const
|
|
207
|
-
? [
|
|
208
|
-
client.config.protocol.releaseCoverArt,
|
|
209
|
-
...client.config.protocol.legacyReleaseCoverArt,
|
|
210
|
-
]
|
|
198
|
+
const coverFieldIds = wantsCover
|
|
199
|
+
? [releaseCoverFieldId(releaseId, client.config.protocol.releaseCoverArt)]
|
|
211
200
|
: [];
|
|
212
|
-
const coverFieldIds = coverPackages.map((packageId) =>
|
|
213
|
-
releaseCoverFieldId(releaseId, packageId),
|
|
214
|
-
);
|
|
215
201
|
const creditsFieldId = wantsCredits
|
|
216
202
|
? releaseCreditsFieldId(releaseId, client.config.protocol.releaseCredits)
|
|
217
203
|
: null;
|
|
@@ -222,7 +208,7 @@ export async function getReleaseResources(
|
|
|
222
208
|
];
|
|
223
209
|
const { objects } = await client.protocol.core.getObjects({
|
|
224
210
|
objectIds,
|
|
225
|
-
include: { content: true
|
|
211
|
+
include: { content: true },
|
|
226
212
|
});
|
|
227
213
|
const releaseObject = objects[0];
|
|
228
214
|
if (!releaseObject) throw new Error(`Release not found: ${releaseId}`);
|
|
@@ -232,7 +218,6 @@ export async function getReleaseResources(
|
|
|
232
218
|
const release = parseReleaseObject(
|
|
233
219
|
releaseObject.objectId,
|
|
234
220
|
releaseObject.content,
|
|
235
|
-
releaseObject.json,
|
|
236
221
|
);
|
|
237
222
|
|
|
238
223
|
let cover: Cover | null | undefined;
|
|
@@ -440,10 +425,7 @@ export async function getDiscoverShelf(
|
|
|
440
425
|
|
|
441
426
|
const [releases, coverViews, credits] = await Promise.all([
|
|
442
427
|
getReleasesByIds(client.protocol, releaseIds),
|
|
443
|
-
getReleaseCoversByIds(client.protocol, releaseIds,
|
|
444
|
-
client.config.protocol.releaseCoverArt,
|
|
445
|
-
...client.config.protocol.legacyReleaseCoverArt,
|
|
446
|
-
]).catch(() => ({}) as Partial<Record<string, ReleaseCoverView>>),
|
|
428
|
+
getReleaseCoversByIds(client.protocol, releaseIds, client.config.protocol.releaseCoverArt).catch(() => ({}) as Partial<Record<string, ReleaseCoverView>>),
|
|
447
429
|
getReleaseCreditsByIds(
|
|
448
430
|
client.protocol,
|
|
449
431
|
releaseIds,
|
|
@@ -476,9 +458,7 @@ export async function getDiscoverShelf(
|
|
|
476
458
|
// ── Record → release ─────────────────────────────────────────────────────────
|
|
477
459
|
|
|
478
460
|
/**
|
|
479
|
-
* A record's parent release.
|
|
480
|
-
* checkout's `{ release_id, number }` and the SDK view's
|
|
481
|
-
* `{ release_id, edition, variant }` — so we probe both spellings.
|
|
461
|
+
* A record's parent release. Fresh `Record` objects expose `release_id`.
|
|
482
462
|
*
|
|
483
463
|
* This answer is IMMUTABLE for the life of the record, which is what lets the
|
|
484
464
|
* endpoint in front of it cache for a year.
|
|
@@ -500,7 +480,7 @@ export async function getRecordAlbum(
|
|
|
500
480
|
include: { json: true },
|
|
501
481
|
});
|
|
502
482
|
const json = (object?.json ?? {}) as Record<string, unknown>;
|
|
503
|
-
const raw = json.release_id
|
|
483
|
+
const raw = json.release_id;
|
|
504
484
|
const releaseId = typeof raw === "string" && raw ? raw : null;
|
|
505
485
|
const includeRelease =
|
|
506
486
|
options.include?.some(
|
package/src/read/config.ts
CHANGED
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
// `lib/money.ts`, `lib/drops.ts`) lives here instead, so a redeploy is a change
|
|
8
8
|
// in ONE file that every surface picks up.
|
|
9
9
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// silently reading testnet ids on a mainnet deployment.
|
|
10
|
+
// Both networks stay unavailable until the fresh protocol publish is configured;
|
|
11
|
+
// pre-launch has no compatibility lane for the old deployment.
|
|
13
12
|
|
|
14
13
|
export type Network = "testnet" | "mainnet";
|
|
15
14
|
|
|
@@ -24,17 +23,12 @@ export interface ProtocolIds {
|
|
|
24
23
|
miso: string;
|
|
25
24
|
/** `miso_drop` — `drop::buy` and the `Drop` objects the pressing pages read. */
|
|
26
25
|
drop: string;
|
|
26
|
+
/** `miso_record` package — the exact owner/type namespace for `record::Record`. */
|
|
27
|
+
record: string;
|
|
27
28
|
/** `miso_record` shared `Settings` object — the mint witness authorizer. */
|
|
28
29
|
recordSettings: string;
|
|
29
|
-
/** `release_cover_art` — the release cover extension
|
|
30
|
+
/** `release_cover_art` — the release cover extension. */
|
|
30
31
|
releaseCoverArt: string;
|
|
31
|
-
/**
|
|
32
|
-
* Cover-art packages from before the `cover_art` package split. A cover set
|
|
33
|
-
* under one of these is invisible to a current-package read, so cover reads
|
|
34
|
-
* fall back through this list in order. Drop an entry once every cover it
|
|
35
|
-
* holds has been re-set under `releaseCoverArt`.
|
|
36
|
-
*/
|
|
37
|
-
legacyReleaseCoverArt: readonly string[];
|
|
38
32
|
/** `composition_credits` / `recording_credits` / `release_credits` extensions. */
|
|
39
33
|
compositionCredits: string;
|
|
40
34
|
recordingCredits: string;
|
|
@@ -94,51 +88,17 @@ export interface MisoConfig {
|
|
|
94
88
|
discoverReleaseIds: readonly string[];
|
|
95
89
|
}
|
|
96
90
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
credit: "0x96c82da135bbd534850ca0a2445fdd2531dd4e0947ffa14645a2eb6636d83646",
|
|
109
|
-
},
|
|
110
|
-
party: {
|
|
111
|
-
partyPackageId: "0xd1c0253f837c57bd0a572673a28374e32c118059356e0c9db26784897175197e",
|
|
112
|
-
partyProfilePackageId: "0x6f8841bb252d3ba0f59f9027546be7a0e0a59d84757214df216eb14ef8a9719e",
|
|
113
|
-
countryCodePackageId: "0x6c3a53f228ccd089825d0fb5ee1f0465a4b7a438bc1b1735b4e2f01df8d056e9",
|
|
114
|
-
languageCodePackageId: "0xa18b786807cfc45488691f93aa647800b77cf9993e420d110afd7024c5b15948",
|
|
115
|
-
partyMediaPackageId: "0xc04dbdc05076f642fa8dc79257de9d45ee71fc8fee4a4fe1c05c6bb27e8982ee",
|
|
116
|
-
partyRolesPackageId: "0x18e6d59fe3a6496bd42273fd97e6e4b0ae7d3a8a876a6bbe4f6ae1b6057a6f38",
|
|
117
|
-
partyTagsPackageId: "0x5a5ed50aac1146b34490949ab33fd29dc2ba13ddf1b8f90b4797e67e1301609d",
|
|
118
|
-
partyGenrePackageId: "0x2d489291ce41392ae887e2e048f752a9bd6bea9f540b2c3d2356e36f0e624e29",
|
|
119
|
-
partyCtaPackageId: "0xbf4b04afa5b9c87b7385c6a1f116165a6e3f9bed3e16ea064fed7be4da14db7f",
|
|
120
|
-
partyPlatformLinkPackageId: "0x2bf95053493e640e3641abef2a9d6080ac563da62a5ca8e878e6d3459fdf27c8",
|
|
121
|
-
partySocialPackageId: "0x24bdc5f4cdf68d5cbd6f2b4b791f8b0311060a7fac7e54c10d3a101aa7d6b56d",
|
|
122
|
-
partyMusicPackageId: "0x40d8c48aa7cd8ade4ccfc7eb68de958403b08a897589934c191993b25961c453",
|
|
123
|
-
partyProLinkPackageId: "0xe2f0160eeac627378538b82209c2cd58b6a73827dae46f5f92368a6c7e84ee8d",
|
|
124
|
-
partyFeaturedDropPackageId: "0x5205a9f88702ed2dadd95e4d0096c691a40c96d8bb05d77127f1a62a6eb72cf7",
|
|
125
|
-
genrePackageId: "0x7ee69a2f1440152ecdacad997364fb28fe1fc140fd720e4c6d37ad78e29a376d",
|
|
126
|
-
},
|
|
127
|
-
money: {
|
|
128
|
-
usdCoinType: "0x77774cb7b8cb5622b4ef2658101bf5f1e965418297fe874b683df8f760b6e749::fakeusd::FakeUsd",
|
|
129
|
-
usdDecimals: 6,
|
|
130
|
-
},
|
|
131
|
-
grpcUrl: "https://fullnode.testnet.sui.io",
|
|
132
|
-
graphqlUrl: "https://graphql.testnet.sui.io/graphql",
|
|
133
|
-
walrusAggregatorUrl: "https://aggregator.walrus-testnet.walrus.space",
|
|
134
|
-
apiBaseUrl: "https://api.testnet.miso.fm",
|
|
135
|
-
discoverReleaseIds: [
|
|
136
|
-
// AMIANGELIKA — BLCK SUN
|
|
137
|
-
"0xa16e7ef7af5104690117321c749995db1164db668a5559cf6a0706b26141c327",
|
|
138
|
-
// Gateway Girl — Between the Doors
|
|
139
|
-
"0x7144600de3bb037f23b9371a2bcd5c0d84a80abc381a9d03b00ff7e03f412623",
|
|
140
|
-
],
|
|
141
|
-
};
|
|
91
|
+
// TODO(publish): replace this guard with a fresh `TESTNET: MisoConfig` after
|
|
92
|
+
// republishing every protocol package. Set every `protocol` package/object id
|
|
93
|
+
// from that publish; do not reuse any id from the retired deployment.
|
|
94
|
+
// TODO(publish): set `protocol.record` to the fresh `miso_record` package id;
|
|
95
|
+
// it is distinct from the `protocol.recordSettings` shared object id.
|
|
96
|
+
// TODO(publish): at the `ProtocolIds` declaration above, add `releaseRegistry`
|
|
97
|
+
// and `releaseRegistryId`; set the latter from
|
|
98
|
+
// `ReleaseRegistryCreatedEvent.registry_id` in the release_registry publish tx.
|
|
99
|
+
// TODO(publish): recreate Discover content under the fresh packages, then add
|
|
100
|
+
// only those release ids to `discoverReleaseIds`.
|
|
101
|
+
const TESTNET: MisoConfig | null = null;
|
|
142
102
|
|
|
143
103
|
/** Fields a deployment may override without forking the whole config (endpoints, shelf). */
|
|
144
104
|
export type MisoConfigOverrides = Partial<
|
|
@@ -150,9 +110,9 @@ export type MisoConfigOverrides = Partial<
|
|
|
150
110
|
* filled in here — a mainnet worker must fail loudly, never read testnet ids.
|
|
151
111
|
*/
|
|
152
112
|
export function misoConfig(network: Network, overrides: MisoConfigOverrides = {}): MisoConfig {
|
|
153
|
-
if (network === "mainnet") {
|
|
113
|
+
if (network === "mainnet" || !TESTNET) {
|
|
154
114
|
throw new Error(
|
|
155
|
-
"@misofm/sdk/read: no
|
|
115
|
+
"@misofm/sdk/read: no fresh deployment configuration yet. Publish the protocol packages, then fill in src/read/config.ts.",
|
|
156
116
|
);
|
|
157
117
|
}
|
|
158
118
|
return { ...TESTNET, ...stripUndefined(overrides) };
|
package/src/read/index.ts
CHANGED
package/src/read/types.ts
CHANGED
|
@@ -270,7 +270,7 @@ export interface PartySummary {
|
|
|
270
270
|
export interface OwnedRecord {
|
|
271
271
|
/** Canonical object id — the `recordId` route param. */
|
|
272
272
|
id: string;
|
|
273
|
-
/** Full on-chain type, e.g.
|
|
273
|
+
/** Full on-chain type, e.g. `<miso_record>::record::Record`. */
|
|
274
274
|
type: string;
|
|
275
275
|
releaseId: string | null;
|
|
276
276
|
/** Copy / edition number, when the struct exposes one. */
|
package/src/read/wallet.ts
CHANGED
|
@@ -32,9 +32,6 @@ import type {
|
|
|
32
32
|
} from "./types.ts";
|
|
33
33
|
import { getRecordingTitles, getWorkAddressesByShareTypes, getWorksByIds } from "./works.ts";
|
|
34
34
|
|
|
35
|
-
/** The on-chain type suffix every record object shares, across both live packages. */
|
|
36
|
-
export const RECORD_TYPE_SUFFIX = "::record::Record";
|
|
37
|
-
|
|
38
35
|
/**
|
|
39
36
|
* Page cap on the owned-objects scan, so a wallet holding a huge unrelated object
|
|
40
37
|
* set can't spin forever. 50/page × 20 = 1000 objects — far beyond any realistic
|
|
@@ -52,53 +49,29 @@ function coerceNumber(v: unknown): number | null {
|
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
/**
|
|
55
|
-
* This copy's number in its run
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* The gRPC JSON enum shape varies by transport, so this probes defensively.
|
|
59
|
-
*
|
|
60
|
-
* Precedence is MOST SPECIFIC FIRST — a top-level `number`, then the variant's
|
|
61
|
-
* `number`, and only then `edition`. miso-app's original
|
|
62
|
-
* (`lib/records.ts:readRecordNumber`) checked `edition` before descending into
|
|
63
|
-
* the variant, so an SDK-view record reported which EDITION it came from (2)
|
|
64
|
-
* where the field means which COPY it is (12). `edition` survives as the last
|
|
65
|
-
* resort for a layout that carries nothing better.
|
|
52
|
+
* This copy's number in its run. Fresh records expose the canonical
|
|
53
|
+
* `{ release_id, number }` shape; pre-publish layouts are intentionally not
|
|
54
|
+
* accepted by the pre-launch SDK.
|
|
66
55
|
*/
|
|
67
56
|
function readRecordNumber(json: Record<string, unknown>): number | null {
|
|
68
|
-
|
|
69
|
-
if (direct != null) return direct;
|
|
70
|
-
|
|
71
|
-
const variant = json.variant;
|
|
72
|
-
if (variant && typeof variant === "object") {
|
|
73
|
-
const v = variant as Record<string, unknown>;
|
|
74
|
-
const top = coerceNumber(v.number);
|
|
75
|
-
if (top != null) return top;
|
|
76
|
-
for (const inner of Object.values(v)) {
|
|
77
|
-
if (inner && typeof inner === "object") {
|
|
78
|
-
const n = coerceNumber((inner as Record<string, unknown>).number);
|
|
79
|
-
if (n != null) return n;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return coerceNumber(json.edition);
|
|
57
|
+
return coerceNumber(json.number);
|
|
84
58
|
}
|
|
85
59
|
|
|
86
60
|
function readReleaseId(json: Record<string, unknown>): string | null {
|
|
87
|
-
const r = json.release_id
|
|
61
|
+
const r = json.release_id;
|
|
88
62
|
return typeof r === "string" && r ? r : null;
|
|
89
63
|
}
|
|
90
64
|
|
|
91
65
|
/**
|
|
92
66
|
* The records `owner` holds. Ownership is DIRECT — a record is an address-owned
|
|
93
|
-
* `<
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* live, so we match the `::record::Record` SUFFIX client-side and catch both with
|
|
97
|
-
* no package-id config. Objects that fail to parse are skipped, never thrown.
|
|
67
|
+
* `<miso_record>::record::Record` with no pressing/license/receipt intermediary.
|
|
68
|
+
* The server-side type filter and exact local check deliberately exclude records
|
|
69
|
+
* from any retired package namespace.
|
|
98
70
|
*/
|
|
99
71
|
export async function getOwnedRecords(client: MisoClient, owner: string): Promise<OwnedRecord[]> {
|
|
100
72
|
const out: OwnedRecord[] = [];
|
|
101
73
|
let cursor: string | null = null;
|
|
74
|
+
const recordType = `${client.config.protocol.record}::record::Record`;
|
|
102
75
|
|
|
103
76
|
for (let page = 0; page < MAX_PAGES; page++) {
|
|
104
77
|
// Annotated: `cursor` is both an input and assigned from the result, which
|
|
@@ -106,12 +79,13 @@ export async function getOwnedRecords(client: MisoClient, owner: string): Promis
|
|
|
106
79
|
const res: Awaited<ReturnType<typeof client.protocol.core.listOwnedObjects>> =
|
|
107
80
|
await client.protocol.core.listOwnedObjects({
|
|
108
81
|
owner,
|
|
82
|
+
type: recordType,
|
|
109
83
|
cursor,
|
|
110
84
|
limit: 50,
|
|
111
85
|
include: { json: true },
|
|
112
86
|
});
|
|
113
87
|
for (const obj of res.objects) {
|
|
114
|
-
if (
|
|
88
|
+
if (obj.type !== recordType) continue;
|
|
115
89
|
const json = (obj.json ?? {}) as Record<string, unknown>;
|
|
116
90
|
out.push({
|
|
117
91
|
id: obj.objectId,
|
package/src/read/works.ts
CHANGED
|
@@ -179,31 +179,7 @@ function parseRecording(id: string, content: Uint8Array): Recording {
|
|
|
179
179
|
export function parseReleaseObject(
|
|
180
180
|
id: string,
|
|
181
181
|
content: Uint8Array,
|
|
182
|
-
json: unknown,
|
|
183
182
|
): Release {
|
|
184
|
-
const deployed = json as {
|
|
185
|
-
discs?: Parsed[];
|
|
186
|
-
state?: Parsed;
|
|
187
|
-
title?: unknown;
|
|
188
|
-
} | null;
|
|
189
|
-
if (deployed?.discs) {
|
|
190
|
-
const tracks = deployed.discs.flatMap((disc) => disc.tracks ?? []);
|
|
191
|
-
const publishedAt =
|
|
192
|
-
deployed.state?.["@variant"] === "Published" ? deployed.state.pos0 : null;
|
|
193
|
-
return {
|
|
194
|
-
id,
|
|
195
|
-
state:
|
|
196
|
-
publishedAt == null
|
|
197
|
-
? { type: "Initialized" }
|
|
198
|
-
: { type: "Published", timestampMs: Number(publishedAt) },
|
|
199
|
-
title: String(deployed.title ?? ""),
|
|
200
|
-
tracks: tracks.map((track) => ({
|
|
201
|
-
state: (track.state?.["@variant"] ?? "Unassigned") as TrackState,
|
|
202
|
-
recordingId: String(track.recording_id),
|
|
203
|
-
splitBps: { value: Number(track.split_bps?.pos0 ?? track.split_bps) },
|
|
204
|
-
})),
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
183
|
const value = contracts.release.Release.parse(content) as Parsed;
|
|
208
184
|
return {
|
|
209
185
|
id,
|
|
@@ -245,7 +221,7 @@ export async function getWorksByIds(
|
|
|
245
221
|
if (kinds.size === 0) return out;
|
|
246
222
|
const { objects } = await client.core.getObjects({
|
|
247
223
|
objectIds: [...kinds.keys()],
|
|
248
|
-
include: { content: true
|
|
224
|
+
include: { content: true },
|
|
249
225
|
});
|
|
250
226
|
for (const object of objects) {
|
|
251
227
|
if (object instanceof Error || !object.content) continue;
|
|
@@ -264,16 +240,12 @@ export async function getWorksByIds(
|
|
|
264
240
|
out.releases[object.objectId] = parseReleaseObject(
|
|
265
241
|
object.objectId,
|
|
266
242
|
object.content,
|
|
267
|
-
object.json,
|
|
268
243
|
);
|
|
269
244
|
}
|
|
270
245
|
return out;
|
|
271
246
|
}
|
|
272
247
|
|
|
273
|
-
/**
|
|
274
|
-
* Resolve display titles for both deployed recording layouts. Older recordings
|
|
275
|
-
* carry `title` in JSON; current recordings inherit it from their composition.
|
|
276
|
-
*/
|
|
248
|
+
/** Resolve recording titles through each recording's canonical composition type. */
|
|
277
249
|
export async function getRecordingTitles(
|
|
278
250
|
client: ClientWithCoreApi,
|
|
279
251
|
graphql: SuiGraphQLClient,
|
|
@@ -285,24 +257,15 @@ export async function getRecordingTitles(
|
|
|
285
257
|
|
|
286
258
|
const { objects } = await client.core.getObjects({
|
|
287
259
|
objectIds: ids,
|
|
288
|
-
include: {
|
|
260
|
+
include: {},
|
|
289
261
|
});
|
|
290
262
|
const titles: Record<string, string> = {};
|
|
291
263
|
const compositionShareByRecording: Record<string, string> = {};
|
|
292
264
|
|
|
293
265
|
for (const object of objects) {
|
|
294
266
|
if (object instanceof Error) continue;
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
titles[object.objectId] = json.title;
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
try {
|
|
301
|
-
const [, compositionShareType] = extractTypeParams2(object.type);
|
|
302
|
-
compositionShareByRecording[object.objectId] = compositionShareType;
|
|
303
|
-
} catch {
|
|
304
|
-
// A deployed layout with no composition type and no JSON title remains Untitled.
|
|
305
|
-
}
|
|
267
|
+
const [, compositionShareType] = extractTypeParams2(object.type);
|
|
268
|
+
compositionShareByRecording[object.objectId] = compositionShareType;
|
|
306
269
|
}
|
|
307
270
|
|
|
308
271
|
const compositionShareTypes = Object.values(compositionShareByRecording);
|