@mpgd/game-services 0.21.1 → 0.23.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/README.md +30 -0
- package/dist/admob-ssv-conformance.js +3 -1
- package/dist/app-store-recovery.js +5 -0
- package/dist/client.d.ts +39 -1
- package/dist/client.js +198 -0
- package/dist/commerce-evidence-registry.d.ts +406 -0
- package/dist/commerce-evidence-registry.js +773 -0
- package/dist/commerce-ledger.d.ts +64 -0
- package/dist/commerce-ledger.js +146 -0
- package/dist/commerce-reconciler.d.ts +191 -0
- package/dist/commerce-reconciler.js +1251 -0
- package/dist/contract.d.ts +4 -1
- package/dist/contract.js +8 -0
- package/dist/evidence-verification.d.ts +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/monetization-operation-store.d.ts +20 -0
- package/dist/monetization-operation-store.js +80 -0
- package/dist/monetization-recovery.d.ts +57 -2
- package/dist/monetization-recovery.js +102 -8
- package/dist/notification-delivery.d.ts +9 -1
- package/dist/notification-delivery.js +45 -5
- package/dist/operation-results.d.ts +14 -0
- package/dist/operations.d.ts +2 -1
- package/dist/platform-order.d.ts +47 -0
- package/dist/platform-order.js +86 -0
- package/dist/runtime.d.ts +7 -0
- package/dist/runtime.js +13 -1
- package/dist/server.d.ts +43 -1
- package/dist/server.js +305 -7
- package/dist/types.d.ts +79 -3
- package/dist/types.js +97 -6
- package/package.json +18 -6
package/dist/types.js
CHANGED
|
@@ -7,6 +7,9 @@ export function assertVerifyPurchaseRequest(input) {
|
|
|
7
7
|
return validateRequest(() => {
|
|
8
8
|
assertRecord(input, 'VerifyPurchaseRequest');
|
|
9
9
|
assertStoreTarget(input.target);
|
|
10
|
+
if (input.store !== undefined) {
|
|
11
|
+
assertCommerceStoreId(input.store, 'store');
|
|
12
|
+
}
|
|
10
13
|
assertOptionalGameServicesDeploymentTarget(input.deploymentTarget);
|
|
11
14
|
assertRequestString(input.playerId, 'playerId');
|
|
12
15
|
assertRequestString(input.productId, 'productId');
|
|
@@ -29,6 +32,49 @@ export function assertVerifyPurchaseResponse(input) {
|
|
|
29
32
|
}
|
|
30
33
|
return input;
|
|
31
34
|
}
|
|
35
|
+
/** Bounds one ledger status read; a client asks for the grants of one journal window. */
|
|
36
|
+
export const maxPurchaseLedgerStatusEntries = 256;
|
|
37
|
+
/**
|
|
38
|
+
* Validates an untrusted ledger status read. Failures throw
|
|
39
|
+
* `GameServicesRequestValidationError` so transports can answer with a stable 400.
|
|
40
|
+
*/
|
|
41
|
+
export function assertPurchaseLedgerStatusRequest(input) {
|
|
42
|
+
return validateRequest(() => {
|
|
43
|
+
assertRecord(input, 'PurchaseLedgerStatusRequest');
|
|
44
|
+
if (!Array.isArray(input.ledgerEntryIds)) {
|
|
45
|
+
throw new Error('ledgerEntryIds must be an array.');
|
|
46
|
+
}
|
|
47
|
+
if (input.ledgerEntryIds.length > maxPurchaseLedgerStatusEntries) {
|
|
48
|
+
throw new Error(`ledgerEntryIds must not exceed ${String(maxPurchaseLedgerStatusEntries)} entries.`);
|
|
49
|
+
}
|
|
50
|
+
for (const ledgerEntryId of input.ledgerEntryIds) {
|
|
51
|
+
assertRequestString(ledgerEntryId, 'ledgerEntryIds[]');
|
|
52
|
+
}
|
|
53
|
+
assertRequestString(input.playerId, 'playerId');
|
|
54
|
+
return input;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
export function assertPurchaseLedgerStatusResponse(input) {
|
|
58
|
+
assertRecord(input, 'PurchaseLedgerStatusResponse');
|
|
59
|
+
if (!Array.isArray(input.statuses)) {
|
|
60
|
+
throw new Error('statuses must be an array.');
|
|
61
|
+
}
|
|
62
|
+
for (const status of input.statuses) {
|
|
63
|
+
assertRecord(status, 'statuses[]');
|
|
64
|
+
assertNonEmptyString(status.ledgerEntryId, 'statuses[].ledgerEntryId');
|
|
65
|
+
if (status.status !== 'active' && status.status !== 'reversed' && status.status !== 'unknown') {
|
|
66
|
+
throw new Error('statuses[].status must be active, reversed, or unknown.');
|
|
67
|
+
}
|
|
68
|
+
assertOptionalNonEmptyString(status.reversedBy, 'statuses[].reversedBy');
|
|
69
|
+
if (status.status === 'reversed' && status.reversedBy === undefined) {
|
|
70
|
+
throw new Error('a reversed status names the entry that reversed it.');
|
|
71
|
+
}
|
|
72
|
+
if (status.status !== 'reversed' && status.reversedBy !== undefined) {
|
|
73
|
+
throw new Error('only a reversed status names a reversing entry.');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return input;
|
|
77
|
+
}
|
|
32
78
|
export function assertPurchaseGrantFinalization(input) {
|
|
33
79
|
assertRecord(input, 'PurchaseGrantFinalization');
|
|
34
80
|
if (input.status !== 'completed' && input.status !== 'pending') {
|
|
@@ -124,6 +170,38 @@ export function assertEntitlementLedgerResult(input) {
|
|
|
124
170
|
assertBoolean(input.alreadyProcessed, 'alreadyProcessed');
|
|
125
171
|
return input;
|
|
126
172
|
}
|
|
173
|
+
export function assertEntitlementLedgerRevocation(input) {
|
|
174
|
+
assertRecord(input, 'EntitlementLedgerRevocation');
|
|
175
|
+
assertNonEmptyString(input.playerId, 'playerId');
|
|
176
|
+
assertNonEmptyString(input.revokesLedgerEntryId, 'revokesLedgerEntryId');
|
|
177
|
+
assertNonEmptyString(input.idempotencyKey, 'idempotencyKey');
|
|
178
|
+
assertRevocationReason(input.reason);
|
|
179
|
+
assertNonEmptyString(input.revokedAt, 'revokedAt');
|
|
180
|
+
assertPayload(input.payload);
|
|
181
|
+
assertOptionalNonEmptyString(input.evidenceVerificationId, 'evidenceVerificationId');
|
|
182
|
+
return input;
|
|
183
|
+
}
|
|
184
|
+
export function assertEntitlementRevocationTransaction(input) {
|
|
185
|
+
assertEntitlementLedgerRevocation(input);
|
|
186
|
+
assertNonEmptyString(input.ledgerEntryId, 'ledgerEntryId');
|
|
187
|
+
return input;
|
|
188
|
+
}
|
|
189
|
+
export function assertEntitlementLedgerPeriod(input) {
|
|
190
|
+
assertRecord(input, 'EntitlementLedgerPeriod');
|
|
191
|
+
assertNonEmptyString(input.playerId, 'playerId');
|
|
192
|
+
assertNonEmptyString(input.extendsLedgerEntryId, 'extendsLedgerEntryId');
|
|
193
|
+
assertNonEmptyString(input.idempotencyKey, 'idempotencyKey');
|
|
194
|
+
if (!Number.isSafeInteger(input.periodIndex) || input.periodIndex < 0) {
|
|
195
|
+
throw new Error('periodIndex must be a non-negative integer.');
|
|
196
|
+
}
|
|
197
|
+
assertNonEmptyString(input.startedAt, 'startedAt');
|
|
198
|
+
assertNonEmptyString(input.expiresAt, 'expiresAt');
|
|
199
|
+
if (!(Date.parse(input.expiresAt) > Date.parse(input.startedAt))) {
|
|
200
|
+
throw new Error('expiresAt must be a timestamp after startedAt.');
|
|
201
|
+
}
|
|
202
|
+
assertPayload(input.payload);
|
|
203
|
+
return input;
|
|
204
|
+
}
|
|
127
205
|
export function assertProductGrantTransaction(input) {
|
|
128
206
|
assertRecord(input, 'ProductGrantTransaction');
|
|
129
207
|
assertNonEmptyString(input.ledgerEntryId, 'ledgerEntryId');
|
|
@@ -150,13 +228,21 @@ function assertRecord(input, label) {
|
|
|
150
228
|
throw new Error(`${label} must be an object.`);
|
|
151
229
|
}
|
|
152
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* The purchase target is open (RFC "Open store ids"): any bounded kebab-case
|
|
233
|
+
* identifier passes here, and the backend's commerce evidence registry decides
|
|
234
|
+
* whether the store it names is served.
|
|
235
|
+
*/
|
|
153
236
|
function assertStoreTarget(input) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
237
|
+
assertCommerceStoreId(input, 'target');
|
|
238
|
+
}
|
|
239
|
+
/** A store id is a bounded kebab-case identifier such as `google-play` or `credit-wallet`. */
|
|
240
|
+
export function assertCommerceStoreId(input, label = 'store') {
|
|
241
|
+
if (typeof input !== 'string'
|
|
242
|
+
|| input.length === 0
|
|
243
|
+
|| input.length > 64
|
|
244
|
+
|| !/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(input)) {
|
|
245
|
+
throw new Error(`${label} must be a lowercase kebab-case store identifier.`);
|
|
160
246
|
}
|
|
161
247
|
}
|
|
162
248
|
function assertAdRewardTarget(input) {
|
|
@@ -262,6 +348,11 @@ function assertPurchaseGrantFinalizationAction(input) {
|
|
|
262
348
|
throw new Error('finalization.action must be acknowledge, consume, finish, or complete.');
|
|
263
349
|
}
|
|
264
350
|
}
|
|
351
|
+
function assertRevocationReason(input) {
|
|
352
|
+
if (input !== 'refund' && input !== 'chargeback' && input !== 'voided' && input !== 'admin') {
|
|
353
|
+
throw new Error('reason must be refund, chargeback, voided, or admin.');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
265
356
|
function assertLedgerSource(input) {
|
|
266
357
|
if (input !== 'purchase' && input !== 'ad_reward' && input !== 'admin') {
|
|
267
358
|
throw new Error('source must be purchase, ad_reward, or admin.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/game-services",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Client, contract, server, store, and test helpers for authoritative mpgd game services.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -77,6 +77,18 @@
|
|
|
77
77
|
"types": "./dist/apps-in-toss-partner-api.d.ts",
|
|
78
78
|
"default": "./dist/apps-in-toss-partner-api.js"
|
|
79
79
|
},
|
|
80
|
+
"./commerce-evidence-registry": {
|
|
81
|
+
"types": "./dist/commerce-evidence-registry.d.ts",
|
|
82
|
+
"default": "./dist/commerce-evidence-registry.js"
|
|
83
|
+
},
|
|
84
|
+
"./commerce-reconciler": {
|
|
85
|
+
"types": "./dist/commerce-reconciler.d.ts",
|
|
86
|
+
"default": "./dist/commerce-reconciler.js"
|
|
87
|
+
},
|
|
88
|
+
"./monetization-operation-store": {
|
|
89
|
+
"types": "./dist/monetization-operation-store.d.ts",
|
|
90
|
+
"default": "./dist/monetization-operation-store.js"
|
|
91
|
+
},
|
|
80
92
|
"./client": {
|
|
81
93
|
"types": "./dist/client.d.ts",
|
|
82
94
|
"default": "./dist/client.js"
|
|
@@ -190,9 +202,9 @@
|
|
|
190
202
|
"@orpc/client": "2.0.0-beta.14",
|
|
191
203
|
"@orpc/contract": "2.0.0-beta.14",
|
|
192
204
|
"@orpc/server": "2.0.0-beta.14",
|
|
193
|
-
"@mpgd/
|
|
194
|
-
"@mpgd/
|
|
195
|
-
"@mpgd/
|
|
205
|
+
"@mpgd/platform": "0.22.0",
|
|
206
|
+
"@mpgd/analytics": "0.4.8",
|
|
207
|
+
"@mpgd/catalog": "0.9.3"
|
|
196
208
|
},
|
|
197
209
|
"peerDependencies": {
|
|
198
210
|
"@apple/app-store-server-library": "^3.1.0"
|
|
@@ -221,8 +233,8 @@
|
|
|
221
233
|
"fix": "ttsc fix",
|
|
222
234
|
"build": "cd ../.. && node tools/run-ttsx.mjs tools/package/build-packages.ts @mpgd/game-services",
|
|
223
235
|
"test:packed-transport": "pnpm build && node test/runtime-transport-package-import.mjs && node test/reward-evidence-import.mjs",
|
|
224
|
-
"test:unit": "cd ../.. && node tools/run-ttsx.mjs packages/game-services/src/client.test.ts && node tools/run-ttsx.mjs packages/game-services/src/client-progress.test.ts && node tools/run-ttsx.mjs packages/game-services/src/runtime.test.ts && node tools/run-ttsx.mjs packages/game-services/src/types.test.ts && node tools/run-ttsx.mjs packages/game-services/src/server.test.ts && node tools/run-ttsx.mjs packages/game-services/src/google-play-purchase.test.ts && node tools/run-ttsx.mjs packages/game-services/src/google-play-publisher-client.test.ts && node tools/run-ttsx.mjs packages/game-services/src/microsoft-store-purchase.test.ts && node tools/run-ttsx.mjs packages/game-services/src/microsoft-store-identity.test.ts && node tools/run-ttsx.mjs packages/game-services/src/platform-order.test.ts && node tools/run-ttsx.mjs packages/game-services/src/progress-link.test.ts && node tools/run-ttsx.mjs packages/game-services/src/notification-delivery.test.ts && node tools/run-ttsx.mjs packages/game-services/src/admob-ssv.test.ts && node tools/run-ttsx.mjs packages/game-services/src/app-store-verifier.test.ts && node tools/run-ttsx.mjs packages/game-services/src/apps-in-toss-evidence-verification-conformance.test.ts && node tools/run-ttsx.mjs packages/game-services/src/apps-in-toss-partner-api.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard-conformance.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard-durability-conformance.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard-transport.test.ts && node tools/run-ttsx.mjs packages/game-services/src/guest-session.test.ts && node tools/run-ttsx.mjs packages/game-services/src/client-reward-evidence.test.ts && node tools/run-ttsx.mjs packages/game-services/src/ad-reward-verifier-registry.test.ts && node tools/run-ttsx.mjs packages/game-services/src/oneplay-reward.test.ts && node tools/run-ttsx.mjs packages/game-services/src/oneplay-purchase.test.ts",
|
|
225
|
-
"test:recovery": "cd ../.. && node tools/run-ttsx.mjs packages/game-services/src/monetization-recovery.test.ts && node tools/run-ttsx.mjs packages/game-services/src/app-store-recovery.test.ts",
|
|
236
|
+
"test:unit": "cd ../.. && node tools/run-ttsx.mjs packages/game-services/src/client.test.ts && node tools/run-ttsx.mjs packages/game-services/src/client-progress.test.ts && node tools/run-ttsx.mjs packages/game-services/src/runtime.test.ts && node tools/run-ttsx.mjs packages/game-services/src/types.test.ts && node tools/run-ttsx.mjs packages/game-services/src/server.test.ts && node tools/run-ttsx.mjs packages/game-services/src/google-play-purchase.test.ts && node tools/run-ttsx.mjs packages/game-services/src/google-play-publisher-client.test.ts && node tools/run-ttsx.mjs packages/game-services/src/microsoft-store-purchase.test.ts && node tools/run-ttsx.mjs packages/game-services/src/microsoft-store-identity.test.ts && node tools/run-ttsx.mjs packages/game-services/src/platform-order.test.ts && node tools/run-ttsx.mjs packages/game-services/src/progress-link.test.ts && node tools/run-ttsx.mjs packages/game-services/src/notification-delivery.test.ts && node tools/run-ttsx.mjs packages/game-services/src/admob-ssv.test.ts && node tools/run-ttsx.mjs packages/game-services/src/app-store-verifier.test.ts && node tools/run-ttsx.mjs packages/game-services/src/apps-in-toss-evidence-verification-conformance.test.ts && node tools/run-ttsx.mjs packages/game-services/src/apps-in-toss-partner-api.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard-conformance.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard-durability-conformance.test.ts && node tools/run-ttsx.mjs packages/game-services/src/verified-leaderboard-transport.test.ts && node tools/run-ttsx.mjs packages/game-services/src/guest-session.test.ts && node tools/run-ttsx.mjs packages/game-services/src/client-reward-evidence.test.ts && node tools/run-ttsx.mjs packages/game-services/src/ad-reward-verifier-registry.test.ts && node tools/run-ttsx.mjs packages/game-services/src/oneplay-reward.test.ts && node tools/run-ttsx.mjs packages/game-services/src/oneplay-purchase.test.ts && node tools/run-ttsx.mjs packages/game-services/src/commerce-registry-routing.test.ts && node tools/run-ttsx.mjs packages/game-services/src/commerce-registry-server.test.ts && node tools/run-ttsx.mjs packages/game-services/src/commerce-ledger-revocation.test.ts",
|
|
237
|
+
"test:recovery": "cd ../.. && node tools/run-ttsx.mjs packages/game-services/src/monetization-recovery.test.ts && node tools/run-ttsx.mjs packages/game-services/src/app-store-recovery.test.ts && node tools/run-ttsx.mjs packages/game-services/src/commerce-reconciler.test.ts && node tools/run-ttsx.mjs packages/game-services/src/commerce-reconciler-conformance.test.ts",
|
|
226
238
|
"test": "pnpm test:unit && pnpm test:app-store-server && pnpm test:recovery && pnpm test:packed-transport",
|
|
227
239
|
"test:app-store-server": "vitest run"
|
|
228
240
|
}
|