@misofm/platform 0.25.0 → 0.26.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.
- package/README.md +144 -45
- package/dist/auth.d.ts +8 -13
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +78 -59
- package/dist/auth.js.map +1 -1
- package/dist/catalog.d.ts +5 -5
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +33 -21
- package/dist/catalog.js.map +1 -1
- package/dist/client.d.ts +17 -30
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +53 -75
- package/dist/client.js.map +1 -1
- package/dist/cover.d.ts +4 -3
- package/dist/cover.d.ts.map +1 -1
- package/dist/cover.js +28 -17
- package/dist/cover.js.map +1 -1
- package/dist/credits.d.ts +12 -10
- package/dist/credits.d.ts.map +1 -1
- package/dist/credits.js +60 -33
- package/dist/credits.js.map +1 -1
- package/dist/deployments.d.ts +21 -13
- package/dist/deployments.d.ts.map +1 -1
- package/dist/deployments.js +84 -37
- package/dist/deployments.js.map +1 -1
- package/dist/errors.d.ts +91 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +111 -0
- package/dist/errors.js.map +1 -0
- package/dist/execute.d.ts +3 -1
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +9 -4
- package/dist/execute.js.map +1 -1
- package/dist/genre.d.ts +25 -41
- package/dist/genre.d.ts.map +1 -1
- package/dist/genre.js +71 -20
- package/dist/genre.js.map +1 -1
- package/dist/party/client.d.ts +16 -13
- package/dist/party/client.d.ts.map +1 -1
- package/dist/party/client.js +33 -22
- package/dist/party/client.js.map +1 -1
- package/dist/party/extensions/links.d.ts +2 -1
- package/dist/party/extensions/links.d.ts.map +1 -1
- package/dist/party/extensions/links.js +2 -1
- package/dist/party/extensions/links.js.map +1 -1
- package/dist/party/queries.d.ts +12 -11
- package/dist/party/queries.d.ts.map +1 -1
- package/dist/party/queries.js +63 -57
- package/dist/party/queries.js.map +1 -1
- package/dist/party/types.d.ts +31 -20
- package/dist/party/types.d.ts.map +1 -1
- package/dist/party/types.js +82 -1
- package/dist/party/types.js.map +1 -1
- package/dist/pressing.d.ts +55 -35
- package/dist/pressing.d.ts.map +1 -1
- package/dist/pressing.js +99 -76
- package/dist/pressing.js.map +1 -1
- package/dist/queries.d.ts +1 -1
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +5 -4
- package/dist/queries.js.map +1 -1
- package/dist/read/artist.d.ts +6 -4
- package/dist/read/artist.d.ts.map +1 -1
- package/dist/read/artist.js +29 -27
- package/dist/read/artist.js.map +1 -1
- package/dist/read/catalog.d.ts +20 -17
- package/dist/read/catalog.d.ts.map +1 -1
- package/dist/read/catalog.js +120 -141
- package/dist/read/catalog.js.map +1 -1
- package/dist/read/client.d.ts +10 -9
- package/dist/read/client.d.ts.map +1 -1
- package/dist/read/client.js.map +1 -1
- package/dist/read/genres.d.ts +5 -3
- package/dist/read/genres.d.ts.map +1 -1
- package/dist/read/genres.js +18 -15
- package/dist/read/genres.js.map +1 -1
- package/dist/read/index.d.ts.map +1 -1
- package/dist/read/index.js +7 -1
- package/dist/read/index.js.map +1 -1
- package/dist/read/receipts.d.ts +15 -6
- package/dist/read/receipts.d.ts.map +1 -1
- package/dist/read/receipts.js +73 -60
- package/dist/read/receipts.js.map +1 -1
- package/dist/read/wallet.d.ts +11 -9
- package/dist/read/wallet.d.ts.map +1 -1
- package/dist/read/wallet.js +117 -132
- package/dist/read/wallet.js.map +1 -1
- package/dist/read/works.d.ts +9 -16
- package/dist/read/works.d.ts.map +1 -1
- package/dist/read/works.js +48 -117
- package/dist/read/works.js.map +1 -1
- package/dist/recording-extensions.d.ts +8 -7
- package/dist/recording-extensions.d.ts.map +1 -1
- package/dist/recording-extensions.js +30 -63
- package/dist/recording-extensions.js.map +1 -1
- package/dist/release-extensions.d.ts +3 -2
- package/dist/release-extensions.d.ts.map +1 -1
- package/dist/release-extensions.js +9 -10
- package/dist/release-extensions.js.map +1 -1
- package/dist/royalty.d.ts +51 -51
- package/dist/royalty.d.ts.map +1 -1
- package/dist/royalty.js +93 -11
- package/dist/royalty.js.map +1 -1
- package/dist/share.d.ts +7 -6
- package/dist/share.d.ts.map +1 -1
- package/dist/share.js +37 -30
- package/dist/share.js.map +1 -1
- package/dist/vault.d.ts +20 -8
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js +31 -15
- package/dist/vault.js.map +1 -1
- package/package.json +11 -4
- package/src/auth.ts +89 -70
- package/src/catalog.ts +33 -49
- package/src/client.ts +117 -97
- package/src/cover.ts +17 -26
- package/src/credits.ts +43 -75
- package/src/deployments.ts +103 -69
- package/src/errors.ts +156 -0
- package/src/execute.ts +10 -6
- package/src/genre.ts +38 -23
- package/src/party/client.ts +35 -23
- package/src/party/extensions/links.ts +3 -2
- package/src/party/queries.ts +77 -65
- package/src/party/types.ts +52 -48
- package/src/pressing.ts +158 -161
- package/src/queries.ts +5 -5
- package/src/read/artist.ts +47 -42
- package/src/read/catalog.ts +200 -223
- package/src/read/client.ts +12 -11
- package/src/read/genres.ts +24 -16
- package/src/read/index.ts +7 -1
- package/src/read/receipts.ts +128 -67
- package/src/read/wallet.ts +194 -162
- package/src/read/works.ts +75 -194
- package/src/recording-extensions.ts +38 -92
- package/src/release-extensions.ts +7 -12
- package/src/royalty.ts +117 -20
- package/src/share.ts +44 -29
- package/src/vault.ts +47 -24
package/src/catalog.ts
CHANGED
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
// to fetch, and chooses a concurrency/rate-limit tradeoff. Those are platform
|
|
12
12
|
// calls, not protocol facts.
|
|
13
13
|
|
|
14
|
-
import
|
|
15
|
-
import type { SuiGraphQLClient } from "@mysten/sui/graphql";
|
|
14
|
+
import { Effect } from "effect";
|
|
16
15
|
import {
|
|
17
16
|
extractTypeParams2,
|
|
18
17
|
getOwnedRecordingAdminCaps,
|
|
19
18
|
getRecordingsByIds,
|
|
20
19
|
getReleaseById,
|
|
20
|
+
getWorkAddressesByShareTypes,
|
|
21
21
|
type Recording,
|
|
22
22
|
} from "@misofm/musicos";
|
|
23
|
-
import {
|
|
23
|
+
import { SuiClient, SuiGraphQL, SuiRpcError, type BcsDecodeError, type ObjectNotFoundError } from "@misofm/effect";
|
|
24
24
|
import {
|
|
25
25
|
getCompositionCreditsByIds,
|
|
26
26
|
getRecordingCreditsByIds,
|
|
@@ -58,42 +58,40 @@ const EMPTY_RECORDING_CREDITS: RecordingCreditsView = {
|
|
|
58
58
|
* are then resolved concurrently, deduplicated, and all composition credit
|
|
59
59
|
* fields are fetched concurrently as well.
|
|
60
60
|
*/
|
|
61
|
-
export
|
|
62
|
-
client: ClientWithCoreApi,
|
|
63
|
-
graphqlClient: SuiGraphQLClient,
|
|
61
|
+
export const getReleaseTrackCredits = Effect.fn("getReleaseTrackCredits")(function* (
|
|
64
62
|
releaseId: string,
|
|
65
63
|
options: GetReleaseTrackCreditsOptions,
|
|
66
|
-
):
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
): Effect.fn.Return<
|
|
65
|
+
Record<string, ReleaseTrackCredits>,
|
|
66
|
+
ObjectNotFoundError | SuiRpcError | BcsDecodeError,
|
|
67
|
+
SuiClient | SuiGraphQL
|
|
68
|
+
> {
|
|
69
|
+
const release = yield* getReleaseById(releaseId);
|
|
70
|
+
return yield* getTrackCreditsByRecordingIds(
|
|
71
71
|
release.tracks.map((track) => track.recordingId),
|
|
72
72
|
options,
|
|
73
73
|
);
|
|
74
|
-
}
|
|
74
|
+
});
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
77
|
* Composition and recording credits for the supplied recordings, keyed by
|
|
78
78
|
* recording id. This form is intended for consumers that already loaded a
|
|
79
79
|
* release and do not need to fetch it again.
|
|
80
80
|
*/
|
|
81
|
-
export
|
|
82
|
-
client: ClientWithCoreApi,
|
|
83
|
-
graphqlClient: SuiGraphQLClient,
|
|
81
|
+
export const getTrackCreditsByRecordingIds = Effect.fn("getTrackCreditsByRecordingIds")(function* (
|
|
84
82
|
recordingIdsInput: readonly string[],
|
|
85
83
|
options: GetReleaseTrackCreditsOptions,
|
|
86
|
-
):
|
|
84
|
+
): Effect.fn.Return<Record<string, ReleaseTrackCredits>, SuiRpcError | BcsDecodeError, SuiClient | SuiGraphQL> {
|
|
87
85
|
const recordingIds = [...new Set(recordingIdsInput)];
|
|
88
86
|
if (recordingIds.length === 0) return {};
|
|
89
87
|
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
const client = yield* SuiClient;
|
|
89
|
+
const [recordingCreditsById, recordingObjects] = yield* Effect.all([
|
|
90
|
+
getRecordingCreditsByIds(recordingIds, options.recordingCreditsPackageId),
|
|
91
|
+
Effect.tryPromise({
|
|
92
|
+
try: (signal) => client.core.getObjects({ objectIds: recordingIds, signal }),
|
|
93
|
+
catch: (cause) => new SuiRpcError({ operation: "getObjects", cause }),
|
|
94
|
+
}),
|
|
97
95
|
]);
|
|
98
96
|
const recordingReads = recordingObjects.objects.map((object, index) => {
|
|
99
97
|
const recordingId = recordingIds[index]!;
|
|
@@ -106,11 +104,8 @@ export async function getTrackCreditsByRecordingIds(
|
|
|
106
104
|
};
|
|
107
105
|
});
|
|
108
106
|
|
|
109
|
-
const compositionShareTypes = [
|
|
110
|
-
|
|
111
|
-
];
|
|
112
|
-
const addresses = await getWorkAddressesByShareTypes(
|
|
113
|
-
graphqlClient,
|
|
107
|
+
const compositionShareTypes = [...new Set(recordingReads.map((read) => read.compositionShareType))];
|
|
108
|
+
const addresses = yield* getWorkAddressesByShareTypes(
|
|
114
109
|
{ compositions: compositionShareTypes, recordings: [] },
|
|
115
110
|
options.misoPackageId,
|
|
116
111
|
);
|
|
@@ -120,14 +115,9 @@ export async function getTrackCreditsByRecordingIds(
|
|
|
120
115
|
}
|
|
121
116
|
}
|
|
122
117
|
const compositionIds = [
|
|
123
|
-
...new Set(
|
|
124
|
-
Object.values(addresses.compositions).filter(
|
|
125
|
-
(id): id is string => id !== undefined,
|
|
126
|
-
),
|
|
127
|
-
),
|
|
118
|
+
...new Set(Object.values(addresses.compositions).filter((id): id is string => id !== undefined)),
|
|
128
119
|
];
|
|
129
|
-
const compositionCreditsById =
|
|
130
|
-
client,
|
|
120
|
+
const compositionCreditsById = yield* getCompositionCreditsByIds(
|
|
131
121
|
compositionIds,
|
|
132
122
|
options.compositionCreditsPackageId,
|
|
133
123
|
);
|
|
@@ -144,7 +134,7 @@ export async function getTrackCreditsByRecordingIds(
|
|
|
144
134
|
];
|
|
145
135
|
}),
|
|
146
136
|
);
|
|
147
|
-
}
|
|
137
|
+
});
|
|
148
138
|
|
|
149
139
|
export interface GetAdministeredRecordingsOptions {
|
|
150
140
|
/**
|
|
@@ -160,30 +150,24 @@ export interface GetAdministeredRecordingsOptions {
|
|
|
160
150
|
* Three bounded stages: list the owner's `RecordingAdminCap`s, resolve every
|
|
161
151
|
* share type in one aliased GraphQL query, then batch-fetch the recordings.
|
|
162
152
|
*/
|
|
163
|
-
export
|
|
164
|
-
client: ClientWithCoreApi,
|
|
165
|
-
graphqlClient: SuiGraphQLClient,
|
|
153
|
+
export const getAdministeredRecordings = Effect.fn("getAdministeredRecordings")(function* (
|
|
166
154
|
owner: string,
|
|
167
155
|
misoPackageId: string,
|
|
168
156
|
options: GetAdministeredRecordingsOptions = {},
|
|
169
|
-
):
|
|
157
|
+
): Effect.fn.Return<Recording[], SuiRpcError | BcsDecodeError, SuiClient | SuiGraphQL> {
|
|
170
158
|
void options;
|
|
171
|
-
const caps =
|
|
159
|
+
const caps = yield* getOwnedRecordingAdminCaps(owner, misoPackageId);
|
|
172
160
|
if (caps.length === 0) return [];
|
|
173
|
-
const addresses =
|
|
174
|
-
graphqlClient,
|
|
161
|
+
const addresses = yield* getWorkAddressesByShareTypes(
|
|
175
162
|
{ compositions: [], recordings: caps.map((cap) => cap.shareType) },
|
|
176
163
|
misoPackageId,
|
|
177
164
|
);
|
|
178
|
-
const byId =
|
|
179
|
-
|
|
180
|
-
Object.values(addresses.recordings).filter(
|
|
181
|
-
(id): id is string => id !== undefined,
|
|
182
|
-
),
|
|
165
|
+
const byId = yield* getRecordingsByIds(
|
|
166
|
+
Object.values(addresses.recordings).filter((id): id is string => id !== undefined),
|
|
183
167
|
);
|
|
184
168
|
return caps.flatMap((cap) => {
|
|
185
169
|
const id = addresses.recordings[cap.shareType];
|
|
186
170
|
const recording = id ? byId[id] : undefined;
|
|
187
171
|
return recording ? [recording] : [];
|
|
188
172
|
});
|
|
189
|
-
}
|
|
173
|
+
});
|
package/src/client.ts
CHANGED
|
@@ -90,13 +90,13 @@ import {
|
|
|
90
90
|
} from "./pressing.ts";
|
|
91
91
|
import type {
|
|
92
92
|
GetSaleParams,
|
|
93
|
-
|
|
93
|
+
Listing,
|
|
94
94
|
OpenListingParams,
|
|
95
95
|
OpenPressingParams,
|
|
96
|
+
Pressing,
|
|
96
97
|
PressingAdministrationParams,
|
|
97
|
-
|
|
98
|
+
PressingRecord,
|
|
98
99
|
PurchaseRecordParams,
|
|
99
|
-
RecordView,
|
|
100
100
|
SetListingPriceParams,
|
|
101
101
|
SetListingStateParams,
|
|
102
102
|
} from "./pressing.ts";
|
|
@@ -165,6 +165,25 @@ import {
|
|
|
165
165
|
executeViaExecutor as executePlatformViaExecutor,
|
|
166
166
|
type PlatformExecResult,
|
|
167
167
|
} from "./execute.ts";
|
|
168
|
+
import { Effect } from "effect";
|
|
169
|
+
import {
|
|
170
|
+
SuiClient,
|
|
171
|
+
SuiRpcError,
|
|
172
|
+
type BcsDecodeError,
|
|
173
|
+
type ObjectTypeMismatchError,
|
|
174
|
+
type TransactionFailedError,
|
|
175
|
+
} from "@misofm/effect";
|
|
176
|
+
import {
|
|
177
|
+
MisoChainIdentifierMismatchError,
|
|
178
|
+
MisoClientNotReadyError,
|
|
179
|
+
MisoNetworkMismatchError,
|
|
180
|
+
} from "./errors.ts";
|
|
181
|
+
|
|
182
|
+
export {
|
|
183
|
+
MisoChainIdentifierMismatchError,
|
|
184
|
+
MisoClientNotReadyError,
|
|
185
|
+
MisoNetworkMismatchError,
|
|
186
|
+
} from "./errors.ts";
|
|
168
187
|
|
|
169
188
|
type BoundMoveFunction<F> = F extends (options: infer Options) => infer Result
|
|
170
189
|
? Options extends { package?: unknown }
|
|
@@ -243,39 +262,6 @@ export interface MisoOptions<Name extends string = "miso"> {
|
|
|
243
262
|
graphqlClient?: SuiGraphQLClient;
|
|
244
263
|
}
|
|
245
264
|
|
|
246
|
-
export class MisoNetworkMismatchError extends Error {
|
|
247
|
-
override readonly name = "MisoNetworkMismatchError";
|
|
248
|
-
constructor(
|
|
249
|
-
readonly clientNetwork: string,
|
|
250
|
-
readonly deploymentNetwork: string,
|
|
251
|
-
) {
|
|
252
|
-
super(
|
|
253
|
-
`@misofm/platform: client network "${clientNetwork}" does not match deployment network "${deploymentNetwork}"`,
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
export class MisoChainIdentifierMismatchError extends Error {
|
|
259
|
-
override readonly name = "MisoChainIdentifierMismatchError";
|
|
260
|
-
constructor(
|
|
261
|
-
readonly actual: string,
|
|
262
|
-
readonly expected: string,
|
|
263
|
-
) {
|
|
264
|
-
super(
|
|
265
|
-
`@misofm/platform: endpoint chain identifier "${actual}" does not match deployment chain identifier "${expected}"`,
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export class MisoClientNotReadyError extends Error {
|
|
271
|
-
override readonly name = "MisoClientNotReadyError";
|
|
272
|
-
constructor(readonly operation: string) {
|
|
273
|
-
super(
|
|
274
|
-
`@misofm/platform: ${operation} requires an exact-chain validation lifecycle; call and await client.miso.ready() first`,
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
265
|
export interface MisoPlatformConfig {
|
|
280
266
|
/** Exact client network label for deprecated `misoPlatform()` registration. */
|
|
281
267
|
network?: string;
|
|
@@ -411,7 +397,10 @@ export class MisoPlatformClient {
|
|
|
411
397
|
readonly deployment?: MisoPlatformDeployment;
|
|
412
398
|
#readyState: "unvalidated" | "validating" | "ready" | "failed" =
|
|
413
399
|
"unvalidated";
|
|
414
|
-
|
|
400
|
+
/** Set once in the constructor via `Effect.cached`, so every caller of
|
|
401
|
+
* `ready()` shares the same in-flight/completed chain read. */
|
|
402
|
+
readonly #readyEffect: Effect.Effect<void, MisoChainIdentifierMismatchError | SuiRpcError>;
|
|
403
|
+
readonly #layer: ReturnType<typeof SuiClient.layer>;
|
|
415
404
|
|
|
416
405
|
constructor(
|
|
417
406
|
client: ClientWithCoreApi,
|
|
@@ -451,6 +440,38 @@ export class MisoPlatformClient {
|
|
|
451
440
|
: undefined;
|
|
452
441
|
this.#chainIdentifier =
|
|
453
442
|
deploymentSnapshot?.chainIdentifier ?? configSnapshot.chainIdentifier;
|
|
443
|
+
this.#layer = SuiClient.layer(client);
|
|
444
|
+
// Built once; `Effect.cached` shares the same in-flight/completed chain
|
|
445
|
+
// read across every caller of `ready()` — the outer `Effect.cached(...)`
|
|
446
|
+
// itself only sets up the memoization ref, so running it synchronously
|
|
447
|
+
// here does not perform the underlying Core API read.
|
|
448
|
+
this.#readyEffect = Effect.runSync(
|
|
449
|
+
Effect.cached(
|
|
450
|
+
Effect.suspend(() => {
|
|
451
|
+
this.#readyState = "validating";
|
|
452
|
+
if (!this.#chainIdentifier) {
|
|
453
|
+
return Effect.die(
|
|
454
|
+
new Error(
|
|
455
|
+
"misoPlatform: chain readiness requires a complete deployment or an explicit `chainIdentifier`.",
|
|
456
|
+
),
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
const expected = this.#chainIdentifier;
|
|
460
|
+
return Effect.tryPromise({
|
|
461
|
+
try: (signal) => this.#client.core.getChainIdentifier({ signal }),
|
|
462
|
+
catch: (cause) => new SuiRpcError({ operation: "getChainIdentifier", cause }),
|
|
463
|
+
}).pipe(
|
|
464
|
+
Effect.flatMap(({ chainIdentifier }) =>
|
|
465
|
+
chainIdentifier === expected
|
|
466
|
+
? Effect.void
|
|
467
|
+
: new MisoChainIdentifierMismatchError({ actual: chainIdentifier, expected }),
|
|
468
|
+
),
|
|
469
|
+
Effect.tap(() => Effect.sync(() => { this.#readyState = "ready"; })),
|
|
470
|
+
Effect.tapError(() => Effect.sync(() => { this.#readyState = "failed"; })),
|
|
471
|
+
);
|
|
472
|
+
}),
|
|
473
|
+
),
|
|
474
|
+
);
|
|
454
475
|
}
|
|
455
476
|
|
|
456
477
|
/** Permissionless protocol APIs bound to the same validated ledger. */
|
|
@@ -465,38 +486,13 @@ export class MisoPlatformClient {
|
|
|
465
486
|
* synchronous network-label mismatch; this Core API read protects every
|
|
466
487
|
* client-bound write surface from a mislabeled or custom endpoint.
|
|
467
488
|
*/
|
|
468
|
-
ready():
|
|
469
|
-
|
|
470
|
-
this.#readyState = "validating";
|
|
471
|
-
this.#readyPromise = (async () => {
|
|
472
|
-
try {
|
|
473
|
-
if (!this.#chainIdentifier) {
|
|
474
|
-
throw new Error(
|
|
475
|
-
"misoPlatform: chain readiness requires a complete deployment or an explicit `chainIdentifier`.",
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
const { chainIdentifier } =
|
|
479
|
-
await this.#client.core.getChainIdentifier();
|
|
480
|
-
if (chainIdentifier !== this.#chainIdentifier) {
|
|
481
|
-
throw new MisoChainIdentifierMismatchError(
|
|
482
|
-
chainIdentifier,
|
|
483
|
-
this.#chainIdentifier,
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
this.#readyState = "ready";
|
|
487
|
-
} catch (error) {
|
|
488
|
-
this.#readyState = "failed";
|
|
489
|
-
throw error;
|
|
490
|
-
}
|
|
491
|
-
})();
|
|
492
|
-
}
|
|
493
|
-
return this.#readyPromise;
|
|
489
|
+
ready(): Effect.Effect<void, MisoChainIdentifierMismatchError | SuiRpcError> {
|
|
490
|
+
return this.#readyEffect;
|
|
494
491
|
}
|
|
495
492
|
|
|
496
|
-
/** Compatibility hook; prefer `
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
return this.#chainIdentifier!;
|
|
493
|
+
/** Compatibility hook; prefer `client.miso.ready()`. */
|
|
494
|
+
validateChainIdentifier(): Effect.Effect<string, MisoChainIdentifierMismatchError | SuiRpcError> {
|
|
495
|
+
return this.ready().pipe(Effect.map(() => this.#chainIdentifier!));
|
|
500
496
|
}
|
|
501
497
|
|
|
502
498
|
#requireReady(operation: string): void {
|
|
@@ -523,10 +519,23 @@ export class MisoPlatformClient {
|
|
|
523
519
|
this.#operations();
|
|
524
520
|
}
|
|
525
521
|
if (this.#readyState !== "ready") {
|
|
526
|
-
throw new MisoClientNotReadyError(operation);
|
|
522
|
+
throw new MisoClientNotReadyError({ operation });
|
|
527
523
|
}
|
|
528
524
|
}
|
|
529
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Runs the exact-ledger readiness gate, then provides `SuiClient` from this
|
|
528
|
+
* client's `ClientWithCoreApi`, so a read method's program has `R = never`.
|
|
529
|
+
*/
|
|
530
|
+
#run<A, E>(
|
|
531
|
+
effect: Effect.Effect<A, E, SuiClient>,
|
|
532
|
+
): Effect.Effect<A, E | MisoChainIdentifierMismatchError | SuiRpcError> {
|
|
533
|
+
return this.ready().pipe(
|
|
534
|
+
Effect.flatMap(() => effect),
|
|
535
|
+
Effect.provide(this.#layer),
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
|
|
530
539
|
/** Party identity and profile APIs, backed by the network SDK. */
|
|
531
540
|
get party(): PartyPlatformClient {
|
|
532
541
|
if (!this.#party) {
|
|
@@ -611,34 +620,47 @@ export class MisoPlatformClient {
|
|
|
611
620
|
// ── Reads ─────────────────────────────────────────────────────────────────
|
|
612
621
|
|
|
613
622
|
/** The run itself, or `null` if this release has never opened one. */
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
623
|
+
getPressing(
|
|
624
|
+
pressingId: string,
|
|
625
|
+
): Effect.Effect<
|
|
626
|
+
Pressing | null,
|
|
627
|
+
ObjectTypeMismatchError | BcsDecodeError | SuiRpcError | MisoChainIdentifierMismatchError
|
|
628
|
+
> {
|
|
629
|
+
return this.#run(getPressing(pressingId, this.recordPackageId));
|
|
617
630
|
}
|
|
618
631
|
|
|
619
632
|
/** One currency's offer, or `null` if the run does not sell in it. */
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
633
|
+
getListing(
|
|
634
|
+
listingId: string,
|
|
635
|
+
): Effect.Effect<
|
|
636
|
+
Listing | null,
|
|
637
|
+
ObjectTypeMismatchError | BcsDecodeError | SuiRpcError | MisoChainIdentifierMismatchError
|
|
638
|
+
> {
|
|
639
|
+
return this.#run(getListing(listingId, this.recordShopPackageId));
|
|
623
640
|
}
|
|
624
641
|
|
|
625
642
|
/** One concrete purchased Record, including immutable purchase provenance. */
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
643
|
+
getRecord(
|
|
644
|
+
recordId: string,
|
|
645
|
+
): Effect.Effect<
|
|
646
|
+
PressingRecord | null,
|
|
647
|
+
ObjectTypeMismatchError | BcsDecodeError | SuiRpcError | MisoChainIdentifierMismatchError
|
|
648
|
+
> {
|
|
649
|
+
return this.#run(getRecord(recordId, this.recordPackageId));
|
|
629
650
|
}
|
|
630
651
|
|
|
631
652
|
/** Run + one currency's offer in a single round trip, by address math. */
|
|
632
|
-
|
|
633
|
-
pressing:
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
653
|
+
getSale(p: Configured<GetSaleParams>): Effect.Effect<
|
|
654
|
+
{ pressing: Pressing | null; listing: Listing | null },
|
|
655
|
+
ObjectTypeMismatchError | BcsDecodeError | SuiRpcError | MisoChainIdentifierMismatchError
|
|
656
|
+
> {
|
|
657
|
+
return this.#run(
|
|
658
|
+
getSale({
|
|
659
|
+
...p,
|
|
660
|
+
recordPackageId: this.recordPackageId,
|
|
661
|
+
recordShopPackageId: this.recordShopPackageId,
|
|
662
|
+
}),
|
|
663
|
+
);
|
|
642
664
|
}
|
|
643
665
|
|
|
644
666
|
// ── Address math ──────────────────────────────────────────────────────────
|
|
@@ -898,21 +920,19 @@ export class MisoPlatformClient {
|
|
|
898
920
|
// ── Share currency provisioning (executes; Signer pattern) ─────────────────
|
|
899
921
|
|
|
900
922
|
/** Publishes + initializes a fresh share currency (two txs). */
|
|
901
|
-
|
|
923
|
+
createShareCurrency(
|
|
902
924
|
signer: Signer,
|
|
903
925
|
params: share.CreateShareCurrencyParams,
|
|
904
|
-
):
|
|
905
|
-
|
|
906
|
-
return share.createShareCurrency(this.#client, signer, params);
|
|
926
|
+
): Effect.Effect<share.ShareCurrency, SuiRpcError | TransactionFailedError | MisoChainIdentifierMismatchError> {
|
|
927
|
+
return this.#run(share.createShareCurrency(signer, params));
|
|
907
928
|
}
|
|
908
929
|
|
|
909
930
|
/** Execute a composed platform PTB only after exact-ledger validation. */
|
|
910
|
-
|
|
931
|
+
executeViaExecutor(
|
|
911
932
|
executor: ParallelTransactionExecutor,
|
|
912
933
|
...thunks: TxThunk[]
|
|
913
|
-
):
|
|
914
|
-
|
|
915
|
-
return executePlatformViaExecutor(executor, ...thunks);
|
|
934
|
+
): Effect.Effect<PlatformExecResult, SuiRpcError | MisoChainIdentifierMismatchError> {
|
|
935
|
+
return this.ready().pipe(Effect.flatMap(() => executePlatformViaExecutor(executor, ...thunks)));
|
|
916
936
|
}
|
|
917
937
|
|
|
918
938
|
// ── Generated layer ───────────────────────────────────────────────────────
|
|
@@ -1304,7 +1324,7 @@ export function miso<const Name extends string = "miso">(
|
|
|
1304
1324
|
options.deployment ?? getMisoPlatformDeployment(client.network),
|
|
1305
1325
|
);
|
|
1306
1326
|
if (deployment.network !== client.network) {
|
|
1307
|
-
throw new MisoNetworkMismatchError(client.network, deployment.network);
|
|
1327
|
+
throw new MisoNetworkMismatchError({ clientNetwork: client.network, deploymentNetwork: deployment.network });
|
|
1308
1328
|
}
|
|
1309
1329
|
const protocol = protocolMiso({
|
|
1310
1330
|
deployment: deployment.protocol,
|
|
@@ -1356,7 +1376,7 @@ export function misoPlatform(config: MisoPlatformConfig) {
|
|
|
1356
1376
|
register: (client: ClientWithCoreApi) => {
|
|
1357
1377
|
const configSnapshot = immutableSnapshot(config);
|
|
1358
1378
|
if (configSnapshot.network && configSnapshot.network !== client.network) {
|
|
1359
|
-
throw new MisoNetworkMismatchError(client.network, configSnapshot.network);
|
|
1379
|
+
throw new MisoNetworkMismatchError({ clientNetwork: client.network, deploymentNetwork: configSnapshot.network });
|
|
1360
1380
|
}
|
|
1361
1381
|
const protocol = configSnapshot.misoPackageId
|
|
1362
1382
|
? protocolMiso({
|
package/src/cover.ts
CHANGED
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
// opinion attached to it through the release's cap-gated `uid_mut` hook, which is
|
|
15
15
|
// why this module ships from `@misofm/platform` rather than the protocol SDK.
|
|
16
16
|
|
|
17
|
-
import type { ClientWithCoreApi } from "@mysten/sui/client";
|
|
18
17
|
import { bcs } from "@mysten/sui/bcs";
|
|
19
18
|
import { deriveDynamicFieldID } from "@mysten/sui/utils";
|
|
20
19
|
import type { Transaction, TransactionObjectArgument } from "@mysten/sui/transactions";
|
|
20
|
+
import { Effect } from "effect";
|
|
21
|
+
import { getObjectsContent, type SuiClient, type SuiRpcError } from "@misofm/effect";
|
|
21
22
|
import type { TxThunk } from "./transactions.ts";
|
|
22
23
|
import { asU64, directAdminCap, invokeWithAdminCap, type AdminCapAuthority, type ObjectInput, type U64Input } from "./vault.ts";
|
|
23
24
|
import { OPTION_NONE, OPTION_SOME, unencryptedWalrusBlob } from "./internal.ts";
|
|
@@ -149,17 +150,13 @@ function toCoverImageRef(blob: ParsedWalrusBlob): CoverImageRef {
|
|
|
149
150
|
* release, parses the `ReleaseCoverArt`, and returns the still (+ optional
|
|
150
151
|
* animation) as normalized Walrus refs for release displays.
|
|
151
152
|
*/
|
|
152
|
-
export
|
|
153
|
-
client: ClientWithCoreApi,
|
|
153
|
+
export const getReleaseCover = Effect.fn("getReleaseCover")(function* (
|
|
154
154
|
releaseId: string,
|
|
155
155
|
releaseCoverArtPackageId: string,
|
|
156
|
-
):
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)[releaseId] ?? null
|
|
161
|
-
);
|
|
162
|
-
}
|
|
156
|
+
): Effect.fn.Return<ReleaseCoverView | null, SuiRpcError, SuiClient> {
|
|
157
|
+
const found = yield* getReleaseCoversByIds([releaseId], releaseCoverArtPackageId);
|
|
158
|
+
return found[releaseId] ?? null;
|
|
159
|
+
});
|
|
163
160
|
|
|
164
161
|
export function parseReleaseCoverContent(
|
|
165
162
|
content: Uint8Array,
|
|
@@ -191,11 +188,10 @@ export function releaseCoverFieldId(
|
|
|
191
188
|
/**
|
|
192
189
|
* Read covers for many releases from the configured package in one Core request.
|
|
193
190
|
*/
|
|
194
|
-
export
|
|
195
|
-
client: ClientWithCoreApi,
|
|
191
|
+
export const getReleaseCoversByIds = Effect.fn("getReleaseCoversByIds")(function* (
|
|
196
192
|
releaseIdsInput: readonly string[],
|
|
197
193
|
releaseCoverArtPackageId: string,
|
|
198
|
-
):
|
|
194
|
+
): Effect.fn.Return<Partial<Record<string, ReleaseCoverView>>, SuiRpcError, SuiClient> {
|
|
199
195
|
const releaseIds = [...new Set(releaseIdsInput)];
|
|
200
196
|
const targets = releaseIds.map((releaseId) => ({
|
|
201
197
|
releaseId,
|
|
@@ -203,18 +199,13 @@ export async function getReleaseCoversByIds(
|
|
|
203
199
|
}));
|
|
204
200
|
if (targets.length === 0) return {};
|
|
205
201
|
|
|
206
|
-
const
|
|
207
|
-
objectIds: targets.map((target) => target.fieldId),
|
|
208
|
-
include: { content: true },
|
|
209
|
-
});
|
|
202
|
+
const contentById = yield* getObjectsContent(targets.map((target) => target.fieldId));
|
|
210
203
|
const out: Partial<Record<string, ReleaseCoverView>> = {};
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
if (!
|
|
214
|
-
const cover = parseReleaseCoverContent(
|
|
215
|
-
if (cover)
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
});
|
|
204
|
+
for (const target of targets) {
|
|
205
|
+
const found = contentById.get(target.fieldId);
|
|
206
|
+
if (!found) continue;
|
|
207
|
+
const cover = parseReleaseCoverContent(found.content);
|
|
208
|
+
if (cover) out[target.releaseId] = cover;
|
|
209
|
+
}
|
|
219
210
|
return out;
|
|
220
|
-
}
|
|
211
|
+
});
|