@withpica/mcp-sdk 3.23.1 → 3.25.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/dist/index.d.ts CHANGED
@@ -1,7 +1,3 @@
1
- /**
2
- * Lightweight PICA SDK client for MCP server
3
- * Uses the PICA API directly without external dependencies
4
- */
5
1
  /**
6
2
  * ADR-179 resolver result shape. Mirrors the server-side
7
3
  * `ResolveWorkResult` in `lib/services/enrichment-cascade/resolver.ts`.
@@ -264,7 +260,12 @@ interface PicaClientConfig {
264
260
  }
265
261
  interface PaginatedResult<T> {
266
262
  data: T[];
267
- total: number;
263
+ /**
264
+ * The real total, or null when the server says it is unknown (a
265
+ * platform-wide registry it will not count, or a filter applied after
266
+ * the read). Never the page length dressed up as a total (row-cap T3).
267
+ */
268
+ total: number | null;
268
269
  hasMore: boolean;
269
270
  /**
270
271
  * Server-provided next-step guidance when a search legitimately returns
@@ -865,6 +866,68 @@ export declare class ApiError extends Error {
865
866
  retryAfterMs?: number | undefined;
866
867
  constructor(message: string, status: number, retryable: boolean, retryAfterMs?: number | undefined);
867
868
  }
869
+ /**
870
+ * ADR-333 D7 — acting for a client catalogue, one call at a time.
871
+ *
872
+ * An organisation's assistant names the client catalogue on each tool call
873
+ * (the optional `catalogue` argument). The MCP server runs that call inside
874
+ * `withCatalogue(id, …)`, and every request the call makes carries
875
+ * `x-pica-catalogue: <id>`. The app resolves it through the relationship on
876
+ * every request (PR 1.3) and answers with `x-pica-catalogue-resolved: <id>`.
877
+ *
878
+ * A per-call context, not a field on the client: the stdio server shares one
879
+ * client across concurrent tool calls, so a field would leak one call's
880
+ * catalogue into another's requests.
881
+ *
882
+ * Fails closed: a 2xx answer without a matching echo means the route did not
883
+ * act for that catalogue (it may have used the caller's own), so the call
884
+ * throws `CatalogueNotHonouredError` instead of reporting success. This is the
885
+ * client's check only; stopping such a route from writing at all is the app's
886
+ * job (PR 1.3 refuses a catalogue header it did not resolve).
887
+ */
888
+ export declare const CATALOGUE_HEADER = "x-pica-catalogue";
889
+ export declare const CATALOGUE_RESOLVED_HEADER = "x-pica-catalogue-resolved";
890
+ /**
891
+ * What the app did with one call's requests in a client catalogue: how many it
892
+ * answered for that catalogue, and which it refused because the route does
893
+ * not open through a relationship, or because the relationship does not
894
+ * allow it (code RELATIONSHIP_REFUSED: proxy.ts, the request-context
895
+ * builders, requireCatalogueContext).
896
+ * The MCP server reads it after the tool returns: a tool that fails its parts
897
+ * soft would otherwise answer "success" with every part refused.
898
+ */
899
+ export interface CatalogueCallReport {
900
+ catalogueId: string;
901
+ answered: number;
902
+ refused: Array<{
903
+ path: string;
904
+ reason: string | null;
905
+ }>;
906
+ }
907
+ /** Run `fn` with every SDK request in it acting for `catalogueId`. */
908
+ export declare function withCatalogue<T>(catalogueId: string | undefined, fn: () => Promise<T>): Promise<T>;
909
+ /**
910
+ * `withCatalogue`, also returning the call's report. The report is the one
911
+ * the call's requests wrote to; it is complete once `fn` settles.
912
+ */
913
+ export declare function runInCatalogue<T>(catalogueId: string, fn: () => Promise<T>): Promise<{
914
+ value: T;
915
+ report: CatalogueCallReport;
916
+ }>;
917
+ /** The catalogue the current call acts for, if any. */
918
+ export declare function currentCatalogue(): string | undefined;
919
+ /**
920
+ * Run `fn` in the current client catalogue (its requests still name it), but
921
+ * leave its requests off the current call's report: for a check PICA makes
922
+ * for itself (the billing gate reading the client's plan), which must not
923
+ * read as the tool's own work having been answered (the MCP server judges a
924
+ * call "every part refused" by that report).
925
+ */
926
+ export declare function asideFromReport<T>(fn: () => Promise<T>): Promise<T>;
927
+ export declare class CatalogueNotHonouredError extends ApiError {
928
+ catalogueId: string;
929
+ constructor(catalogueId: string, path: string);
930
+ }
868
931
  /**
869
932
  * Uniform delete outcome (mirrors the server's deletion contract). `deleted` =
870
933
  * gone; `archived` = hidden but kept (registry data / dependents preserved);
@@ -1032,6 +1095,12 @@ declare class WorksResource extends BaseResource {
1032
1095
  */
1033
1096
  has_lyrics?: boolean;
1034
1097
  }): Promise<PaginatedResult<Work>>;
1098
+ /**
1099
+ * The agreements linked to ONE work (GET /admin/works/:id/agreements).
1100
+ * Inspect used `agreements.list()`, which returned the org's first page of
1101
+ * agreements under a work's heading (row-cap T3).
1102
+ */
1103
+ getAgreements(workId: string): Promise<any[]>;
1035
1104
  get(id: string): Promise<Work>;
