@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.
Files changed (42) hide show
  1. package/CONVENTION.md +168 -0
  2. package/DESIGN.md +1056 -0
  3. package/README.md +227 -5
  4. package/SPEC.md +1471 -0
  5. package/conformance/index.d.ts +303 -0
  6. package/conformance/index.mjs +2126 -0
  7. package/conformance/mock-provider.mjs +491 -0
  8. package/examples/entitlement-granted-no-subscription.json +12 -0
  9. package/examples/entitlement-revoked.json +21 -0
  10. package/examples/provider-capabilities.json +209 -0
  11. package/examples/store-event-mapping.json +287 -0
  12. package/examples/subscription-canceled.json +22 -0
  13. package/examples/subscription-product-changed.json +30 -0
  14. package/examples/subscription-renewed.json +29 -0
  15. package/examples/verify-purchase-request.json +6 -0
  16. package/examples/verify-purchase-result.json +7 -0
  17. package/generated/bindings/graphql-operations.json +87 -0
  18. package/generated/bindings/http-binding.json +143 -0
  19. package/generated/bindings/introspection-signature.json +320 -0
  20. package/generated/bindings/operations-sdl.json +4 -0
  21. package/generated/bindings/operations.graphql +366 -0
  22. package/generated/commerce-protocol.graphql +1219 -0
  23. package/generated/openapi/commerce-protocol.openapi.json +1413 -0
  24. package/generated/schemas/commerce-event.schema.json +499 -0
  25. package/generated/schemas/commerce-protocol.bundle.schema.json +1576 -0
  26. package/generated/schemas/operations.schema.json +578 -0
  27. package/generated/schemas/primitives.schema.json +101 -0
  28. package/generated/schemas/provider-capabilities.schema.json +205 -0
  29. package/generated/schemas/store-event-mapping.schema.json +211 -0
  30. package/generated/vectors/lifecycle.json +908 -0
  31. package/generated/vectors/operations.json +1122 -0
  32. package/package.json +62 -12
  33. package/schema/01-primitives.graphql +102 -0
  34. package/schema/02-commerce-event.graphql +195 -0
  35. package/schema/03-provider-capabilities.graphql +139 -0
  36. package/schema/04-store-event-mapping.graphql +98 -0
  37. package/schema/05-operations.graphql +461 -0
  38. package/schema/06-compiler-vocabulary.graphql +139 -0
  39. package/schema/07-protocol-metadata.graphql +76 -0
  40. package/src/index.d.ts +63 -0
  41. package/src/index.mjs +121 -0
  42. package/vectors/signatures.json +139 -0
