@misonetwork/sdk 0.3.1 → 0.5.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 (60) hide show
  1. package/README.md +97 -503
  2. package/dist/client.d.ts +6 -55
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +7 -52
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts/miso/release.d.ts +34 -31
  7. package/dist/contracts/miso/release.d.ts.map +1 -1
  8. package/dist/contracts/miso/release.js +32 -29
  9. package/dist/contracts/miso/release.js.map +1 -1
  10. package/dist/contracts/miso/track.d.ts +66 -22
  11. package/dist/contracts/miso/track.d.ts.map +1 -1
  12. package/dist/contracts/miso/track.js +65 -20
  13. package/dist/contracts/miso/track.js.map +1 -1
  14. package/dist/contracts/utils/index.d.ts +44 -0
  15. package/dist/contracts/utils/index.d.ts.map +1 -1
  16. package/dist/contracts/utils/index.js +104 -2
  17. package/dist/contracts/utils/index.js.map +1 -1
  18. package/dist/contracts.d.ts +0 -1
  19. package/dist/contracts.d.ts.map +1 -1
  20. package/dist/contracts.js +0 -1
  21. package/dist/contracts.js.map +1 -1
  22. package/dist/internal.d.ts +0 -7
  23. package/dist/internal.d.ts.map +1 -1
  24. package/dist/internal.js +0 -22
  25. package/dist/internal.js.map +1 -1
  26. package/dist/parsers.d.ts +1 -4
  27. package/dist/parsers.d.ts.map +1 -1
  28. package/dist/parsers.js +0 -24
  29. package/dist/parsers.js.map +1 -1
  30. package/dist/queries.d.ts +31 -5
  31. package/dist/queries.d.ts.map +1 -1
  32. package/dist/queries.js +179 -56
  33. package/dist/queries.js.map +1 -1
  34. package/dist/transactions.d.ts +10 -71
  35. package/dist/transactions.d.ts.map +1 -1
  36. package/dist/transactions.js +15 -72
  37. package/dist/transactions.js.map +1 -1
  38. package/dist/types.d.ts +3 -40
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/view.d.ts +7 -7
  41. package/dist/view.d.ts.map +1 -1
  42. package/dist/view.js +9 -9
  43. package/dist/view.js.map +1 -1
  44. package/package.json +4 -4
  45. package/src/client.ts +82 -89
  46. package/src/contracts/miso/release.ts +39 -36
  47. package/src/contracts/miso/track.ts +81 -23
  48. package/src/contracts/utils/index.ts +156 -4
  49. package/src/contracts.ts +0 -1
  50. package/src/internal.ts +0 -24
  51. package/src/parsers.ts +0 -35
  52. package/src/queries.ts +357 -83
  53. package/src/transactions.ts +20 -112
  54. package/src/types.ts +3 -53
  55. package/src/view.ts +13 -13
  56. package/dist/contracts/miso/deal.d.ts +0 -184
  57. package/dist/contracts/miso/deal.d.ts.map +0 -1
  58. package/dist/contracts/miso/deal.js +0 -184
  59. package/dist/contracts/miso/deal.js.map +0 -1
  60. package/src/contracts/miso/deal.ts +0 -257
package/src/client.ts CHANGED
@@ -1,20 +1,27 @@
1
1
  // Copyright (c) Miso Labs, Inc.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import type { ClientWithCoreApi, SuiClientRegistration } from "@mysten/sui/client";
4
+ import type {
5
+ ClientWithCoreApi,
6
+ SuiClientRegistration,
7
+ } from "@mysten/sui/client";
5
8
  import type { SuiGraphQLClient } from "@mysten/sui/graphql";
6
- import type { TxThunk } from "./transactions.ts";
7
9
  import * as parsers from "./parsers.ts";
8
10
  import * as queries from "./queries.ts";
9
- import * as transactions from "./transactions.ts";
10
11
  import * as view from "./view.ts";
11
- import type { Composition, CompositionAdminCap, Deal, Recording, RecordingAdminCap, Release, ReleaseAdminCap } from "./types.ts";
12
+ import type {
13
+ Composition,
14
+ CompositionAdminCap,
15
+ Recording,
16
+ RecordingAdminCap,
17
+ Release,
18
+ ReleaseAdminCap,
19
+ } from "./types.ts";
12
20
 
13
21
  // Generated call modules (type-safe Move calls) and BCS structs.
14
22
  import * as composition from "./contracts/miso/composition.ts";
