@honest-pitches/pitch-sdk 0.5.1 → 0.5.2

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,72 @@ and this project adheres to
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ### Fixed
15
+
16
+ - **`client.pitches.list is not a function` on every auth-required
17
+ list path (2026-07-28).** The `list` alias existed in local
18
+ source under the 0.5.1 version number but was never published
19
+ to npmjs (the 0.5.1 tarball only had `find`). Bumped to
20
+ **0.5.2** so a fresh `npm install @honest-pitches/pitch-sdk`
21
+ actually gets the alias. TSDoc updated to say stable-since
22
+ 0.5.2 (honest about the 0.5.1 publish gap). Detail:
23
+ control-repo
24
+ [`CHANGELOG.d/2026-07-28-sdk-list-alias-and-creatorid-filter.md`](../CHANGELOG.d/2026-07-28-sdk-list-alias-and-creatorid-filter.md).
25
+
26
+ ### Fixes
27
+
28
+ - **`videoSource` type widening to keep `pnpm run build:deploy:all`
29
+ green (commit `86f7ab1`, 2026-07-27).** The 2026-07-27 bug #2
30
+ commit `7f8b748` (`feat(pitcher-sdk): forward
31
+ videoSource/videoExternalId/videoExternalUrl + video helpers on
32
+ create/update`) widened `CreatePitchInput.videoSource` to a
33
+ 3-literal union (`"bunny_video_id" | "external_url" | "none" |
34
+ null`) AND added an `input.videoSource !== ""` guard at
35
+ `src/pitches.ts:215`. The guard's intent — drop empty-string
36
+ form-field values from the wire body — is correct, but the
37
+ type doesn't permit `""`, so tsc flagged the comparison as
38
+ unreachable (TS2367) and `pnpm run build:deploy:all` failed at
39
+ the SDK build step. **Fix:** widen the union to add `""` on
40
+ both `CreatePitchInput` and `UpdatePitchInput` (the latter for
41
+ symmetry, since the spread-forward site could see an
42
+ empty-string value too). `""` now lives in the canonical
43
+ "do not overwrite" club alongside `null` and absent, matching
44
+ the MCP server's `raw[key] !== ""` guard at `pitch-write`.
45
+ Two pre-existing typecheck failures from the same
46
+ `7f8b748` commit were also repaired:
47
+ - **9× TS2741** — pitch-test sections were missing the
48
+ required `mediaIds: string[]` field (the `PitchSection`
49
+ contract has required it since at least the v0.3.0
50
+ platform-libs cut). Added `mediaIds: []` to all three
51
+ test-section triples.
52
+ - **1× TS7006** — `Headers.forEach((v, k) => …)` had
53
+ implicit-any parameters because the outer
54
+ `vi.fn(async (input: any, init?: any) => …)` signature
55
+ leaves `init` untyped, so the `instanceof Headers`
56
+ narrowing does not propagate to `init.headers`. Added
57
+ explicit `(v: string, k: string)` types.
58
+
59
+ ### Tests
60
+
61
+ - **New regression test** (2026-07-27):
62
+ `pitches.test.ts#PitchesApi.create — body builder
63
+ does NOT forward videoSource/videoExternalId/videoExternalUrl
64
+ when set to empty string (regression: form-field hygiene)`.
65
+ Pins the `!== ""` guard's runtime behaviour — without it, a
66
+ future refactor that drops the guard would silently start
67
+ writing `""` to the server, which the server then rejects or
68
+ misinterprets depending on column nullability.
69
+ - **Test counts:** `pnpm test` 47/47 vitest (was 46/46);
70
+ `pnpm test:ci` 47 vitest + 54 contract assertions across 9
71
+ contract suites, 0 regressions.
72
+
73
+ ### Version
74
+
75
+ - **No version bump in this commit.** The bug #2 commit
76
+ (`7f8b748`) was unversioned at HEAD; this fix lands on top.
77
+ The next operator-pushed SDK tag should cut `v0.5.2` to ship
78
+ both fixes together.
79
+
14
80
  Next package version: `0.4.1`. See
15
81
  `CHANGELOG.d/2026-07-19-package-rename.md` for the rename to
16
82
  `@honest-pitches/pitch-sdk`.
package/dist/index.cjs CHANGED
@@ -16849,10 +16849,34 @@ var PitchesApi = class {
16849
16849
  intendedAudience: input.intendedAudience ?? "",
16850
16850
  visibility: input.visibility ?? "private"
16851
16851
  };
16852
+ if (input.honestyDisclosure != null && input.honestyDisclosure !== "") {
16853
+ payload.honestyDisclosure = String(input.honestyDisclosure).slice(0, 2e3);
16854
+ }
16852
16855
  if (input.categorySlug != null) payload.categorySlug = input.categorySlug;
