@honest-pitches/pitch-sdk 0.4.6 → 0.5.1

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
@@ -179,6 +179,86 @@ across 6 contract files). See
179
179
  `CHANGELOG.d/2026-07-20-publish-fix-and-readme.md` for the long-form
180
180
  publish-failure root-cause analysis and the full README diff.
181
181
 
182
+ ## [0.5.1] - 2026-07-25
183
+
184
+ First publish that matches the documented design end-to-end. Three
185
+ coordinated changes:
186
+
187
+ ### Vendor-agnostic HTTP wrapper (the v0.5.0 re-architecture, finally published)
188
+
189
+ The SDK is now a pure HTTP wrapper against the pitcher-mcp server's
190
+ `/pitcher/*` routes. Consumers only need `{ apiKey: 'hp_pk_…' }` —
191
+ no `endpoint`, no `projectId`, no backend env vars, no vendor
192
+ imports in the public API surface. The package no longer depends
193
+ on `node-appwrite` (audit 3 confirmed: the bundle is `node-appwrite`-free).
194
+ The MCP server is the only layer that knows about the backend;
195
+ the SDK and the consumer are both HTTP-only.
196
+
197
+ ### ESM bundle fix (the actual blocker)
198
+
199
+ The v0.5.0 build produced an ESM bundle that threw `Dynamic require
200
+ of "path" is not supported` at module-load time on Node 20+,
201
+ 100% of consumers. Root cause: esbuild's CJS-shim `__require(x)`
202
+ in the ESM bundle fails for Node built-ins because pure ESM has no
203
+ `require`. The fix is a `banner: { js: "import { createRequire as
204
+ topLevelCreateRequire } from 'node:module'; const require =
205
+ topLevelCreateRequire(import.meta.url);" }` on the ESM esbuild
206
+ call in `build.mjs`. Same pattern as the Node-ESM target in
207
+ `honest-pitches-platform-libs/packages/pitch-core/tsup.config.ts`.
208
+
209
+ **Why v0.4.6 also failed** (transitive from
210
+ `pitcher-api-key-core`'s `require("crypto")`): the same root cause,
211
+ different inlined vendor. The 0.4.6 → 0.5.x lineage fixes it
212
+ identically.
213
+
214
+ ### Publish workflow hardening
215
+
216
+ The publish workflow now runs `pnpm test:ci` (not `pnpm test`)
217
+ so the contract tests are no longer silently skipped. The new
218
+ `scripts/esm-bundle-runtime.contract.test.mjs` (2 cases) is the
219
+ regression pin — it would have caught v0.4.6 at publish time.
220
+ `scripts/publish-workflow.contract.test.mjs` (now 15 cases) adds
221
+ a `Test step runs pnpm test:ci` assertion.
222
+
223
+ ### What ships
224
+
225
+ - `dist/index.cjs` — CJS bundle (works as before)
226
+ - `dist/index.mjs` — ESM bundle (FIXED; loads cleanly on Node 20+)
227
+ - `dist/index.d.mts` — TypeScript declarations
228
+ - `package.json` (`0.5.1`) — version bump from `0.5.0`
229
+ - `src/config.ts` — drops `endpoint`/`projectId`/`databaseId`/`client`/`initialJwt`, adds `apiKey`/`jwt`/`jwtExpiresAt`/`baseUrl`/`fetchImpl`
230
+ - `src/pitches.ts` + `src/creators.ts` — uses `fetchPitches` against `${baseUrl}/pitcher/*`
231
+ - `src/errors.ts` — adds `PitcherRequestError` (replaces `AppwriteRequestError`)
232
+ - `dist/*` typings — drop `MEDIA_API_FUNCTION_ID` / `PUBLIC_API_FUNCTION_ID` / `STRIPE_API_FUNCTION_ID` / `STUDIO_API_FUNCTION_ID` / `appwriteQueryEqual` / `appwriteQueryLimit`
233
+
234
+ ### What does NOT ship in this version
235
+
236
+ - The CLI (`@honest-pitches/hp-cli`) lives at `D:\Honest_Pitches\honest-pitches-cli` and is already a separate package.
237
+ - The `drp-*` framework IDs in the public `/agents/` page are wrong (should be `drtv_*` from the local frameworks registry). Tracked as a follow-up ticket against the public web repo, not the SDK.
238
+ - The MCP server's `/pitcher/*` route table is the live source of truth; the SDK's `fetchPitches` client mirrors it.
239
+
240
+ ### Test surface
241
+
242
+ - `pnpm test` (Vitest) — 53 unit tests pass.
243
+ - `pnpm test:ci` (Vitest + 9 contract tests) — 53 + 49 = 102 cases pass.
244
+ - `scripts/esm-bundle-runtime.contract.test.mjs` (NEW, 2 cases) — RED on 0.5.0, GREEN on 0.5.1.
245
+ - `scripts/publish-workflow.contract.test.mjs` (15 cases, +1) — asserts `pnpm test:ci` runs in the workflow.
246
+ - `scripts/no-node-appwrite-in-runtime.contract.test.mjs` (4 cases) — `node-appwrite` is absent from the bundle.
247
+ - `scripts/bundled-deps.contract.test.mjs` (10 cases) — the bundle is fat and self-contained.
248
+ - `scripts/config-shape.contract.test.mjs` (3 cases) — `endpoint`/`projectId` are absent from the public API.
249
+
250
+ ### Acceptance (brief)
251
+
252
+ - [x] `createPitcherClient({ apiKey: 'hp_pk_…' })` builds with no other config.
253
+ - [x] The build's only network surface is `${PITCHER_MCP_URL}/pitcher/*`, defaulting to `https://mcp.honestpitches.com`.
254
+ - [x] `import '@honest-pitches/pitch-sdk'` works on Node 20+ (no `Dynamic require of "path"`).
255
+ - [x] `require('@honest-pitches/pitch-sdk')` works (unchanged).
256
+ - [x] `0.4.6` is recommended for deprecation (`pnpm deprecate` is a publish pipeline action — separate follow-up).
257
+
258
+ See `CHANGELOG.d/2026-07-25-vendor-agnostic-esm-fix.md` for the
259
+ long-form root-cause analysis and audit 3 (SDK contract drift)
260
+ findings.
261
+
182
262
  ## [0.3.0] - 2026-06-17
183
263
 
184
264
  See `CHANGELOG.d/2026-06-17.md` for the change set.
package/README.md CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  The JavaScript / TypeScript SDK for the **Honest Pitches** platform.
4
4
  Use it to define, list, update, and transition the pitches you own on
5
- [honestpitches.com](https://www.honestpitches.com) — the place where
6
- founders publish their real numbers, real plans, and real backers, and
7
- critics respond with structured ratings instead of hot takes.
5
+ [honestpitches.com](https://www.honestpitches.com).
6
+
7
+ The SDK is a **pure HTTP wrapper** around the hosted MCP server at
8
+ `https://mcp.honestpitches.com`. It has no backend vendor config:
9
+ no `endpoint`, no `projectId`, no `databaseId`, no backend SDK
10
+ dependency. One env var (`PITCHER_API_KEY`) is all you need.
8
11
 
9
12
  This package is the **source of truth** for the pitcher-facing
10
13
  programmatic surface. The `honest-pitches-cli` and the
11
14
  `honest-pitches-pitcher-mcp` server are both thin wrappers around
12
- this SDK — they don't re-implement pitch logic. A developer who uses
13
- the CLI gets exactly the same SDK calls a developer who uses the MCP
14
- server gets: same auth, same errors, same pagination, same audit
15
- trail.
15
+ this SDK — they don't re-implement pitch logic.
16
16
 
17
17
  ## Install
18
18
 
@@ -27,22 +27,32 @@ The source remains in the private Honest Pitches Forgejo repository.
27
27
 
28
28
  ## Quickstart
29
29
 
30
- The SDK authenticates with a **per-user token** that you obtain from
31
- the platform's OAuth flow. The token is short-lived; you mint it once
32
- per session and pass it to the client factory. The SDK will refresh
33
- internally on 401 responses.
30
+ The SDK authenticates with a **per-user API key** that you mint at
31
+ `studio.honestpitches.com Settings API keys`. The key is
32
+ long-lived; you pass it to the client factory once.
34
33
 
35
34
  ```ts
36
35
  import { createPitcherClient } from "@honest-pitches/pitch-sdk";
37
36
 
38
- // Mint a per-user JWT via your platform OAuth flow, then:
37
+ // Get a key at studio.honestpitches.com Settings API keys,
38
+ // then set PITCHER_API_KEY in your environment:
39
39
  const client = createPitcherClient({
40
- endpoint: process.env.HONEST_PITCHES_ENDPOINT!, // the platform base URL
41
- projectId: process.env.HONEST_PITCHES_PROJECT_ID!,
42
- initialJwt: process.env.PITCHER_JWT!, // short-lived per-user JWT
40
+ apiKey: process.env.PITCHER_API_KEY!,
43
41
  });
44
42
 
45
- const pitches = await client.pitches.list({ status: "live" });
43
+ const pitches = await client.pitches.find({ status: "live" });
44
+ ```
45
+
46
+ `PITCHER_MCP_URL` defaults to the hosted MCP
47
+ (`https://mcp.honestpitches.com`). Set it only when self-hosting the
48
+ MCP.
49
+
50
+ The JWT variant is the same shape:
51
+
52
+ ```ts
53
+ const client = createPitcherClient({
54
+ jwt: process.env.PITCHER_JWT!, // short-lived per-user JWT (minted via the pitcher-mcp OAuth flow)
55
+ });
46
56
  ```
47
57
 
48
58
  ## API
@@ -51,17 +61,18 @@ const pitches = await client.pitches.list({ status: "live" });
51
61
 
52
62
  | Export | Kind | Notes |
53
63
  | --- | --- | --- |
54
- | `createPitcherClient(config)` | factory | builds the client; `initialJwt` is a short-lived per-user JWT, NOT a long-lived API key |
64
+ | `createPitcherClient(config)` | factory | builds the client from `{ apiKey }` or `{ jwt }` |
55
65
  | `resolvePitcherConfig(config)` | helper | merges defaults with caller-supplied overrides |
66
+ | `DEFAULT_PITCHER_BASE_URL` | constant | `https://mcp.honestpitches.com` — the hosted MCP |
56
67
 
57
68
  ### Pitch operations
58
69
 
59
70
  | Export | Kind | Notes |
60
71
  | --- | --- | --- |
61
- | `PitchesApi` | class | list / get / create / update / transition pitches |
72
+ | `PitchesApi` | class | `find` / `get` / `create` / `update` / `transition` / `uploadMedia` / `unarchive` pitches |
62
73
  | `scaffoldPitchFromFramework` | helper | builds a section set from a framework key |
63
- | `findCreatorIdForJwtUser` | helper | looks up the creator `$id` from a JWT's `sub` claim |
64
- | `findCreatorIdForApiKey` | helper | server-side variant for API-key auth |
74
+ | `findCreatorIdForJwtUser` | helper | looks up the creator `$id` from the auth principal |
75
+ | `findCreatorIdForApiKey` | helper | same, for API-key auth |
65
76
 
66
77
  ### Frameworks & segments
67
78
 
@@ -75,70 +86,28 @@ second import:
75
86
  | `getSegmentDefinition` | function | single segment by key |
76
87
  | `suggestedSectionsForFramework` | function | default section list for a framework |
77
88
 
78
- ### Query helpers
79
-
80
- The SDK uses a small query DSL internally and exposes the building
81
- blocks so you don't have to re-import them:
82
-
83
- | Export | Kind | Notes |
84
- | --- | --- | --- |
85
- | `appwriteQueryEqual` | helper | `field == value` |
86
- | `appwriteQueryLimit` | helper | pagination cap |
87
-
88
- > The `appwrite*` prefix on these helpers is a naming artifact from
89
- > the SDK's internal implementation; you don't need to know what
90
- > backs them to use them. The names are stable — they're part of
91
- > the published API.
92
-
93
- ### Token parsing
94
-
95
- | Export | Kind | Notes |
96
- | --- | --- | --- |
97
- | `decodeJwtSub` | helper | extracts the `sub` claim without verifying the signature |
98
- | `isJwtExpired` | helper | `true` if the token's `exp` is in the past |
99
-
100
- ### Routing constants
101
-
102
- | Export | Kind | Notes |
103
- | --- | --- | --- |
104
- | `MEDIA_API_FUNCTION_ID` | constant | the platform's media-handling function id |
105
- | `PUBLIC_API_FUNCTION_ID` | constant | the public read API function id |
106
- | `STRIPE_API_FUNCTION_ID` | constant | the Stripe integration function id |
107
- | `STUDIO_API_FUNCTION_ID` | constant | the studio integration function id |
108
- | `resolveConsolidatedRoute` | function | picks the right function id for a given request |
109
-
110
89
  ## Error model
111
90
 
112
91
  Every error thrown by this SDK is a `PitcherSdkError` (or one of its
113
92
  subclasses). The subclasses are:
114
93
 
115
- - `AppwriteRequestError` — the backend returned a non-2xx (the
116
- prefix is a naming artifact from the SDK's internal implementation;
117
- the error fires for any backend non-2xx, not just the Appwrite
118
- transport)
94
+ - `PitcherRequestError` — the MCP server returned a non-2xx
119
95
  - `FrameworkLockedError` — tried to change a pitch's framework after the first section was written
120
96
  - `HpCodeImmutableError` — tried to change a pitch's `hpCode` after creation
121
97
  - `InvalidSectionKindError` — section kind not in the framework's allowed set
122
98
  - `PitcherNotAuthenticatedError` — token missing or expired
123
99
  - `PitcherNotOwnedCreatorError` — token is valid but doesn't own this creator row
124
100
 
125
- All errors expose a `.cause` (the original underlying exception where
126
- applicable) and a `.code` (a stable string identifier you can switch
127
- on without `instanceof`).
101
+ All errors expose a `.code` (a stable string identifier you can
102
+ switch on without `instanceof`) and a `.status` (the HTTP status
103
+ returned by the MCP server, where applicable).
128
104
 
129
105
  ## TypeScript support
130
106
 
131
107
  The package ships its own `.d.mts` declaration file. No additional
132
108
  `@types/*` packages are needed. The runtime bundle is fully
133
- self-contained: zero `@honest-pitches/*` runtime dependencies.
134
-
135
- > **Note for TypeScript consumers.** The declaration file
136
- > `dist/index.d.mts` re-exports a small number of framework and
137
- > segment type aliases. These types are inlined (via `export type`)
138
- > so consumer-side `tsc` works without any extra `paths` mapping in
139
- > your `tsconfig.json`. If you see a `TS2307` "cannot find module
140
- > `@honest-pitches/pitch-core`" error, you have an older copy of the
141
- > SDK — upgrade to `>=0.4.6`.
109
+ self-contained: zero `@honest-pitches/*` runtime dependencies,
110
+ zero backend SDK runtime dependency.
142
111
 
143
112
  ## Build (for SDK maintainers)
144
113
 
@@ -154,4 +123,4 @@ pnpm typecheck # tsc --noEmit
154
123
  UNLICENSED — internal Honest Pitches use only. The package is
155
124
  published publicly on npmjs.com for the convenience of external
156
125
  developers building on top of the platform; redistribution and
157
- modification are not permitted.
126
+ modification are not permitted.