@mpgd/game-services 0.11.1 → 0.12.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/dist/apps-in-toss-partner-api.d.ts +49 -0
- package/dist/apps-in-toss-partner-api.js +190 -8
- package/dist/client.js +39 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/microsoft-store-purchase.d.ts +131 -0
- package/dist/microsoft-store-purchase.js +835 -0
- package/dist/notification-delivery.js +1 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +9 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +37 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.js +7 -3
- package/package.json +9 -5
package/dist/runtime.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface CreateGameServicesRuntimeInput {
|
|
|
20
20
|
readonly deploymentTarget?: string;
|
|
21
21
|
readonly baseUrl?: string;
|
|
22
22
|
readonly transport?: 'http' | 'orpc';
|
|
23
|
+
/** Static headers sent with every authoritative game-services request. */
|
|
24
|
+
readonly headers?: Record<string, string>;
|
|
23
25
|
readonly allowLocalBackend?: boolean;
|
|
24
26
|
readonly localBackend?: GameServicesBackendApi;
|
|
25
27
|
readonly analytics?: AnalyticsSink;
|
package/dist/runtime.js
CHANGED
|
@@ -19,9 +19,15 @@ export function createGameServicesRuntime(input) {
|
|
|
19
19
|
}
|
|
20
20
|
mode = input.transport === 'orpc' ? 'orpc' : 'http';
|
|
21
21
|
backend = mode === 'orpc'
|
|
22
|
-
? createGameServicesOrpcBackendApi(createGameServicesOrpcClient({
|
|
22
|
+
? createGameServicesOrpcBackendApi(createGameServicesOrpcClient({
|
|
23
|
+
url: baseUrl,
|
|
24
|
+
...(input.headers === undefined ? {} : { headers: input.headers }),
|
|
25
|
+
}))
|
|
23
26
|
: createGameServicesHttpBackendApi({
|
|
24
|
-
transport: createGameServicesFetchBackendTransport({
|
|
27
|
+
transport: createGameServicesFetchBackendTransport({
|
|
28
|
+
baseUrl,
|
|
29
|
+
...(input.headers === undefined ? {} : { headers: input.headers }),
|
|
30
|
+
}),
|
|
25
31
|
});
|
|
26
32
|
}
|
|
27
33
|
else {
|
|
@@ -59,6 +65,7 @@ export function createGameServicesRuntime(input) {
|
|
|
59
65
|
}
|
|
60
66
|
export function resolveGameServicesLedgerTarget(target) {
|
|
61
67
|
if (target === 'browser'
|
|
68
|
+
|| target === 'microsoft-store'
|
|
62
69
|
|| target === 'android'
|
|
63
70
|
|| target === 'ios'
|
|
64
71
|
|| target === 'ait'
|
package/dist/server.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type AdPlacements, type ProductCatalog } from '@mpgd/catalog';
|
|
|
3
3
|
import { type GameServicesBackendApi, type GameServicesBackendTransport, type GameServicesBackendTransportRequest, type GameServicesBackendTransportResponse } from './client';
|
|
4
4
|
import { type GameServicesHealthResponse } from './contract';
|
|
5
5
|
import { type GameServicesEvidenceVerifier, type GameServicesPurchaseGrantFinalizer } from './evidence-verification';
|
|
6
|
-
import { type ClaimAdRewardRequest, type ClaimAdRewardResponse, type EntitlementLedgerGrant, type EntitlementLedgerResult, type GameServicesAdRewardTarget, type LeaderboardScoreTransaction, type ProductGrantTransaction, type RecordLeaderboardScoreRequest, type RecordLeaderboardScoreResponse, type VerifyPurchaseRequest, type VerifyPurchaseResponse } from './types';
|
|
6
|
+
import { type ClaimAdRewardRequest, type ClaimAdRewardResponse, type EntitlementLedgerGrant, type EntitlementLedgerResult, type GameServicesAdRewardTarget, type GameServicesStoreTarget, type LeaderboardScoreTransaction, type ProductGrantTransaction, type RecordLeaderboardScoreRequest, type RecordLeaderboardScoreResponse, type VerifyPurchaseRequest, type VerifyPurchaseResponse } from './types';
|
|
7
7
|
type CorsHeaders = Record<string, string>;
|
|
8
8
|
export interface CreateGameServicesBackendInput {
|
|
9
9
|
readonly catalog: ProductCatalog;
|
|
@@ -20,7 +20,7 @@ export interface CreateGameServicesBackendInput {
|
|
|
20
20
|
readonly purchaseGrantFinalizationTimeoutMs?: number;
|
|
21
21
|
readonly purchaseGrantFinalizer?: GameServicesPurchaseGrantFinalizer;
|
|
22
22
|
}
|
|
23
|
-
export type GameServicesDeploymentTargetBindings = Readonly<Partial<Record<GameServicesAdRewardTarget, string>>>;
|
|
23
|
+
export type GameServicesDeploymentTargetBindings = Readonly<Partial<Record<GameServicesAdRewardTarget | GameServicesStoreTarget, string>>>;
|
|
24
24
|
export interface GameServicesBackendApiHandler {
|
|
25
25
|
readonly version?: string;
|
|
26
26
|
handle(request: GameServicesBackendTransportRequest): Promise<GameServicesBackendTransportResponse>;
|
package/dist/server.js
CHANGED
|
@@ -318,6 +318,7 @@ export function createGameServicesHttpFetchHandler(handler, options = {}) {
|
|
|
318
318
|
};
|
|
319
319
|
}
|
|
320
320
|
const gameServicesDeploymentTargetPlatforms = new Set([
|
|
321
|
+
'microsoft-store',
|
|
321
322
|
'android',
|
|
322
323
|
'ios',
|
|
323
324
|
'ait',
|
|
@@ -445,6 +446,30 @@ async function verifyPurchaseWithStore(input, context) {
|
|
|
445
446
|
},
|
|
446
447
|
});
|
|
447
448
|
if (grant.status === 'evidence_already_processed') {
|
|
449
|
+
const existingEvidence = await findEntitlementTransactionByEvidenceVerificationId(context.store, { source: 'purchase', evidenceVerificationId: verification.verificationId });
|
|
450
|
+
if (existingEvidence !== undefined
|
|
451
|
+
&& matchesPurchaseEvidenceRecovery(existingEvidence, {
|
|
452
|
+
playerId: request.playerId,
|
|
453
|
+
grantId: request.productId,
|
|
454
|
+
target: request.target,
|
|
455
|
+
...(request.deploymentTarget === undefined
|
|
456
|
+
? {}
|
|
457
|
+
: { deploymentTarget: request.deploymentTarget }),
|
|
458
|
+
evidenceVerificationId: verification.verificationId,
|
|
459
|
+
})) {
|
|
460
|
+
const finalization = await finalizeExistingPurchaseGrant(request, existingEvidence, context);
|
|
461
|
+
// A different idempotency key is evidence replay unless a configured finalizer can resume
|
|
462
|
+
// the provider operation. Keep generic stores fail-closed while allowing Store consume
|
|
463
|
+
// recovery to report the already-recorded grant.
|
|
464
|
+
if (finalization !== undefined) {
|
|
465
|
+
return assertVerifyPurchaseResponse({
|
|
466
|
+
verified: true,
|
|
467
|
+
ledgerEntryId: existingEvidence.ledgerEntryId,
|
|
468
|
+
alreadyProcessed: true,
|
|
469
|
+
finalization,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
448
473
|
return assertVerifyPurchaseResponse({
|
|
449
474
|
verified: false,
|
|
450
475
|
alreadyProcessed: false,
|
|
@@ -947,9 +972,20 @@ async function recordedEntitlementMatchesRetry(store, result, identity) {
|
|
|
947
972
|
return transaction !== undefined && matchesEntitlementRetry(transaction, identity);
|
|
948
973
|
}
|
|
949
974
|
function matchesEntitlementRetry(transaction, identity) {
|
|
975
|
+
return matchesEntitlementTransactionIdentity(transaction, identity)
|
|
976
|
+
&& transaction.idempotencyKey === identity.idempotencyKey;
|
|
977
|
+
}
|
|
978
|
+
function matchesPurchaseEvidenceRecovery(transaction, identity) {
|
|
979
|
+
return matchesEntitlementTransactionIdentity(transaction, {
|
|
980
|
+
...identity,
|
|
981
|
+
source: 'purchase',
|
|
982
|
+
})
|
|
983
|
+
&& (transaction.evidenceVerificationId
|
|
984
|
+
?? transaction.payload.evidenceVerificationId) === identity.evidenceVerificationId;
|
|
985
|
+
}
|
|
986
|
+
function matchesEntitlementTransactionIdentity(transaction, identity) {
|
|
950
987
|
return transaction.source === identity.source
|
|
951
988
|
&& transaction.playerId === identity.playerId
|
|
952
|
-
&& transaction.idempotencyKey === identity.idempotencyKey
|
|
953
989
|
&& transaction.grantId === identity.grantId
|
|
954
990
|
&& transaction.payload.target === identity.target
|
|
955
991
|
&& transaction.payload.deploymentTarget === identity.deploymentTarget;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ProductGrant } from '@mpgd/catalog';
|
|
2
2
|
import type { LeaderboardScoreInput, LogicalAdPlacementId, LogicalProductId, PlatformEvidenceEnvelope, PlatformTarget } from '@mpgd/platform';
|
|
3
3
|
export type { PlatformEvidenceEnvelope } from '@mpgd/platform';
|
|
4
|
-
export type GameServicesStoreTarget = Extract<PlatformTarget, 'android' | 'ios' | 'ait'>;
|
|
4
|
+
export type GameServicesStoreTarget = Extract<PlatformTarget, 'microsoft-store' | 'android' | 'ios' | 'ait'>;
|
|
5
5
|
export type GameServicesAdRewardTarget = Extract<PlatformTarget, 'android' | 'ios' | 'ait' | 'verse8'>;
|
|
6
|
-
export type GameServicesLeaderboardTarget = Extract<PlatformTarget, 'browser' | 'android' | 'ios' | 'ait' | 'reddit'>;
|
|
7
|
-
export type GameServicesLedgerTarget = Extract<PlatformTarget, 'browser' | 'android' | 'ios' | 'ait' | 'reddit' | 'verse8'>;
|
|
6
|
+
export type GameServicesLeaderboardTarget = Extract<PlatformTarget, 'browser' | 'microsoft-store' | 'android' | 'ios' | 'ait' | 'reddit'>;
|
|
7
|
+
export type GameServicesLedgerTarget = Extract<PlatformTarget, 'browser' | 'microsoft-store' | 'android' | 'ios' | 'ait' | 'reddit' | 'verse8'>;
|
|
8
8
|
export type PurchaseIdempotencyKey = string;
|
|
9
9
|
export type AdRewardIdempotencyKey = string;
|
|
10
10
|
export type EntitlementIdempotencyKey = PurchaseIdempotencyKey | AdRewardIdempotencyKey;
|
package/dist/types.js
CHANGED
|
@@ -128,8 +128,11 @@ function assertRecord(input, label) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
function assertStoreTarget(input) {
|
|
131
|
-
if (input !== '
|
|
132
|
-
|
|
131
|
+
if (input !== 'microsoft-store'
|
|
132
|
+
&& input !== 'android'
|
|
133
|
+
&& input !== 'ios'
|
|
134
|
+
&& input !== 'ait') {
|
|
135
|
+
throw new Error('target must be microsoft-store, android, ios, or ait.');
|
|
133
136
|
}
|
|
134
137
|
}
|
|
135
138
|
function assertAdRewardTarget(input) {
|
|
@@ -167,11 +170,12 @@ const reservedDeploymentTargetNames = new Set([
|
|
|
167
170
|
]);
|
|
168
171
|
function assertLeaderboardTarget(input) {
|
|
169
172
|
if (input !== 'browser'
|
|
173
|
+
&& input !== 'microsoft-store'
|
|
170
174
|
&& input !== 'android'
|
|
171
175
|
&& input !== 'ios'
|
|
172
176
|
&& input !== 'ait'
|
|
173
177
|
&& input !== 'reddit') {
|
|
174
|
-
throw new Error('target must be browser, android, ios, ait, or reddit.');
|
|
178
|
+
throw new Error('target must be browser, microsoft-store, android, ios, ait, or reddit.');
|
|
175
179
|
}
|
|
176
180
|
}
|
|
177
181
|
function assertNonEmptyString(input, label) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/game-services",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Client, contract, server, store, and test helpers for authoritative mpgd game services.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -73,6 +73,10 @@
|
|
|
73
73
|
"types": "./dist/google-play-purchase.d.ts",
|
|
74
74
|
"default": "./dist/google-play-purchase.js"
|
|
75
75
|
},
|
|
76
|
+
"./microsoft-store-purchase": {
|
|
77
|
+
"types": "./dist/microsoft-store-purchase.d.ts",
|
|
78
|
+
"default": "./dist/microsoft-store-purchase.js"
|
|
79
|
+
},
|
|
76
80
|
"./google-play-purchase-conformance": {
|
|
77
81
|
"types": "./dist/google-play-purchase-conformance.d.ts",
|
|
78
82
|
"default": "./dist/google-play-purchase-conformance.js"
|
|
@@ -126,9 +130,9 @@
|
|
|
126
130
|
"@orpc/client": "2.0.0-beta.14",
|
|
127
131
|
"@orpc/contract": "2.0.0-beta.14",
|
|
128
132
|
"@orpc/server": "2.0.0-beta.14",
|
|
129
|
-
"@mpgd/
|
|
130
|
-
"@mpgd/
|
|
131
|
-
"@mpgd/
|
|
133
|
+
"@mpgd/catalog": "0.6.0",
|
|
134
|
+
"@mpgd/platform": "0.9.0",
|
|
135
|
+
"@mpgd/analytics": "0.3.9"
|
|
132
136
|
},
|
|
133
137
|
"devDependencies": {
|
|
134
138
|
"ttsc": "0.18.4",
|
|
@@ -144,6 +148,6 @@
|
|
|
144
148
|
"lint": "ttsc --noEmit",
|
|
145
149
|
"format": "ttsc format",
|
|
146
150
|
"fix": "ttsc fix",
|
|
147
|
-
"test": "cd ../.. && node tools/run-ttsx.mjs packages/game-services/src/client.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/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"
|
|
151
|
+
"test": "cd ../.. && node tools/run-ttsx.mjs packages/game-services/src/client.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/microsoft-store-purchase.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"
|
|
148
152
|
}
|
|
149
153
|
}
|