@misofm/platform 0.19.0 → 0.20.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/src/cover.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  // Release cover art. A cover is a still image (optionally an animation) stored as
5
- // a Walrus blob and referenced on-chain via `ori::WalrusData`. We build the ref
6
- // (`ori::walrus_data::new_blob`, a raw call — ori is an external dep), wrap it in a
7
- // `cover_art::CoverArt`, and attach it to the Release with
5
+ // a Walrus blob and referenced on-chain via `ori::data::WalrusBlob`. We build the
6
+ // plaintext ref (`ori::data::new_blob`, a raw call — ori is an external dep), wrap
7
+ // it in a `cover_art::CoverArt`, and attach it to the Release with
8
8
  // `release_cover_art::set_cover` (gated by the ReleaseAdminCap).
9
9
  //
10
10
  // Blob ids are passed as `u256` (decimal string or bigint) — the CLI converts the
@@ -20,7 +20,7 @@ import { deriveDynamicFieldID } from "@mysten/sui/utils";
20
20
  import type { Transaction, TransactionObjectArgument } from "@mysten/sui/transactions";
21
21
  import type { TxThunk } from "./transactions.ts";
22
22
  import { asU64, directAdminCap, invokeWithAdminCap, type AdminCapAuthority, type ObjectInput, type U64Input } from "./vault.ts";
23
- import { OPTION_NONE, OPTION_SOME } from "./internal.ts";
23
+ import { OPTION_NONE, OPTION_SOME, unencryptedWalrusBlob } from "./internal.ts";
24
24
  import * as coverArt from "@misofm/protocol/contracts/cover_art/cover_art";
25
25
  import * as releaseCoverArt from "@misofm/protocol/contracts/release_cover_art/release_cover_art";
26
26
 
@@ -44,7 +44,7 @@ interface SetReleaseCoverParamsBase {
44
44
  coverArtPackageId: string;
45
45
  /** `release_cover_art` package — home of the `set_cover` extension entry point. */
46
46
  releaseCoverArtPackageId: string;
47
- /** `ori` package (home of `walrus_data::new_blob` / the `WalrusData` type). */
47
+ /** `ori` package (home of `data::new_blob` / the `WalrusBlob` type). */
48
48
  oriPackageId: string;
49
49
  }
50
50
 
@@ -59,12 +59,8 @@ export type SetReleaseTrackCoverParams = SetReleaseCoverParams & {
59
59
  };
60
60
 