16853
16856
  if (input.priceNote != null && input.priceNote !== "") {
16854
16857
  payload.priceNote = String(input.priceNote).slice(0, 64);
16855
16858
  }
16859
+ if (input.videoSource != null && input.videoSource !== "") {
16860
+ payload.videoSource = input.videoSource;
16861
+ }
16862
+ if (input.videoExternalId != null && input.videoExternalId !== "") {
16863
+ payload.videoExternalId = String(input.videoExternalId);
16864
+ }
16865
+ if (input.videoExternalUrl != null && input.videoExternalUrl !== "") {
16866
+ payload.videoExternalUrl = String(input.videoExternalUrl);
16867
+ }
16868
+ if (input.bunnyVideoId != null && input.bunnyVideoId !== "") {
16869
+ payload.bunnyVideoId = String(input.bunnyVideoId);
16870
+ }
16871
+ if (input.primaryVideo != null && input.primaryVideo !== "") {
16872
+ payload.primaryVideo = String(input.primaryVideo);
16873
+ }
16874
+ if (input.primaryVideoId != null && input.primaryVideoId !== "") {
16875
+ payload.primaryVideoId = String(input.primaryVideoId);
16876
+ }
16877
+ if (input.honestyDisclosure != null && input.honestyDisclosure !== "") {
16878
+ payload.honestyDisclosure = String(input.honestyDisclosure).slice(0, 2e3);
16879
+ }
16856
16880
  const doc = await fetchPitches(this.config, {
16857
16881
  method: "POST",
16858
16882
  path: "/pitches",
@@ -16870,7 +16894,9 @@ var PitchesApi = class {
16870
16894
  async find(opts = {}) {
16871
16895
  const params = new URLSearchParams();
16872
16896
  if (opts.status) params.set("status", opts.status);
16897
+ if (opts.creatorId) params.set("creatorId", opts.creatorId);
16873
16898
  if (typeof opts.limit === "number") params.set("limit", String(opts.limit));
16899
+ if (opts.cursor) params.set("cursor", opts.cursor);
16874
16900
  const qs = params.toString();
16875
16901
  const docs = await fetchPitches(this.config, {
16876
16902
  method: "GET",
@@ -16878,6 +16904,20 @@ var PitchesApi = class {
16878
16904
  });
16879
16905
  return docs.map((d) => rowToPitch(d));
16880
16906
  }
16907
+ /**
16908
+ * Public alias for {@link PitchesApi.find}. Stable on the public
16909
+ * npm registry since `@honest-pitches/pitch-sdk@0.5.2` (2026-07-28).
16910
+ * If you see "client.pitches.list is not a function" you are on
16911
+ * an older SDK — bump to `>=0.5.2`. (The 0.5.1 tarball on npmjs
16912
+ * never shipped this alias even though the source landed under
16913
+ * that version number locally; 0.5.2 is the first published cut.)
16914
+ *
16915
+ * (Added 2026-07-27; published 2026-07-28 after the agent bug
16916
+ * report against CLI 0.5.1 / hosted MCP `list_pitches`.)
16917
+ */
16918
+ async list(opts = {}) {
16919
+ return this.find(opts);
16920
+ }
16881
16921
  async update(id, input) {
16882
16922
  const doc = await fetchPitches(this.config, {
16883
16923
  method: "PATCH",
@@ -16886,6 +16926,43 @@ var PitchesApi = class {
16886
16926
  });
16887
16927
  return rowToPitch(doc);
16888
16928
  }
16929
+ /**
16930
+ * Move a pitch through its lifecycle. The returned row carries BOTH
16931
+ * `status` (row-level persisted) and `lifecycle` (computed from
16932
+ * `status + previewToken` server-side).
16933
+ *
16934
+ * Status vs lifecycle (2026-07-28 FlexTape retest doc bundle):
16935
+ * `lifecycle` is the canonical, computed view of where the row sits
16936
+ * (`draft | preview | live | expired | archived`). It is derived
16937
+ * from `status + previewToken` server-side in
16938
+ * `honest-pitches-studio-api/legacy/pitch-write/src/handler.ts`.
16939
+ * Branch on `lifecycle` for terminal-state checks.
16940
+ *
16941
+ * The mapping is:
16942
+ * - `lifecycle: "draft"` ⟷ `status: "draft"` (no previewToken)
16943
+ * - `lifecycle: "preview"` ⟷ `status: "draft"` (previewToken set)
16944
+ * - `lifecycle: "live"` ⟷ `status: "live"`
16945
+ * - `lifecycle: "expired"` ⟷ `status: "expired"`
16946
+ * - `lifecycle: "archived"` ⟷ `status: "removed"` (intentional vocab split)
16947
+ *
16948
+ * Token gate (Finding #17, FlexTape retest):
16949
+ * `to: "preview"` requires a `previewToken` that matches the row's
16950
+ * stored token. The server returns
16951
+ * `400 previewToken is required to transition to preview`
16952
+ * when the token is missing or wrong.
16953
+ *
16954
+ * `to: "draft"` from an `archived` row ALSO requires the same
16955
+ * `previewToken` (the token is the only proof the caller owns the
16956
+ * unarchive). There is NO `archived → preview` single-step path —
16957
+ * the supported path is `archived → draft` (token required) and
16958
+ * then `draft → preview` (which may issue a NEW token).
16959
+ *
16960
+ * Visibility on archive (Finding #17, FlexTape retest):
16961
+ * `to: "archived"` does NOT touch `visibility` — the row keeps
16962
+ * whatever visibility it had at the time of the archive (usually
16963
+ * `"public"`, but `"unlisted"` is preserved too). Only `to: "live"`
16964
+ * assigns `visibility: "public"`.
16965
+ */
16889
16966
  async transition(id, input) {
16890
16967
  const doc = await fetchPitches(this.config, {
16891
16968
  method: "POST",
@@ -16913,11 +16990,56 @@ var PitchesApi = class {
16913
16990
  });
16914
16991
  return doc;
16915
16992
  }
16993
+ /**
16994
+ * List every media asset for a pitch, joining two server-side sources:
16995
+ *
16996
+ * - `pitch_assets` rows with `pitchId === id` (the explicit
16997
+ * uploads via `POST /pitcher/pitches/:id/media`).
16998
+ * - The auto-generated `thumbnailFileId` and `ogImageFileId` fields
16999
+ * on the pitch row itself (synthesised by `pitch-write`'s
17000
+ * `to=live` path; they live on the row, NOT in `pitch_assets`).
17001
+ *
17002
+ * Each result carries a `source: "pitch_assets" | "pitch_row"`
17003
+ * discriminator so consumers can tell the two apart. The server
17004
+ * may synthesise `pitch_row` rows with `sizeBytes: 0` (the auto
17005
+ * images don't carry an upload byte count — the `cdnUrl` is the
17006
+ * canonical handle).
17007
+ *
17008
+ * Added 2026-07-28 to address Bug #12 of the FlexTape retest brief
17009
+ * (`testing-feedback/2026-07-27-flextape-rerun-3surface-retest.md`).
17010
+ * Prior to this, `hp pitches media list <id>` returned `[]` for
17011
+ * every pitch whose only assets were auto-generated.
17012
+ */
17013
+ async listMedia(id) {
17014
+ return fetchPitches(this.config, {
17015
+ method: "GET",
17016
+ path: `/pitches/${encodeURIComponent(id)}/media`
17017
+ });
17018
+ }
16916
17019
  /**
16917
17020
  * Restore an archived pitch to `draft`. Same as `transition(id, {
16918
17021
  * to: "draft", previewToken })` but with a placeholder previewToken
16919
17022
  * if the caller didn't pass one. The server's "to=draft" path
16920
17023
  * mirrors the existing "to=preview" pre-condition.
17024
+ *
17025
+ * Status vs lifecycle (2026-07-28 FlexTape retest doc bundle):
17026
+ * `pitches.lifecycle` is the canonical, computed view of where
17027
+ * the row sits (`draft, preview, live, expired, archived`). It is
17028
+ * derived from `status + previewToken` server-side
17029
+ * (`honest-pitches-studio-api/legacy/pitch-write/src/handler.ts`).
17030
+ * Branch on `lifecycle` for terminal-state checks.
17031
+ *
17032
+ * The mapping is:
17033
+ * - `lifecycle: "preview"` ⟷ `status: "draft"` (previewToken set)
17034
+ * - `lifecycle: "live"` ⟷ `status: "live"`
17035
+ * - `lifecycle: "archived"` ⟷ `status: "removed"` (intentional vocab split)
17036
+ *
17037
+ * There is NO direct `archived → preview` path — the server only
17038
+ * exposes `archived → draft`. To resume preview after a draft,
17039
+ * transition twice (`archived → draft` then `draft → preview` with
17040
+ * a new preview token), or use `transition(id, { to: "preview",
17041
+ * previewToken })` directly if your `lifecycle` is `draft` (NOT
17042
+ * `archived`).
16921
17043
  */
16922
17044
  async unarchive(id, opts = {}) {
16923
17045
  return this.transition(id, {