1036
1105
  create(data: Partial<Work> & {
1037
1106
  create_twin?: boolean;
@@ -1177,6 +1246,49 @@ declare class WorksResource extends BaseResource {
1177
1246
  person_id?: string;
1178
1247
  }>;
1179
1248
  }>;
1249
+ /** A song's directory topics: approved, proposed, moods awaiting review, settings. */
1250
+ getThemes(workId: string): Promise<WorkThemeState>;
1251
+ /** Set the song's approved topics directly, and/or its switch and lyric visibility. */
1252
+ setThemes(workId: string, body: {
1253
+ themes?: string[];
1254
+ themes_enabled?: boolean;
1255
+ lyrics_visibility?: "themes" | "snippet" | "full";
1256
+ }): Promise<WorkThemeState>;
1257
+ /** Propose topics (and recording moods) for the owner to review. Nothing goes public. */
1258
+ proposeThemes(workId: string, body: {
1259
+ themes?: string[];
1260
+ moods?: Array<{
1261
+ recording_id: string;
1262
+ moods: string[];
1263
+ }>;
1264
+ }): Promise<WorkThemeState>;
1265
+ /** The owner's review of proposed topics and moods. */
1266
+ reviewThemes(workId: string, body: {
1267
+ approve?: string[] | "all";
1268
+ reject?: string[];
1269
+ approve_moods_for?: string[] | "all";
1270
+ reject_moods_for?: string[] | "all";
1271
+ }): Promise<WorkThemeState>;
1272
+ }
1273
+ /** GET /api/admin/works/[id]/themes (lib/services/directory/themes.ts ThemeState). */
1274
+ export interface WorkThemeState {
1275
+ work_id: string;
1276
+ title: string;
1277
+ has_lyrics: boolean;
1278
+ themes_enabled: boolean;
1279
+ lyrics_visibility: "themes" | "snippet" | "full";
1280
+ approved: Array<{
1281
+ theme: string;
1282
+ source: "owner" | "assistant";
1283
+ }>;
1284
+ proposed: Array<{
1285
+ theme: string;
1286
+ source: "owner" | "assistant";
1287
+ }>;
1288
+ proposed_moods: Array<{
1289
+ recording_id: string;
1290
+ moods: string[];
1291
+ }>;
1180
1292
  }
