@misofm/platform 0.22.1 → 0.24.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.
@@ -13,6 +13,7 @@
13
13
 
14
14
  import type { MisoDeployment } from "@misofm/protocol/deployments";
15
15
  import { getMisoPlatformDeployment, type RecordSalesDeployment } from "../deployments.ts";
16
+ import { walrusAggregatorUrl } from "../walrus.ts";
16
17
 
17
18
  export type Network = "testnet" | "mainnet";
18
19
 
@@ -33,6 +34,10 @@ export interface ProtocolIds {
33
34
  releaseKind: string;
34
35
  /** `recording_master_reference` — optional Walrus master pointers. */
35
36
  recordingMasterReference: string;
37
+ /** `recording_streaming_transcode` — the `miso-hls/v1` Quilt a track streams from, or null when the generation lacks it. */
38
+ recordingStreamingTranscode: string | null;
39
+ /** `recording_engine_session` — the Session V1 blob and stems a track mixes from, or null when the generation lacks it. */
40
+ recordingEngineSession: string | null;
36
41
  /** `composition_credits` / `recording_credits` / `release_credits` extensions. */
37
42
  compositionCredits: string;
38
43
  recordingCredits: string;
@@ -111,6 +116,8 @@ export function misoConfig(network: Network, overrides: MisoConfigOverrides = {}
111
116
  releaseCoverArt: platform.packages.releaseCoverArt,
112
117
  releaseKind: platform.packages.releaseKind,
113
118
  recordingMasterReference: platform.packages.recordingMasterReference,
119
+ recordingStreamingTranscode: platform.packages.recordingStreamingTranscode ?? null,
120
+ recordingEngineSession: platform.packages.recordingEngineSession ?? null,
114
121
  compositionCredits: platform.packages.compositionCredits,
115
122
  recordingCredits: platform.packages.recordingCredits,
116
123
  releaseCredits: platform.packages.releaseCredits,
@@ -123,7 +130,7 @@ export function misoConfig(network: Network, overrides: MisoConfigOverrides = {}
123
130
  },
124
131
  grpcUrl: "https://fullnode.testnet.sui.io",
125
132
  graphqlUrl: "https://graphql.testnet.sui.io/graphql",
126
- walrusAggregatorUrl: "https://aggregator.walrus-testnet.walrus.space",
133
+ walrusAggregatorUrl: walrusAggregatorUrl(network),
127
134
  apiBaseUrl: "https://api.testnet.miso.fm",
128
135
  discoverSales: [],
129
136
  };
package/src/read/types.ts CHANGED
@@ -74,8 +74,23 @@ export interface TrackView {
74
74
  splitBps: number;
75
75
  /** 1-based disc this track sits on. */
76
76
  disc: number;
77
- /** Base64url Walrus blob id for the master stream, when attached on-chain. */
77
+ /** Base64url Walrus blob id of the archival master, when attached on-chain. */
78
78
  masterBlobId?: string;
79
+ /**
80
+ * Base64url Walrus Quilt id of the `miso-hls/v1` streaming transcode, when
81
+ * attached on-chain. The playback key: `streamUrl(network, transcodeQuiltId)`.
82
+ */
83
+ transcodeQuiltId?: string;
84
+ /** The Miso Engine session attached on-chain, when present. */
85
+ engineSession?: TrackEngineSession;
86
+ }
87
+
88
+ /** A track's on-chain engine session: ids are base64url Walrus blob ids. */
89
+ export interface TrackEngineSession {
90
+ /** The canonical Session V1 JSON document. */
91
+ sessionBlobId: string;
92
+ /** One FLAC blob per session source, keyed by the source's canonical PCM digest (64 hex chars), sorted by digest. */
93
+ stems: { digest: string; blobId: string }[];
79
94
  }
80
95
 
81
96
  /** A release with everything a page renders: metadata, cover, credits, tracklist. */
@@ -241,6 +241,99 @@ export function unsetRecordingStreamingTranscode(
241
241
  };
242
242
  }
243
243
 
