@withpica/mcp-sdk 3.12.0 → 3.14.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/CHANGELOG.md CHANGED
@@ -11,6 +11,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ PR #2118 (`fix/avatar-import-path-2026-09-03`) is merged into the release branch, so its changes ship in the version below; publish in the order mcp-utils → mcp-sdk → mcp-server.
15
+
16
+ ## [3.14.0] - 2026-09-04
17
+
18
+ ### Added
19
+
20
+ - `MultimediaResource.importFromUrl` returns `MultimediaImportResult` (item + `via`, `source_url`, `profile_image`, `work_link` receipts) via `requestWithEnvelope` and accepts `person_id` (PR #2118, merged into this release).
21
+ - `requestWithEnvelope<T, TRest>` keeps top-level envelope fields (PR #2118).
22
+
23
+ - **`offset` on `AudioFilesResource.list()`, `NotesResource.list()`,
24
+ `SessionsResource.list()`** — companions to the mcp-server `offset`
25
+ additions on `pica_audio_query`/`pica_notes_query`/`pica_sessions_query`
26
+ (Task 10, 2026-09-03). Each forwards `offset` as a query-string param
27
+ exactly like the existing `limit`, omitted when not passed.
28
+
29
+ ## [3.13.0] - 2026-08-26
30
+
31
+ The MPP pay rail (spec 2026-08-24 WS-B): a new resource to mint a pay link,
32
+ and two optional fields on the existing subscription-status response so a
33
+ client can say what pica costs and what it is holding.
34
+
35
+ ### Added
36
+
37
+ - **`BillingResource.mintPayLink()` on `PicaClient.billing`.** Wraps
38
+ `POST /admin/billing/pay-link`. Takes `{ offer: PayOffer; entity_id?: string }`
39
+ and returns a `PayLinkResponse` (`pay_url`, `expires_at`, `offer`, `offers`,
40
+ `held`, `how`) — the route's own envelope, since this route has no
41
+ `{success, data}` wrapper. Minting is not charging: the link is a capability
42
+ an agent POSTs with a Machine Payments credential, or a person opens in a
43
+ browser and pays by card. Refusals arrive as `ApiError` (403 billing not
44
+ enabled; 400 `nothing_held_for_entity` / entity_id required; 409
45
+ `offer_no_longer_applies` with the offers that do apply) and are
46
+ deliberately not caught inside the resource — callers decide what each
47
+ refusal means.
48
+ - **New exported types**: `PayOffer` (`"resident_month" | "unlock" | "settle"`),
49
+ `PayLinkOffer` (`{ offer, amount_minor, currency, label }`), `PayLinkResponse`,
50
+ `HeldSummary` (`{ count, entities }`), `PricingSummary` (`currency`,
51
+ `freeRunwayDeepProcesses`, `residentFeeMinorUnits`,
52
+ `residentIncludedDeepProcesses`, `overagePerSongMinorUnits`,
53
+ `overageCurrency`, `unlockMinorUnits`).
54
+ - **`SubscriptionStatusResponse` gains optional `pricing?: PricingSummary | null`
55
+ and `held?: HeldSummary | null`.** Both are `null` when billing enforcement
56
+ is off on the deployment, and absent entirely against a deployment whose
57
+ route predates the fields — consumers must read "no pricing" as "do not
58
+ state a price," never as "free."
59
+
14
60
  ## [3.12.0] - 2026-08-25
15
61
 
16
62
  Adds the ADR-314 import continuation surface (below); everything else is documentation — no other method signature, request path or response shape changes.
package/dist/index.d.ts CHANGED
@@ -493,6 +493,37 @@ interface MultimediaItem {
493
493
  created_at: string;
494
494
  updated_at: string;
495
495
  }
496
+ /**
497
+ * The full response of `POST /admin/multimedia/import-from-url`.
498
+ *
499
+ * The route returns the created row in `data` and its receipts as SIBLINGS
500
+ * of `data`: `via` (was the given URL a direct image, or a page whose
501
+ * declared og:image was followed?), the `source_url` actually downloaded,
502
+ * and the outcome of the two optional follow-on writes — `profile_image`
503
+ * (the person's avatar) and `work_link`. Those receipts are the only way a
504
+ * caller learns whether the artist photo was really set, so
505
+ * `MultimediaResource.importFromUrl` reads the whole envelope rather than
506
+ * `request()`'s `.data`. `item` is the created row (`data` on the wire).
507
+ */
508
+ interface MultimediaImportResult {
509
+ item: MultimediaItem;
510
+ multimedia_id: string;
511
+ s3_url: string;
512
+ via: "direct" | "og:image";
513
+ source_url: string;
514
+ message: string;
515
+ profile_image?: {
516
+ person_id: string;
517
+ set: boolean;
518
+ code?: string;
519
+ reason?: string;
520
+ };
521
+ work_link?: {
522
+ work_id: string;
523
+ linked: boolean;
524
+ reason?: string;
525
+ };
526
+ }
496
527
  interface Agreement {
497
528
  id: string;
498
529
  organisation_id: string;
@@ -861,12 +892,18 @@ declare class BaseResource {
861
892
  * carries `twin`/`twin_error` as siblings of `data` — `request()`'s
862
893
  * `return data.data || data` would otherwise silently drop them before
863
894
  * the MCP tool ever sees a twin was created.
895
+ *
896
+ * `TRest` types any FURTHER siblings a specific route puts next to
897
+ * `data` (e.g. `POST /admin/multimedia/import-from-url` returns `via`,
898
+ * `source_url`, `profile_image`, `work_link`). It defaults to `unknown`,
899
+ * which is the identity for intersection, so the existing
900
+ * `requestWithEnvelope<Work>` call sites keep exactly the type they had.
864
901
  */
865
- protected requestWithEnvelope<T>(method: string, path: string, body?: any): Promise<{
902
+ protected requestWithEnvelope<T, TRest = unknown>(method: string, path: string, body?: any): Promise<{
866
903
  data: T;
867
904
  twin?: unknown;
868
905
  twin_error?: string;
869
- }>;
906
+ } & TRest>;
870
907
  /**
871
908
  * Make a request whose SUCCESS body is raw text, not a JSON envelope —
872
909
  * for routes that stream a generated file (e.g. `text/csv`) rather than
@@ -1479,6 +1516,7 @@ declare class AudioFilesResource extends BaseResource {
1479
1516
  unassigned?: boolean;
1480
1517
  query?: string;
1481
1518
  limit?: number;
1519
+ offset?: number;
1482
1520
  }): Promise<AudioFile[]>;
1483
1521
  get(id: string): Promise<AudioFile>;
1484
1522
  /**
@@ -1577,7 +1615,8 @@ declare class MultimediaResource extends BaseResource {
1577
1615
  title?: string;
1578
1616
  source?: string;
1579
1617
  work_id?: string;
1580
- }): Promise<MultimediaItem>;
1618
+ person_id?: string;
1619
+ }): Promise<MultimediaImportResult>;
1581
1620
  linkYoutube(params: {
1582
1621
  youtube_video_id: string;
1583
1622
  title: string;
@@ -1795,6 +1834,7 @@ declare class NotesResource extends BaseResource {
1795
1834
  work?: string;
1796
1835
  person?: string;
1797
1836
  limit?: number;
1837
+ offset?: number;
1798
1838
  }): Promise<any[]>;
1799
1839
  get(id: string): Promise<any>;
1800
1840
  create(content: string, metadata?: {
@@ -2196,6 +2236,11 @@ export interface CatalogHealthVerdict {
2196
2236
  completeness: number | null;
2197
2237
  cleanliness: number | null;
2198
2238
  };
2239
+ /** entities considered per dimension — what each dimension score is a share of; null iff that score is null (2026-08-26) */
2240
+ dimensionConsidered: {
2241
+ completeness: number | null;
2242
+ cleanliness: number | null;
2243
+ };
2199
2244
  assessed: string[];
2200
2245
  notAssessed: string[];
2201
2246
  items: CatalogHealthItem[];
@@ -2672,6 +2717,97 @@ export interface SubscriptionStatusResponse {
2672
2717
  recommendedTier: BillingTier;
2673
2718
  } | null;
2674
2719
  organisationId: string;
2720
+ /**
2721
+ * The org's price card, in its own billing currency. `null` when billing
2722
+ * enforcement is off on this deployment, and ABSENT against a deployment
2723
+ * whose route predates the field — hence both `?` and `| null`. Consumers
2724
+ * must read "no pricing" as "do not state a price", never as "free".
2725
+ */
2726
+ pricing?: PricingSummary | null;
2727
+ /**
2728
+ * How much enrichment is being withheld pending payment. Same two-shaped
2729
+ * absence as `pricing` above.
2730
+ */
2731
+ held?: HeldSummary | null;
2732
+ }
2733
+ /**
2734
+ * The three things a caller can be asked to pay for. Mirrors `PayOffer` in
2735
+ * `lib/services/billing-engine/pay-link.ts`; the route 400s on anything else,
2736
+ * so this union is the wire contract rather than a convenience.
2737
+ */
2738
+ export type PayOffer = "resident_month" | "unlock" | "settle";
2739
+ /**
2740
+ * One priced offer as the routes publish it. The server composes `label`,
2741
+ * which already carries the formatted money — a client that re-words the
2742
+ * amount out of `amount_minor` becomes a second home for the price, which is
2743
+ * what `publicOffer` exists to prevent on the server side.
2744
+ */
2745
+ export interface PayLinkOffer {
2746
+ offer: PayOffer;
2747
+ amount_minor: number;
2748
+ currency: string;
2749
+ label: string;
2750
+ }
2751
+ /** Findings pica is holding: `count` proposals across `entities` works. */
2752
+ export interface HeldSummary {
2753
+ count: number;
2754
+ entities: number;
2755
+ }
2756
+ /**
2757
+ * Every figure a reader of "what does pica cost" needs, derived server-side
2758
+ * from the constants that are actually charged (`pricingSummary()`).
2759
+ *
2760
+ * `overagePerSongMinorUnits` is denominated in `overageCurrency`, NOT
2761
+ * `currency` — the overage is charged in the canonical currency until
2762
+ * per-currency event pricing lands. The two fields are separate for that
2763
+ * reason; collapsing them would misprice every non-GBP org.
2764
+ */
2765
+ export interface PricingSummary {
2766
+ currency: string;
2767
+ freeRunwayDeepProcesses: number;
2768
+ residentFeeMinorUnits: number;
2769
+ residentIncludedDeepProcesses: number;
2770
+ overagePerSongMinorUnits: number;
2771
+ overageCurrency: string;
2772
+ unlockMinorUnits: number;
2773
+ }
2774
+ /**
2775
+ * `POST /admin/billing/pay-link`. There is no `{success, data}` envelope on
2776
+ * this route — the body IS the response, so `BaseResource.request`'s
2777
+ * `data.data || data` returns it whole.
2778
+ */
2779
+ export interface PayLinkResponse {
2780
+ pay_url: string;
2781
+ expires_at: string;
2782
+ offer: PayOffer;
2783
+ /** Every offer that currently applies, including the one minted. */
2784
+ offers: PayLinkOffer[];
2785
+ held: HeldSummary;
2786
+ /** One sentence naming both ways the link can be paid. */
2787
+ how: string;
2788
+ }
2789
+ declare class BillingResource extends BaseResource {
2790
+ /**
2791
+ * Mint a pay link for one offer. Minting is not charging: the link is a
2792
+ * capability an agent POSTs with a Machine Payments credential, or a person
2793
+ * opens in a browser and pays by card.
2794
+ *
2795
+ * Refusals arrive as `ApiError` carrying the route's status with its JSON
2796
+ * body embedded in the message (the shape `duplicates.ts` and
2797
+ * `integrity.ts` already parse): 403 `billing not enabled`; 400
2798
+ * `nothing_held_for_entity` / `entity_id is required to unlock`; 409
2799
+ * `offer_no_longer_applies`, whose body lists the offers that DO apply.
2800
+ * A 403 can ALSO come from the auth wrapper in front of the route rather
2801
+ * than the route itself (`{ error: { code: "INSUFFICIENT_SCOPE", … } }`),
2802
+ * so status alone never identifies which refusal this is — read the body.
2803
+ * They are deliberately not caught here — the MCP tool turns each into a
2804
+ * structured refusal, and a resource that swallowed them would leave every
2805
+ * other caller unable to tell a refusal from an outage.
2806
+ */
2807
+ mintPayLink(params: {
2808
+ offer: PayOffer;
2809
+ entity_id?: string;
2810
+ }): Promise<PayLinkResponse>;
2675
2811
  }
2676
2812
  /**
2677
2813
  * ADR-210 Phase 2 — Stripe Checkout session output for
@@ -3196,11 +3332,16 @@ interface ImportAnalysis {
3196
3332
  };
3197
3333
  }
3198
3334
  interface ImportValidation {
3335
+ /** True when no row carries a severity "error" entry — warnings do not
3336
+ * invalidate a row, so `valid` can be true with `errors` non-empty. */
3199
3337
  valid: boolean;
3200
3338
  errors: Array<{
3201
3339
  row: number;
3202
3340
  field: string;
3203
- message: string;
3341
+ /** The server's ValidationError carries the text in `error`; `message`
3342
+ * is kept for callers that normalised it. Read `error ?? message`. */
3343
+ error?: string;
3344
+ message?: string;
3204
3345
  severity: "error" | "warning";
3205
3346
  }>;
3206
3347
  validRowCount: number;
@@ -4309,6 +4450,7 @@ declare class ReleasesResource extends BaseResource {
4309
4450
  declare class SessionsResource extends BaseResource {
4310
4451
  list(params?: {
4311
4452
  limit?: number;
4453
+ offset?: number;
4312
4454
  }): Promise<any>;
4313
4455
  get(id: string): Promise<any>;
4314
4456
  create(data: Record<string, any>): Promise<any>;
@@ -4732,6 +4874,8 @@ export declare class PicaClient {
4732
4874
  workflowOutcomes: WorkflowOutcomesResource;
4733
4875
  feedback: FeedbackResource;
4734
4876
  subscription: SubscriptionResource;
4877
+ /** MPP pay rail (WS-B) — mints pay links; never charges. */
4878
+ billing: BillingResource;
4735
4879
  opsIssues: OpsIssuesResource;
4736
4880
  discoveries: DiscoveriesResource;
4737
4881
  agentIdentity: AgentIdentityResource;
@@ -4752,5 +4896,5 @@ export declare class PicaClient {
4752
4896
  }): Promise<CatalogStats | Record<string, unknown>>;
4753
4897
  constructor(config: PicaClientConfig);
4754
4898
  }
4755
- export type { Work, Person, Recording, PaginatedResult, PicaClientConfig, SyncSearchParams, SyncTrack, SyncSearchResult, LicenseEnquiryInput, LicenseEnquiry, BookingEnquiry, WorkCredit, WorkCreditsInput, PicaScore, PicaScorePillar, AudioFile, AudioAnalysisStatus, PresignedUploadResult, CompleteUploadResult, IdentifyResult, MultimediaItem, Agreement, AgreementWorkLink, CreateAgreementFromTemplateParams, AgreementSendForSignatureResult, AgreementSendForSignatureSentEntry, AgreementSendForSignatureSkippedEntry, AgreementSendForSignatureSkipReason, SyncPlacement, SyncPlacementSource, SyncPlacementRecording, SyncPlacementWithRelations, SyncPlacementContactInput, SyncPlacementRecordingInput, SyncPlacementSourceInput, CreateSyncPlacementInput, UpdateSyncPlacementInput, SyncPlacementQueryParams, SyncPlacementStatus, SyncPlacementVerificationStatus, SyncPlacementConfidentialityLevel, SyncPlacementSourceKind, CatalogStats, NotificationsSummary, CreateUploadSessionInput, CreateUploadSessionResult, };
4899
+ export type { Work, Person, Recording, PaginatedResult, PicaClientConfig, SyncSearchParams, SyncTrack, SyncSearchResult, LicenseEnquiryInput, LicenseEnquiry, BookingEnquiry, WorkCredit, WorkCreditsInput, PicaScore, PicaScorePillar, AudioFile, AudioAnalysisStatus, PresignedUploadResult, CompleteUploadResult, IdentifyResult, MultimediaItem, MultimediaImportResult, Agreement, AgreementWorkLink, CreateAgreementFromTemplateParams, AgreementSendForSignatureResult, AgreementSendForSignatureSentEntry, AgreementSendForSignatureSkippedEntry, AgreementSendForSignatureSkipReason, SyncPlacement, SyncPlacementSource, SyncPlacementRecording, SyncPlacementWithRelations, SyncPlacementContactInput, SyncPlacementRecordingInput, SyncPlacementSourceInput, CreateSyncPlacementInput, UpdateSyncPlacementInput, SyncPlacementQueryParams, SyncPlacementStatus, SyncPlacementVerificationStatus, SyncPlacementConfidentialityLevel, SyncPlacementSourceKind, CatalogStats, NotificationsSummary, CreateUploadSessionInput, CreateUploadSessionResult, };
4756
4900
  //# sourceMappingURL=index.d.ts.map