Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d368391
docs: cross-link wrapper SDKs + doc pages to openiap.dev API references
hyochan Apr 26, 2026
863eec9
chore: prettier format on enriched docs pages
hyochan Apr 26, 2026
c6eceac
docs: address coderabbit review (provider list, defaults, API mappings)
hyochan Apr 26, 2026
caf19d2
docs: address Copilot follow-up on PR #107
hyochan Apr 26, 2026
deb5fdd
docs: address coderabbit Round 3 on PR #107
hyochan Apr 26, 2026
2fb40e5
docs(init-connection): correct iOS description to match impl
hyochan Apr 26, 2026
f84f0a6
docs: address Copilot Round 5 — accurate iOS/Android impl mappings
hyochan Apr 26, 2026
92eec3d
feat(docs): make type identifiers in CodeBlock signatures clickable
hyochan Apr 26, 2026
8e29cf8
fix(docs): linkifyType regex skips text already inside highlight spans
hyochan Apr 26, 2026
e184475
docs(types/purchase): add PurchaseOptions section
hyochan Apr 26, 2026
c2eb94d
docs: add Parameters / Returns sections to every API page
hyochan Apr 26, 2026
0e6410c
docs: expand Params/Returns into field-level tables on API pages
hyochan Apr 26, 2026
db1a918
docs: add 5-language Signature + Example tabs to iOS/Android API pages
hyochan Apr 26, 2026
27524b9
docs: address Coderabbit Round 7 — type accuracy + link targets
hyochan Apr 26, 2026
5a1e069
docs: convert API page Params/Returns tables to prose lists
hyochan Apr 26, 2026
c2b487e
docs: move Parameters/Returns/Throws below Signature on every API page
hyochan Apr 26, 2026
2a58906
docs: address Coderabbit Round 9 — Safari regex + casing + bad links
hyochan Apr 26, 2026
5c8ea3e
fix(docs): table column squeeze + horizontal scroll fallback
hyochan Apr 26, 2026
e58c27c
docs: address Coderabbit Round 11 — type/field accuracy + Safari fix
hyochan Apr 26, 2026
7a14aa6
chore(docs): prettier-format get-storefront after orphan paragraph re…
hyochan Apr 26, 2026
7a298b4
docs: address Gemini Round 12 — fetchProducts default, JSDoc params, …
hyochan Apr 26, 2026
ab49572
docs: harden mobile drawer + add SSOT consistency audit
hyochan Apr 26, 2026
224b833
fix(docs): harden mobile sidebar drawer for iOS Safari
hyochan Apr 26, 2026
33df55a
docs: address coderabbit Round 13 findings
hyochan Apr 26, 2026
4cd0df3
docs(fetch-products): show both Builder and DSL patterns for KMP
hyochan Apr 26, 2026
50efd5b
docs: address copilot Round 14 findings
hyochan Apr 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This document provides an overview for AI agents working across the OpenIAP mono
| Platform Packages | [`knowledge/internal/04-platform-packages.md`](knowledge/internal/04-platform-packages.md) |
| Docs Patterns | [`knowledge/internal/05-docs-patterns.md`](knowledge/internal/05-docs-patterns.md) |
| Git & Deployment | [`knowledge/internal/06-git-deployment.md`](knowledge/internal/06-git-deployment.md) |
| Docs Consistency / SSOT | [`knowledge/internal/07-docs-consistency.md`](knowledge/internal/07-docs-consistency.md) (run `bun audit:docs` before pushing API/Type doc edits) |

## Monorepo Structure

Expand Down
5 changes: 4 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

190 changes: 190 additions & 0 deletions knowledge/internal/07-docs-consistency.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Docs Consistency Rules — Single Source of Truth (SSOT)

This document captures the consistency rules for OpenIAP documentation, code
comments, and generated types. PR #107 (and earlier rounds) repeatedly
surfaced the same class of drift — the docs claimed one field/default/type,
but the SDK code actually used another. These rules + the companion audit
script (`scripts/audit-docs.ts`) catch those before review.