244
+ // ── Streaming-transcode reads ────────────────────────────────────────────────
245
+
246
+ // recording_streaming_transcode stores the ori::data::WalrusQuilt inline in a
247
+ // dynamic field on the Recording; its empty ExtensionKey serializes to one
248
+ // false byte, so the field id derives without listing dynamic fields.
249
+ const StreamingTranscodeField = bcs.struct("Field", {
250
+ id: bcs.Address,
251
+ name: streamingTranscode.ExtensionKey,
252
+ value: streamingTranscode.StreamingTranscode,
253
+ });
254
+ const STREAMING_TRANSCODE_KEY_BYTES = streamingTranscode.ExtensionKey.serialize([false]).toBytes();
255
+
256
+ /** Parse a streaming-transcode dynamic field into its Quilt id (decimal `u256`). */
257
+ export function parseRecordingStreamingTranscodeContent(content: Uint8Array): string {
258
+ return String(StreamingTranscodeField.parse(content).value.quilt.quilt_id);
259
+ }
260
+
261
+ /** Deterministic dynamic-field id for a Recording's streaming transcode. */
262
+ export function recordingStreamingTranscodeFieldId(
263
+ recordingId: string,
264
+ recordingStreamingTranscodePackageId: string,
265
+ ): string {
266
+ return deriveDynamicFieldID(
267
+ recordingId,
268
+ `${recordingStreamingTranscodePackageId}::recording_streaming_transcode::ExtensionKey`,
269
+ STREAMING_TRANSCODE_KEY_BYTES,
270
+ );
271
+ }
272
+
273
+ /** Read one Recording's streaming-transcode Quilt id, or null when absent. */
274
+ export async function getRecordingStreamingTranscode(
275
+ client: ClientWithCoreApi,
276
+ recordingId: string,
277
+ recordingStreamingTranscodePackageId: string,
278
+ ): Promise<string | null> {
279
+ return (
280
+ (
281
+ await getRecordingStreamingTranscodesByIds(
282
+ client,
283
+ [recordingId],
284
+ recordingStreamingTranscodePackageId,
285
+ )
286
+ )[recordingId] ?? null
287
+ );
288
+ }
289
+
290
+ /**
291
+ * Read streaming-transcode Quilt ids for many Recordings in one Core request.
292
+ * Missing and malformed fields are omitted, like master references.
293
+ */
294
+ export async function getRecordingStreamingTranscodesByIds(
295
+ client: ClientWithCoreApi,
296
+ recordingIdsInput: readonly string[],
297
+ recordingStreamingTranscodePackageId: string,
298
+ ): Promise<Partial<Record<string, string>>> {
299
+ return readSoftFields(
300
+ client,
301
+ recordingIdsInput,
302
+ (recordingId) => recordingStreamingTranscodeFieldId(recordingId, recordingStreamingTranscodePackageId),
303
+ parseRecordingStreamingTranscodeContent,
304
+ );
305
+ }
306
+
307
+ /**
308
+ * Fetch one derived dynamic field per Recording in a single Core request and
309
+ * parse each, dropping Recordings whose field is missing or malformed so one
310
+ * stale extension cannot take a whole tracklist down.
311
+ */
312
+ async function readSoftFields<T>(
313
+ client: ClientWithCoreApi,
314
+ recordingIdsInput: readonly string[],
315
+ fieldIdOf: (recordingId: string) => string,
316
+ parse: (content: Uint8Array) => T,
317
+ ): Promise<Partial<Record<string, T>>> {
318
+ const recordingIds = [...new Set(recordingIdsInput)];
319
+ if (recordingIds.length === 0) return {};
320
+ const { objects } = await client.core.getObjects({
321
+ objectIds: recordingIds.map(fieldIdOf),
322
+ include: { content: true },
323
+ });
324
+ const out: Partial<Record<string, T>> = {};
325
+ objects.forEach((object, index) => {
326
+ const recordingId = recordingIds[index];
327
+ if (!recordingId || object instanceof Error || !object.content) return;
328
+ try {
329
+ out[recordingId] = parse(object.content);
330
+ } catch {
331
+ // Extension metadata is soft: retain valid tracks when one field is stale.
332
+ }
333
+ });
334
+ return out;
335
+ }
336
+
244
337
  // ── Engine-session reads ─────────────────────────────────────────────────────
245
338
 
246
339
  /** A Recording's attached engine session, ids as decimal `u256` strings. */
@@ -308,6 +401,23 @@ export async function getRecordingEngineSession(
308
401
  return parseRecordingEngineSessionContent(field.content);
309
402
  }
310
403
 
404
+ /**
405
+ * Read engine sessions for many Recordings in one Core request. Missing and
406
+ * malformed fields are omitted.
407
+ */
408
+ export async function getRecordingEngineSessionsByIds(
409
+ client: ClientWithCoreApi,
410
+ recordingIdsInput: readonly string[],
411
+ recordingEngineSessionPackageId: string,
412
+ ): Promise<Partial<Record<string, RecordingEngineSessionView>>> {
413
+ return readSoftFields(
414
+ client,
415
+ recordingIdsInput,
416
+ (recordingId) => recordingEngineSessionFieldId(recordingId, recordingEngineSessionPackageId),
417
+ parseRecordingEngineSessionContent,
418
+ );
419
+ }
420
+
311
421
  // ── Master-reference reads ───────────────────────────────────────────────────
312
422
 
313
423
  // recording_master_reference stores the ori::data::WalrusBlob value inline in a
package/src/vault.ts CHANGED
@@ -734,17 +734,18 @@ export function redeemAllAndDistributeReleaseRevenue(
734
734
  readonly accumulatorRoot?: ObjectInput;
735
735
  },
736
736
  ): void {
737
- tx.add(
738
- releaseRevenueDistributorPlugin.redeemAllAndDistribute({
739
- package: params.pluginPackageId,
740
- typeArguments: [params.currencyType],
741
- arguments: [
742
- params.vault,
743
- params.release,
744
- object(tx, params.accumulatorRoot ?? SUI_ACCUMULATOR_ROOT_OBJECT_ID),
745
- ],
746
- }),
747
- );
737
+ // The generated binding resolves the chain-wide accumulator root itself, so it
738
+ // no longer accepts one. Call the target directly to keep honoring an explicit
739
+ // `accumulatorRoot` (a test fixture root) while the on-chain shape is unchanged.
740
+ tx.moveCall({
741
+ target: `${params.pluginPackageId}::release_revenue_distributor_plugin::redeem_all_and_distribute`,
742
+ typeArguments: [params.currencyType],
743
+ arguments: [
744
+ object(tx, params.vault),
745
+ params.release,
746
+ object(tx, params.accumulatorRoot ?? SUI_ACCUMULATOR_ROOT_OBJECT_ID),
747
+ ],
748
+ });
748
749
  }
749
750
 
750
751
  /** Convenience form of the fixed crank for a known Release object ID. */