@honest-pitches/pitch-sdk 0.4.6

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 ADDED
@@ -0,0 +1,197 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@honest-pitches/pitch-sdk` will be
4
+ documented in this file. Per-date detail lives in
5
+ `CHANGELOG.d/YYYY-MM-DD.md`.
6
+
7
+ The format is based on
8
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
9
+ and this project adheres to
10
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
11
+
12
+ ## [Unreleased]
13
+
14
+ Next package version: `0.4.1`. See
15
+ `CHANGELOG.d/2026-07-19-package-rename.md` for the rename to
16
+ `@honest-pitches/pitch-sdk`.
17
+
18
+ See `CHANGELOG.d/2026-06-23.md`, `CHANGELOG.d/2026-06-25-link-protocol.md`,
19
+ and `CHANGELOG.d/2026-07-18-publish-to-public-npmjs.md` for the earlier
20
+ change sets.
21
+
22
+ ## [0.4.3] - 2026-07-19
23
+
24
+ The CI build that v0.4.2 was supposed to ship finally ships:
25
+ `pnpm install --frozen-lockfile` succeeds (lockfile is now committed),
26
+ the build reads from the vendored `vendor/platform-libs/<pkg>/dist/`
27
+ snapshot instead of the sibling workspace, and no `prebuild` step is
28
+ needed. All `pnpm test:ci` tests green (56 Vitest + 36 contract tests).
29
+ See `CHANGELOG.d/2026-07-19-vendor-snapshot-ci-buildable.md` for the
30
+ full change set and the v0.4.2 → v0.4.3 migration notes.
31
+
32
+ ## [0.4.4] - 2026-07-20
33
+
34
+ Fixes the v0.4.3 CI build failure: `node build.mjs` failed with
35
+ `Could not resolve "marked" / "sanitize-html" / "json5"` because the
36
+ SDK's esbuild alias pointed at `pitch-core/dist/index.js` (the tsup
37
+ **browser** target, which leaves `marked`/`sanitize-html`/`json5` as
38
+ external imports for Vite to bundle at the Studio SPA build time).
39
+ The SDK runs under Node — no Vite — so the unresolved imports broke
40
+ the build. The fix aliases to `pitch-core/dist/index.cjs` (the tsup
41
+ **CJS** target, which has those three deps **inlined** via tsup's
42
+ `noExternal: ["marked", "sanitize-html", "json5"]`). The published
43
+ SDK tarball stays self-contained — zero runtime deps for external
44
+ consumers to install. See
45
+ `CHANGELOG.d/2026-07-20-pitch-core-cjs-alias.md` for the long-form
46
+ explanation and the browser-vs-node-vs-cjs tsup-target distinction.
47
+
48
+ ## [0.4.5] - 2026-07-20
49
+
50
+ Fixes the v0.4.4 CI test failure that the v0.4.4 commit missed. The
51
+ v0.4.4 fix changed `build.mjs` to alias `pitch-core` to its `index.cjs`
52
+ target — but did **not** update `vitest.config.ts` to match. The CI
53
+ build now succeeded, but `vitest run` in CI failed with
54
+ `Error: Cannot find package 'marked' imported from '.../vendor/platform-libs/pitch-core/dist/index.js'`
55
+ because vitest was still aliasing to the browser target.
56
+
57
+ Worse — once vitest's alias was also pointed at `index.cjs`, the test
58
+ runner hit a deeper issue: `pitch-core/dist/index.cjs` does a bare
59
+ `require("@honest-pitches/hp-codes")` at line 15448, and **vitest
60
+ does not apply `resolve.alias` to `require()` calls inside already-loaded
61
+ CJS bundles** (per the official vitest docs: "Vitest does not support
62
+ aliasing require calls."). Vitest's loader hits Node's native resolver,
63
+ which can't find `@honest-pitches/hp-codes` in the SDK's `node_modules/`
64
+ (the SDK deliberately has zero `@honest-pitches/*` runtime deps — that
65
+ is the "fat SDK" contract).
66
+
67
+ The fix is at the **vendoring layer**, not the vitest config:
68
+ `scripts/copy-vendor-dist.mjs` now has a `rewriteInternalBareSpecifiers`
69
+ pass that rewrites the vendored pitch-core bundles to use **relative
70
+ paths** for cross-package `@honest-pitches/*` references
71
+ (`require("../../hp-codes/dist/index.cjs")` instead of
72
+ `require("@honest-pitches/hp-codes")`). After the rewrite, the vendored
73
+ CJS bundle is self-contained for the SDK environment — the sibling
74
+ file is physically present in `vendor/`, so the relative `require()`
75
+ resolves without needing the alias map. Regression pin:
76
+ `scripts/copy-vendor-dist.contract.test.mjs` ("vendored pitch-core
77
+ bundles reference @honest-pitches/hp-codes by relative path, NOT bare
78
+ specifier") and `scripts/bundled-deps.contract.test.mjs`
79
+ ("vitest.config.ts aliases @honest-pitches/pitch-core to
80
+ vendor/.../index.cjs (MUST match build.mjs)").
81
+
82
+ All `pnpm test:ci` tests green (56 Vitest + 38 contract tests across
83
+ 5 contract files). `pnpm build` produces the same self-contained
84
+ fat-SDK tarball. See
85
+ `CHANGELOG.d/2026-07-20-vendored-internal-relative-paths.md` for the
86
+ full root-cause analysis and the vitest-vs-esbuild resolution story.
87
+
88
+ ## [0.4.6] - 2026-07-20
89
+
90
+ Fixes the v0.4.5 publish failure and rewrites the README to be
91
+ external-developer-facing (the v0.4.5 README leaked the Appwrite /
92
+ TablesDB internal architecture, which is irrelevant to consumers).
93
+
94
+ ### Publish fix
95
+
96
+ The v0.4.5 publish failed in CI with:
97
+
98
+ ```
99
+ npm error code ENEEDAUTH
100
+ npm error need auth This command requires you to be logged in to
101
+ https://git.neutronix.com/api/packages/honest-pitches/npm/
102
+ ```
103
+
104
+ even though the workflow ran `pnpm config set @honest-pitches:registry
105
+ https://registry.npmjs.org/` before publishing. Root cause: the
106
+ project `.npmrc` declared `@honest-pitches:registry=https://git.neutronix.com/...`
107
+ to route installs through the local Verdaccio mirror. That
108
+ project-level config **OVERRIDES** the in-memory `pnpm config set`
109
+ (per pnpm's config precedence: project `.npmrc` > user `~/.npmrc`),
110
+ so the publish auth lookup hit the Verdaccio mirror, which has no
111
+ token configured.
112
+
113
+ Fix:
114
+ 1. Drop the `@honest-pitches:registry=...` line from the project
115
+ `.npmrc`. The SDK has zero `@honest-pitches/*` runtime deps (the
116
+ "fat SDK" contract), so install needs no scoped-registry
117
+ override; the npmjs default (set by `Setup Node`) is correct
118
+ for both install and publish.
119
+ 2. Belt-and-suspenders: the publish workflow now passes
120
+ `--registry https://registry.npmjs.org/` EXPLICITLY on the
121
+ `pnpm publish` call so any future `.npmrc` drift cannot re-break
122
+ the publish path.
123
+ 3. **Dual-publish**: per the operator's "publish to npmjs, neutronix
124
+ is OK too" direction, the workflow now publishes the SDK to BOTH
125
+ npmjs.com (primary, required) and the internal Verdaccio mirror
126
+ at git.neutronix.com (optional, only attempted when
127
+ `secrets.NEUTRONIX_NPM_TOKEN` is set). The mirror publish is
128
+ guarded by `if [ -n "${NEUTRONIX_NPM_TOKEN:-}" ]` so a missing
129
+ token doesn't fail the workflow. The operator provisions the
130
+ mirror token at their convenience — until then, the npmjs
131
+ publish is the canonical artifact.
132
+ 4. Auth model change: replaced the deprecated `NODE_AUTH_TOKEN` env
133
+ (npm warns about it on newer versions) with a per-run
134
+ `~/.npmrc.auth` file containing each registry's `_authToken`,
135
+ pointed at via `NPM_CONFIG_USERCONFIG`. This is the standard
136
+ npm/pnpm multi-registry publish pattern and avoids the legacy
137
+ env-var deprecation warning.
138
+
139
+ Regression pins:
140
+ - `scripts/npmrc.contract.test.mjs` (new) — pins the project
141
+ `.npmrc` against scoped-registry drift
142
+ - `scripts/publish-workflow.contract.test.mjs` — updated to pin
143
+ dual-registry publish, explicit `--registry` flag, and the new
144
+ auth model
145
+
146
+ ### README rewrite
147
+
148
+ The v0.4.5 README read like an internal architecture document —
149
+ "Requires a per-user JWT (obtained via the OAuth flow in
150
+ `@honest-pitches/pitcher-mcp` or minted directly via Appwrite's
151
+ magic-link flow)", "This package is the source of truth for the
152
+ pitcher-facing TablesDB surface", the example used
153
+ `appwriteEndpoint: process.env.APPWRITE_ENDPOINT!`, and the API
154
+ table documented `appwriteQueryEqual` / `appwriteQueryLimit` as "the
155
+ TablesDB query DSL the SDK uses internally". External developers
156
+ installing the SDK don't need to know we use Appwrite / TablesDB
157
+ internally — that's an implementation detail.
158
+
159
+ The v0.4.6 README:
160
+ - Opens with "What this SDK does" instead of "What backend it talks to"
161
+ - Uses neutral config field names (`endpoint`, `projectId`) with a
162
+ brief note explaining what the SDK connects to
163
+ - Describes the error hierarchy in terms of what fired and when, not
164
+ what backend produced the error
165
+ - Adds a single explanatory note that the `appwrite*` prefix on
166
+ helper exports and the `AppwriteRequestError` class name are
167
+ "naming artifacts from the SDK's internal implementation; you
168
+ don't need to know what backs them to use them. The names are
169
+ stable — they're part of the published API." (Renaming the
170
+ exports would be a breaking API change for any v0.4.x consumer
171
+ and is not in scope for v0.4.6.)
172
+ - Replaces the misleading "Build: tsup → dist/" with the actual
173
+ `pnpm build` / `node build.mjs → dist/` command
174
+ - Adds a "TypeScript support" note pointing at the TS2307
175
+ resolution gotcha documented in `src/index.ts`'s header
176
+
177
+ All `pnpm test:ci` tests green (56 Vitest + 44 contract tests
178
+ across 6 contract files). See
179
+ `CHANGELOG.d/2026-07-20-publish-fix-and-readme.md` for the long-form
180
+ publish-failure root-cause analysis and the full README diff.
181
+
182
+ ## [0.3.0] - 2026-06-17
183
+
184
+ See `CHANGELOG.d/2026-06-17.md` for the change set.
185
+
186
+ ## [0.2.0] - 2026-06-15
187
+
188
+ Initial extraction from
189
+ `honest-pitches-platform-libs/packages/pitcher-sdk/`
190
+ (where the package was `0.1.0`, `private: true`, and only
191
+ available to other workspace packages). This is the first
192
+ **publishable** release; the `0.1.0` line stays in
193
+ `platform-libs/` as a deprecation stub re-exporting the
194
+ published `0.2.0` artifact.
195
+
196
+ See `CHANGELOG.d/2026-06-15.md` for the full extraction
197
+ notes.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # `@honest-pitches/pitch-sdk`
2
+
3
+ The JavaScript / TypeScript SDK for the **Honest Pitches** platform.
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.
8
+
9
+ This package is the **source of truth** for the pitcher-facing
10
+ programmatic surface. The `honest-pitches-cli` and the
11
+ `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.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @honest-pitches/pitch-sdk
21
+ # or
22
+ pnpm add @honest-pitches/pitch-sdk
23
+ ```
24
+
25
+ The package is published publicly on [npmjs.com](https://www.npmjs.com/package/@honest-pitches/pitch-sdk).
26
+ The source remains in the private Honest Pitches Forgejo repository.
27
+
28
+ ## Quickstart
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.
34
+
35
+ ```ts
36
+ import { createPitcherClient } from "@honest-pitches/pitch-sdk";
37
+
38
+ // Mint a per-user JWT via your platform OAuth flow, then:
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
43
+ });
44
+
45
+ const pitches = await client.pitches.list({ status: "live" });
46
+ ```
47
+
48
+ ## API
49
+
50
+ ### Client factory
51
+
52
+ | Export | Kind | Notes |
53
+ | --- | --- | --- |
54
+ | `createPitcherClient(config)` | factory | builds the client; `initialJwt` is a short-lived per-user JWT, NOT a long-lived API key |
55
+ | `resolvePitcherConfig(config)` | helper | merges defaults with caller-supplied overrides |
56
+
57
+ ### Pitch operations
58
+
59
+ | Export | Kind | Notes |
60
+ | --- | --- | --- |
61
+ | `PitchesApi` | class | list / get / create / update / transition pitches |
62
+ | `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 |
65
+
66
+ ### Frameworks & segments
67
+
68
+ Re-exported from the SDK's framework module so you don't need a
69
+ second import:
70
+
71
+ | Export | Kind | Notes |
72
+ | --- | --- | --- |
73
+ | `loadFrameworks` | function | returns every framework definition |
74
+ | `loadSegments` | function | returns every segment definition |
75
+ | `getSegmentDefinition` | function | single segment by key |
76
+ | `suggestedSectionsForFramework` | function | default section list for a framework |
77
+
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
+ ## Error model
111
+
112
+ Every error thrown by this SDK is a `PitcherSdkError` (or one of its
113
+ subclasses). The subclasses are:
114
+
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)
119
+ - `FrameworkLockedError` — tried to change a pitch's framework after the first section was written
120
+ - `HpCodeImmutableError` — tried to change a pitch's `hpCode` after creation
121
+ - `InvalidSectionKindError` — section kind not in the framework's allowed set
122
+ - `PitcherNotAuthenticatedError` — token missing or expired
123
+ - `PitcherNotOwnedCreatorError` — token is valid but doesn't own this creator row
124
+
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`).
128
+
129
+ ## TypeScript support
130
+
131
+ The package ships its own `.d.mts` declaration file. No additional
132
+ `@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`.
142
+
143
+ ## Build (for SDK maintainers)
144
+
145
+ ```bash
146
+ pnpm install
147
+ pnpm build # node build.mjs → dist/
148
+ pnpm test # vitest run
149
+ pnpm typecheck # tsc --noEmit
150
+ ```
151
+
152
+ ## License
153
+
154
+ UNLICENSED — internal Honest Pitches use only. The package is
155
+ published publicly on npmjs.com for the convenience of external
156
+ developers building on top of the platform; redistribution and
157
+ modification are not permitted.