## Sources of truth

When two places disagree, the upstream wins:

```
GraphQL schema → generated Types → hand-written wrapper SDK → docs page
(packages/gql (libraries/*/src (Swift / Kotlin / (packages/docs/
/src/*.graphql) /types.{ts,kt,...}) Dart / TS / GDScript) src/pages/...)
```

- `packages/gql/src/*.graphql` — schema descriptions ARE the canonical doc
string. Edits propagate via `bun run generate` to every generated
`Types.{ts,kt,swift,dart,gd}`.
- `libraries/*/src/types.ts` (or equivalent) — generated; never hand-edit.
When a docs page mentions a field name, that field MUST exist in the
generated TS type. The audit script enforces this.
- Wrapper SDK source (e.g. `libraries/expo-iap/src/index.ts`) — JSDoc
parameter names MUST match the actual function-signature parameter
names. ESLint rule `tsdoc/syntax` + the audit script catch drift.
- Doc pages — the surface visible to users. Must reflect what each upstream
layer actually exposes.

## Rules

### R1 — JSDoc / KDoc / Dartdoc / Swift `@param` names match the signature

If the function declares `(args) =>`, the JSDoc tag is `@param args …`.
If it declares `(request) =>`, the tag is `@param request …`. Don't carry
over the schema field name (`props`, `params`) when the wrapper destructured
or renamed.

```ts
// ✅ wrapper destructures from `args`
/** @param args Purchase request. … */
export const requestPurchase = async (args) => { … };

// ❌ JSDoc says `props`; signature says `args`
/** @param props … */
export const requestPurchase = async (args) => { … };
```

### R2 — Defaults match across SDKs

If `fetchProducts.type` defaults to `'in-app'` in Flutter / expo-iap /
react-native-iap / godot-iap, then the Apple wrapper must also default to
`.inApp` — and the Apple doc comment must say `.inApp`. The schema
description is the canonical statement.

When changing a default, update:
1. The GraphQL schema description.
2. Re-run `bun run generate`.
3. Every wrapper SDK's `?? <default>` expression and JSDoc / KDoc / etc.
4. Every API doc page (`packages/docs/src/pages/docs/apis/<symbol>.tsx`).

### R3 — Doc pages reference real fields only