61
61
  function buildCover(tx: Parameters<TxThunk>[0], p: SetReleaseCoverParams) {
62
- const walrusType = `${p.oriPackageId}::walrus_data::WalrusData`;
63
- const blob = (id: bigint | string) =>
64
- tx.moveCall({
65
- target: `${p.oriPackageId}::walrus_data::new_blob`,
66
- arguments: [tx.pure.u256(id)],
67
- });
62
+ const walrusType = `${p.oriPackageId}::data::WalrusBlob`;
63
+ const blob = (id: bigint | string) => unencryptedWalrusBlob(tx, p.oriPackageId, id);
68
64
 
69
65
  const still = blob(p.stillBlobId);
70
66
  const animated =
@@ -113,17 +109,12 @@ export function setReleaseTrackCover(p: SetReleaseTrackCoverParams): TxThunk {
113
109
  /**
114
110
  * A normalized reference to a cover image's Walrus data. Blob ids are returned as
115
111
  * `u256` decimal strings (the on-chain form); callers convert to a base64url
116
- * aggregator URL with `@unconfirmed/ori` (`u256ToB64Url` / `walrusDataUrl`).
112
+ * aggregator URL with `@unconfirmed/ori` (`u256ToB64Url` / `walrusBlobUrl`).
113
+ *
114
+ * The current `cover_art` generation stores standalone `ori::data::WalrusBlob`
115
+ * values only, so every cover image is a `blob` reference.
117
116
  */
118
- export type CoverImageRef =
119
- | { kind: "blob"; blobId: string }
120
- | {
121
- kind: "quiltPatch";
122
- quiltId: string;
123
- version: number;
124
- startIndex: number;
125
- endIndex: number;
126
- };
117
+ export type CoverImageRef = { kind: "blob"; blobId: string };
127
118
 
128
119
  /** A release's album-level cover: a still image and an optional animation. */
129
120
  export interface ReleaseCoverView {
@@ -143,24 +134,13 @@ const COVER_ART_KEY_BYTES = releaseCoverArt.ExtensionKey.serialize([
143
134
  false,
144
135
  ]).toBytes();
145
136
 
146
- /** A parsed `ori::WalrusData` value (a MoveEnum: `Blob` or `QuiltPatch`). */
147
- type ParsedWalrusData =
148
- | { $kind: "Blob"; Blob: [string | number | bigint, unknown] }
149
- | {
150
- $kind: "QuiltPatch";
151
- QuiltPatch: [string | number | bigint, number, number, number];
152
- };
153
-
154
- function toCoverImageRef(wd: ParsedWalrusData): CoverImageRef {
155
- if (wd.$kind === "Blob") return { kind: "blob", blobId: String(wd.Blob[0]) };
156
- const [quiltId, version, startIndex, endIndex] = wd.QuiltPatch;
157
- return {
158
- kind: "quiltPatch",
159
- quiltId: String(quiltId),
160
- version,
161
- startIndex,
162
- endIndex,
163
- };
137
+ /** A parsed `ori::data::WalrusBlob` value. */
138
+ interface ParsedWalrusBlob {
139
+ blob_id: string | number | bigint;
140
+ }
141
+
142
+ function toCoverImageRef(blob: ParsedWalrusBlob): CoverImageRef {
143
+ return { kind: "blob", blobId: String(blob.blob_id) };
164
144
  }
165
145
 
166
146
  /**
@@ -185,8 +165,8 @@ export function parseReleaseCoverContent(
185
165
  content: Uint8Array,
186
166
  ): ReleaseCoverView | null {
187
167
  const cover = CoverArtField.parse(content).value.cover as {
188
- still: ParsedWalrusData;
189
- animated: ParsedWalrusData | null;
168
+ still: ParsedWalrusBlob;
169
+ animated: ParsedWalrusBlob | null;
190
170
  } | null;
191
171
  if (!cover) return null;
192
172
 
@@ -216,11 +216,11 @@ export interface MisoPlatformDeployment {
216
216
  readonly recordingMasterReference: string;
217
217
  /** Complete Walrus Quilt containing the Recording's streaming transcodes. */
218
218
  readonly recordingStreamingTranscode?: string;
219
- /** Canonical plaintext session pointer extension; absent before publication. */
219
+ /** Unencrypted Walrus blob of a Recording's Miso Engine session file; absent before publication. */
220
220
  readonly recordingEngineSession?: string;
221
221
  /** Original immutable Record-gated Seal policy; absent before publication. */
222
222
  readonly recordSealPolicy?: string;
223
- /** External `ori::walrus_data::WalrusData` dependency used by cover art. */
223
+ /** External `ori` package (`data::WalrusBlob`, `data::WalrusQuilt`) used by Walrus-backed extensions. */
224
224
  readonly ori: string;
225
225
  };
226
226
  readonly objects: {
package/src/internal.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  // Internal shared helpers (deliberately NOT exported from the package root).
5
+
6
+ import type { Transaction, TransactionArgument } from "@mysten/sui/transactions";
5
7
  //
6
8
  // PTB building blocks — the `0x1::option` move-call targets used when a generated
7
9
  // call needs an `Option` argument built inline. Consumed by `./cover` and
@@ -18,6 +20,29 @@
18
20
  export const OPTION_NONE = "0x1::option::none";
19
21
  export const OPTION_SOME = "0x1::option::some";
20
22
 
23
+ /**
24
+ * Build a plaintext `ori::data::WalrusBlob` in the PTB: `confidentiality::new_unencrypted()`
25
+ * followed by `data::new_blob(blob_id, confidentiality)`. `ori` is an external
26
+ * dependency, so these are raw calls against the deployment's `ori` package.
27
+ *
28
+ * Every platform extension that stores a standalone blob (cover art, master
29
+ * reference, engine session) builds its reference here so the ori ABI is pinned
30
+ * in exactly one place.
31
+ */
32
+ export function unencryptedWalrusBlob(
33
+ tx: Transaction,
34
+ oriPackageId: string,
35
+ blobId: bigint | string,
36
+ ): TransactionArgument {
37
+ const confidentiality = tx.moveCall({
38
+ target: `${oriPackageId}::confidentiality::new_unencrypted`,
39
+ });
40
+ return tx.moveCall({
41
+ target: `${oriPackageId}::data::new_blob`,
42
+ arguments: [tx.pure.u256(blobId), confidentiality],
43
+ });
44
+ }
45
+
21
46
  /**
22
47
  * Clone arrays and plain records recursively, then freeze the clone.
23
48
  *
package/src/mix.ts CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  parseStructTag,
24
24
  } from "@mysten/sui/utils";
25
25
  import { getReleaseById, isNotFound } from "@misofm/protocol";
26
- import { WalrusData } from "@misofm/protocol/contracts/recording_master_reference/deps/ori/walrus_data";
26
+ import * as engineSessionContract from "@misofm/protocol/contracts/recording_engine_session/recording_engine_session";
27
27
  import * as recordContract from "@misofm/protocol/contracts/miso_record/record";
28
28
  import type { TxThunk } from "./transactions.ts";
29
29
  import {
@@ -432,14 +432,27 @@ export function inspectEngineSessionKey(
432
432
 
433
433
  const EngineSessionField = bcs.struct("Field", {
434
434
  id: bcs.Address,
435
- name: bcs.tuple([bcs.bool()]),
436
- value: bcs.struct("EngineSession", { reference: WalrusData }),
435
+ name: engineSessionContract.ExtensionKey,
436
+ value: engineSessionContract.EngineSession,
437
+ });
438
+ const ENGINE_SESSION_KEY_BYTES = engineSessionContract.ExtensionKey.serialize([
439
+ false,
440
+ ]).toBytes();
441
+ // `release_mix_reference` predates the ori `walrus_data` → `data` split and is
442
+ // not part of the current deployment. Its stored value is still the legacy
443
+ // `ori::walrus_data::WalrusData` enum, kept here verbatim for reads.
444
+ const LegacyConfidentiality = bcs.enum("Confidentiality", {
445
+ Unencrypted: null,
446
+ Encrypted: bcs.struct("Confidentiality.Encrypted", { dek: bcs.vector(bcs.u8()) }),
447
+ });
448
+ const LegacyWalrusData = bcs.enum("WalrusData", {
449
+ Blob: bcs.tuple([bcs.u256(), LegacyConfidentiality]),
450
+ QuiltPatch: bcs.tuple([bcs.u256(), bcs.u8(), bcs.u16(), bcs.u16()]),
437
451
  });
438
- const ENGINE_SESSION_KEY_BYTES = new Uint8Array([0]);
439
452
  const ReleaseMixReferenceField = bcs.struct("Field", {
440
453
  id: bcs.Address,
441
454
  name: bcs.tuple([bcs.bool()]),
442
- value: bcs.tuple([bcs.vector(bcs.option(WalrusData))]),
455
+ value: bcs.tuple([bcs.vector(bcs.option(LegacyWalrusData))]),
443
456
  });
444
457
 
445
458
  export interface RecordingEngineSessionReference {
@@ -492,15 +505,11 @@ export function recordingEngineSessionFieldId(
492
505
  export function parseRecordingEngineSessionContent(
493
506
  content: Uint8Array,
494
507
  ): RecordingEngineSessionReference {
495
- const reference = EngineSessionField.parse(content).value.reference;
496
- if (reference.$kind !== "Blob") {
497
- throw new Error("Recording engine session is not a standalone Walrus blob");
498
- }
499
- const [id, confidentiality] = reference.Blob;
500
- if (confidentiality.$kind !== "Unencrypted") {
508
+ const { data } = EngineSessionField.parse(content).value;
509
+ if (data.confidentiality.$kind !== "Unencrypted") {
501
510
  throw new Error("Recording engine session is unexpectedly encrypted");
502
511
  }
503
- return { blobId: BigInt(id) };
512
+ return { blobId: BigInt(data.blob_id) };
504
513
  }
505
514
 
506
515
  export async function getRecordingEngineSession(
@@ -596,62 +605,6 @@ export async function resolveRecordEngineSession(
596
605
  };
597
606
  }
598
607
 
599
- // ── Recording extension writes ──────────────────────────────────────────────
600
-
601
- export interface WriteRecordingEngineSessionParams {
602
- readonly recordingId: ObjectInput;
603
- readonly authority: AdminCapAuthority;
604
- readonly recordingShareType: string;
605
- readonly compositionShareType: string;
606
- readonly sessionBlobId: bigint | string;
607
- readonly oriPackageId: string;
608
- readonly recordingEngineSessionPackageId: string;
609
- }
610
-
611
- export function attachRecordingEngineSession(
612
- params: WriteRecordingEngineSessionParams,
613
- ): TxThunk {
614
- return writeRecordingEngineSession("attach_engine_session", params);
615
- }
616
-
617
- export function replaceRecordingEngineSession(
618
- params: WriteRecordingEngineSessionParams,
619
- ): TxThunk {
620
- return writeRecordingEngineSession("replace_engine_session", params);
621
- }
622
-
623
- export function unsetRecordingEngineSession(
624
- params: Omit<WriteRecordingEngineSessionParams, "sessionBlobId" | "oriPackageId">,
625
- ): TxThunk {
626
- return (tx) => {
627
- invokeWithAdminCap(tx, params.authority, {
628
- target: `${params.recordingEngineSessionPackageId}::recording_engine_session::unset_engine_session`,
629
- typeArguments: [params.recordingShareType, params.compositionShareType],
630
- arguments: [object(tx, params.recordingId)],
631
- adminCapIndex: 1,
632
- });
633
- };
634
- }
635
-
636
- function writeRecordingEngineSession(
637
- fn: "attach_engine_session" | "replace_engine_session",
638
- params: WriteRecordingEngineSessionParams,
639
- ): TxThunk {
640
- const blob = u256("sessionBlobId", params.sessionBlobId);
641
- return (tx) => {
642
- const reference = tx.moveCall({
643
- target: `${params.oriPackageId}::walrus_data::new_blob`,
644
- arguments: [tx.pure.u256(blob)],
645
- });
646
- invokeWithAdminCap(tx, params.authority, {
647
- target: `${params.recordingEngineSessionPackageId}::recording_engine_session::${fn}`,
648
- typeArguments: [params.recordingShareType, params.compositionShareType],
649
- arguments: [object(tx, params.recordingId), reference],
650
- adminCapIndex: 1,
651
- });
652
- };
653
- }
654
-
655
608
  function object(tx: Transaction, input: ObjectInput): TransactionObjectArgument {
656
609
  return typeof input === "string" ? tx.object(input) : input;
657
610
  }
@@ -48,11 +48,13 @@ import {
48
48
  } from "./credits.ts";
49
49
  import {
50
50
  setRecordingAdvisory,
51
+ setRecordingEngineSession,
51
52
  setRecordingInstrumental,
52
53
  setRecordingLanguages,
53
54
  setRecordingMasterReference,
54
55
  setRecordingStreamingTranscode,
55
56
  } from "./recording-extensions.ts";
57
+ import { unencryptedWalrusBlob } from "./internal.ts";
56
58
  import {
57
59
  setReleaseDescription,
58
60
  setReleaseDspLinks,
@@ -171,6 +173,8 @@ export type PublicationRecording = PublicationRecordingParent & {
171
173
  readonly masterReferenceBlobId?: bigint | string;
172
174
  /** Complete Walrus Quilt ID containing this Recording's streaming transcodes. */
173
175
  readonly streamingTranscodeQuiltId?: bigint | string;
176
+ /** Unencrypted Walrus blob ID of this Recording's Miso Engine session file. */
177
+ readonly engineSessionBlobId?: bigint | string;
174
178
  };
175
179
 
176
180
  export interface PublicationFreshTrack {
@@ -332,10 +336,7 @@ function languageVector(tx: Transaction, p: AtomicPublicationParams, codes: stri
332
336
  }
333
337
 
334
338
  function walrusBlob(tx: Transaction, p: AtomicPublicationParams, blobId: bigint | string) {
335
- return tx.moveCall({
336
- target: `${p.deployment.packages.ori}::walrus_data::new_blob`,
337
- arguments: [tx.pure.u256(blobId)],
338
- });
339
+ return unencryptedWalrusBlob(tx, p.deployment.packages.ori, blobId);
339
340
  }
340
341
 
341
342
  function listingPrice(tx: Transaction, p: AtomicPublicationParams, price: ListingPrice) {
@@ -652,6 +653,14 @@ export function publishAtomicCatalog(p: AtomicPublicationParams): TxThunk {
652
653
  "A recording streaming transcode requires deployment.packages.recordingStreamingTranscode",
653
654
  );
654
655
  }
656
+ if (
657
+ p.recordings.some((node) => node.engineSessionBlobId !== undefined) &&
658
+ !p.deployment.packages.recordingEngineSession
659
+ ) {
660
+ throw new Error(
661
+ "A recording engine session requires deployment.packages.recordingEngineSession",
662
+ );
663
+ }
655
664
  if (publicationUsesVault(p)) {
656
665
  requireOperationsDeployment(p.deployment.operations);
657
666
  }
@@ -869,6 +878,14 @@ export function publishAtomicCatalog(p: AtomicPublicationParams): TxThunk {
869
878
  oriPackageId: p.deployment.packages.ori,
870
879
  quiltId: node.streamingTranscodeQuiltId,
871
880
  })(tx);
881
+ if (node.engineSessionBlobId !== undefined) setRecordingEngineSession({
882
+ recordingId: parts.work, authority,
883
+ recordingShareType: node.shareType,
884
+ compositionShareType: node.compositionShareType,
885
+ recordingEngineSessionPackageId: p.deployment.packages.recordingEngineSession!,
886
+ oriPackageId: p.deployment.packages.ori,
887
+ sessionBlobId: node.engineSessionBlobId,
888
+ })(tx);
872
889
  });
873
890
 
874
891
  if (p.release && releaseObject && releaseAdminCap) {
@@ -49,7 +49,6 @@ import type { MisoClient } from "./client.ts";
49
49
  import { getRecordingTitles, parseReleaseObject } from "./works.ts";
50
50
  import { int } from "./internal/scalars.ts";
51
51
  import {
52
- quiltPatchId,
53
52
  u256ToB64Url,
54
53
  walrusBlobReadUrl,
55
54
  } from "./internal/walrus.ts";
@@ -75,17 +74,9 @@ import type {
75
74
 
76
75
  // ── Walrus URLs ──────────────────────────────────────────────────────────────
77
76
 
78
- /** Aggregator URL for a cover image ref, whichever Walrus variant it is. */
77
+ /** Aggregator URL for a cover image ref (a standalone Walrus blob). */
79
78
  function imageUrl(aggregator: string, ref: CoverImageRef): string {
80
- const base = aggregator.replace(/\/$/, "");
81
- if (ref.kind === "blob") return walrusBlobReadUrl(base, ref.blobId);
82
- const patch = quiltPatchId(
83
- ref.quiltId,
84
- ref.version,
85
- ref.startIndex,
86
- ref.endIndex,
87
- );
88
- return `${base}/v1/blobs/by-quilt-patch-id/${patch}`;
79
+ return walrusBlobReadUrl(aggregator.replace(/\/$/, ""), ref.blobId);
89
80
  }
90
81
 
91
82
  function toCover(
@@ -11,9 +11,11 @@ import type { TxThunk } from "./transactions.ts";
11
11
  import { invokeWithAdminCap, type AdminCapAuthority, type ObjectInput } from "./vault.ts";
12
12
  import * as advisory from "@misofm/protocol/contracts/recording_advisory/recording_advisory";
13
13
  import * as language from "@misofm/protocol/contracts/recording_language/recording_language";
14
- import * as walrusData from "@misofm/protocol/contracts/recording_master_reference/deps/ori/walrus_data";
14
+ import * as walrusData from "@misofm/protocol/contracts/recording_master_reference/deps/ori/data";
15
15
  import * as masterReference from "@misofm/protocol/contracts/recording_master_reference/recording_master_reference";
16
+ import * as engineSession from "@misofm/protocol/contracts/recording_engine_session/recording_engine_session";
16
17
  import * as streamingTranscode from "@misofm/protocol/contracts/recording_streaming_transcode/recording_streaming_transcode";
18
+ import { unencryptedWalrusBlob } from "./internal.ts";
17
19
 
18
20
  export interface RecordingExtensionTarget {
19
21
  readonly recordingId: ObjectInput;
@@ -77,7 +79,7 @@ export function setRecordingInstrumental(p: Omit<SetRecordingLanguagesParams, "l
77
79
  }
78
80
 
79
81
  interface RecordingWalrusReferenceParams extends RecordingExtensionTarget {
80
- /** An ori::WalrusData value assembled in the same PTB (must be a standalone blob on chain). */
82
+ /** An `ori::data::WalrusBlob` value assembled in the same PTB. */
81
83
  readonly reference: TransactionArgument;
82
84
  }
83
85
 
@@ -130,6 +132,52 @@ export type UnsetRecordingStreamingTranscodeParams = Omit<
130
132
  "oriPackageId" | "quiltId"
131
133
  >;
132
134
 
135
+ export interface SetRecordingEngineSessionParams extends RecordingExtensionTarget {
136
+ readonly recordingEngineSessionPackageId: string;
137
+ /** External `ori` package used to construct the plaintext Walrus blob reference. */
138
+ readonly oriPackageId: string;
139
+ /** Unencrypted Walrus blob ID of the Miso Engine session file, as its on-chain `u256`. */
140
+ readonly sessionBlobId: bigint | string;
141
+ }
142
+
143
+ /**
144
+ * Sets or replaces the Miso Engine session file attached to a Recording.
145
+ *
146
+ * `recording_engine_session::new` rejects encrypted blobs on chain, so the
147
+ * reference is always built as a plaintext `ori::data::WalrusBlob`.
148
+ */
149
+ export function setRecordingEngineSession(p: SetRecordingEngineSessionParams): TxThunk {
150
+ return (tx) => {
151
+ const session = tx.add(engineSession._new({
152
+ package: p.recordingEngineSessionPackageId,
153
+ arguments: [unencryptedWalrusBlob(tx, p.oriPackageId, p.sessionBlobId)],
154
+ }));
155
+ invokeWithAdminCap(tx, p.authority, {
156
+ target: `${p.recordingEngineSessionPackageId}::recording_engine_session::set_engine_session`,
157
+ typeArguments: [p.recordingShareType, p.compositionShareType],
158
+ arguments: [object(tx, p.recordingId), session],
159
+ adminCapIndex: 1,
160
+ });
161
+ };
162
+ }
163
+
164
+ export type UnsetRecordingEngineSessionParams = Omit<
165
+ SetRecordingEngineSessionParams,
166
+ "oriPackageId" | "sessionBlobId"
167
+ >;
168
+
169
+ /** Removes the Recording's Miso Engine session reference, if present. */
170
+ export function unsetRecordingEngineSession(p: UnsetRecordingEngineSessionParams): TxThunk {
171
+ return (tx) => {
172
+ invokeWithAdminCap(tx, p.authority, {
173
+ target: `${p.recordingEngineSessionPackageId}::recording_engine_session::unset_engine_session`,
174
+ typeArguments: [p.recordingShareType, p.compositionShareType],
175
+ arguments: [object(tx, p.recordingId)],
176
+ adminCapIndex: 1,
177
+ });
178
+ };
179
+ }
180
+
133
181
  /** Removes the Recording's streaming-transcode reference, if present. */
134
182
  export function unsetRecordingStreamingTranscode(
135
183
  p: UnsetRecordingStreamingTranscodeParams,
@@ -146,30 +194,26 @@ export function unsetRecordingStreamingTranscode(
146
194
 
147
195
  // ── Master-reference reads ───────────────────────────────────────────────────
148
196
 
149
- // recording_master_reference stores the ori::WalrusData value inline in a
197
+ // recording_master_reference stores the ori::data::WalrusBlob value inline in a
150
198
  // dynamic field on the Recording. Its empty ExtensionKey serializes to one false
151
199
  // byte, so the field object id can be derived without listing the Recording's
152
200
  // dynamic fields.
153
201
  const MasterReferenceField = bcs.struct("Field", {
154
202
  id: bcs.Address,
155
203
  name: masterReference.ExtensionKey,
156
- value: walrusData.WalrusData,
204
+ value: walrusData.WalrusBlob,
157
205
  });
158
206
  const MASTER_REFERENCE_KEY_BYTES = masterReference.ExtensionKey.serialize([
159
207
  false,
160
208
  ]).toBytes();
161
209
 
162
- /** Parse an attached master reference's standalone Walrus blob id. */
163
- export function parseRecordingMasterReferenceContent(
164
- content: Uint8Array,
165
- ): string | null {
166
- const reference = MasterReferenceField.parse(content).value as
167
- | { $kind: "Blob"; Blob: [string | number | bigint, unknown] }
168
- | {
169
- $kind: "QuiltPatch";
170
- QuiltPatch: [string | number | bigint, number, number, number];
171
- };
172
- return reference.$kind === "Blob" ? String(reference.Blob[0]) : null;
210
+ /**
211
+ * Parse an attached master reference's standalone Walrus blob id (decimal
212
+ * `u256`). Encrypted masters are returned as-is: the reference is the same
213
+ * either way, and access control belongs to the caller.
214
+ */
215
+ export function parseRecordingMasterReferenceContent(content: Uint8Array): string {
216
+ return String(MasterReferenceField.parse(content).value.blob_id);
173
217
  }
174
218
 
175
219
  /** Deterministic dynamic-field id for a Recording's master reference. */
@@ -231,8 +275,7 @@ export async function getRecordingMasterReferencesByIds(
231
275
  const target = targets[index];
232
276
  if (!target || object instanceof Error || !object.content) return;
233
277
  try {
234
- const blobId = parseRecordingMasterReferenceContent(object.content);
235
- if (blobId) out[target.recordingId] = blobId;
278
+ out[target.recordingId] = parseRecordingMasterReferenceContent(object.content);
236
279
  } catch {
237
280
  // Extension metadata is soft: retain valid tracks when one field is stale.
238
281
  }