@hyodotdev/openiap-commerce-protocol 0.0.0-bootstrap.0 → 0.1.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/CONVENTION.md +168 -0
- package/DESIGN.md +1056 -0
- package/README.md +227 -5
- package/SPEC.md +1471 -0
- package/conformance/index.d.ts +303 -0
- package/conformance/index.mjs +2126 -0
- package/conformance/mock-provider.mjs +491 -0
- package/examples/entitlement-granted-no-subscription.json +12 -0
- package/examples/entitlement-revoked.json +21 -0
- package/examples/provider-capabilities.json +209 -0
- package/examples/store-event-mapping.json +287 -0
- package/examples/subscription-canceled.json +22 -0
- package/examples/subscription-product-changed.json +30 -0
- package/examples/subscription-renewed.json +29 -0
- package/examples/verify-purchase-request.json +6 -0
- package/examples/verify-purchase-result.json +7 -0
- package/generated/bindings/graphql-operations.json +87 -0
- package/generated/bindings/http-binding.json +143 -0
- package/generated/bindings/introspection-signature.json +320 -0
- package/generated/bindings/operations-sdl.json +4 -0
- package/generated/bindings/operations.graphql +366 -0
- package/generated/commerce-protocol.graphql +1219 -0
- package/generated/openapi/commerce-protocol.openapi.json +1413 -0
- package/generated/schemas/commerce-event.schema.json +499 -0
- package/generated/schemas/commerce-protocol.bundle.schema.json +1576 -0
- package/generated/schemas/operations.schema.json +578 -0
- package/generated/schemas/primitives.schema.json +101 -0
- package/generated/schemas/provider-capabilities.schema.json +205 -0
- package/generated/schemas/store-event-mapping.schema.json +211 -0
- package/generated/vectors/lifecycle.json +908 -0
- package/generated/vectors/operations.json +1122 -0
- package/package.json +62 -12
- package/schema/01-primitives.graphql +102 -0
- package/schema/02-commerce-event.graphql +195 -0
- package/schema/03-provider-capabilities.graphql +139 -0
- package/schema/04-store-event-mapping.graphql +98 -0
- package/schema/05-operations.graphql +461 -0
- package/schema/06-compiler-vocabulary.graphql +139 -0
- package/schema/07-protocol-metadata.graphql +76 -0
- package/src/index.d.ts +63 -0
- package/src/index.mjs +121 -0
- package/vectors/signatures.json +139 -0
package/README.md
CHANGED
|
@@ -1,8 +1,230 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OpenIAP Commerce Protocol
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@hyodotdev/openiap-commerce-protocol)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
a usable implementation. Functional releases will be published separately.
|
|
5
|
+
A vendor-neutral specification for the **server side** of in-app purchases.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
OpenIAP normalizes the client-side purchase API across stores. This normalizes
|
|
8
|
+
the server side: one commerce vocabulary, one portable operation surface with
|
|
9
|
+
REST and GraphQL bindings, one event envelope, one webhook contract — so a
|
|
10
|
+
backend or an analytics pipeline can verify purchases, read entitlements, and
|
|
11
|
+
handle renewals, refunds, and entitlement changes from Apple, Google, Meta
|
|
12
|
+
Horizon, and Amazon without parsing any store-native payload, and can replace
|
|
13
|
+
the provider behind those calls without rewriting the integration.
|
|
14
|
+
|
|
15
|
+
Nothing in this contract routes through infrastructure the OpenIAP project
|
|
16
|
+
operates. Two parties exchange events directly, using a secret they share
|
|
17
|
+
between themselves, and validate offline. The project distributes the contract;
|
|
18
|
+
it does not sit in the path of anyone's commerce.
|
|
19
|
+
|
|
20
|
+
**[Read the specification →](./SPEC.md)**
|
|
21
|
+
|
|
22
|
+
## Choose your role
|
|
23
|
+
|
|
24
|
+
A paywall specialist can supply the experience, a commerce service the purchase
|
|
25
|
+
and access decisions, and an analytics platform the event processing. An
|
|
26
|
+
integrated platform can supply several roles. Explore the [role map](https://openiap.dev/commerce-protocol#architecture)
|
|
27
|
+
and [AI integration brief](https://openiap.dev/commerce-example/integration-brief.md)
|
|
28
|
+
to connect your product to apps using OpenIAP. These product roles do not add
|
|
29
|
+
protocol profiles or a universal paywall API.
|
|
30
|
+
|
|
31
|
+
## Start implementing
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install @hyodotdev/openiap-commerce-protocol
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or use `pnpm add`, `yarn add`, or `bun add` with the same package name.
|
|
38
|
+
|
|
39
|
+
Give your AI the installed package's `SPEC.md`, `DESIGN.md`, and `generated/`
|
|
40
|
+
artifacts. The package supplies the contract; your AI implements the backend.
|
|
41
|
+
|
|
42
|
+
- **See what AI built:** the [recorded walkthrough](https://openiap.dev/commerce-protocol#build-walkthrough)
|
|
43
|
+
shows a real local HTTP + SQLite backend in six milestones, with captured
|
|
44
|
+
responses. The [IAPKit comparison](https://openiap.dev/commerce-protocol/implementation#iapkit) explains what was tested. Give the
|
|
45
|
+
[build brief](https://openiap.dev/commerce-example/build-brief.md)
|
|
46
|
+
to your AI to build the same flow in your own stack.
|
|
47
|
+
- **Integrate your backend:** [Use a provider](https://openiap.dev/commerce-protocol/getting-started)
|
|
48
|
+
walks through discovery, verification, account binding, and entitlement reads.
|
|
49
|
+
- **Build a provider:** [Build with AI](https://openiap.dev/commerce-protocol/implementation)
|
|
50
|
+
provides the brief, runnable example, and next implementation steps.
|
|
51
|
+
[DESIGN.md §5](./DESIGN.md#5-implementation-blueprint) contains the architecture
|
|
52
|
+
blueprint, storage keys, transaction boundaries, and recovery design.
|
|
53
|
+
- **Try the contract locally:** from the repository root, run `bun install`,
|
|
54
|
+
then `cd specs/commerce-protocol && bun run quickstart`. The
|
|
55
|
+
[development walkthrough](https://github.com/hyodotdev/openiap/blob/main/specs/commerce-protocol/scripts/quickstart.mjs) uses the in-memory mock,
|
|
56
|
+
checks authorization and binding behavior, and runs REST/GraphQL conformance.
|
|
57
|
+
It uses fixture evidence, opens no HTTP server, and does not validate real
|
|
58
|
+
store purchases. Its Ajv and GraphQL dependencies come from this package's
|
|
59
|
+
development setup.
|
|
60
|
+
|
|
61
|
+
[DESIGN.md](./DESIGN.md) explains why the boundaries sit where they do. It is
|
|
62
|
+
background, not normative: where the two disagree, `SPEC.md` is right. It is
|
|
63
|
+
also published as a PDF at
|
|
64
|
+
<https://www.openiap.dev/commerce-protocol-rationale.pdf>.
|
|
65
|
+
|
|
66
|
+
The contract sits between the stores and everything downstream of a backend:
|
|
67
|
+
|
|
68
|
+
```mermaid
|
|
69
|
+
flowchart TB
|
|
70
|
+
stores["Apple / Google / Meta / Amazon<br/>the stores"]
|
|
71
|
+
backend["A backend that implements this spec<br/>IAPKit, another provider, or the adopter's own — in any language<br/><br/>verify → normalize → lifecycle → entitle"]
|
|
72
|
+
app["shipped application<br/>verification role (§5)"]
|
|
73
|
+
server["the adopter's backend<br/>server role (§5)"]
|
|
74
|
+
consumers["any consumer<br/>data pipeline / CRM / analytics"]
|
|
75
|
+
|
|
76
|
+
stores -->|"store-native notifications and APIs"| backend
|
|
77
|
+
app -->|"verifyPurchase, providerCapabilities (§4.1, §4.6)<br/>over REST (§6) or GraphQL (§7)"| backend
|
|
78
|
+
server -->|"those, plus subscriptionStatus, entitlements, bindPurchase, eraseUser (§4.2–§4.5)<br/>server role only — never a shipped app"| backend
|
|
79
|
+
backend -->|"OpenIAP Commerce Protocol events (§9)"| consumers
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Reviewing a change
|
|
83
|
+
|
|
84
|
+
Review only the authored surfaces, in this order:
|
|
85
|
+
|
|
86
|
+
1. [`SPEC.md`](./SPEC.md) — behavior, operations, bindings, lifecycle,
|
|
87
|
+
transport, and compatibility.
|
|
88
|
+
2. [`schema/`](./schema/) — the authored contract layers: wire structure, the
|
|
89
|
+
operation surface, and validation directives.
|
|
90
|
+
[`generated/commerce-protocol.graphql`](./generated/commerce-protocol.graphql)
|
|
91
|
+
is their generated single-file assembly (also exported at the package path
|
|
92
|
+
`@hyodotdev/openiap-commerce-protocol/commerce-protocol.graphql`).
|
|
93
|
+
3. [`examples/`](./examples/) — representative documents and store mappings.
|
|
94
|
+
4. [`vectors/signatures.json`](./vectors/signatures.json) — hand-authored
|
|
95
|
+
cryptographic truth cases.
|
|
96
|
+
5. [`conformance/`](./conformance/) — the portable runner and its independent
|
|
97
|
+
mock provider.
|
|
98
|
+
|
|
99
|
+
Ignore `generated/` during a human review. It is compiler output, kept only for
|
|
100
|
+
validators and drift checks.
|
|
101
|
+
|
|
102
|
+
## What ships here
|
|
103
|
+
|
|
104
|
+
| Path | Contents |
|
|
105
|
+
| ------------------------- | --------------------------------------------------------------------------- |
|
|
106
|
+
| `schema/` | Authored type, operation, and validation contract layers — edit these |
|
|
107
|
+
| `SPEC.md` | Normative meaning, operations, bindings, transport, and compatibility rules |
|
|
108
|
+
| `DESIGN.md` | Why the boundaries sit where they do — background, never normative |
|
|
109
|
+
| `generated/` | Compiler output: schemas, binding manifests, OpenAPI, and vectors |
|
|
110
|
+
| `examples/` | Canonical documents that must validate |
|
|
111
|
+
| `vectors/signatures.json` | Signature vectors every implementation must reproduce |
|
|
112
|
+
| `conformance/` | Portable conformance runner plus an IAPKit-free mock provider |
|
|
113
|
+
| `src/index.mjs` | Runtime access to the generated schemas and their derived constants |
|
|
114
|
+
|
|
115
|
+
The `schema/` layers govern wire structure. Their custom directives retain
|
|
116
|
+
patterns, bounds, maps, open objects, and conditional rules that standard SDL
|
|
117
|
+
cannot express. `bun run build` compiles that source into the JSON Schemas a Go,
|
|
118
|
+
Python, or other backend executes against incoming webhook bodies. `SPEC.md`
|
|
119
|
+
governs meaning and transport.
|
|
120
|
+
|
|
121
|
+
Do not add this SDL to `specs/client/schema-files.mjs`. `specs/client` owns the
|
|
122
|
+
client purchase API and the SDK types compiled from it; this file independently
|
|
123
|
+
owns the server-to-server commerce contract. Its Query and Mutation types are
|
|
124
|
+
the portable server operation surface — compiled into the REST and GraphQL
|
|
125
|
+
bindings, never into client SDK types — and it defines no Subscription root:
|
|
126
|
+
the operation surface is bounded request/response by rule.
|
|
127
|
+
|
|
128
|
+
## Receiving events
|
|
129
|
+
|
|
130
|
+
An endpoint you register receives one JSON event per request. Verify the
|
|
131
|
+
signature — `SPEC.md` §9.4.2 states the rule and `vectors/signatures.json` pins
|
|
132
|
+
it — then handle the event; `SPEC.md` §9.5 walks a consumer end to end.
|
|
133
|
+
|
|
134
|
+
Three rules that are easy to get wrong, all specified in detail in `SPEC.md`:
|
|
135
|
+
|
|
136
|
+
- **Sign the bytes you received.** Re-serializing the JSON before verifying
|
|
137
|
+
changes key order and whitespace, and the signature will not match.
|
|
138
|
+
- **Read `subscription.active`, not `state`.** A canceled subscription keeps
|
|
139
|
+
access until its paid period ends — `subscription.canceled` means auto-renew
|
|
140
|
+
was turned off, not that access was revoked.
|
|
141
|
+
- **A missing amount means unknown.** It never means zero.
|
|
142
|
+
|
|
143
|
+
## Calling a provider
|
|
144
|
+
|
|
145
|
+
Start with the provider's capability descriptor. Every conforming provider
|
|
146
|
+
supports discovery; its declared profiles determine which purchase, status,
|
|
147
|
+
entitlement, binding, and erasure operations it supports. Check those profiles
|
|
148
|
+
before calling an operation. REST and GraphQL bindings share one error-code
|
|
149
|
+
space. `SPEC.md` §4–§8 define the surface and authorization rules.
|
|
150
|
+
|
|
151
|
+
## Certifying a provider
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
import Ajv from "ajv/dist/2020.js";
|
|
155
|
+
import {
|
|
156
|
+
createRestAdapter,
|
|
157
|
+
createGraphqlAdapter,
|
|
158
|
+
runConformance,
|
|
159
|
+
} from "@hyodotdev/openiap-commerce-protocol/conformance";
|
|
160
|
+
|
|
161
|
+
const report = await runConformance({
|
|
162
|
+
adapters: [
|
|
163
|
+
createRestAdapter({ baseUrl, fetch, credentials }),
|
|
164
|
+
createGraphqlAdapter({ url: graphqlUrl, fetch, credentials }),
|
|
165
|
+
],
|
|
166
|
+
Ajv,
|
|
167
|
+
// The same role-to-credential map the adapters use — required, so the
|
|
168
|
+
// runner can reject an error message that echoes a credential.
|
|
169
|
+
credentials,
|
|
170
|
+
// Required when your capability descriptor declares the events profile:
|
|
171
|
+
// your outbound webhook implementation, driven through SPEC.md §9's
|
|
172
|
+
// signing, verification, delivery, response, entitlement, and emission
|
|
173
|
+
// vectors.
|
|
174
|
+
eventsAdapter,
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The runner is offline, needs no hosted service, and imports no implementation;
|
|
179
|
+
supply the Ajv 2020 class yourself, since the published runtime carries zero
|
|
180
|
+
dependencies. It certifies the transport contract — never real store receipt
|
|
181
|
+
validity (`SPEC.md` §11.3). A provider that declares the `events` profile must
|
|
182
|
+
also pass an `eventsAdapter` covering the full `EventsAdapter` surface
|
|
183
|
+
(`conformance/index.d.ts`); a signing-only adapter fails.
|
|
184
|
+
|
|
185
|
+
## Validating
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
bun install
|
|
189
|
+
bun run test
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The suite recompiles every schema and binding artifact, validates every
|
|
193
|
+
example, checks that each rejection case is actually rejected, reproduces
|
|
194
|
+
every signature vector using an implementation written only from `SPEC.md`,
|
|
195
|
+
and certifies an independent mock provider on both bindings.
|
|
196
|
+
|
|
197
|
+
## Relationship to the rest of OpenIAP
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
OpenIAP Commerce Protocol ← this package: the server-side contract
|
|
201
|
+
│
|
|
202
|
+
┌──────────────┼──────────────┐
|
|
203
|
+
│ │ │
|
|
204
|
+
IAPKit vendor backend custom backend
|
|
205
|
+
(reference)
|
|
206
|
+
│ │ │
|
|
207
|
+
└──────────────┼──────────────┘
|
|
208
|
+
↓
|
|
209
|
+
normalized commerce events
|
|
210
|
+
↓
|
|
211
|
+
┌──────────────┼──────────────┐
|
|
212
|
+
│ │ │
|
|
213
|
+
SaaS analytics enterprise
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
No box in that diagram is required to be operated by the OpenIAP project. An
|
|
217
|
+
adopter may self-host IAPKit, use a hosted conforming provider, or implement the
|
|
218
|
+
contract in the backend they already have — and a consumer supports _the
|
|
219
|
+
specification_, so any of the three can feed it.
|
|
220
|
+
|
|
221
|
+
## Status
|
|
222
|
+
|
|
223
|
+
Implements protocol version 1.0. The event vocabulary,
|
|
224
|
+
envelope, webhook contract, operation surface, REST and GraphQL bindings, and
|
|
225
|
+
portable conformance runner are implemented and tested. `SPEC.md` §14 lists
|
|
226
|
+
what is deliberately not in this version.
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT
|