@withpica/mcp-sdk 3.23.1 → 3.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -54,6 +54,14 @@ function getTimeoutForPath(path) {
54
54
  ? LONG_TIMEOUT_MS
55
55
  : DEFAULT_TIMEOUT_MS;
56
56
  }
57
+ /** The `offset` query parameter of a request path (0 when absent). */
58
+ function offsetOf(path) {
59
+ const q = path.indexOf("?");
60
+ if (q === -1)
61
+ return 0;
62
+ const n = Number(new URLSearchParams(path.slice(q + 1)).get("offset"));
63
+ return Number.isFinite(n) && n > 0 ? n : 0;
64
+ }
57
65
  function sleep(ms) {
58
66
  return new Promise((resolve) => setTimeout(resolve, ms));
59
67
  }
@@ -312,8 +320,18 @@ class BaseResource {
312
320
  // `total`/`hasMore` (e.g. GET /admin/recordings/search, ADR unified
313
321
  // catalog search). Check nested first, then flat, then fall back to
314
322
  // `count` / items.length so untouched callers keep their prior behaviour.
315
- const total = json.pagination?.total ?? json.total ?? json.count ?? items.length;
316
- const hasMore = json.pagination?.hasMore ?? json.hasMore ?? total > items.length;
323
+ // An explicit `pagination.total: null` means the server does not know
324
+ // the total — keep it null rather than falling through to the page
325
+ // length, which would read as "that's all of them".
326
+ const total = json.pagination && json.pagination.total === null
327
+ ? null
328
+ : (json.pagination?.total ?? json.total ?? json.count ?? items.length);
329
+ // With no server-side hasMore, the answer is offset + this page < total.
330
+ // `total > items.length` alone ignored the offset, so every LAST page of
331
+ // a multi-page result said "more" (row-cap T3).
332
+ const hasMore = json.pagination?.hasMore ??
333
+ json.hasMore ??
334
+ (total !== null && offsetOf(path) + items.length < total);
317
335
  // Carry the server's zero-result guidance through — silently dropping it
318
336
  // here left agents staring at a bare empty list (ops_issue 689a8e9a).
319
337
  const recovery_hint = typeof json.recovery_hint === "string" ? json.recovery_hint : undefined;
@@ -406,6 +424,15 @@ class WorksResource extends BaseResource {
406
424
  const qs = qp.toString();
407
425
  return this.requestPaginated("GET", `/admin/works${qs ? `?${qs}` : ""}`);
408
426
  }
427
+ /**
428
+ * The agreements linked to ONE work (GET /admin/works/:id/agreements).
429
+ * Inspect used `agreements.list()`, which returned the org's first page of
430
+ * agreements under a work's heading (row-cap T3).
431
+ */
432
+ async getAgreements(workId) {
433
+ const res = await this.request("GET", `/admin/works/${workId}/agreements`);
434
+ return Array.isArray(res) ? res : [];
435
+ }
409
436
  async get(id) {
410
437
  return this.request("GET", `/admin/works/${id}`);
411
438
  }
@@ -517,6 +544,22 @@ class WorksResource extends BaseResource {
517
544
  async addWriters(workId, names) {
518
545
  return this.request("POST", `/admin/works/${workId}/writers`, { names });
519
546
  }
547
+ /** A song's directory topics: approved, proposed, moods awaiting review, settings. */
548
+ async getThemes(workId) {
549
+ return this.request("GET", `/admin/works/${encodeURIComponent(workId)}/themes`);
550
+ }
551
+ /** Set the song's approved topics directly, and/or its switch and lyric visibility. */
552
+ async setThemes(workId, body) {
553
+ return this.request("PUT", `/admin/works/${encodeURIComponent(workId)}/themes`, body);
554
+ }
555
+ /** Propose topics (and recording moods) for the owner to review. Nothing goes public. */
556
+ async proposeThemes(workId, body) {
557
+ return this.request("POST", `/admin/works/${encodeURIComponent(workId)}/themes/proposals`, body);
558
+ }
559
+ /** The owner's review of proposed topics and moods. */
560
+ async reviewThemes(workId, body) {
561
+ return this.request("PATCH", `/admin/works/${encodeURIComponent(workId)}/themes/proposals`, body);
562
+ }
520
563
  }
521
564
  class PeopleResource extends BaseResource {
522
565
  async list(params) {
@@ -628,6 +671,23 @@ class PeopleResource extends BaseResource {
628
671
  return this.request("GET", `/admin/people/triangulate?${qp.toString()}`);
629
672
  }
630
673
  }
674
+ function licenseEnquiryListPath(params) {
675
+ const queryParams = new URLSearchParams();
676
+ if (params?.work_id)
677
+ queryParams.set("work_id", params.work_id);
678
+ if (params?.status)
679
+ queryParams.set("status", params.status);
680
+ if (params?.project_type)
681
+ queryParams.set("project_type", params.project_type);
682
+ if (params?.territory)
683
+ queryParams.set("territory", params.territory);
684
+ if (params?.limit !== undefined)
685
+ queryParams.set("limit", String(params.limit));
686
+ if (params?.offset !== undefined)
687
+ queryParams.set("offset", String(params.offset));
688
+ const query = queryParams.toString();
689
+ return `/admin/license-enquiries${query ? `?${query}` : ""}`;
690
+ }
631
691
  class LicensingResource extends BaseResource {
632
692
  /**
633
693
  * Search for sync-licensable tracks by audio characteristics
@@ -673,33 +733,26 @@ class LicensingResource extends BaseResource {
673
733
  return this.request("POST", "/admin/license-enquiries", enquiry);
674
734
  }
675
735
  /**
676
- * List license enquiries with optional filters
736
+ * List license enquiries with optional filters (one page, the bare array;
737
+ * see listEnquiriesPage for the real total).
677
738
  */
678
739
  async listEnquiries(params) {
679
- const queryParams = new URLSearchParams();
680
- if (params?.work_id)
681
- queryParams.set("work_id", params.work_id);
682
- if (params?.status)
683
- queryParams.set("status", params.status);
684
- if (params?.project_type)
685
- queryParams.set("project_type", params.project_type);
686
- if (params?.territory)
687
- queryParams.set("territory", params.territory);
688
- if (params?.limit !== undefined)
689
- queryParams.set("limit", String(params.limit));
690
- if (params?.offset !== undefined)
691
- queryParams.set("offset", String(params.offset));
692
- const query = queryParams.toString();
693
- const path = `/admin/license-enquiries${query ? `?${query}` : ""}`;
694
- // The admin route returns successResponse({ data: [...], count }); after
695
- // request() unwraps the outer { success, data } envelope the payload is the
696
- // { data, count } object, not the array. Tolerate both shapes (mirrors
697
- // listDiscoveriesRecent + the other list resources) so the caller never
698
- // calls `.map` on a non-array — the "t.map is not a function" crash that
699
- // made pica_list_license_enquiries fail on every call shape.
700
- const res = (await this.request("GET", path));
740
+ // Older servers nested the list as `{ data: { data: [...], count } }`, so
741
+ // after request() unwraps the outer envelope the payload was an object,
742
+ // not the array. Tolerate both shapes so the caller never calls `.map` on
743
+ // a non-array — the "t.map is not a function" crash that made
744
+ // pica_list_license_enquiries fail on every call shape.
745
+ const res = (await this.request("GET", licenseEnquiryListPath(params)));
701
746
  return Array.isArray(res) ? res : (res?.data ?? []);
702
747
  }
748
+ /**
749
+ * One page of license enquiries WITH the real total and has_more
750
+ * (row-cap T3): `listEnquiries()` returns the bare array, so callers
751
+ * reported the page length as the total.
752
+ */
753
+ async listEnquiriesPage(params) {
754
+ return this.requestPaginated("GET", licenseEnquiryListPath(params));
755
+ }
703
756
  /**
704
757
  * Get a specific license enquiry by ID
705
758
  */
@@ -722,34 +775,40 @@ class LicensingResource extends BaseResource {
722
775
  return this.request("PATCH", `/admin/license-enquiries/${id}`, { counterOffer, notes });
723
776
  }
724
777
  }
725
- /**
726
- * ADR-289 Wave C1 — booking enquiries (internal-team session/production
727
- * bookings, distinct from `LicensingResource`'s sync-license enquiries).
728
- * Wraps `/admin/bookings` + `/admin/bookings/[id]`.
729
- */
778
+ function bookingListPath(params) {
779
+ const qp = new URLSearchParams();
780
+ if (params?.status)
781
+ qp.set("status", params.status);
782
+ if (params?.priority)
783
+ qp.set("priority", params.priority);
784
+ if (params?.query)
785
+ qp.set("query", params.query);
786
+ if (params?.enquiry_type)
787
+ qp.set("enquiry_type", params.enquiry_type);
788
+ if (params?.follow_up_required !== undefined)
789
+ qp.set("follow_up_required", String(params.follow_up_required));
790
+ if (params?.limit !== undefined)
791
+ qp.set("limit", String(params.limit));
792
+ if (params?.offset !== undefined)
793
+ qp.set("offset", String(params.offset));
794
+ const qs = qp.toString();
795
+ return `/admin/bookings${qs ? `?${qs}` : ""}`;
796
+ }
730
797
  class BookingsResource extends BaseResource {
731
798
  /**
732
- * List/search booking enquiries. `GET /admin/bookings` returns the raw
733
- * array (not `{data, count}`) — `request()` unwraps to that array.
799
+ * One page of booking enquiries (the bare array; see listPage for the real
800
+ * total). `request()` unwraps the route's `{ data, count }` envelope.
734
801
  */
735
802
  async list(params) {
736
- const qp = new URLSearchParams();
737
- if (params?.status)
738
- qp.set("status", params.status);
739
- if (params?.priority)
740
- qp.set("priority", params.priority);
741
- if (params?.query)
742
- qp.set("query", params.query);
743
- if (params?.enquiry_type)
744
- qp.set("enquiry_type", params.enquiry_type);
745
- if (params?.follow_up_required !== undefined)
746
- qp.set("follow_up_required", String(params.follow_up_required));
747
- if (params?.limit !== undefined)
748
- qp.set("limit", String(params.limit));
749
- if (params?.offset !== undefined)
750
- qp.set("offset", String(params.offset));
751
- const qs = qp.toString();
752
- return this.request("GET", `/admin/bookings${qs ? `?${qs}` : ""}`);
803
+ return this.request("GET", bookingListPath(params));
804
+ }
805
+ /**
806
+ * One page of booking enquiries WITH the real total and has_more
807
+ * (row-cap T3): `list()` returns the bare array, so callers reported the
808
+ * page length as the total.
809
+ */
810
+ async listPage(params) {
811
+ return this.requestPaginated("GET", bookingListPath(params));
753
812
  }
754
813
  async get(id) {
755
814
  return this.request("GET", `/admin/bookings/${encodeURIComponent(id)}`);
@@ -1084,39 +1143,51 @@ class MultimediaResource extends BaseResource {
1084
1143
  });
1085
1144
  }
1086
1145
  }
1146
+ function agreementListPath(params) {
1147
+ const queryParams = new URLSearchParams();
1148
+ if (params?.query)
1149
+ queryParams.set("query", params.query);
1150
+ if (params?.agreement_type)
1151
+ queryParams.set("agreement_type", params.agreement_type);
1152
+ if (params?.status)
1153
+ queryParams.set("status", params.status);
1154
+ if (params?.party_name)
1155
+ queryParams.set("party_name", params.party_name);
1156
+ if (params?.includeWorkCounts)
1157
+ queryParams.set("includeWorkCounts", "true");
1158
+ if (params?.awaiting_signature)
1159
+ queryParams.set("awaiting_signature", "true");
1160
+ if (params?.start_date_from)
1161
+ queryParams.set("start_date_from", params.start_date_from);
1162
+ if (params?.start_date_to)
1163
+ queryParams.set("start_date_to", params.start_date_to);
1164
+ if (params?.end_date_from)
1165
+ queryParams.set("end_date_from", params.end_date_from);
1166
+ if (params?.end_date_to)
1167
+ queryParams.set("end_date_to", params.end_date_to);
1168
+ if (params?.expiring_within_days !== undefined)
1169
+ queryParams.set("expiring_within_days", String(params.expiring_within_days));
1170
+ if (params?.has_end_date !== undefined)
1171
+ queryParams.set("has_end_date", String(params.has_end_date));
1172
+ if (params?.limit !== undefined)
1173
+ queryParams.set("limit", String(params.limit));
1174
+ if (params?.offset !== undefined)
1175
+ queryParams.set("offset", String(params.offset));
1176
+ const query = queryParams.toString();
1177
+ return `/admin/agreements${query ? `?${query}` : ""}`;
1178
+ }
1087
1179
  class AgreementsResource extends BaseResource {
1180
+ /** One page of agreements (the bare array; see listPage for the real total). */
1088
1181
  async list(params) {
1089
- const queryParams = new URLSearchParams();
1090
- if (params?.query)
1091
- queryParams.set("query", params.query);
1092
- if (params?.agreement_type)
1093
- queryParams.set("agreement_type", params.agreement_type);
1094
- if (params?.status)
1095
- queryParams.set("status", params.status);
1096
- if (params?.party_name)
1097
- queryParams.set("party_name", params.party_name);
1098
- if (params?.includeWorkCounts)
1099
- queryParams.set("includeWorkCounts", "true");
1100
- if (params?.awaiting_signature)
1101
- queryParams.set("awaiting_signature", "true");
1102
- if (params?.start_date_from)
1103
- queryParams.set("start_date_from", params.start_date_from);
1104
- if (params?.start_date_to)
1105
- queryParams.set("start_date_to", params.start_date_to);
1106
- if (params?.end_date_from)
1107
- queryParams.set("end_date_from", params.end_date_from);
1108
- if (params?.end_date_to)
1109
- queryParams.set("end_date_to", params.end_date_to);
1110
- if (params?.expiring_within_days !== undefined)
1111
- queryParams.set("expiring_within_days", String(params.expiring_within_days));
1112
- if (params?.has_end_date !== undefined)
1113
- queryParams.set("has_end_date", String(params.has_end_date));
1114
- if (params?.limit !== undefined)
1115
- queryParams.set("limit", String(params.limit));
1116
- if (params?.offset !== undefined)
1117
- queryParams.set("offset", String(params.offset));
1118
- const query = queryParams.toString();
1119
- return this.request("GET", `/admin/agreements${query ? `?${query}` : ""}`);
1182
+ return this.request("GET", agreementListPath(params));
1183
+ }
1184
+ /**
1185
+ * One page of agreements WITH the real total and has_more (row-cap T3):
1186
+ * `list()` returns the bare array, so callers reported the page length
1187
+ * as the total.
1188
+ */
1189
+ async listPage(params) {
1190
+ return this.requestPaginated("GET", agreementListPath(params));
1120
1191
  }
1121
1192
  async get(id) {
1122
1193
  return this.request("GET", `/admin/agreements/${id}`);
@@ -1189,10 +1260,28 @@ class AgreementsResource extends BaseResource {
1189
1260
  return this.request("POST", `/admin/agreements/${id}/send-for-signature`, { expiresInDays: params?.expires_in_days });
1190
1261
  }
1191
1262
  }
1192
- // ADR-222 — sync placements as a first-class domain. REST routes implemented
1193
- // by W4 at /api/admin/sync-placements (paired PR on the same parent feature
1194
- // branch). All methods scope to the caller's organisation server-side via
1195
- // requireOrganisationContext — no orgId param needed on the SDK surface.
1263
+ /** Sync fit: GET /admin/sync-fit, the same read as /inspect/sync. */
1264
+ class SyncFitResource extends BaseResource {
1265
+ async query(params) {
1266
+ const q = new URLSearchParams();
1267
+ if (params?.work_id)
1268
+ q.set("work_id", params.work_id);
1269
+ if (params?.screen_project_id)
1270
+ q.set("screen_project_id", params.screen_project_id);
1271
+ if (params?.song_facts)
1272
+ q.set("song_facts", "true");
1273
+ if (params?.limit)
1274
+ q.set("limit", String(params.limit));
1275
+ if (params?.offset)
1276
+ q.set("offset", String(params.offset));
1277
+ const qs = q.toString();
1278
+ const res = await this.request("GET", `/admin/sync-fit${qs ? `?${qs}` : ""}`);
1279
+ if (res && typeof res === "object" && "data" in res && res.data) {
1280
+ return res.data;
1281
+ }
1282
+ return res;
1283
+ }
1284
+ }
1196
1285
  class SyncPlacementsResource extends BaseResource {
1197
1286
  async list(params) {
1198
1287
  const queryParams = new URLSearchParams();
@@ -1735,6 +1824,16 @@ class EnrichmentResource extends BaseResource {
1735
1824
  async bulkRejectProposals(input) {
1736
1825
  return this.request("POST", "/admin/enrichment-proposals/bulk-reject", input);
1737
1826
  }
1827
+ /**
1828
+ * What bulkRejectProposals would reject, without rejecting: the route
1829
+ * resolves the same pending set the real call would (row-cap T3).
1830
+ */
1831
+ async previewBulkRejectProposals(input) {
1832
+ return this.request("POST", "/admin/enrichment-proposals/bulk-reject", {
1833
+ ...input,
1834
+ dry_run: true,
1835
+ });
1836
+ }
1738
1837
  /**
1739
1838
  * Apply many pending proposals in one call — the accept side of the
1740
1839
  * /inspect/found queue.
@@ -2943,6 +3042,40 @@ class CollaboratorsResource extends BaseResource {
2943
3042
  const qs = qp.toString();
2944
3043
  return this.request("GET", `/admin/collaborators/invites${qs ? `?${qs}` : ""}`);
2945
3044
  }
3045
+ /**
3046
+ * One page of the invites this org sent WITH the real total and has_more
3047
+ * (row-cap T3). `listInvites()` is typed as an array but the route nests
3048
+ * its rows as `data: { data, count }`, so it never carried a usable total.
3049
+ */
3050
+ async listInvitesPage(params) {
3051
+ const qp = new URLSearchParams();
3052
+ if (params?.status)
3053
+ qp.set("status", params.status);
3054
+ if (params?.workId)
3055
+ qp.set("workId", params.workId);
3056
+ if (params?.limit !== undefined)
3057
+ qp.set("limit", String(params.limit));
3058
+ if (params?.offset)
3059
+ qp.set("offset", String(params.offset));
3060
+ const qs = qp.toString();
3061
+ return this.requestNestedPage(`/admin/collaborators/invites${qs ? `?${qs}` : ""}`, params?.offset ?? 0);
3062
+ }
3063
+ /**
3064
+ * Reads a collaborator list route, whose rows sit at `data.data` (kept
3065
+ * for published SDKs) with the total in the top-level `pagination`.
3066
+ */
3067
+ async requestNestedPage(path, offset) {
3068
+ const json = await this.requestWithEnvelope("GET", path);
3069
+ const inner = json.data;
3070
+ const rows = Array.isArray(inner) ? inner : (inner?.data ?? []);
3071
+ const pagination = json.pagination;
3072
+ const total = pagination?.total ?? rows.length;
3073
+ return {
3074
+ data: rows,
3075
+ total,
3076
+ hasMore: pagination?.hasMore ?? offset + rows.length < total,
3077
+ };
3078
+ }
2946
3079
  async resendInvite(inviteId) {
2947
3080
  return this.request("POST", `/admin/collaborators/invites/${inviteId}/resend`);
2948
3081
  }
@@ -2961,6 +3094,21 @@ class CollaboratorsResource extends BaseResource {
2961
3094
  const res = await this.request("GET", `/admin/collaborators/incoming${qs ? `?${qs}` : ""}`);
2962
3095
  return res.data;
2963
3096
  }
3097
+ /**
3098
+ * One page of the invites addressed to the caller WITH the real total and
3099
+ * has_more (row-cap T3: `listIncoming()` returns only the rows).
3100
+ */
3101
+ async listIncomingPage(params) {
3102
+ const qp = new URLSearchParams();
3103
+ if (params?.status)
3104
+ qp.set("status", params.status);
3105
+ if (params?.limit !== undefined)
3106
+ qp.set("limit", String(params.limit));
3107
+ if (params?.offset)
3108
+ qp.set("offset", String(params.offset));
3109
+ const qs = qp.toString();
3110
+ return this.requestNestedPage(`/admin/collaborators/incoming${qs ? `?${qs}` : ""}`, params?.offset ?? 0);
3111
+ }
2964
3112
  /**
2965
3113
  * ADR-157 warm path — accept an invite addressed to the authenticated
2966
3114
  * user, and flip its status to confirmed. The credit write is
@@ -3192,6 +3340,10 @@ class DirectoryResource extends BaseResource {
3192
3340
  async updateSettings(updates) {
3193
3341
  return this.request("PATCH", "/admin/directory/settings", updates);
3194
3342
  }
3343
+ /** Listed songs with lyrics and topics on, but no approved topic yet. */
3344
+ async untaggedThemes() {
3345
+ return this.request("GET", "/admin/directory/themes/untagged");
3346
+ }
3195
3347
  }
3196
3348
  class ProjectsResource extends BaseResource {
3197
3349
  async list(params) {
@@ -3438,6 +3590,21 @@ class RecordingSplitsResource extends BaseResource {
3438
3590
  }
3439
3591
  }
3440
3592
  class PublishersResource extends BaseResource {
3593
+ /**
3594
+ * One page of the publisher registry with an honest has_more. The total
3595
+ * is null: the route does not count the platform-wide registry.
3596
+ */
3597
+ async listPage(params) {
3598
+ const queryParams = new URLSearchParams();
3599
+ if (params?.query)
3600
+ queryParams.set("query", params.query);
3601
+ if (params?.limit)
3602
+ queryParams.set("limit", String(params.limit));
3603
+ if (params?.offset)
3604
+ queryParams.set("offset", String(params.offset));
3605
+ const qs = queryParams.toString();
3606
+ return this.requestPaginated("GET", `/admin/publishers${qs ? `?${qs}` : ""}`);
3607
+ }
3441
3608
  async list(params) {
3442
3609
  const queryParams = new URLSearchParams();
3443
3610
  if (params?.query)
@@ -3452,6 +3619,25 @@ class PublishersResource extends BaseResource {
3452
3619
  }
3453
3620
  }
3454
3621
  class LabelsResource extends BaseResource {
3622
+ /**
3623
+ * One page of label/distributor organisations with an honest has_more.
3624
+ * The total is null: the route does not count platform-wide rows.
3625
+ */
3626
+ async listPage(params) {
3627
+ const queryParams = new URLSearchParams();
3628
+ if (params?.query)
3629
+ queryParams.set("query", params.query);
3630
+ if (params?.limit)
3631
+ queryParams.set("limit", String(params.limit));
3632
+ if (params?.offset)
3633
+ queryParams.set("offset", String(params.offset));
3634
+ if (params?.org_type)
3635
+ queryParams.set("org_type", params.org_type);
3636
+ if (params?.ids?.length)
3637
+ queryParams.set("ids", params.ids.join(","));
3638
+ const qs = queryParams.toString();
3639
+ return this.requestPaginated("GET", `/admin/labels${qs ? `?${qs}` : ""}`);
3640
+ }
3455
3641
  async list(params) {
3456
3642
  const queryParams = new URLSearchParams();
3457
3643
  if (params?.query)
@@ -3480,14 +3666,20 @@ class LabelsResource extends BaseResource {
3480
3666
  return (res ?? null);
3481
3667
  }
3482
3668
  }
3483
- /**
3484
- * ADR-268 WS1 — party org claim flow. `invite()` sends an artist-anchored
3485
- * claim invite for an unclaimed label/distributor/publisher org;
3486
- * `list()` reads the claims the calling org has sent.
3487
- *
3488
- * Typed against the UNWRAPPED reality (ADR-265 lesson): BaseResource.request
3489
- * auto-unwraps the `{success,data}` envelope, so methods see `data` itself.
3490
- */
3669
+ function partyClaimListPath(params) {
3670
+ const queryParams = new URLSearchParams();
3671
+ if (params?.target_organisation_id) {
3672
+ queryParams.set("target_organisation_id", params.target_organisation_id);
3673
+ }
3674
+ if (params?.status)
3675
+ queryParams.set("status", params.status);
3676
+ if (params?.limit)
3677
+ queryParams.set("limit", String(params.limit));
3678
+ if (params?.offset)
3679
+ queryParams.set("offset", String(params.offset));
3680
+ const qs = queryParams.toString();
3681
+ return `/admin/party-claims${qs ? `?${qs}` : ""}`;
3682
+ }
3491
3683
  class PartyClaimsResource extends BaseResource {
3492
3684
  async invite(params) {
3493
3685
  const res = await this.request("POST", "/admin/party-claims", params);
@@ -3499,20 +3691,19 @@ class PartyClaimsResource extends BaseResource {
3499
3691
  return (res ?? null);
3500
3692
  }
3501
3693
  async list(params) {
3502
- const queryParams = new URLSearchParams();
3503
- if (params?.target_organisation_id) {
3504
- queryParams.set("target_organisation_id", params.target_organisation_id);
3505
- }
3506
- if (params?.status)
3507
- queryParams.set("status", params.status);
3508
- if (params?.limit)
3509
- queryParams.set("limit", String(params.limit));
3510
- const qs = queryParams.toString();
3511
- const res = await this.request("GET", `/admin/party-claims${qs ? `?${qs}` : ""}`);
3694
+ const res = await this.request("GET", partyClaimListPath(params));
3512
3695
  if (Array.isArray(res))
3513
3696
  return res;
3514
3697
  return (res?.data ?? []);
3515
3698
  }
3699
+ /**
3700
+ * One page of sent claim invites WITH the real total and has_more
3701
+ * (row-cap T3): `list()` returns the bare array, so callers reported the
3702
+ * page length as the total.
3703
+ */
3704
+ async listPage(params) {
3705
+ return this.requestPaginated("GET", partyClaimListPath(params));
3706
+ }
3516
3707
  }
3517
3708
  /**
3518
3709
  * Claim your profile: invite people to claim their profile (a preview
@@ -3544,25 +3735,38 @@ class ProfileClaimsResource extends BaseResource {
3544
3735
  };
3545
3736
  }
3546
3737
  }
3738
+ function releaseListPath(params) {
3739
+ const parts = [];
3740
+ if (params?.limit != null)
3741
+ parts.push(`limit=${params.limit}`);
3742
+ if (params?.offset != null)
3743
+ parts.push(`offset=${params.offset}`);
3744
+ if (params?.query)
3745
+ parts.push(`query=${encodeURIComponent(params.query)}`);
3746
+ if (params?.upc)
3747
+ parts.push(`upc=${encodeURIComponent(params.upc)}`);
3748
+ if (params?.spotify_album_id)
3749
+ parts.push(`spotify_album_id=${encodeURIComponent(params.spotify_album_id)}`);
3750
+ if (params?.release_date_from)
3751
+ parts.push(`release_date_from=${encodeURIComponent(params.release_date_from)}`);
3752
+ if (params?.release_date_to)
3753
+ parts.push(`release_date_to=${encodeURIComponent(params.release_date_to)}`);
3754
+ const qs = parts.length > 0 ? `?${parts.join("&")}` : "";
3755
+ return `/admin/releases${qs}`;
3756
+ }
3547
3757
  class ReleasesResource extends BaseResource {
3758
+ /** One page of releases (the bare array; see listPage for the real total). */
3548
3759
  async list(params) {
3549
- const parts = [];
3550
- if (params?.limit != null)
3551
- parts.push(`limit=${params.limit}`);
3552
- if (params?.offset != null)
3553
- parts.push(`offset=${params.offset}`);
3554
- if (params?.query)
3555
- parts.push(`query=${encodeURIComponent(params.query)}`);
3556
- if (params?.upc)
3557
- parts.push(`upc=${encodeURIComponent(params.upc)}`);
3558
- if (params?.spotify_album_id)
3559
- parts.push(`spotify_album_id=${encodeURIComponent(params.spotify_album_id)}`);
3560
- if (params?.release_date_from)
3561
- parts.push(`release_date_from=${encodeURIComponent(params.release_date_from)}`);
3562
- if (params?.release_date_to)
3563
- parts.push(`release_date_to=${encodeURIComponent(params.release_date_to)}`);
3564
- const qs = parts.length > 0 ? `?${parts.join("&")}` : "";
3565
- return this.request("GET", `/admin/releases${qs}`);
3760
+ return this.request("GET", releaseListPath(params));
3761
+ }
3762
+ /**
3763
+ * One page of releases WITH the real total and has_more (row-cap T3):
3764
+ * `list()` returns the bare array, so callers guessed has_more from "the
3765
+ * page came back full". `total` is null when the server cannot count (a
3766
+ * title search past its match cap); has_more is the server's own answer.
3767
+ */
3768
+ async listPage(params) {
3769
+ return this.requestPaginated("GET", releaseListPath(params));
3566
3770
  }
3567
3771
  async get(id) {
3568
3772
  return this.request("GET", `/admin/releases/${id}`);
@@ -3681,15 +3885,27 @@ class ReleasesResource extends BaseResource {
3681
3885
  return this.request("POST", "/admin/releases/create-with-tracks", data);
3682
3886
  }
3683
3887
  }
3888
+ function sessionListPath(params) {
3889
+ const query = new URLSearchParams();
3890
+ if (params?.limit)
3891
+ query.set("limit", String(params.limit));
3892
+ if (params?.offset)
3893
+ query.set("offset", String(params.offset));
3894
+ const qs = query.toString();
3895
+ return `/admin/sessions${qs ? `?${qs}` : ""}`;
3896
+ }
3684
3897
  class SessionsResource extends BaseResource {
3898
+ /** One page of upcoming sessions (see listPage for the real total). */
3685
3899
  async list(params) {
3686
- const query = new URLSearchParams();
3687
- if (params?.limit)
3688
- query.set("limit", String(params.limit));
3689
- if (params?.offset)
3690
- query.set("offset", String(params.offset));
3691
- const qs = query.toString();
3692
- return this.request("GET", `/admin/sessions${qs ? `?${qs}` : ""}`);
3900
+ return this.request("GET", sessionListPath(params));
3901
+ }
3902
+ /**
3903
+ * One page of the next 7 days' sessions WITH the real total and has_more
3904
+ * (row-cap T3): `list()` returns the bare array, so callers could only
3905
+ * guess has_more from "the page came back full".
3906
+ */
3907
+ async listPage(params) {
3908
+ return this.requestPaginated("GET", sessionListPath(params));
3693
3909
  }
3694
3910
  async get(id) {
3695
3911
  return this.request("GET", `/admin/sessions/${id}`);
@@ -4044,6 +4260,11 @@ class CustodyResource extends BaseResource {
4044
4260
  async respond(body) {
4045
4261
  return this.request("POST", "/admin/custody/respond", body);
4046
4262
  }
4263
+ /**
4264
+ * Custody claims, one page per direction. Since row-cap T3 the result also
4265
+ * carries `totals: { incoming, outgoing }` (null for a direction not asked
4266
+ * for), `has_more: { incoming, outgoing }`, `limit` and `offset`.
4267
+ */
4047
4268
  async list(params) {
4048
4269
  const qp = new URLSearchParams();
4049
4270
  if (params?.direction)
@@ -4052,6 +4273,8 @@ class CustodyResource extends BaseResource {
4052
4273
  qp.set("status", params.status);
4053
4274
  if (params?.limit !== undefined)
4054
4275
  qp.set("limit", String(params.limit));
4276
+ if (params?.offset)
4277
+ qp.set("offset", String(params.offset));
4055
4278
  const qs = qp.toString();
4056
4279
  return this.request("GET", `/admin/custody/list${qs ? `?${qs}` : ""}`);
4057
4280
  }
@@ -4270,6 +4493,7 @@ export class PicaClient {
4270
4493
  agreements;
4271
4494
  // ADR-222 — sync placements (W3, paired with W4 REST routes).
4272
4495
  syncPlacements;
4496
+ syncFit;
4273
4497
  workspace;
4274
4498
  memory;
4275
4499
  audit;
@@ -4382,6 +4606,7 @@ export class PicaClient {
4382
4606
  this.multimedia = new MultimediaResource(baseUrl, config.apiKey, debug);
4383
4607
  this.agreements = new AgreementsResource(baseUrl, config.apiKey, debug);
4384
4608
  this.syncPlacements = new SyncPlacementsResource(baseUrl, config.apiKey, debug);
4609
+ this.syncFit = new SyncFitResource(baseUrl, config.apiKey, debug);
4385
4610
  this.workspace = new WorkspaceResource(baseUrl, config.apiKey, debug);
4386
4611
  this.memory = new MemoryResource(baseUrl, config.apiKey, debug);
4387
4612
  this.audit = new AuditResource(baseUrl, config.apiKey, debug);