15
23
  import * as recording from "./contracts/miso/recording.ts";
16
24
  import * as release from "./contracts/miso/release.ts";
17
- import * as deal from "./contracts/miso/deal.ts";
18
25
  import * as track from "./contracts/miso/track.ts";
19
26
 
20
27
  export interface MisoOptions<Name extends string = "miso"> {
@@ -22,45 +29,23 @@ export interface MisoOptions<Name extends string = "miso"> {
22
29
  name?: Name;
23
30
  /** The Miso package ID. Required for type-based queries and derivation. */
24
31
  misoPackageId: string;
25
- /**
26
- * The `ReleaseRegistry` object ID for this deployment.
27
- *
28
- * Created once in `release::init` and shared, so it is FIXED for the lifetime
29
- * of a published package — deployment config, not runtime state. Supply it
30
- * (alongside `misoPackageId`, from the same deployment manifest) and
31
- * `getReleaseRegistry()` needs no network call at all. Omit it and the SDK
32
- * falls back to a GraphQL scan, which is why this is worth configuring.
33
- */
34
- releaseRegistryId?: string;
35
32
  /**
36
33
  * Optional GraphQL client, required ONLY for the global type-discovery reads
37
34
  * the Core API cannot express: `getCompositionByShareType`,
38
- * `getRecordingByShareType`, and `getReleaseRegistry` when
39
- * `releaseRegistryId` is not configured. Everything else — including every
35
+ * `getRecordingByShareType`. Everything else — including every
40
36
  * `getOwned*AdminCaps` — goes over the Core API.
41
37
  */
42
38
  graphqlClient?: SuiGraphQLClient;
43
39
  }
44
40
 
45
- /**
46
- * Wraps a builder so the client's `misoPackageId` is injected, dropping it from
47
- * the caller's params. Explicit call-sites (the free functions in
48
- * `./transactions`) remain available for full control.
49
- */
50
- function bindPackages<P extends { misoPackageId: string }>(
51
- fn: (params: P) => TxThunk,
52
- misoPackageId: string,
53
- ): (params: Omit<P, "misoPackageId">) => TxThunk {
54
- return (params) => fn({ misoPackageId, ...params } as unknown as P);
55
- }
56
-
57
41
  /** Defaults `options.package` to `pkg` for every call-function in a generated module. */
58
42
  function bindModulePackage<M extends object>(mod: M, pkg: string): M {
59
43
  const out: Record<string, unknown> = {};
60
44
  for (const [key, value] of Object.entries({ ...mod })) {
61
45
  out[key] =
62
46
  typeof value === "function"
63
- ? (options: { package?: string }) => (value as (o: unknown) => unknown)({ package: pkg, ...options })
47
+ ? (options: { package?: string }) =>
48
+ (value as (o: unknown) => unknown)({ package: pkg, ...options })
64
49
  : value;
65
50
  }
66
51
  return out as M;
@@ -90,13 +75,11 @@ export class MisoClient {
90
75
  #client: ClientWithCoreApi;
91
76
  #graphqlClient?: SuiGraphQLClient;
92
77
  #misoPackageId: string;
93
- #releaseRegistryId?: string;
94
78
 
95
79
  constructor(client: ClientWithCoreApi, options: Omit<MisoOptions, "name">) {
96
80
  this.#client = client;
97
81
  this.#graphqlClient = options.graphqlClient;
98
82
  this.#misoPackageId = options.misoPackageId;
99
- this.#releaseRegistryId = options.releaseRegistryId;
100
83
  }
101
84
 
102
85
  // === Composition ===
@@ -104,23 +87,53 @@ export class MisoClient {
104
87
  async getCompositionById(compositionId: string): Promise<Composition> {
105
88
  return queries.getCompositionById(this.#client, compositionId);
106
89
  }
107
- async getCompositionsByIds(ids: string[]): Promise<Record<string, Composition>> {
90
+ async getCompositionsByIds(
91
+ ids: string[],
92
+ ): Promise<Record<string, Composition>> {
108
93
  return queries.getCompositionsByIds(this.#client, ids);
109
94
  }
95
+ async getWorksByIds(ids: queries.WorkIds): Promise<queries.WorksById> {
96
+ return queries.getWorksByIds(this.#client, ids);
97
+ }
98
+ async getWorkAddressesByShareTypes(
99
+ shareTypes: queries.WorkShareTypes,
100
+ ): Promise<queries.WorkAddressesByShareType> {
101
+ return queries.getWorkAddressesByShareTypes(
102
+ this.#requireGraphQL(),
103
+ shareTypes,
104
+ this.#misoPackageId,
105
+ );
106
+ }
110
107
  async getCompositionShareType(compositionId: string): Promise<string> {
111
108
  return queries.getCompositionShareType(this.#client, compositionId);
112
109
  }
113
110
  async getCompositionByShareType(shareType: string): Promise<Composition> {
114
- return queries.getCompositionByShareType(this.#client, this.#requireGraphQL(), shareType, this.#misoPackageId);
111
+ return queries.getCompositionByShareType(
112
+ this.#client,
113
+ this.#requireGraphQL(),
114
+ shareType,
115
+ this.#misoPackageId,
116
+ );
115
117
  }
116
- async getCompositionAdminCapById(adminCapId: string): Promise<CompositionAdminCap> {
118
+ async getCompositionAdminCapById(
119
+ adminCapId: string,
120
+ ): Promise<CompositionAdminCap> {
117
121
  return queries.getCompositionAdminCapById(this.#client, adminCapId);
118
122
  }
119
- async getOwnedCompositionAdminCaps(owner: string): Promise<CompositionAdminCap[]> {
120
- return queries.getOwnedCompositionAdminCaps(this.#client, owner, this.#misoPackageId);
123
+ async getOwnedCompositionAdminCaps(
124
+ owner: string,
125
+ ): Promise<CompositionAdminCap[]> {
126
+ return queries.getOwnedCompositionAdminCaps(
127
+ this.#client,
128
+ owner,
129
+ this.#misoPackageId,
130
+ );
121
131
  }
122
132
  deriveCompositionAdminCapId(compositionId: string): string {
123
- return queries.deriveCompositionAdminCapId(compositionId, this.#misoPackageId);
133
+ return queries.deriveCompositionAdminCapId(
134
+ compositionId,
135
+ this.#misoPackageId,
136
+ );
124
137
  }
125
138
 
126
139
  // === Recording ===
@@ -135,24 +148,31 @@ export class MisoClient {
135
148
  return queries.getRecordingShareType(this.#client, recordingId);
136
149
  }
137
150
  async getRecordingByShareType(shareType: string): Promise<Recording> {
138
- return queries.getRecordingByShareType(this.#client, this.#requireGraphQL(), shareType, this.#misoPackageId);
151
+ return queries.getRecordingByShareType(
152
+ this.#client,
153
+ this.#requireGraphQL(),
154
+ shareType,
155
+ this.#misoPackageId,
156
+ );
139
157
  }
140
- async getRecordingAdminCapById(adminCapId: string): Promise<RecordingAdminCap> {
158
+ async getRecordingAdminCapById(
159
+ adminCapId: string,
160
+ ): Promise<RecordingAdminCap> {
141
161
  return queries.getRecordingAdminCapById(this.#client, adminCapId);
142
162
  }
143
- async getOwnedRecordingAdminCaps(owner: string): Promise<RecordingAdminCap[]> {
144
- return queries.getOwnedRecordingAdminCaps(this.#client, owner, this.#misoPackageId);
163
+ async getOwnedRecordingAdminCaps(
164
+ owner: string,
165
+ ): Promise<RecordingAdminCap[]> {
166
+ return queries.getOwnedRecordingAdminCaps(
167
+ this.#client,
168
+ owner,
169
+ this.#misoPackageId,
170
+ );
145
171
  }
146
172
  deriveRecordingAdminCapId(recordingId: string): string {
147
173
  return queries.deriveRecordingAdminCapId(recordingId, this.#misoPackageId);
148
174
  }
149
175
 
150
- // === Deal ===
151
-
152
- async getDealById(dealId: string): Promise<Deal> {
153
- return queries.getDealById(this.#client, dealId);
154
- }
155
-
156
176
  // === Release ===
157
177
 
158
178
  async getReleaseById(releaseId: string): Promise<Release> {
@@ -168,22 +188,12 @@ export class MisoClient {
168
188
  return queries.deriveReleaseAdminCapId(releaseId, this.#misoPackageId);
169
189
  }
170
190
  async getOwnedReleaseAdminCaps(owner: string): Promise<ReleaseAdminCap[]> {
171
- return queries.getOwnedReleaseAdminCaps(this.#client, owner, this.#misoPackageId);
191
+ return queries.getOwnedReleaseAdminCaps(
192
+ this.#client,
193
+ owner,
194
+ this.#misoPackageId,
195
+ );
172
196
  }
173
- /**
174
- * The deployment's `ReleaseRegistry` object ID.
175
- *
176
- * Returns the configured `releaseRegistryId` with no network call. Only when
177
- * it was not configured does this fall back to a GraphQL scan — a one-time
178
- * bootstrap for a fresh deployment whose id you have not recorded yet. Prefer
179
- * configuring it: the registry is created once in `release::init` and never
180
- * changes, so scanning for it on every call is pure overhead.
181
- */
182
- async getReleaseRegistry(): Promise<string> {
183
- if (this.#releaseRegistryId) return this.#releaseRegistryId;
184
- return queries.getReleaseRegistry(this.#requireGraphQL(), this.#misoPackageId);
185
- }
186
-
187
197
  // === Share Currency ===
188
198
 
189
199
  async getShareCurrencyType(shareCurrencyId: string): Promise<string> {
@@ -194,32 +204,21 @@ export class MisoClient {
194
204
  * hold only the `Currency` object id, resolve it first with
195
205
  * {@link getShareCurrencyType}.
196
206
  */
197
- async getShareCurrencyTreasuryCap(shareType: string, owner: string): Promise<string> {
207
+ async getShareCurrencyTreasuryCap(
208
+ shareType: string,
209
+ owner: string,
210
+ ): Promise<string> {
198
211
  return queries.getShareCurrencyTreasuryCap(this.#client, shareType, owner);
199
212
  }
200
213
 
201
- // === Transaction builders (thunks) ===
202
-
203
- // Only the `(params) => TxThunk` builders bind here. The primitives that take
204
- // a `Transaction` directly and return values (`createComposition`,
205
- // `createRecording`, `createRelease`, `createDeal`) are free functions by
206
- // design — they thread results into a caller-owned PTB, so there is nothing
207
- // to bind. Import them from the package root and pass `misoPackageId`
208
- // explicitly.
209
- get tx() {
210
- const miso = this.#misoPackageId;
211
- return {
212
- rejectDeal: bindPackages(transactions.rejectDeal, miso),
213
- };
214
- }
215
-
216
214
  // === Simulate-based reads (view) ===
217
215
 
218
216
  get view() {
219
217
  const client = this.#client;
220
218
  const misoPackageId = this.#misoPackageId;
221
219
  return {
222
- deriveReleaseId: (params: view.DeriveReleaseIdParams) => view.deriveReleaseId(client, misoPackageId, params),
220
+ deriveTargetReleaseId: (params: view.DeriveTargetReleaseIdParams) =>
221
+ view.deriveTargetReleaseId(client, misoPackageId, params),
223
222
  };
224
223
  }
225
224
 
@@ -231,7 +230,6 @@ export class MisoClient {
231
230
  composition: bindModulePackage(composition, pkg),
232
231
  recording: bindModulePackage(recording, pkg),
233
232
  release: bindModulePackage(release, pkg),
234
- deal: bindModulePackage(deal, pkg),
235
233
  track: bindModulePackage(track, pkg),
236
234
  };
237
235
  }
@@ -243,15 +241,11 @@ export class MisoClient {
243
241
  Composition: composition.Composition,
244
242
  Recording: recording.Recording,
245
243
  Release: release.Release,
246
- Deal: deal.Deal,
247
244
  Track: track.Track,
248
245
  CompositionPublishedEvent: composition.CompositionPublishedEvent,
249
246
  CompositionRoyaltySetEvent: composition.CompositionRoyaltySetEvent,
250
247
  RecordingPublishedEvent: recording.RecordingPublishedEvent,
251
248
  ReleasePublishedEvent: release.ReleasePublishedEvent,
252
- DealCreatedEvent: deal.DealCreatedEvent,
253
- DealAcceptedEvent: deal.DealAcceptedEvent,
254
- DealRejectedEvent: deal.DealRejectedEvent,
255
249
  };
256
250
  }
257
251
 
@@ -263,15 +257,14 @@ export class MisoClient {
263
257
  compositionRoyaltySetEvent: parsers.parseCompositionRoyaltySetEvent,
264
258
  recordingPublishedEvent: parsers.parseRecordingPublishedEvent,
265
259
  releasePublishedEvent: parsers.parseReleasePublishedEvent,
266
- dealCreatedEvent: parsers.parseDealCreatedEvent,
267
- dealAcceptedEvent: parsers.parseDealAcceptedEvent,
268
- dealRejectedEvent: parsers.parseDealRejectedEvent,
269
260
  };
270
261
  }
271
262
 
272
263
  #requireGraphQL(): SuiGraphQLClient {
273
264
  if (!this.#graphqlClient) {
274
- throw new Error("GraphQL client required. Pass graphqlClient to miso() options.");
265
+ throw new Error(
266
+ "GraphQL client required. Pass graphqlClient to miso() options.",
267
+ );
275
268
  }
276
269
  return this.#graphqlClient;
277
270
  }
@@ -38,14 +38,22 @@
38
38
  *
39
39
  * ### Consent scope
40
40
  *
41
- * The release digest — and therefore the derived release id every `Deal` commits
42
- * to — binds the economics and membership of the release: the ordered list of
43
- * `(recording, split)` pairs and the creator's nonce. It deliberately binds
44
- * nothing else. The title — the one embedded field outside the digest — and
41
+ * The release digest — and therefore the derived release id every `Track` commits
42
+ * to at creation — binds the economics and membership of the release: the ordered
43
+ * list of `(recording, split)` pairs and the creator's nonce. It deliberately
44
+ * binds nothing else. The title — the one embedded field outside the digest — and
45
45
  * everything in the extension layer (artwork, credits, display grouping) are
46
- * chosen by the release creator, before or after deals are signed, and are trusted
47
- * and publicly attributable rather than cryptographically committed. See
48
- * `deal::new` for the signer-side statement of this boundary.
46
+ * chosen by the release creator, before or after tracks are created, and are
47
+ * trusted and publicly attributable rather than cryptographically committed. See
48
+ * `track::new` for the signer-side statement of this boundary.
49
+ *
50
+ * The derived id commits to a `(parent, digest)` pair, not the digest alone — so
51
+ * targeting an id also consents to that namespace's liveness. If the parent object
52
+ * is deleted, or its `&mut UID` becomes permanently unreachable, the release can
53
+ * never exist and every track or offer targeting it is stranded — the same
54
+ * blast-radius class as a release that simply never publishes. A coordinator meant
55
+ * to serve as the default parent namespace should therefore be shared and
56
+ * undeletable.
49
57
  *
50
58
  * ### Lifecycle and trust model
51
59
  *
@@ -65,12 +73,11 @@
65
73
  * holder as able to mutate or delete any extension data, forever.
66
74
  */
67
75
 
68
- import { MoveTuple, MoveEnum, MoveStruct, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js';
76
+ import { MoveEnum, MoveStruct, MoveTuple, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js';
69
77
  import { bcs } from '@mysten/sui/bcs';
70
78
  import { type Transaction, type TransactionArgument } from '@mysten/sui/transactions';
71
79
  import * as track from './track.js';
72
80
  const $moduleName = '@local-pkg/miso::release';
73
- export const RELEASE = new MoveTuple({ name: `${$moduleName}::RELEASE`, fields: [bcs.bool()] });
74
81
  /** Lifecycle state of a release. */
75
82
  export const ReleaseState = new MoveEnum({ name: `${$moduleName}::ReleaseState`, fields: {
76
83
  /** Release is initialized but not yet published. */
@@ -86,15 +93,12 @@ export const Release = new MoveStruct({ name: `${$moduleName}::Release`, fields:
86
93
  /** Title of the release. */
87
94
  title: bcs.string(),
88
95
  /**
89
- * The ordered tracklist. Same shape as the digest pre-image every deal consented
90
- * to; display grouping lives in the metadata extension.
96
+ * The ordered tracklist. Same shape as the digest pre-image every track's creator
97
+ * consented to; display grouping lives in the metadata extension.
91
98
  */
92
99
  tracks: bcs.vector(track.Track)
93
100
  } });
94
101
  export const ReleaseKey = new MoveTuple({ name: `${$moduleName}::ReleaseKey`, fields: [bcs.vector(bcs.u8())] });
95
- export const ReleaseRegistry = new MoveStruct({ name: `${$moduleName}::ReleaseRegistry`, fields: {
96
- id: bcs.Address
97
- } });
98
102
  export const ReleaseAdminCap = new MoveStruct({ name: `${$moduleName}::ReleaseAdminCap`, fields: {
99
103
  /** Unique identifier for this capability. */
100
104
  id: bcs.Address,
@@ -102,10 +106,6 @@ export const ReleaseAdminCap = new MoveStruct({ name: `${$moduleName}::ReleaseAd
102
106
  release_id: bcs.Address
103
107
  } });
104
108
  export const ReleaseAdminCapKey = new MoveTuple({ name: `${$moduleName}::ReleaseAdminCapKey`, fields: [bcs.bool()] });
105
- export const ReleaseRegistryCreatedEvent = new MoveStruct({ name: `${$moduleName}::ReleaseRegistryCreatedEvent`, fields: {
106
- registry_id: bcs.Address,
107
- created_by: bcs.Address
108
- } });
109
109
  export const ReleasePublishedEvent = new MoveStruct({ name: `${$moduleName}::ReleasePublishedEvent`, fields: {
110
110
  release_id: bcs.Address
111
111
  } });
@@ -113,7 +113,7 @@ export interface NewArguments {
113
113
  title: RawTransactionArgument<string>;
114
114
  tracks: TransactionArgument;
115
115
  nonce: RawTransactionArgument<number | bigint>;
116
- registry: RawTransactionArgument<string>;
116
+ parent: RawTransactionArgument<string>;
117
117
  }
118
118
  export interface NewOptions {
119
119
  package?: string;
@@ -121,12 +121,15 @@ export interface NewOptions {
121
121
  title: RawTransactionArgument<string>,
122
122
  tracks: TransactionArgument,
123
123
  nonce: RawTransactionArgument<number | bigint>,
124
- registry: RawTransactionArgument<string>
124
+ parent: RawTransactionArgument<string>
125
125
  ];
126
126
  }
127
127
  /**
128
- * Creates a new release with the given configuration. Returns the release and
129
- * admin capability.
128
+ * Creates a new release with the given configuration. Claims the release's UID as
129
+ * a derived child of `parent`, keyed by the release digest (see the module doc's
130
+ * "Consent scope" section) — so contention is per-parent, and which object serves
131
+ * as parent is entirely the caller's choice. Returns the release and admin
132
+ * capability.
130
133
  */
131
134
  export function _new(options: NewOptions) {
132
135
  const packageAddress = options.package ?? '@local-pkg/miso';
@@ -134,9 +137,9 @@ export function _new(options: NewOptions) {
134
137
  '0x1::string::String',
135
138
  'vector<null>',
136
139
  'u256',
137
- null
140
+ '0x2::object::ID'
138
141
  ] satisfies (string | null)[];
139
- const parameterNames = ["title", "tracks", "nonce", "registry"];
142
+ const parameterNames = ["title", "tracks", "nonce", "parent"];
140
143
  return (tx: Transaction) => tx.moveCall({
141
144
  package: packageAddress,
142
145
  module: 'release',
@@ -203,39 +206,39 @@ export function authorize(options: AuthorizeOptions) {
203
206
  arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
204
207
  });
205
208
  }
206
- export interface DeriveReleaseIdArguments {
209
+ export interface DeriveTargetReleaseIdArguments {
207
210
  recordingIds: RawTransactionArgument<Array<string>>;
208
211
  trackSplitValues: RawTransactionArgument<Array<number | bigint>>;
209
212
  nonce: RawTransactionArgument<number | bigint>;
210
- registry: RawTransactionArgument<string>;
213
+ parent: RawTransactionArgument<string>;
211
214
  }
212
- export interface DeriveReleaseIdOptions {
215
+ export interface DeriveTargetReleaseIdOptions {
213
216
  package?: string;
214
- arguments: DeriveReleaseIdArguments | [
217
+ arguments: DeriveTargetReleaseIdArguments | [
215
218
  recordingIds: RawTransactionArgument<Array<string>>,
216
219
  trackSplitValues: RawTransactionArgument<Array<number | bigint>>,
217
220
  nonce: RawTransactionArgument<number | bigint>,
218
- registry: RawTransactionArgument<string>
221
+ parent: RawTransactionArgument<string>
219
222
  ];
220
223
  }
221
224
  /**
222
- * Derives the release ID that `new()` would produce for the given inputs, without
223
- * creating the object. This is the on-chain equivalent of the client-side
224
- * `deriveReleaseId()` function.
225
+ * Derives the target release ID that `new()` would produce for the given inputs
226
+ * and parent, without creating the object. This is the on-chain equivalent of the
227
+ * client-side `deriveReleaseId()` function.
225
228
  */
226
- export function deriveReleaseId(options: DeriveReleaseIdOptions) {
229
+ export function deriveTargetReleaseId(options: DeriveTargetReleaseIdOptions) {
227
230
  const packageAddress = options.package ?? '@local-pkg/miso';
228
231
  const argumentsTypes = [
229
232
  'vector<0x2::object::ID>',
230
233
  'vector<u64>',
231
234
  'u256',
232
- null
235
+ '0x2::object::ID'
233
236
  ] satisfies (string | null)[];
234
- const parameterNames = ["recordingIds", "trackSplitValues", "nonce", "registry"];
237
+ const parameterNames = ["recordingIds", "trackSplitValues", "nonce", "parent"];
235
238
  return (tx: Transaction) => tx.moveCall({
236
239
  package: packageAddress,
237
240
  module: 'release',
238
- function: 'derive_release_id',
241
+ function: 'derive_target_release_id',
239
242
  arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
240
243
  });
241
244
  }
@@ -14,8 +14,8 @@
14
14
  * recording/composition share-type identities) is reached.
15
15
  * - `split_bps` — this track's share of the release's revenue; genuinely
16
16
  * release-specific and not derivable from the recording.
17
- * - `state` — the assign-once lifecycle that carries (then sheds) each deal's
18
- * target release commitment; see `TrackState`.
17
+ * - `state` — the assign-once lifecycle that carries (then sheds) the recording
18
+ * admin's target release commitment, made at creation; see `TrackState`.
19
19
  *
20
20
  * `Track` is intentionally monomorphic: a `Release` holds a `vector<Track>` of
21
21
  * tracks from many different recordings/compositions, so it cannot be generic over
@@ -30,16 +30,16 @@ import * as bps from './deps/bps/bps.js';
30
30
  const $moduleName = '@local-pkg/miso::track';
31
31
  /**
32
32
  * Lifecycle state of a track within a release. A track is born `Unassigned`,
33
- * carrying the target `release_id` its originating `Deal` committed to (the
34
- * release id is a digest of the whole tracklist, so this is the recording owner's
35
- * consent to the exact release configuration). At publish the release verifies the
36
- * match and transitions the track to `Assigned`, which carries no id — shedding
37
- * the 32-byte commitment once it has served its purpose.
33
+ * carrying the target release id the consent committed to at creation (the release
34
+ * id is a digest of the whole tracklist, so this is the recording owner's consent
35
+ * to the exact release configuration). At publish the release verifies the match
36
+ * and transitions the track to `Assigned`, which carries no id — shedding the
37
+ * 32-byte commitment once it has served its purpose.
38
38
  */
39
39
  export const TrackState = new MoveEnum({ name: `${$moduleName}::TrackState`, fields: {
40
40
  /**
41
41
  * Track has been created but not yet assigned to a release. Carries the target
42
- * release id the originating deal committed to.
42
+ * release id the consent committed to at creation.
43
43
  */
44
44
  Unassigned: bcs.Address,
45
45
  /** Track has been assigned to its target release. */
@@ -63,14 +63,18 @@ export const Track = new MoveStruct({ name: `${$moduleName}::Track`, fields: {
63
63
  split_bps: bps.BPS
64
64
  } });
65
65
  export interface NewArguments {
66
- deal: RawTransactionArgument<string>;
66
+ _: RawTransactionArgument<string>;
67
67
  recording: RawTransactionArgument<string>;
68
+ targetReleaseId: RawTransactionArgument<string>;
69
+ trackSplitBpsValue: RawTransactionArgument<number>;
68
70
  }
69
71
  export interface NewOptions {
70
72
  package?: string;
71
73
  arguments: NewArguments | [
72
- deal: RawTransactionArgument<string>,
73
- recording: RawTransactionArgument<string>
74
+ _: RawTransactionArgument<string>,
75
+ recording: RawTransactionArgument<string>,
76
+ targetReleaseId: RawTransactionArgument<string>,
77
+ trackSplitBpsValue: RawTransactionArgument<number>
74
78
  ];
75
79
  typeArguments: [
76
80
  string,
@@ -78,25 +82,52 @@ export interface NewOptions {
78
82
  ];
79
83
  }
80
84
  /**
81
- * Creates a new track by accepting a deal. The deal is the authorization — created
82
- * by the recording's admin, carrying the target release and the agreed split.
83
- * Emits a `DealAcceptedEvent`.
85
+ * Creates a new track: the recording admin's consent to that recording's inclusion
86
+ * in a specific future release with an agreed split. Requires the recording admin
87
+ * capability. No event: a `Track` has `drop` and is not an object, so a creation
88
+ * event could announce a consent that is then silently discarded, and indexers
89
+ * would be unable to distinguish pending from dead. Pre-publish observability is
90
+ * the responsibility of whatever wraps the track (see below).
84
91
  *
85
- * The deal's `RecordingShare`/`CompositionShare` phantoms are erased here: a
86
- * `Track` is monomorphic so it can live in a release's heterogeneous
87
- * `vector<Track>`. Identity rides on those phantoms up to this point, but the
88
- * monomorphic `Track` must store the recording's _address_ for revenue routing —
89
- * and an address can't come from a phantom. So the matching `Recording` is passed
90
- * in (the deal's phantoms force it to be the right one) purely to read its id; the
91
- * deal no longer stores it.
92
+ * The composition is identified by the recording's `CompositionShare` phantom, so
93
+ * the recording↔composition pairing is compile-time enforced there is no
94
+ * `Composition` argument and no runtime ID check.
95
+ *
96
+ * ### What creating a track consents to
97
+ *
98
+ * `target_release_id` is derived from the release digest, so targeting it consents
99
+ * to that release's exact economics and membership: the ordered list of
100
+ * `(recording, split)` pairs and the creator's nonce, nothing more. The release's
101
+ * title, artwork, credits, and display grouping are chosen by the release creator
102
+ * — before or after this track is created — and are not bound by the digest.
103
+ * Presentation is trusted and publicly attributable, not cryptographically
104
+ * committed.
105
+ *
106
+ * The recording need not be `Published`: its admin can create tracks inside the
107
+ * recording's own creating transaction (an `Initialized` recording cannot escape
108
+ * that transaction, so across transactions tracks always reference `Published`,
109
+ * shared recordings).
110
+ *
111
+ * A `Track` has `store`, not `key`: it carries no identity of its own, so it may
112
+ * be exercised synchronously in the same transaction that creates it, or handed to
113
+ * an offer extension that wraps it in a real object with its own identity.
114
+ * Withdrawal, expiry, and rejection are then whatever that wrapping extension
115
+ * encodes — visible in its type, not in core.
116
+ *
117
+ * `recording` compile-time-binds the `RecordingShare`/`CompositionShare` phantom
118
+ * pairing, and is read for its id: the monomorphic `Track` must store the
119
+ * recording's _address_ for revenue routing, and an address cannot come from a
120
+ * phantom.
92
121
  */
93
122
  export function _new(options: NewOptions) {
94
123
  const packageAddress = options.package ?? '@local-pkg/miso';
95
124
  const argumentsTypes = [
96
125
  null,
97
- null
126
+ null,
127
+ '0x2::object::ID',
128
+ 'u16'
98
129
  ] satisfies (string | null)[];
99
- const parameterNames = ["deal", "recording"];
130
+ const parameterNames = ["_", "recording", "targetReleaseId", "trackSplitBpsValue"];
100
131
  return (tx: Transaction) => tx.moveCall({
101
132
  package: packageAddress,
102
133
  module: 'track',
@@ -150,4 +181,31 @@ export function splitBps(options: SplitBpsOptions) {
150
181
  function: 'split_bps',
151
182
  arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
152
183
  });
184
+ }
185
+ export interface TargetReleaseIdArguments {
186
+ self: TransactionArgument;
187
+ }
188
+ export interface TargetReleaseIdOptions {
189
+ package?: string;
190
+ arguments: TargetReleaseIdArguments | [
191
+ self: TransactionArgument
192
+ ];
193
+ }
194
+ /**
195
+ * Returns the target release id this track's creator consented to. Aborts if the
196
+ * track is `Assigned`: an assigned track only exists inside a published release,
197
+ * so its release is the object you fetched it from.
198
+ */
199
+ export function targetReleaseId(options: TargetReleaseIdOptions) {
200
+ const packageAddress = options.package ?? '@local-pkg/miso';
201
+ const argumentsTypes = [
202
+ null
203
+ ] satisfies (string | null)[];
204
+ const parameterNames = ["self"];
205
+ return (tx: Transaction) => tx.moveCall({
206
+ package: packageAddress,
207
+ module: 'track',
208
+ function: 'target_release_id',
209
+ arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
210
+ });
153
211
  }