When a Type doc page lists fields in a `<table>` or `<ul>`, every field name
MUST exist in the generated `libraries/expo-iap/src/types.ts` (or
`libraries/react-native-iap/src/types.ts` — they're identical in shape).
The audit script greps for fields that don't appear in the type definition
and flags them.

Example failure modes already encountered:
- `BillingProgramAvailabilityResultAndroid` doc listed
`responseCode` + `debugMessage` — neither field exists; the type has
`billingProgram` + `isAvailable`.
- `LaunchExternalLinkParamsAndroid` doc listed `program` + `url` — neither
exists; the type has `billingProgram` + `launchMode` + `linkType` +
`linkUri`.
- `ExternalPurchaseCustomLinkNoticeResultIOS` doc listed `result` +
`noticeType` — neither exists; the type has `continued` + `error`.

### R4 — Enum values listed in docs must exist

When a doc page mentions enum values (e.g.
`'continue' | 'cancelled'`, `.acquisition`, `.services`), they must
appear in the generated enum definition. The audit script extracts string
literals from `<code>'…'</code>` blocks in doc pages and checks them
against the generated TypeScript union types.

`ExternalPurchaseCustomLinkNoticeTypeIOS` is the canonical recent miss —
the union is `'browser'` only, but the doc claimed
`'continue' | 'cancelled' | …`.

### R5 — `<Link to="/docs/...">` targets must resolve

Anchor links should point to existing pages and section anchors. Common
recent failures:
- "Use verifyPurchase" link pointed to `/docs/apis/get-active-subscriptions`
(totally unrelated).
- `getExternalPurchaseCustomLinkTokenIOS` Returns linked to the
`external-purchase-link` page without an anchor — but that page
documents only `ExternalPurchaseNoticeResultIOS`, so users land in the
wrong section. Add a precise `#external-purchase-custom-link-token-result-ios`
anchor on the type page AND link to it.

The audit script crawls every internal `<Link to="/docs/...">` and asserts
the target file (and anchor when given) exists.

### R6 — Native version constraints are honest

`enableBillingProgramAndroid: 'external-payments'` is gated to Play Billing
8.3.0+ (Japan only); the 8.2.0+ programs are `EXTERNAL_CONTENT_LINK` /
`EXTERNAL_OFFER`. A doc page that mixes these up misleads readers about
what works on which SDK.

When you write `<X> 8.2.0+`, you should be able to point to the matching
release-notes line. Don't paraphrase — quote the version requirement
exactly as Google / Apple states it.

### R7 — Code-example snippets compile-check

Code examples in doc pages should at minimum parse / type-check against
the wrapper they target. The audit script does NOT yet run a full
TypeScript / Kotlin / Dart parser, but it does:
- Verify imports (`import {…} from 'expo-iap'`) reference symbols that
expo-iap actually exports.
- Verify field accesses on shown objects (e.g. `purchase.purchaseToken`)
exist on the corresponding generated type.

When in doubt, run the example in a real example app before publishing.

### R8 — Platform-only callouts use the right wrapper

iOS-suffixed APIs (`syncIOS`, `getStorefrontIOS`, …) and Android-suffixed
APIs (`acknowledgePurchaseAndroid`, …) are exposed via every framework
wrapper (expo-iap, rn-iap, kmp-iap, flutter, godot-iap). The TS / Dart /
KMP / GDScript example tabs MUST show how to call the function from each
wrapper, with a `Platform.OS === 'ios'` (or `Platform.isIOS` / etc.)
guard so readers don't accidentally call iOS-only methods on Android.

The native Swift / Kotlin tab keeps the platform-native call. The
wrapper tabs use the suffixed name (`syncIOS()`, etc.) — except in
`packages/google` Kotlin (the Android-only native), where convention
strips the `Android` suffix from method names.

## Pre-commit checklist

Run before every `git push` on docs / SDK changes:

```bash
# 1. Format + lint the docs site
cd packages/docs
bunx prettier --check "src/**/*.{ts,tsx,css}"
bun run lint

# 2. Cross-library typecheck for SDKs you touched
cd libraries/expo-iap && bun run lint:tsc
cd libraries/react-native-iap && yarn typecheck # ignore example-expo errors
cd libraries/flutter_inapp_purchase && dart analyze lib
cd packages/apple && swift build
cd packages/google && ./gradlew :openiap:compilePlayDebugKotlin

# 3. SSOT audit — run the docs-consistency audit script
cd scripts && bun run audit-docs.ts
```

Auto-mode users: the `commit-push-pr` skill runs steps 1 + 2 automatically
before pushing. Step 3 is opt-in until the audit script has zero false
positives in CI.

## Audit script

`scripts/audit-docs.ts` is the executable companion to this guide. It
parses every `/docs/apis/*.tsx` and `/docs/types/*.tsx` page, extracts:
- `<Link to="/docs/...">` targets
- `<code>fieldName</code>` mentions inside Returns / Parameters tables
- String-literal enum values in `<code>'…'</code>` blocks
- `@see {@link openiap.dev/...}` URLs

…and cross-references each against the generated TypeScript types in
`libraries/expo-iap/src/types.ts`. Failures print as a punch-list with the
file, line, and the offending mention.

Run with:

```bash
cd /Users/hyo/Github/hyodotdev/openiap
bun run scripts/audit-docs.ts
```

Exit code 1 means at least one drift; 0 means clean.
Loading
Loading