1181
1293
  declare class PeopleResource extends BaseResource {
1182
1294
  list(params?: {
@@ -1256,6 +1368,14 @@ declare class PeopleResource extends BaseResource {
1256
1368
  musicbrainz_id?: string;
1257
1369
  }): Promise<Record<string, unknown>>;
1258
1370
  }
1371
+ export interface LicenseEnquiryListParams {
1372
+ work_id?: string;
1373
+ status?: string;
1374
+ project_type?: string;
1375
+ territory?: string;
1376
+ limit?: number;
1377
+ offset?: number;
1378
+ }
1259
1379
  declare class LicensingResource extends BaseResource {
1260
1380
  /**
1261
1381
  * Search for sync-licensable tracks by audio characteristics
@@ -1266,16 +1386,16 @@ declare class LicensingResource extends BaseResource {
1266
1386
  */
1267
1387
  submitEnquiry(enquiry: LicenseEnquiryInput): Promise<LicenseEnquiry>;
1268
1388
  /**
1269
- * List license enquiries with optional filters
1389
+ * List license enquiries with optional filters (one page, the bare array;
1390
+ * see listEnquiriesPage for the real total).
1270
1391
  */
1271
- listEnquiries(params?: {
1272
- work_id?: string;
1273
- status?: string;
1274
- project_type?: string;
1275
- territory?: string;
1276
- limit?: number;
1277
- offset?: number;
1278
- }): Promise<LicenseEnquiry[]>;
1392
+ listEnquiries(params?: LicenseEnquiryListParams): Promise<LicenseEnquiry[]>;
1393
+ /**
1394
+ * One page of license enquiries WITH the real total and has_more
1395
+ * (row-cap T3): `listEnquiries()` returns the bare array, so callers
1396
+ * reported the page length as the total.
1397
+ */
1398
+ listEnquiriesPage(params?: LicenseEnquiryListParams): Promise<PaginatedResult<LicenseEnquiry>>;
1279
1399
  /**
1280
1400
  * Get a specific license enquiry by ID
1281
1401
  */
@@ -1297,20 +1417,27 @@ declare class LicensingResource extends BaseResource {
1297
1417
  * bookings, distinct from `LicensingResource`'s sync-license enquiries).
1298
1418
  * Wraps `/admin/bookings` + `/admin/bookings/[id]`.
1299
1419
  */
1420
+ export interface BookingListParams {
1421
+ status?: string;
1422
+ priority?: string;
1423
+ query?: string;
1424
+ enquiry_type?: string;
1425
+ follow_up_required?: boolean;
1426
+ limit?: number;
1427
+ offset?: number;
1428
+ }
1300
1429
  declare class BookingsResource extends BaseResource {
1301
1430
  /**
1302
- * List/search booking enquiries. `GET /admin/bookings` returns the raw
1303
- * array (not `{data, count}`) — `request()` unwraps to that array.
1431
+ * One page of booking enquiries (the bare array; see listPage for the real
1432
+ * total). `request()` unwraps the route's `{ data, count }` envelope.
1304
1433
  */
1305
- list(params?: {
1306
- status?: string;
1307
- priority?: string;
1308
- query?: string;
1309
- enquiry_type?: string;
1310
- follow_up_required?: boolean;
1311
- limit?: number;
1312
- offset?: number;
1313
- }): Promise<BookingEnquiry[]>;
1434
+ list(params?: BookingListParams): Promise<BookingEnquiry[]>;
1435
+ /**
1436
+ * One page of booking enquiries WITH the real total and has_more
1437
+ * (row-cap T3): `list()` returns the bare array, so callers reported the
1438
+ * page length as the total.
1439
+ */
1440
+ listPage(params?: BookingListParams): Promise<PaginatedResult<BookingEnquiry>>;
1314
1441
  get(id: string): Promise<BookingEnquiry>;
1315
1442
  /**
1316
1443
  * `PATCH /admin/bookings/[id]` only processes ONE update mode per call
@@ -1827,36 +1954,44 @@ declare class MultimediaResource extends BaseResource {
1827
1954
  }): Promise<MultimediaItem>;
1828
1955
  linkWork(id: string, workId: string, relationshipType: string, notes?: string): Promise<Record<string, unknown>>;
1829
1956
  }
1957
+ export interface AgreementListParams {
1958
+ query?: string;
1959
+ agreement_type?: string;
1960
+ status?: string;
1961
+ party_name?: string;
1962
+ includeWorkCounts?: boolean;
1963
+ /**
1964
+ * ADR-289 Wave B1 item 4 — filter to agreements in `pending_signature`
1965
+ * or `partially_signed` (ports the bespoke assistant's
1966
+ * `list_pending_signatures`). Maps to `?awaiting_signature=true` on the
1967
+ * route, which already had multi-status filtering (`statuses[]`) under
1968
+ * the hood.
1969
+ */
1970
+ awaiting_signature?: boolean;
1971
+ /** Agreements with start_date on/after this ISO date (YYYY-MM-DD). */
1972
+ start_date_from?: string;
1973
+ /** Agreements with start_date on/before this ISO date. */
1974
+ start_date_to?: string;
1975
+ /** Agreements with end_date on/after this ISO date. */
1976
+ end_date_from?: string;
1977
+ /** Agreements with end_date on/before this ISO date. */
1978
+ end_date_to?: string;
1979
+ /** Active agreements whose end_date falls within N days from today. */
1980
+ expiring_within_days?: number;
1981
+ /** true → only agreements that have an end_date; false → only open-ended. */
1982
+ has_end_date?: boolean;
1983
+ limit?: number;
1984
+ offset?: number;
1985
+ }
1830
1986
  declare class AgreementsResource extends BaseResource {
1831
- list(params?: {
1832
- query?: string;
1833
- agreement_type?: string;
1834
- status?: string;
1835
- party_name?: string;
1836
- includeWorkCounts?: boolean;
1837
- /**
1838
- * ADR-289 Wave B1 item 4 — filter to agreements in `pending_signature`
1839
- * or `partially_signed` (ports the bespoke assistant's
1840
- * `list_pending_signatures`). Maps to `?awaiting_signature=true` on the
1841
- * route, which already had multi-status filtering (`statuses[]`) under
1842
- * the hood.
1843
- */
1844
- awaiting_signature?: boolean;
1845
- /** Agreements with start_date on/after this ISO date (YYYY-MM-DD). */
1846
- start_date_from?: string;
1847
- /** Agreements with start_date on/before this ISO date. */
1848
- start_date_to?: string;
1849
- /** Agreements with end_date on/after this ISO date. */
1850
- end_date_from?: string;
1851
- /** Agreements with end_date on/before this ISO date. */
1852
- end_date_to?: string;
1853
- /** Active agreements whose end_date falls within N days from today. */
1854
- expiring_within_days?: number;
1855
- /** true → only agreements that have an end_date; false → only open-ended. */
1856
- has_end_date?: boolean;
1857
- limit?: number;
1858
- offset?: number;
1859
- }): Promise<Agreement[]>;
1987
+ /** One page of agreements (the bare array; see listPage for the real total). */
1988
+ list(params?: AgreementListParams): Promise<Agreement[]>;
1989
+ /**
1990
+ * One page of agreements WITH the real total and has_more (row-cap T3):
1991
+ * `list()` returns the bare array, so callers reported the page length
1992
+ * as the total.
1993
+ */
1994
+ listPage(params?: AgreementListParams): Promise<PaginatedResult<Agreement>>;
1860
1995
  get(id: string): Promise<{
1861
1996
  agreement: Agreement;
1862
1997
  signatureStatus: unknown;
@@ -1921,6 +2056,59 @@ declare class AgreementsResource extends BaseResource {
1921
2056
  expires_in_days?: number;
1922
2057
  }): Promise<AgreementSendForSignatureResult>;
1923
2058
  }
2059
+ /** One production behind a sync-fit match (TMDB and Wikidata facts). */
2060
+ export interface SyncFitProduction {
2061
+ tmdb_id: number | null;
2062
+ release_date: string | null;
2063
+ genres: string[];
2064
+ themes: string[];
2065
+ countries: string[];
2066
+ language: string | null;
2067
+ companies: string[];
2068
+ networks: string[];
2069
+ }
2070
+ /** One analysed master's measured facts (the MCPs' shared `measured` names). */
2071
+ export interface SyncFitMeasured {
2072
+ audio_file_id: string;
2073
+ tempo_bpm: number | null;
2074
+ key: string | null;
2075
+ mode: "major" | "minor" | null;
2076
+ duration_seconds: number | null;
2077
+ }
2078
+ export interface SyncFitSongFacts {
2079
+ genres: string[];
2080
+ language: string | null;
2081
+ measured: SyncFitMeasured[];
2082
+ }
2083
+ export interface SyncFitRow {
2084
+ work_id: string;
2085
+ screen_project_id: string;
2086
+ work_title: string | null;
2087
+ production_title: string | null;
2088
+ production_type: string | null;
2089
+ production_status: string | null;
2090
+ band: "strong" | "possible";
2091
+ reasons: string[];
2092
+ production: SyncFitProduction;
2093
+ song?: SyncFitSongFacts;
2094
+ }
2095
+ export interface SyncFitPage {
2096
+ rows: SyncFitRow[];
2097
+ total: number;
2098
+ songs: number;
2099
+ offset: number;
2100
+ limit: number;
2101
+ }
2102
+ /** Sync fit: GET /admin/sync-fit, the same read as /inspect/sync. */
2103
+ declare class SyncFitResource extends BaseResource {
2104
+ query(params?: {
2105
+ work_id?: string;
2106
+ screen_project_id?: string;
2107
+ song_facts?: boolean;
2108
+ limit?: number;
2109
+ offset?: number;
2110
+ }): Promise<SyncFitPage>;
2111
+ }
1924
2112
  declare class SyncPlacementsResource extends BaseResource {
1925
2113
  list(params?: SyncPlacementQueryParams): Promise<PaginatedResult<SyncPlacement>>;
1926
2114
  get(id: string): Promise<SyncPlacementWithRelations>;
@@ -2339,6 +2527,26 @@ declare class EnrichmentResource extends BaseResource {
2339
2527
  rejected: number;
2340
2528
  skipped: string[];
2341
2529
  }>;
2530
+ /**
2531
+ * What bulkRejectProposals would reject, without rejecting: the route
2532
+ * resolves the same pending set the real call would (row-cap T3).
2533
+ */
2534
+ previewBulkRejectProposals(input: {
2535
+ proposal_ids?: string[];
2536
+ filter?: {
2537
+ rule_id?: string;
2538
+ source?: string;
2539
+ max_confidence?: number;
2540
+ };
2541
+ }): Promise<{
2542
+ dry_run: true;
2543
+ would_affect: string[];
2544
+ /** null when exceeds_cap: the count past the cap is not read. */
2545
+ count: number | null;
2546
+ skipped: string[];
2547
+ exceeds_cap: boolean;
2548
+ cap: number;
2549
+ }>;
2342
2550
  /**
2343
2551
  * Apply many pending proposals in one call — the accept side of the
2344
2552
  * /inspect/found queue.
@@ -3504,6 +3712,14 @@ declare class DuplicatesResource extends BaseResource {
3504
3712
  */
3505
3713
  findDuplicates(entityType: "works" | "people" | "releases" | "recordings" | "audio_files"): Promise<any>;
3506
3714
  merge(entityType: "work" | "person" | "recording" | "release", winnerId: string, loserIds: string[]): Promise<any>;
3715
+ /**
3716
+ * "They're different": mark every pair among `ids` (2–25 recordings or
3717
+ * releases of this catalogue) as not duplicates, so findDuplicates stops
3718
+ * offering them. Idempotent. Resolves {entity_type, ids, pairs, changed}.
3719
+ */
3720
+ markDifferent(entityType: "recordings" | "releases", ids: string[]): Promise<any>;
3721
+ /** Take back markDifferent for every pair among `ids`. */
3722
+ unmarkDifferent(entityType: "recordings" | "releases", ids: string[]): Promise<any>;
3507
3723
  }
3508
3724
  declare class EntityContextResource extends BaseResource {
3509
3725
  getWorkFull(workId: string): Promise<Record<string, unknown>>;
@@ -4031,6 +4247,22 @@ declare class CollaboratorsResource extends BaseResource {
4031
4247
  workId?: string;
4032
4248
  limit?: number;
4033
4249
  }): Promise<CollaboratorInvite[]>;
4250
+ /**
4251
+ * One page of the invites this org sent WITH the real total and has_more
4252
+ * (row-cap T3). `listInvites()` is typed as an array but the route nests
4253
+ * its rows as `data: { data, count }`, so it never carried a usable total.
4254
+ */
4255
+ listInvitesPage(params?: {
4256
+ status?: "pending" | "verified" | "confirmed" | "expired" | "cancelled" | "disputed";
4257
+ workId?: string;
4258
+ limit?: number;
4259
+ offset?: number;
4260
+ }): Promise<PaginatedResult<CollaboratorInvite>>;
4261
+ /**
4262
+ * Reads a collaborator list route, whose rows sit at `data.data` (kept
4263
+ * for published SDKs) with the total in the top-level `pagination`.
4264
+ */
4265
+ private requestNestedPage;
4034
4266
  resendInvite(inviteId: string): Promise<Record<string, unknown>>;
4035
4267
  /**
4036
4268
  * ADR-157 warm path — list invites addressed to the authenticated
@@ -4046,6 +4278,20 @@ declare class CollaboratorsResource extends BaseResource {
4046
4278
  credit_type: string;
4047
4279
  percentage_split: number | null;
4048
4280
  }>>;
4281
+ /**
4282
+ * One page of the invites addressed to the caller WITH the real total and
4283
+ * has_more (row-cap T3: `listIncoming()` returns only the rows).
4284
+ */
4285
+ listIncomingPage(params?: {
4286
+ status?: "pending" | "verified" | "confirmed" | "expired" | "cancelled" | "disputed";
4287
+ limit?: number;
4288
+ offset?: number;
4289
+ }): Promise<PaginatedResult<CollaboratorInvite & {
4290
+ work_title: string | null;
4291
+ inviter_org_name: string | null;
4292
+ credit_type: string;
4293
+ percentage_split: number | null;
4294
+ }>>;
4049
4295
  /**
4050
4296
  * ADR-157 warm path — accept an invite addressed to the authenticated
4051
4297
  * user, and flip its status to confirmed. The credit write is
@@ -4279,6 +4525,15 @@ declare class DirectoryResource extends BaseResource {
4279
4525
  eligible_work_count: number;
4280
4526
  }>;
4281
4527
  updateSettings(updates: Partial<DirectorySettings>): Promise<DirectorySettings>;
4528
+ /** Listed songs with lyrics and topics on, but no approved topic yet. */
4529
+ untaggedThemes(): Promise<{
4530
+ count: number;
4531
+ songs: Array<{
4532
+ work_id: string;
4533
+ title: string;
4534
+ pending_proposals: number;
4535
+ }>;
4536
+ }>;
4282
4537
  }
4283
4538
  declare class ProjectsResource extends BaseResource {
4284
4539
  list(params?: {
@@ -4601,6 +4856,15 @@ declare class RecordingSplitsResource extends BaseResource {
4601
4856
  verify(recordingId: string, splitId: string): Promise<any>;
4602
4857
  }
4603
4858
  declare class PublishersResource extends BaseResource {
4859
+ /**
4860
+ * One page of the publisher registry with an honest has_more. The total
4861
+ * is null: the route does not count the platform-wide registry.
4862
+ */
4863
+ listPage(params?: {
4864
+ query?: string;
4865
+ limit?: number;
4866
+ offset?: number;
4867
+ }): Promise<PaginatedResult<any>>;
4604
4868
  list(params?: {
4605
4869
  query?: string;
4606
4870
  limit?: number;
@@ -4629,6 +4893,18 @@ export interface LabelIdentifiers {
4629
4893
  deezer_label_id?: string;
4630
4894
  }
4631
4895
  declare class LabelsResource extends BaseResource {
4896
+ /**
4897
+ * One page of label/distributor organisations with an honest has_more.
4898
+ * The total is null: the route does not count platform-wide rows.
4899
+ */
4900
+ listPage(params?: {
4901
+ query?: string;
4902
+ limit?: number;
4903
+ offset?: number;
4904
+ org_type?: "label" | "distributor";
4905
+ /** Only these organisation ids — a lookup by id. */
4906
+ ids?: string[];
4907
+ }): Promise<PaginatedResult<LabelOrganisation>>;
4632
4908
  list(params?: {
4633
4909
  query?: string;
4634
4910
  limit?: number;
@@ -4684,6 +4960,12 @@ export interface PartyClaimInviteResult {
4684
4960
  * Typed against the UNWRAPPED reality (ADR-265 lesson): BaseResource.request
4685
4961
  * auto-unwraps the `{success,data}` envelope, so methods see `data` itself.
4686
4962
  */
4963
+ export interface PartyClaimListParams {
4964
+ target_organisation_id?: string;
4965
+ status?: string;
4966
+ limit?: number;
4967
+ offset?: number;
4968
+ }
4687
4969
  declare class PartyClaimsResource extends BaseResource {
4688
4970
  invite(params: {
4689
4971
  target_organisation_id: string;
@@ -4691,11 +4973,13 @@ declare class PartyClaimsResource extends BaseResource {
4691
4973
  release_id?: string;
4692
4974
  recording_id?: string;
4693
4975
  }): Promise<PartyClaimInviteResult | null>;
4694
- list(params?: {
4695
- target_organisation_id?: string;
4696
- status?: string;
4697
- limit?: number;
4698
- }): Promise<PartyClaimInviteSummary[]>;
4976
+ list(params?: PartyClaimListParams): Promise<PartyClaimInviteSummary[]>;
4977
+ /**
4978
+ * One page of sent claim invites WITH the real total and has_more
4979
+ * (row-cap T3): `list()` returns the bare array, so callers reported the
4980
+ * page length as the total.
4981
+ */
4982
+ listPage(params?: PartyClaimListParams): Promise<PaginatedResult<PartyClaimInviteSummary>>;
4699
4983
  }
4700
4984
  /** One person's outcome from POST /admin/people/claim-invites. */
4701
4985
  export interface ProfileClaimInviteOutcome {
@@ -4754,16 +5038,25 @@ declare class ProfileClaimsResource extends BaseResource {
4754
5038
  limit?: number;
4755
5039
  }): Promise<ProfileClaimStatusResult>;
4756
5040
  }
5041
+ export interface ReleaseListParams {
5042
+ limit?: number;
5043
+ offset?: number;
5044
+ query?: string;
5045
+ upc?: string;
5046
+ spotify_album_id?: string;
5047
+ release_date_from?: string;
5048
+ release_date_to?: string;
5049
+ }
4757
5050
  declare class ReleasesResource extends BaseResource {
4758
- list(params?: {
4759
- limit?: number;
4760
- offset?: number;
4761
- query?: string;
4762
- upc?: string;
4763
- spotify_album_id?: string;
4764
- release_date_from?: string;
4765
- release_date_to?: string;
4766
- }): Promise<any>;
5051
+ /** One page of releases (the bare array; see listPage for the real total). */
5052
+ list(params?: ReleaseListParams): Promise<any>;
5053
+ /**
5054
+ * One page of releases WITH the real total and has_more (row-cap T3):
5055
+ * `list()` returns the bare array, so callers guessed has_more from "the
5056
+ * page came back full". `total` is null when the server cannot count (a
5057
+ * title search past its match cap); has_more is the server's own answer.
5058
+ */
5059
+ listPage(params?: ReleaseListParams): Promise<PaginatedResult<any>>;
4767
5060
  get(id: string): Promise<any>;
4768
5061
  /**
4769
5062
  * ADR-208 Phase 3 Primitive D — fetch a server-resized ≤512px JPEG
@@ -4897,10 +5190,20 @@ declare class ReleasesResource extends BaseResource {
4897
5190
  }): Promise<any>;
4898
5191
  }
4899
5192
  declare class SessionsResource extends BaseResource {
5193
+ /** One page of upcoming sessions (see listPage for the real total). */
4900
5194
  list(params?: {
4901
5195
  limit?: number;
4902
5196
  offset?: number;
4903
5197
  }): Promise<any>;
5198
+ /**
5199
+ * One page of the next 7 days' sessions WITH the real total and has_more
5200
+ * (row-cap T3): `list()` returns the bare array, so callers could only
5201
+ * guess has_more from "the page came back full".
5202
+ */
5203
+ listPage(params?: {
5204
+ limit?: number;
5205
+ offset?: number;
5206
+ }): Promise<PaginatedResult<any>>;
4904
5207
  get(id: string): Promise<any>;
4905
5208
  create(data: Record<string, any>): Promise<any>;
4906
5209
  update(id: string, data: Record<string, any>): Promise<any>;
@@ -4970,6 +5273,318 @@ declare class RightsResource extends BaseResource {
4970
5273
  /** GET /admin/rights-statements/measures — the four measures (ADR-321 §7a). */
4971
5274
  measures(): Promise<any>;
4972
5275
  }
5276
+ /** A relationship's scope, as the routes return it (camelCase). */
5277
+ export interface RelationshipScopeRecord {
5278
+ half: "both" | "composition" | "master";
5279
+ territories: string[];
5280
+ termStartsOn: string | null;
5281
+ termEndsOn: string | null;
5282
+ money: boolean;
5283
+ directory: boolean;
5284
+ catalogue: "whole" | "chosen";
5285
+ workIds: string[];
5286
+ recordingIds: string[];
5287
+ }
5288
+ /**
5289
+ * One relationship (`org_grants` row) as GET /admin/relationships returns it.
5290
+ * `version` is passed back as `expected_version` on every step, so a step
5291
+ * never lands on terms that changed since they were read.
5292
+ */
5293
+ export interface RelationshipRecord {
5294
+ id: string;
5295
+ grantorOrgId: string;
5296
+ grantorOrgName: string;
5297
+ granteeOrgId: string;
5298
+ granteeOrgName: string;
5299
+ type: "co_owner" | "administrator" | "representative" | "viewer";
5300
+ status: "proposed" | "active" | "declined" | "revoked" | "stepped_down" | "expired" | "suspended";
5301
+ proposedBySide: "grantor" | "grantee";
5302
+ scope: RelationshipScopeRecord;
5303
+ proposedAt: string;
5304
+ respondedAt: string | null;
5305
+ endedAt: string | null;
5306
+ endReason: string | null;
5307
+ proposalExpiresAt: string | null;
5308
+ suspendedAt: string | null;
5309
+ version: number;
5310
+ [key: string]: unknown;
5311
+ }
5312
+ /** An invitation waiting for the person (no address in it). */
5313
+ export interface ClaimableInviteRecord {
5314
+ invite_id: string;
5315
+ direction: "grantee_invites_owner" | "owner_invites_grantee";
5316
+ inviting_org_id: string;
5317
+ inviting_org_name: string;
5318
+ type: RelationshipRecord["type"];
5319
+ scope: RelationshipScopeRecord;
5320
+ expires_at: string;
5321
+ eligible_organisations: Array<{
5322
+ id: string;
5323
+ name: string;
5324
+ }>;
5325
+ }
5326
+ export interface RelationshipListPage {
5327
+ rows: RelationshipRecord[];
5328
+ nextCursor: string | null;
5329
+ waiting_for_you: ClaimableInviteRecord[];
5330
+ /** Set when the waiting invitations could not be read: never "none waiting". */
5331
+ waiting_for_you_unavailable?: "email_not_verified" | "check_failed";
5332
+ }
5333
+ /** One audit row (`org_grant_events`). */
5334
+ export interface RelationshipEventRecord {
5335
+ id: string;
5336
+ relationshipId: string;
5337
+ kind: string;
5338
+ at: string;
5339
+ actorSide: "grantor" | "grantee" | "system" | "platform";
5340
+ actorDisplayName: string | null;
5341
+ grantorOrgId: string;
5342
+ grantorOrgName: string;
5343
+ granteeOrgId: string;
5344
+ granteeOrgName: string;
5345
+ type: RelationshipRecord["type"];
5346
+ typeBefore: RelationshipRecord["type"] | null;
5347
+ statusBefore: RelationshipRecord["status"] | null;
5348
+ statusAfter: RelationshipRecord["status"];
5349
+ version: number;
5350
+ /** The scope before this event (null for `proposed`). */
5351
+ scopeBefore: RelationshipScopeRecord | null;
5352
+ /** The scope after this event (for an ending: the scope that ended). */
5353
+ scope: RelationshipScopeRecord;
5354
+ reason: string | null;
5355
+ action: string | null;
5356
+ entityType: string | null;
5357
+ entityId: string | null;
5358
+ detail: Record<string, unknown>;
5359
+ [key: string]: unknown;
5360
+ }
5361
+ export interface RelationshipPageOf<T> {
5362
+ rows: T[];
5363
+ nextCursor: string | null;
5364
+ }
5365
+ /** The result of accepting, declining, editing, revoking or stepping down. */
5366
+ export interface RelationshipStepRecord {
5367
+ relationship: RelationshipRecord;
5368
+ event: RelationshipEventRecord | null;
5369
+ }
5370
+ /** The result of accepting an invitation: the claim and the accept, both recorded. */
5371
+ export interface RelationshipInviteAcceptRecord {
5372
+ relationship: RelationshipRecord;
5373
+ events: RelationshipEventRecord[];
5374
+ }
5375
+ /** A hand-over just created (ADR-333 D5): nothing is sent yet. */
5376
+ export interface HandoverCreatedRecord {
5377
+ handover_id: string;
5378
+ catalogue_org_id: string;
5379
+ }
5380
+ /** A hand-over as its builder sees it (POST /admin/handovers/{id}/send). */
5381
+ export interface HandoverRecord {
5382
+ handover_id: string;
5383
+ catalogue_org_id: string;
5384
+ catalogue_name: string | null;
5385
+ builder_org_id: string;
5386
+ builder_name: string | null;
5387
+ client_name: string;
5388
+ client_email?: string;
5389
+ status: string;
5390
+ relationship_type: string;
5391
+ sent_at: string | null;
5392
+ expires_at: string | null;
5393
+ version: number;
5394
+ }
5395
+ /**
5396
+ * Catalogues an organisation builds for a client, who accepts to own them
5397
+ * (ADR-333 D5). Builder side only: the client answers on screen, signed in.
5398
+ */
5399
+ declare class HandoversResource extends BaseResource {
5400
+ /**
5401
+ * POST /admin/handovers — create a catalogue for a client
5402
+ * (catalogue_name), or a new hand-over on one this organisation built whose
5403
+ * last one closed (catalogue_org_id). Nothing is sent.
5404
+ */
5405
+ create(body: {
5406
+ catalogue_name?: string;
5407
+ catalogue_org_id?: string;
5408
+ client_name: string;
5409
+ client_email: string;
5410
+ relationship_type: string;
5411
+ }): Promise<HandoverCreatedRecord>;
5412
+ /** POST /admin/handovers/{id}/send { expected_version? } — email the client. */
5413
+ send(id: string, body: {
5414
+ expected_version?: number;
5415
+ }): Promise<HandoverRecord>;
5416
+ }
5417
+ /**
5418
+ * /admin/relationships/** — both sides of a relationship. Refusals arrive as
5419
+ * `{ success: false, error: { code, message, details? } }` (read them with
5420
+ * the MCP package's parseApiErrorBody); a step whose terms changed since they
5421
+ * were read is a 409 `status_changed` carrying `details.relationship`.
5422
+ */
5423
+ declare class RelationshipsResource extends BaseResource {
5424
+ /** GET /admin/relationships?side=owner|organisation&status=&cursor=&limit= */
5425
+ list(params: {
5426
+ side: "owner" | "organisation";
5427
+ statuses?: string[];
5428
+ cursor?: string;
5429
+ limit?: number;
5430
+ }): Promise<RelationshipListPage>;
5431
+ /** GET /admin/relationships/{id} */
5432
+ get(id: string): Promise<RelationshipRecord>;
5433
+ /**
5434
+ * POST /admin/relationships { as, email, type, scope? } — invite someone by
5435
+ * email. as="owner" asks someone at an organisation to look after this
5436
+ * catalogue; as="organisation" asks a client to let this organisation look
5437
+ * after theirs. The reply is the same whether or not the address is on PICA.
5438
+ */
5439
+ invite(body: {
5440
+ as: "owner" | "organisation";
5441
+ email: string;
5442
+ type: string;
5443
+ scope?: Record<string, unknown>;
5444
+ }): Promise<Record<string, unknown>>;
5445
+ /** PATCH /admin/relationships/{id} { action: accept | decline | edit, expected_version, … } */
5446
+ answer(id: string, body: {
5447
+ action: "accept" | "decline" | "edit";
5448
+ expected_version: number;
5449
+ type?: string;
5450
+ scope?: Record<string, unknown>;
5451
+ reason?: string;
5452
+ }): Promise<RelationshipStepRecord>;
5453
+ /** DELETE /admin/relationships/{id} { expected_version, reason? } — the owner ends it. */
5454
+ revoke(id: string, body: {
5455
+ expected_version: number;
5456
+ reason?: string;
5457
+ }): Promise<RelationshipStepRecord>;
5458
+ /** POST /admin/relationships/{id}/step-down { expected_version, reason? } — the organisation ends its side. */
5459
+ stepDown(id: string, body: {
5460
+ expected_version: number;
5461
+ reason?: string;
5462
+ }): Promise<RelationshipStepRecord>;
5463
+ /** GET /admin/relationships/{id}/activity — one relationship's history, either party. */
5464
+ events(id: string, params?: {
5465
+ cursor?: string;
5466
+ limit?: number;
5467
+ }): Promise<RelationshipPageOf<RelationshipEventRecord>>;
5468
+ /**
5469
+ * GET /admin/relationships/activity?side=&org= — side=owner: what
5470
+ * organisations did in this catalogue (org = one organisation);
5471
+ * side=organisation: this organisation's own actions (org = one catalogue).
5472
+ */
5473
+ activity(params: {
5474
+ side: "owner" | "organisation";
5475
+ org?: string;
5476
+ cursor?: string;
5477
+ limit?: number;
5478
+ }): Promise<RelationshipPageOf<RelationshipEventRecord>>;
5479
+ /**
5480
+ * PATCH /admin/relationships/invites/{id} { action: "accept", organisation_id, type?, scope? }
5481
+ * — answer yes to an invitation for one of the person's organisations.
5482
+ */
5483
+ acceptInvite(inviteId: string, body: {
5484
+ organisation_id: string;
5485
+ type?: string;
5486
+ scope?: Record<string, unknown>;
5487
+ }): Promise<RelationshipInviteAcceptRecord>;
5488
+ }
5489
+ /** A portfolio section: checked, out of scope, unavailable, or failed (never 0). */
5490
+ export type PortfolioSection<T> = {
5491
+ state: "ok";
5492
+ data: T;
5493
+ } | {
5494
+ state: "not_in_scope" | "unavailable" | "failed";
5495
+ reason: string;
5496
+ };
5497
+ /** One client catalogue an organisation looks after (portfolio PR 1.4). */
5498
+ export interface PortfolioClientRecord {
5499
+ relationshipId: string;
5500
+ catalogue: {
5501
+ orgId: string;
5502
+ name: string;
5503
+ };
5504
+ relationship: {
5505
+ type: RelationshipRecord["type"];
5506
+ typeLabel: string;
5507
+ status: "active" | "suspended";
5508
+ access: "open" | "paused" | "not_started";
5509
+ acceptedAt: string | null;
5510
+ termEndsOn: string | null;
5511
+ endingSoon: boolean;
5512
+ version: number;
5513
+ /** What a change by this caller does in that catalogue. */
5514
+ changes: "direct" | "proposal" | "none";
5515
+ scope: {
5516
+ half: RelationshipScopeRecord["half"];
5517
+ territories: string[];
5518
+ termStartsOn: string | null;
5519
+ termEndsOn: string | null;
5520
+ money: boolean;
5521
+ directory: boolean;
5522
+ catalogue: "whole" | "chosen";
5523
+ songsChosen: number;
5524
+ recordingsChosen: number;
5525
+ };
5526
+ };
5527
+ /** null = the scope doesn't cover that half ("not covered", never 0). */
5528
+ missing: PortfolioSection<{
5529
+ songs: number | null;
5530
+ songsWithGaps: number | null;
5531
+ recordings: number | null;
5532
+ recordingsWithGaps: number | null;
5533
+ }>;
5534
+ moneyBlockers: PortfolioSection<{
5535
+ songs: number;
5536
+ blocked: number;
5537
+ clear: number;
5538
+ unknown: number;
5539
+ byCode: Array<{
5540
+ code: string;
5541
+ label: string;
5542
+ songs: number;
5543
+ }>;
5544
+ }>;
5545
+ enquiries: PortfolioSection<{
5546
+ waiting: number;
5547
+ oldestAt: string | null;
5548
+ }>;
5549
+ deadlines: PortfolioSection<{
5550
+ total: number;
5551
+ items: Array<{
5552
+ kind: string;
5553
+ on: string;
5554
+ label: string;
5555
+ }>;
5556
+ }>;
5557
+ /** Briefing only: at most five, in scope only. */
5558
+ highlights?: Array<{
5559
+ kind: string;
5560
+ label: string;
5561
+ workId?: string;
5562
+ recordingId?: string;
5563
+ }>;
5564
+ [key: string]: unknown;
5565
+ }
5566
+ export interface PortfolioPage {
5567
+ rows: PortfolioClientRecord[];
5568
+ nextCursor: string | null;
5569
+ asOf: string;
5570
+ }
5571
+ /**
5572
+ * /admin/portfolio — the client catalogues an organisation looks after. A
5573
+ * page may hold fewer rows than `limit` and still not be the last: follow
5574
+ * `nextCursor` until it is null.
5575
+ */
5576
+ declare class PortfolioResource extends BaseResource {
5577
+ /** GET /admin/portfolio?cursor=&limit= (limit ≤ 25) */
5578
+ list(params?: {
5579
+ cursor?: string;
5580
+ limit?: number;
5581
+ }): Promise<PortfolioPage>;
5582
+ /** GET /admin/portfolio/briefing?cursor=&limit= — the list plus what needs attention. */
5583
+ briefing(params?: {
5584
+ cursor?: string;
5585
+ limit?: number;
5586
+ }): Promise<PortfolioPage>;
5587
+ }
4973
5588
  declare class RoyaltiesResource extends BaseResource {
4974
5589
  payments(params?: {
4975
5590
  source?: string;
@@ -5209,10 +5824,16 @@ declare class CustodyResource extends BaseResource {
5209
5824
  action: "accept" | "decline" | "dispute";
5210
5825
  reason?: string;
5211
5826
  }): Promise<any>;
5827
+ /**
5828
+ * Custody claims, one page per direction. Since row-cap T3 the result also
5829
+ * carries `totals: { incoming, outgoing }` (null for a direction not asked
5830
+ * for), `has_more: { incoming, outgoing }`, `limit` and `offset`.
5831
+ */
5212
5832
  list(params?: {
5213
5833
  direction?: "incoming" | "outgoing" | "both";
5214
5834
  status?: string;
5215
5835
  limit?: number;
5836
+ offset?: number;
5216
5837
  }): Promise<any>;
5217
5838
  history(params: {
5218
5839
  work_id: string;
@@ -5459,6 +6080,7 @@ export declare class PicaClient {
5459
6080
  multimedia: MultimediaResource;
5460
6081
  agreements: AgreementsResource;
5461
6082
  syncPlacements: SyncPlacementsResource;
6083
+ syncFit: SyncFitResource;
5462
6084
  workspace: WorkspaceResource;
5463
6085
  memory: MemoryResource;
5464
6086
  audit: AuditResource;
@@ -5504,6 +6126,11 @@ export declare class PicaClient {
5504
6126
  producerAgreements: ProducerAgreementsResource;
5505
6127
  workForHire: WorkForHireResource;
5506
6128
  royalties: RoyaltiesResource;
6129
+ /** ADR-333 — who looks after whose catalogue, from either side. */
6130
+ relationships: RelationshipsResource;
6131
+ handovers: HandoversResource;
6132
+ /** ADR-333 — the client catalogues an organisation looks after. */
6133
+ portfolio: PortfolioResource;
5507
6134
  /** ADR-321 Phase 2 — programmable rights (propose / status / inspect). */
5508
6135
  rights: RightsResource;
5509
6136
  statements: StatementsResource;