@@ -0,0 +1,499 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openiap.dev/schemas/commerce-protocol/1.0/commerce-event.schema.json",
4
+ "title": "OpenIAP Commerce Protocol event",
5
+ "description": "One normalized commerce lifecycle fact. A consumer reads this without knowing which store produced it and without parsing any store-native payload.",
6
+ "type": "object",
7
+ "required": [
8
+ "eventId",
9
+ "eventType",
10
+ "eventVersion",
11
+ "occurredAt",
12
+ "processedAt",
13
+ "store",
14
+ "environment",
15
+ "projectId"
16
+ ],
17
+ "additionalProperties": true,
18
+ "properties": {
19
+ "eventId": {
20
+ "description": "Unique identity of this event, assigned by the emitter. It is the receiver's deduplication key. An emitter MUST NOT reuse an eventId and MUST NOT change the eventId of an event it has already delivered.",
21
+ "$ref": "primitives.schema.json#/$defs/Identifier"
22
+ },
23
+ "eventType": {
24
+ "description": "What happened. See the taxonomy in SPEC.md. The value space is OPEN: §12 adds an event type in a MINOR version, so a consumer pinned on the major MUST tolerate a type it does not recognise and MUST NOT act on it. The listed values are the ones this version names.",
25
+ "type": "string",
26
+ "pattern": "^[a-z]+\\.[a-z_]+$",
27
+ "examples": [
28
+ "subscription.started",
29
+ "subscription.renewed",
30
+ "subscription.recovered",
31
+ "subscription.entered_grace_period",
32
+ "subscription.entered_billing_retry",
33
+ "subscription.expired",
34
+ "subscription.canceled",
35
+ "subscription.uncanceled",
36
+ "subscription.revoked",
37
+ "subscription.refunded",
38
+ "subscription.product_changed",
39
+ "subscription.price_changed",
40
+ "subscription.deferred",
41
+ "subscription.paused",
42
+ "subscription.resumed",
43
+ "entitlement.granted",
44
+ "entitlement.revoked"
45
+ ]
46
+ },
47
+ "eventVersion": {
48
+ "description": "Schema version of this body, as MAJOR.MINOR. Consumers pin on the major.",
49
+ "type": "string",
50
+ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$"
51
+ },
52
+ "occurredAt": {
53
+ "description": "The best authoritative time for the commerce fact. Use the store-asserted transition time when one exists. When polling only reveals that a value changed since the last observation, use the time the emitter observed the new value and do not invent a more precise instant.",
54
+ "$ref": "primitives.schema.json#/$defs/Timestamp"
55
+ },
56
+ "processedAt": {
57
+ "description": "When the emitter derived this event. Always greater than or equal to occurredAt in practice, but not guaranteed by this specification.",
58
+ "$ref": "primitives.schema.json#/$defs/Timestamp"
59
+ },
60
+ "store": {
61
+ "$ref": "primitives.schema.json#/$defs/Store"
62
+ },
63
+ "environment": {
64
+ "$ref": "primitives.schema.json#/$defs/Environment"
65
+ },
66
+ "projectId": {
67
+ "description": "The emitter-side scope this event belongs to, opaque to the consumer. A scope is whatever boundary the emitter organises commerce by — a tenant, a project, an application, or a single constant when the emitter serves exactly one. It is NOT an identifier issued by any central registry, and an implementation MUST NOT be required to obtain one from a third party. The member name is inherited from the deployed 1.0 wire format.",
68
+ "$ref": "primitives.schema.json#/$defs/Identifier"
69
+ },
70
+ "applicationId": {
71
+ "description": "A finer-grained scope within `projectId`, when the emitter models one. Opaque to the consumer.",
72
+ "$ref": "primitives.schema.json#/$defs/Identifier"
73
+ },
74
+ "userId": {
75
+ "description": "The app user this purchase is bound to, expressed in the identity space shared by the emitter and its consumer. It is an opaque correlation handle: there is no global user directory, and no central identity resolution is implied or required. Absent when no binding exists; required on every entitlement event.",
76
+ "$ref": "primitives.schema.json#/$defs/Identifier"
77
+ },
78
+ "productId": {
79
+ "description": "Store product identifier this event concerns. Required on every entitlement event so a consumer knows which access decision to apply.",
80
+ "type": "string",
81
+ "minLength": 1
82
+ },
83
+ "previousProductId": {
84
+ "description": "The product that was canonical before this event, when the event applies a product switch.",
85
+ "type": "string",
86
+ "minLength": 1
87
+ },
88
+ "transactionId": {
89
+ "description": "Store transaction identity for this specific economic event, where the store exposes one.",
90
+ "type": "string",
91
+ "minLength": 1
92
+ },
93
+ "originalTransactionId": {
94
+ "description": "Store identity of the first transaction in this subscription chain, where the store exposes one.",
95
+ "type": "string",
96
+ "minLength": 1
97
+ },
98
+ "subscription": {
99
+ "description": "The subscription as it stood immediately after this event. Absent for stores that keep no canonical subscription record.",
100
+ "type": "object",
101
+ "required": [
102
+ "state",
103
+ "productId",
104
+ "active"
105
+ ],
106
+ "additionalProperties": true,
107
+ "properties": {
108
+ "state": {
109
+ "$ref": "primitives.schema.json#/$defs/SubscriptionState"
110
+ },
111
+ "productId": {
112
+ "description": "The product the subscription is on after this event. Not always the event's top-level `productId`: where a store defers a product change to the next period — Apple's scheduled downgrades do, Google's item changes do not — the top level names the incoming product while this stays on the outgoing one until it renews. A consumer gating access reads this member; one reporting on what the notification announced reads the top level.",
113
+ "type": "string",
114
+ "minLength": 1
115
+ },
116
+ "expiresAt": {
117
+ "description": "When access ends. This is the boundary the entitlement predicate compares against, and the comparison is exclusive — at this instant the subscription is no longer entitled. During a grace period it is the end of the grace window, not of the period that failed to renew; an emitter that reports the failed period here revokes access at the moment grace begins.",
118
+ "$ref": "primitives.schema.json#/$defs/Timestamp"
119
+ },
120
+ "renewsAt": {
121
+ "description": "When the store will next attempt to bill, when it reports one. Distinct from `expiresAt`, which is when access ends: they coincide on a healthy subscription and diverge while a grace period extends access past the billing date. Absent once renewal is no longer expected.",
122
+ "$ref": "primitives.schema.json#/$defs/Timestamp"
123
+ },
124
+ "willRenew": {
125
+ "description": "Whether the store will attempt another billing period. False after a cancellation, while access may still be live.",
126
+ "type": "boolean"
127
+ },
128
+ "cancellationReason": {
129
+ "description": "Why the subscription stopped renewing, as a normalized token — not the store's own wording, which the emitter translates from whatever shape that store uses. This version names `UserCanceled`, `BillingError`, `PriceIncreaseDeclined`, `ProductUnavailable`, `Refunded` and `Other`; the space is open, so a consumer MUST tolerate a token it does not know, and no store yields every token. An emitter that has no store-asserted reason omits this member. Unlike `price`, it has no provenance marker, so treat a present value as advisory rather than as a fact to bill or report on.",
130
+ "type": "string",
131
+ "minLength": 1
132
+ },
133
+ "active": {
134
+ "description": "The entitlement gate after this event. Where this member is present it is the field to read for access — never a re-derivation from `state`. A store that keeps no canonical subscription record omits the whole `subscription` member; there an `entitlement.granted` or `entitlement.revoked` event carries the decision in its type, while a `subscription.*` event carries none.",
135
+ "type": "boolean"
136
+ }
137
+ }
138
+ },
139
+ "price": {
140
+ "description": "Amount associated with the transaction this event concerns, carried at whatever provenance it has — only `store` means the store asserted it. Always the transaction's own magnitude and never negative. It is context rather than a charge record: stores repeat the same figure across successive notifications about one subscription, so a consumer MUST NOT sum every priced event. See SPEC.md 9.3. Absent means the amount is unknown, never zero.",
141
+ "$ref": "primitives.schema.json#/$defs/Money"
142
+ },
143
+ "sourceStoreEventId": {
144
+ "description": "The store's own notification identifier this event was derived from, for support triage against the store console. Absent when the event did not originate from a store notification.",
145
+ "type": "string",
146
+ "minLength": 1
147
+ },
148
+ "extensions": {
149
+ "$ref": "primitives.schema.json#/$defs/Extensions"
150
+ }
151
+ },
152
+ "allOf": [
153
+ {
154
+ "if": {
155
+ "properties": {
156
+ "eventType": {
157
+ "enum": [
158
+ "entitlement.granted",
159
+ "entitlement.revoked"
160
+ ]
161
+ }
162
+ },
163
+ "required": [
164
+ "eventType"
165
+ ]
166
+ },
167
+ "then": {
168
+ "properties": {
169
+ "userId": {},
170
+ "productId": {}
171
+ },
172
+ "required": [
173
+ "userId",
174
+ "productId"
175
+ ]
176
+ }
177
+ },
178
+ {
179
+ "if": {
180
+ "properties": {
181
+ "eventType": {
182
+ "enum": [
183
+ "entitlement.granted"
184
+ ]
185
+ },
186
+ "subscription": {
187
+ "type": "object"
188
+ }
189
+ },
190
+ "required": [
191
+ "eventType",
192
+ "subscription"
193
+ ]
194
+ },
195
+ "then": {
196
+ "properties": {
197
+ "subscription": {
198
+ "type": "object",
199
+ "properties": {
200
+ "active": {
201
+ "const": true
202
+ }
203
+ },
204
+ "required": [
205
+ "active"
206
+ ]
207
+ }
208
+ }
209
+ }
210
+ },
211
+ {
212
+ "if": {
213
+ "properties": {
214
+ "eventType": {
215
+ "enum": [
216
+ "entitlement.revoked"
217
+ ]
218
+ },
219
+ "subscription": {
220
+ "type": "object"
221
+ }
222
+ },
223
+ "required": [
224
+ "eventType",
225
+ "subscription"
226
+ ]
227
+ },
228
+ "then": {
229
+ "properties": {
230
+ "subscription": {
231
+ "type": "object",
232
+ "properties": {
233
+ "active": {
234
+ "const": false
235
+ }
236
+ },
237
+ "required": [
238
+ "active"
239
+ ]
240
+ }
241
+ }
242
+ }
243
+ },
244
+ {
245
+ "if": {
246
+ "properties": {
247
+ "eventType": {
248
+ "enum": [
249
+ "subscription.started",
250
+ "subscription.renewed",
251
+ "subscription.recovered",
252
+ "subscription.resumed"
253
+ ]
254
+ },
255
+ "subscription": {
256
+ "type": "object"
257
+ }
258
+ },
259
+ "required": [
260
+ "eventType",
261
+ "subscription"
262
+ ]
263
+ },
264
+ "then": {
265
+ "properties": {
266
+ "subscription": {
267
+ "type": "object",
268
+ "properties": {
269
+ "state": {
270
+ "const": "Active"
271
+ }
272
+ },
273
+ "required": [
274
+ "state"
275
+ ]
276
+ }
277
+ }
278
+ }
279
+ },
280
+ {
281
+ "if": {
282
+ "properties": {
283
+ "eventType": {
284
+ "enum": [
285
+ "subscription.entered_grace_period"
286
+ ]
287
+ },
288
+ "subscription": {
289
+ "type": "object"
290
+ }
291
+ },
292
+ "required": [
293
+ "eventType",
294
+ "subscription"
295
+ ]
296
+ },
297
+ "then": {
298
+ "properties": {
299
+ "subscription": {
300
+ "type": "object",
301
+ "properties": {
302
+ "state": {
303
+ "const": "InGracePeriod"
304
+ }
305
+ },
306
+ "required": [
307
+ "state"
308
+ ]
309
+ }
310
+ }
311
+ }
312
+ },
313
+ {
314
+ "if": {
315
+ "properties": {
316
+ "eventType": {
317
+ "enum": [
318
+ "subscription.entered_billing_retry"
319
+ ]
320
+ },
321
+ "subscription": {
322
+ "type": "object"
323
+ }
324
+ },
325
+ "required": [
326
+ "eventType",
327
+ "subscription"
328
+ ]
329
+ },
330
+ "then": {
331
+ "properties": {
332
+ "subscription": {
333
+ "type": "object",
334
+ "properties": {
335
+ "state": {
336
+ "const": "InBillingRetry"
337
+ },
338
+ "active": {
339
+ "const": false
340
+ }
341
+ },
342
+ "required": [
343
+ "state",
344
+ "active"
345
+ ]
346
+ }
347
+ }
348
+ }
349
+ },
350
+ {
351
+ "if": {
352
+ "properties": {
353
+ "eventType": {
354
+ "enum": [
355
+ "subscription.expired"
356
+ ]
357
+ },
358
+ "subscription": {
359
+ "type": "object"
360
+ }
361
+ },
362
+ "required": [
363
+ "eventType",
364
+ "subscription"
365
+ ]
366
+ },
367
+ "then": {
368
+ "properties": {
369
+ "subscription": {
370
+ "type": "object",
371
+ "properties": {
372
+ "state": {
373
+ "const": "Expired"
374
+ },
375
+ "active": {
376
+ "const": false
377
+ }
378
+ },
379
+ "required": [
380
+ "state",
381
+ "active"
382
+ ]
383
+ }
384
+ }
385
+ }
386
+ },
387
+ {
388
+ "if": {
389
+ "properties": {
390
+ "eventType": {
391
+ "enum": [
392
+ "subscription.revoked"
393
+ ]
394
+ },
395
+ "subscription": {
396
+ "type": "object"
397
+ }
398
+ },
399
+ "required": [
400
+ "eventType",
401
+ "subscription"
402
+ ]
403
+ },
404
+ "then": {
405
+ "properties": {
406
+ "subscription": {
407
+ "type": "object",
408
+ "properties": {
409
+ "state": {
410
+ "const": "Revoked"
411
+ },
412
+ "active": {
413
+ "const": false
414
+ }
415
+ },
416
+ "required": [
417
+ "state",
418
+ "active"
419
+ ]
420
+ }
421
+ }
422
+ }
423
+ },
424
+ {
425
+ "if": {
426
+ "properties": {
427
+ "eventType": {
428
+ "enum": [
429
+ "subscription.refunded"
430
+ ]
431
+ },
432
+ "subscription": {
433
+ "type": "object"
434
+ }
435
+ },
436
+ "required": [
437
+ "eventType",
438
+ "subscription"
439
+ ]
440
+ },
441
+ "then": {
442
+ "properties": {
443
+ "subscription": {
444
+ "type": "object",
445
+ "properties": {
446
+ "state": {
447
+ "const": "Refunded"
448
+ },
449
+ "active": {
450
+ "const": false
451
+ }
452
+ },
453
+ "required": [
454
+ "state",
455
+ "active"
456
+ ]
457
+ }
458
+ }
459
+ }
460
+ },
461
+ {
462
+ "if": {
463
+ "properties": {
464
+ "eventType": {
465
+ "enum": [
466
+ "subscription.paused"
467
+ ]
468
+ },
469
+ "subscription": {
470
+ "type": "object"
471
+ }
472
+ },
473
+ "required": [
474
+ "eventType",
475
+ "subscription"
476
+ ]
477
+ },
478
+ "then": {
479
+ "properties": {
480
+ "subscription": {
481
+ "type": "object",
482
+ "properties": {
483
+ "state": {
484
+ "const": "Paused"
485
+ },
486
+ "active": {
487
+ "const": false
488
+ }
489
+ },
490
+ "required": [
491
+ "state",
492
+ "active"
493
+ ]
494
+ }
495
+ }
496
+ }
497
+ }
498
+ ]
499
+ }