@mpgd/platform 0.9.0 → 0.11.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/capability-conformance.d.ts +1 -0
- package/dist/capability-conformance.js +20 -6
- package/dist/index.d.ts +42 -0
- package/dist/index.js +43 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PlatformCapabilities, PlatformGateway, PlatformTarget } from './index.js';
|
|
2
2
|
export declare const platformCapabilityKeys: readonly ["nativeIap", "nativeAds", "rewardedAds", "interstitialAds", "nativeLeaderboard", "remoteLeaderboard", "achievements", "cloudSave", "socialShare", "haptics", "localizedContent"];
|
|
3
|
+
export declare const optionalPlatformCapabilityKeys: readonly ["bannerAds"];
|
|
3
4
|
export interface PlatformGatewayCapabilityConformanceTransition {
|
|
4
5
|
readonly update: () => Promise<void> | void;
|
|
5
6
|
readonly expectedCapabilities: PlatformCapabilities;
|
|
@@ -11,6 +11,15 @@ export const platformCapabilityKeys = Object.freeze([
|
|
|
11
11
|
'haptics',
|
|
12
12
|
'localizedContent',
|
|
13
13
|
]);
|
|
14
|
+
export const optionalPlatformCapabilityKeys = Object.freeze([
|
|
15
|
+
'bannerAds',
|
|
16
|
+
]);
|
|
17
|
+
const allowedPlatformCapabilityKeys = Object.freeze([
|
|
18
|
+
...platformCapabilityKeys,
|
|
19
|
+
...optionalPlatformCapabilityKeys,
|
|
20
|
+
]);
|
|
21
|
+
const allowedPlatformCapabilityKeySet = new Set(allowedPlatformCapabilityKeys);
|
|
22
|
+
const optionalPlatformCapabilityKeySet = new Set(optionalPlatformCapabilityKeys);
|
|
14
23
|
/**
|
|
15
24
|
* Runs provider-neutral capability checks against real adapter gateways or
|
|
16
25
|
* target-configured wrappers. Every read must return a complete boolean
|
|
@@ -61,11 +70,15 @@ async function runFixture(fixture) {
|
|
|
61
70
|
}
|
|
62
71
|
function assertCapabilitySnapshot(actual, expected) {
|
|
63
72
|
const actualKeys = Object.keys(actual).sort();
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
const missingKeys = platformCapabilityKeys.filter((key) => !Object.hasOwn(actual, key));
|
|
74
|
+
const unexpectedKeys = actualKeys.filter((key) => !allowedPlatformCapabilityKeySet.has(key));
|
|
75
|
+
assertEqual(JSON.stringify({ missingKeys, unexpectedKeys }), JSON.stringify({ missingKeys: [], unexpectedKeys: [] }), 'capability snapshots must contain all required keys and no unknown keys');
|
|
76
|
+
for (const key of allowedPlatformCapabilityKeys) {
|
|
77
|
+
const optional = optionalPlatformCapabilityKeySet.has(key);
|
|
78
|
+
if (!optional || Object.hasOwn(actual, key)) {
|
|
79
|
+
assertEqual(typeof actual[key], 'boolean', `capability ${key} must be a boolean`);
|
|
80
|
+
}
|
|
81
|
+
assertEqual(optional ? (actual[key] ?? false) : actual[key], optional ? (expected[key] ?? false) : expected[key], `capability ${key} must match the expected provider state`);
|
|
69
82
|
}
|
|
70
83
|
}
|
|
71
84
|
function tryMutateSnapshot(snapshot) {
|
|
@@ -77,7 +90,8 @@ function tryMutateSnapshot(snapshot) {
|
|
|
77
90
|
}
|
|
78
91
|
}
|
|
79
92
|
function hasCapabilityDifference(first, second) {
|
|
80
|
-
return
|
|
93
|
+
return allowedPlatformCapabilityKeys
|
|
94
|
+
.some((key) => (first[key] ?? false) !== (second[key] ?? false));
|
|
81
95
|
}
|
|
82
96
|
function assert(condition, message) {
|
|
83
97
|
if (!condition) {
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,28 @@ export interface PlatformEvidenceEnvelope {
|
|
|
24
24
|
readonly schema: string;
|
|
25
25
|
readonly payload: Readonly<Record<string, string | number | boolean>>;
|
|
26
26
|
}
|
|
27
|
+
export interface PlatformOperationFailure {
|
|
28
|
+
readonly code: string;
|
|
29
|
+
readonly retryable: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Provider-neutral error raised when a platform bridge rejects an operation.
|
|
33
|
+
*
|
|
34
|
+
* Adapters preserve a stable, non-sensitive code and retry hint so game UI can
|
|
35
|
+
* distinguish configuration, environment, and transient failures without
|
|
36
|
+
* importing a provider SDK or parsing localized error messages.
|
|
37
|
+
*/
|
|
38
|
+
export declare class PlatformOperationError extends Error implements PlatformOperationFailure {
|
|
39
|
+
readonly name = "PlatformOperationError";
|
|
40
|
+
readonly code: string;
|
|
41
|
+
readonly retryable: boolean;
|
|
42
|
+
constructor(input?: Readonly<{
|
|
43
|
+
readonly code?: unknown;
|
|
44
|
+
readonly message?: unknown;
|
|
45
|
+
readonly retryable?: unknown;
|
|
46
|
+
}>);
|
|
47
|
+
}
|
|
48
|
+
export declare function readPlatformOperationFailure(error: unknown): PlatformOperationFailure | null;
|
|
27
49
|
export interface PurchaseResult {
|
|
28
50
|
readonly status: 'completed' | 'cancelled' | 'pending' | 'failed';
|
|
29
51
|
readonly transactionId?: string;
|
|
@@ -47,6 +69,16 @@ export interface RewardedAdResult {
|
|
|
47
69
|
export interface InterstitialAdResult {
|
|
48
70
|
readonly status: 'shown' | 'skipped' | 'unavailable';
|
|
49
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Result of mounting a platform-rendered inline banner into a game-owned surface.
|
|
74
|
+
* The platform host owns the native/SDK attachment; games only reserve and name
|
|
75
|
+
* a surface, so this contract does not leak DOM or provider types. Adapters must
|
|
76
|
+
* release any partial attachment before resolving `unavailable` or `failed`;
|
|
77
|
+
* games only need to unmount a successfully mounted banner.
|
|
78
|
+
*/
|
|
79
|
+
export interface BannerAdMountResult {
|
|
80
|
+
readonly status: 'mounted' | 'unavailable' | 'failed';
|
|
81
|
+
}
|
|
50
82
|
export interface CommerceAdapter {
|
|
51
83
|
getProducts(): Promise<readonly ProductInfo[]>;
|
|
52
84
|
purchase(input: {
|
|
@@ -68,6 +100,14 @@ export interface AdAdapter {
|
|
|
68
100
|
showInterstitial?(input: {
|
|
69
101
|
readonly placementId: LogicalAdPlacementId;
|
|
70
102
|
}): Promise<InterstitialAdResult>;
|
|
103
|
+
mountBanner?(input: {
|
|
104
|
+
readonly placementId: LogicalAdPlacementId;
|
|
105
|
+
/** Host-resolvable identifier for an empty, game-owned inline ad surface. */
|
|
106
|
+
readonly surfaceId: string;
|
|
107
|
+
}): Promise<BannerAdMountResult>;
|
|
108
|
+
unmountBanner?(input: {
|
|
109
|
+
readonly surfaceId: string;
|
|
110
|
+
}): Promise<void>;
|
|
71
111
|
}
|
|
72
112
|
export type PromotionRewardAvailability = 'available' | 'configuration-required' | 'unsupported';
|
|
73
113
|
export type PromotionRewardResult = {
|
|
@@ -115,6 +155,8 @@ export interface PlatformCapabilities {
|
|
|
115
155
|
readonly nativeAds: boolean;
|
|
116
156
|
readonly rewardedAds: boolean;
|
|
117
157
|
readonly interstitialAds: boolean;
|
|
158
|
+
/** Optional for compatibility with adapters published before inline ads. */
|
|
159
|
+
readonly bannerAds?: boolean;
|
|
118
160
|
readonly nativeLeaderboard: boolean;
|
|
119
161
|
/** A game-owned server leaderboard is available without a native platform surface. */
|
|
120
162
|
readonly remoteLeaderboard: boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-neutral error raised when a platform bridge rejects an operation.
|
|
3
|
+
*
|
|
4
|
+
* Adapters preserve a stable, non-sensitive code and retry hint so game UI can
|
|
5
|
+
* distinguish configuration, environment, and transient failures without
|
|
6
|
+
* importing a provider SDK or parsing localized error messages.
|
|
7
|
+
*/
|
|
8
|
+
export class PlatformOperationError extends Error {
|
|
9
|
+
name = 'PlatformOperationError';
|
|
10
|
+
code;
|
|
11
|
+
retryable;
|
|
12
|
+
constructor(input) {
|
|
13
|
+
const diagnostics = input ?? {};
|
|
14
|
+
super(typeof diagnostics.message === 'string'
|
|
15
|
+
? diagnostics.message
|
|
16
|
+
: 'The platform operation failed.');
|
|
17
|
+
this.code = normalizePlatformOperationCode(diagnostics.code);
|
|
18
|
+
this.retryable = diagnostics.retryable === true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function readPlatformOperationFailure(error) {
|
|
22
|
+
if (error instanceof PlatformOperationError) {
|
|
23
|
+
return { code: error.code, retryable: error.retryable };
|
|
24
|
+
}
|
|
25
|
+
if (typeof error !== 'object' || error === null || Array.isArray(error)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const record = error;
|
|
29
|
+
return typeof record.code === 'string'
|
|
30
|
+
&& isPlatformOperationCode(record.code)
|
|
31
|
+
&& typeof record.retryable === 'boolean'
|
|
32
|
+
? { code: record.code, retryable: record.retryable }
|
|
33
|
+
: null;
|
|
34
|
+
}
|
|
35
|
+
function normalizePlatformOperationCode(code) {
|
|
36
|
+
return isPlatformOperationCode(code) ? code : 'PLATFORM_OPERATION_FAILED';
|
|
37
|
+
}
|
|
38
|
+
function isPlatformOperationCode(code) {
|
|
39
|
+
return typeof code === 'string'
|
|
40
|
+
&& code.length > 0
|
|
41
|
+
&& code.length <= 128
|
|
42
|
+
&& /^[A-Z][A-Z0-9_:-]*$/u.test(code);
|
|
43
|
+
}
|
|
1
44
|
export function resolveShareCompletion(result) {
|
|
2
45
|
if (result.status !== 'shared') {
|
|
3
46
|
return undefined;
|
package/package.json
CHANGED