@mpgd/target-config 0.10.0 → 0.10.1
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/effective.d.ts +1 -1
- package/dist/effective.js +9 -37
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/releaseIdentity.d.ts +33 -0
- package/dist/releaseIdentity.js +80 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +41 -0
- package/package.json +4 -4
package/dist/effective.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AdPlacementEntry, type AdPlacements, type ProductCatalog, type ProductCatalogEntry } from '@mpgd/catalog';
|
|
2
2
|
import { type FeatureAvailabilityReason, type TargetCapabilityConfig, type TargetConfig, type TargetConfigMatrix, type TargetFeatureConfig, type TargetIntegrationConfig, type TargetLocalizationConfig, type TargetPolicyRestrictions, type TargetReleaseConfig, type TargetRuntimeKind } from './runtime.js';
|
|
3
3
|
export type EffectiveAvailabilityReason = FeatureAvailabilityReason | 'missing-platform-id';
|
|
4
4
|
export interface EffectivePlatformTargetMetadata {
|
package/dist/effective.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveAdPlacementPlatformId, resolveProductPlatformId, } from '@mpgd/catalog';
|
|
2
|
+
import { assertTargetIntegrationRuntimeBounds, } from './runtime.js';
|
|
2
3
|
export const defaultLeaderboardId = 'default';
|
|
3
4
|
const disabledAuthoritativeMonetization = {
|
|
4
5
|
iap: false,
|
|
@@ -10,10 +11,10 @@ export function createEffectiveTargetConfig(input) {
|
|
|
10
11
|
const products = input.catalog.products.map((product) => createEffectiveProductConfig(input.target, config, product));
|
|
11
12
|
const placements = input.adPlacements.placements.map((placement) => createEffectiveAdPlacementConfig(input.target, config, placement));
|
|
12
13
|
const leaderboardEnabled = config.features.leaderboard;
|
|
13
|
-
const integrations =
|
|
14
|
+
const integrations = assertTargetIntegrationRuntimeBounds(config.runtime, {
|
|
14
15
|
...config.integrations,
|
|
15
16
|
...input.platformTarget?.integrations,
|
|
16
|
-
});
|
|
17
|
+
}, `Effective target ${input.target}`);
|
|
17
18
|
return {
|
|
18
19
|
version: effectiveTargetConfigVersion({
|
|
19
20
|
targetConfig: input.targetConfigVersion,
|
|
@@ -107,8 +108,8 @@ export function getEffectiveAdPlacementConfig(config, placementId) {
|
|
|
107
108
|
return config.ads.placements.find((placement) => placement.id === placementId);
|
|
108
109
|
}
|
|
109
110
|
function createEffectiveProductConfig(target, config, product) {
|
|
110
|
-
const platformProductId =
|
|
111
|
-
const reason = effectiveProductReason(
|
|
111
|
+
const platformProductId = resolveProductPlatformId(product, target);
|
|
112
|
+
const reason = effectiveProductReason(config.runtime, config.features.iap, product, platformProductId);
|
|
112
113
|
return {
|
|
113
114
|
id: product.id,
|
|
114
115
|
type: product.type,
|
|
@@ -118,11 +119,11 @@ function createEffectiveProductConfig(target, config, product) {
|
|
|
118
119
|
...(platformProductId === undefined ? {} : { platformProductId }),
|
|
119
120
|
};
|
|
120
121
|
}
|
|
121
|
-
function effectiveProductReason(
|
|
122
|
+
function effectiveProductReason(runtime, targetEnabled, product, platformProductId) {
|
|
122
123
|
if (!targetEnabled) {
|
|
123
124
|
return 'target-disabled';
|
|
124
125
|
}
|
|
125
|
-
if (
|
|
126
|
+
if (runtime === 'verse8-web' && product.grant.type === 'resource') {
|
|
126
127
|
return 'capability-unsupported';
|
|
127
128
|
}
|
|
128
129
|
return effectiveItemReason(targetEnabled, platformProductId);
|
|
@@ -131,7 +132,7 @@ function createEffectiveAdPlacementConfig(target, config, placement) {
|
|
|
131
132
|
const featureEnabled = isRewardedPlacement(placement)
|
|
132
133
|
? config.features.rewardedAds
|
|
133
134
|
: config.features.interstitialAds;
|
|
134
|
-
const platformPlacementId =
|
|
135
|
+
const platformPlacementId = resolveAdPlacementPlatformId(placement, target);
|
|
135
136
|
const reason = effectiveItemReason(featureEnabled, platformPlacementId);
|
|
136
137
|
return {
|
|
137
138
|
id: placement.id,
|
|
@@ -152,35 +153,6 @@ function effectiveItemReason(targetEnabled, platformId) {
|
|
|
152
153
|
function effectiveTargetConfigVersion(input) {
|
|
153
154
|
return `${input.targetConfig}+catalog.${input.productCatalog}+ads.${input.adPlacements}`;
|
|
154
155
|
}
|
|
155
|
-
function productPlatformId(product, target) {
|
|
156
|
-
if (!isProductStoreTarget(target)) {
|
|
157
|
-
return undefined;
|
|
158
|
-
}
|
|
159
|
-
return normalizePlatformId(product.platformProductIds[target]);
|
|
160
|
-
}
|
|
161
|
-
function adPlacementPlatformId(placement, target) {
|
|
162
|
-
if (!isAdStoreTarget(target)) {
|
|
163
|
-
return undefined;
|
|
164
|
-
}
|
|
165
|
-
return normalizePlatformId(placement.platformPlacementIds[target]);
|
|
166
|
-
}
|
|
167
|
-
function normalizePlatformId(platformId) {
|
|
168
|
-
if (platformId === undefined) {
|
|
169
|
-
return undefined;
|
|
170
|
-
}
|
|
171
|
-
const trimmed = platformId.trim();
|
|
172
|
-
return trimmed.length === 0 ? undefined : trimmed;
|
|
173
|
-
}
|
|
174
|
-
function isProductStoreTarget(target) {
|
|
175
|
-
return target === 'android'
|
|
176
|
-
|| target === 'ios'
|
|
177
|
-
|| target === 'ait'
|
|
178
|
-
|| target === 'reddit'
|
|
179
|
-
|| target === 'verse8';
|
|
180
|
-
}
|
|
181
|
-
function isAdStoreTarget(target) {
|
|
182
|
-
return target === 'android' || target === 'ios' || target === 'ait' || target === 'verse8';
|
|
183
|
-
}
|
|
184
156
|
function isRewardedPlacement(placement) {
|
|
185
157
|
return placement.type === 'rewarded';
|
|
186
158
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EffectiveTargetConfigMatrix } from './effective.js';
|
|
2
2
|
import type { TargetConfigMatrix } from './runtime.js';
|
|
3
3
|
export * from './effective.js';
|
|
4
|
+
export * from './releaseIdentity.js';
|
|
4
5
|
export * from './runtime.js';
|
|
5
6
|
export * from './viewport.js';
|
|
6
7
|
export declare const assertEffectiveTargetConfigMatrix: (input: unknown) => EffectiveTargetConfigMatrix;
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as _accessExpressionAsString_1 from "typia/lib/internal/_accessExpressi
|
|
|
3
3
|
const __typia_transform__accessExpressionAsString = _accessExpressionAsString_1._accessExpressionAsString;
|
|
4
4
|
import typia from 'typia';
|
|
5
5
|
export * from './effective.js';
|
|
6
|
+
export * from './releaseIdentity.js';
|
|
6
7
|
export * from './runtime.js';
|
|
7
8
|
export * from './viewport.js';
|
|
8
9
|
export const assertEffectiveTargetConfigMatrix = (() => {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A human-facing release identity shared by every target artifact for one game release.
|
|
3
|
+
*
|
|
4
|
+
* `gameVersion` remains the game's SemVer value. `releaseRevision` is deliberately
|
|
5
|
+
* separate so a game can keep one semantic release while targets are promoted or
|
|
6
|
+
* rebuilt independently. For example, the common label for game `0.3.30` and
|
|
7
|
+
* revision `42` is `0.3.30-v42`.
|
|
8
|
+
*/
|
|
9
|
+
export interface MpgdReleaseIdentity {
|
|
10
|
+
readonly gameVersion: string;
|
|
11
|
+
readonly releaseRevision?: number;
|
|
12
|
+
readonly label: string;
|
|
13
|
+
}
|
|
14
|
+
export interface CreateMpgdReleaseIdentityInput {
|
|
15
|
+
readonly gameVersion: string;
|
|
16
|
+
readonly releaseRevision?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Optional value from a build environment. It must equal the derived label so
|
|
19
|
+
* a stale or hand-edited label cannot be embedded into an artifact.
|
|
20
|
+
*/
|
|
21
|
+
readonly expectedLabel?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function createMpgdReleaseIdentity(input: CreateMpgdReleaseIdentityInput): MpgdReleaseIdentity;
|
|
24
|
+
export declare function formatMpgdReleaseLabel(gameVersion: string, releaseRevision: number | undefined): string;
|
|
25
|
+
/** Whether a normalized game version is eligible for an immutable production release. */
|
|
26
|
+
export declare function isMpgdFinalSemVer(value: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Canonical release-manifest identifier derived from a common release label.
|
|
29
|
+
* Both components must be non-empty canonical tokens without the `+` delimiter.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatMpgdReleaseId(label: string, buildId: string): string;
|
|
32
|
+
/** Parse an optional release revision without making empty values meaningful. */
|
|
33
|
+
export declare function parseMpgdReleaseRevision(value: string | undefined): number | undefined;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const semVerCore = '(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)';
|
|
2
|
+
const preReleaseNumericIdentifier = '(?:0|[1-9]\\d*)';
|
|
3
|
+
const preReleaseAlphanumericIdentifier = '(?:\\d*[A-Za-z-][0-9A-Za-z-]*)';
|
|
4
|
+
const preReleaseIdentifier = `(?:${preReleaseNumericIdentifier}|${preReleaseAlphanumericIdentifier})`;
|
|
5
|
+
const finalSemVerPattern = new RegExp(`^${semVerCore}$`, 'u');
|
|
6
|
+
const semVerPattern = new RegExp(`^${semVerCore}(?:-${preReleaseIdentifier}(?:\\.${preReleaseIdentifier})*)?$`, 'u');
|
|
7
|
+
export function createMpgdReleaseIdentity(input) {
|
|
8
|
+
const gameVersion = normalizeMpgdSemVer(input.gameVersion);
|
|
9
|
+
const releaseRevision = input.releaseRevision;
|
|
10
|
+
const label = formatNormalizedMpgdReleaseLabel(gameVersion, releaseRevision);
|
|
11
|
+
const expectedLabel = input.expectedLabel?.trim();
|
|
12
|
+
if (expectedLabel !== undefined && expectedLabel !== label) {
|
|
13
|
+
const detail = `${label}; received ${expectedLabel}.`;
|
|
14
|
+
throw new TypeError(`Release identity label must equal ${detail}`);
|
|
15
|
+
}
|
|
16
|
+
return releaseRevision === undefined
|
|
17
|
+
? { gameVersion, label }
|
|
18
|
+
: { gameVersion, releaseRevision, label };
|
|
19
|
+
}
|
|
20
|
+
export function formatMpgdReleaseLabel(gameVersion, releaseRevision) {
|
|
21
|
+
return formatNormalizedMpgdReleaseLabel(normalizeMpgdSemVer(gameVersion), releaseRevision);
|
|
22
|
+
}
|
|
23
|
+
function formatNormalizedMpgdReleaseLabel(gameVersion, releaseRevision) {
|
|
24
|
+
if (releaseRevision === undefined) {
|
|
25
|
+
return gameVersion;
|
|
26
|
+
}
|
|
27
|
+
if (!isMpgdFinalSemVer(gameVersion)) {
|
|
28
|
+
throw new TypeError('Release identity gameVersion must be a final SemVer when releaseRevision is set.');
|
|
29
|
+
}
|
|
30
|
+
if (!Number.isSafeInteger(releaseRevision) || releaseRevision < 1) {
|
|
31
|
+
throw new TypeError('Release identity releaseRevision must be a positive safe integer.');
|
|
32
|
+
}
|
|
33
|
+
return `${gameVersion}-v${releaseRevision}`;
|
|
34
|
+
}
|
|
35
|
+
/** Whether a normalized game version is eligible for an immutable production release. */
|
|
36
|
+
export function isMpgdFinalSemVer(value) {
|
|
37
|
+
return finalSemVerPattern.test(value);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Canonical release-manifest identifier derived from a common release label.
|
|
41
|
+
* Both components must be non-empty canonical tokens without the `+` delimiter.
|
|
42
|
+
*/
|
|
43
|
+
export function formatMpgdReleaseId(label, buildId) {
|
|
44
|
+
assertReleaseIdComponent(label, 'label');
|
|
45
|
+
assertReleaseIdComponent(buildId, 'buildId');
|
|
46
|
+
return `mpgd-${label}+${buildId}`;
|
|
47
|
+
}
|
|
48
|
+
/** Parse an optional release revision without making empty values meaningful. */
|
|
49
|
+
export function parseMpgdReleaseRevision(value) {
|
|
50
|
+
if (value === undefined || value.trim().length === 0) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const normalized = value.trim();
|
|
54
|
+
if (!/^[1-9]\d*$/u.test(normalized)) {
|
|
55
|
+
throw new TypeError('Release revision must be a positive safe integer.');
|
|
56
|
+
}
|
|
57
|
+
const releaseRevision = Number.parseInt(normalized, 10);
|
|
58
|
+
if (!Number.isSafeInteger(releaseRevision)) {
|
|
59
|
+
throw new TypeError('Release revision must be a positive safe integer.');
|
|
60
|
+
}
|
|
61
|
+
return releaseRevision;
|
|
62
|
+
}
|
|
63
|
+
function normalizeMpgdSemVer(value) {
|
|
64
|
+
const normalized = value.trim();
|
|
65
|
+
if (normalized.includes('+')) {
|
|
66
|
+
throw new TypeError('Release identity gameVersion must not contain SemVer build metadata because "+" is reserved for release IDs.');
|
|
67
|
+
}
|
|
68
|
+
if (!semVerPattern.test(normalized)) {
|
|
69
|
+
throw new TypeError('Release identity gameVersion must be a SemVer value.');
|
|
70
|
+
}
|
|
71
|
+
return normalized;
|
|
72
|
+
}
|
|
73
|
+
function assertReleaseIdComponent(value, label) {
|
|
74
|
+
if (value.length === 0 || /\s/u.test(value)) {
|
|
75
|
+
throw new TypeError(`Release identifier ${label} must be a non-empty canonical token.`);
|
|
76
|
+
}
|
|
77
|
+
if (value.includes('+')) {
|
|
78
|
+
throw new TypeError(`Release identifier ${label} must not contain "+".`);
|
|
79
|
+
}
|
|
80
|
+
}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -128,6 +128,7 @@ export declare const defaultTargetIntegrationConfig: {
|
|
|
128
128
|
readonly presentationMode: 'fullscreen';
|
|
129
129
|
};
|
|
130
130
|
export declare function normalizeTargetIntegrationConfig(config: Partial<TargetIntegrationConfig> | undefined): TargetIntegrationConfig;
|
|
131
|
+
export declare function assertTargetIntegrationRuntimeBounds(runtime: TargetRuntimeKind, config: Partial<TargetIntegrationConfig> | undefined, label: string): TargetIntegrationConfig;
|
|
131
132
|
export declare function targetConfigKeyForPlatform(target: PlatformConfigTarget): string;
|
|
132
133
|
export declare function getTargetConfig(matrix: TargetConfigMatrix, target: PlatformConfigTarget | string): TargetConfig;
|
|
133
134
|
export declare function isPlatformFeatureEnabled(config: TargetConfig, feature: PlatformFeature): boolean;
|
package/dist/runtime.js
CHANGED
|
@@ -12,6 +12,22 @@ export const targetIntegrations = [
|
|
|
12
12
|
'inboundShare',
|
|
13
13
|
'notifications',
|
|
14
14
|
];
|
|
15
|
+
const integrationUpperBoundsByRuntime = {
|
|
16
|
+
'verse8-web': {
|
|
17
|
+
identityUpgrade: 'unsupported',
|
|
18
|
+
presentation: 'available',
|
|
19
|
+
sharing: 'unsupported',
|
|
20
|
+
inboundShare: 'unsupported',
|
|
21
|
+
notifications: 'unsupported',
|
|
22
|
+
},
|
|
23
|
+
'web-preview': {
|
|
24
|
+
identityUpgrade: 'disabled',
|
|
25
|
+
presentation: 'available',
|
|
26
|
+
sharing: 'available',
|
|
27
|
+
inboundShare: 'available',
|
|
28
|
+
notifications: 'unsupported',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
15
31
|
const integrationAvailabilityStateValues = [
|
|
16
32
|
'available',
|
|
17
33
|
'disabled',
|
|
@@ -48,6 +64,31 @@ export function normalizeTargetIntegrationConfig(config) {
|
|
|
48
64
|
presentationMode: normalizePresentationMode(config.presentationMode),
|
|
49
65
|
};
|
|
50
66
|
}
|
|
67
|
+
export function assertTargetIntegrationRuntimeBounds(runtime, config, label) {
|
|
68
|
+
const integrations = normalizeTargetIntegrationConfig(config);
|
|
69
|
+
if (runtime !== 'verse8-web' && runtime !== 'web-preview') {
|
|
70
|
+
return integrations;
|
|
71
|
+
}
|
|
72
|
+
const upperBounds = integrationUpperBoundsByRuntime[runtime];
|
|
73
|
+
for (const integration of targetIntegrations) {
|
|
74
|
+
const state = integrations[integration];
|
|
75
|
+
const upperBound = upperBounds[integration];
|
|
76
|
+
if (!isIntegrationStateWithinUpperBound(state, upperBound)) {
|
|
77
|
+
throw new Error(`${label} cannot configure ${integration} as ${state} for ${runtime} runtime; maximum supported state is ${upperBound}.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return integrations;
|
|
81
|
+
}
|
|
82
|
+
function isIntegrationStateWithinUpperBound(state, upperBound) {
|
|
83
|
+
switch (upperBound) {
|
|
84
|
+
case 'available':
|
|
85
|
+
return true;
|
|
86
|
+
case 'disabled':
|
|
87
|
+
return state === 'disabled' || state === 'unsupported';
|
|
88
|
+
case 'unsupported':
|
|
89
|
+
return state === 'unsupported';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
51
92
|
export function targetConfigKeyForPlatform(target) {
|
|
52
93
|
return target === 'browser' ? 'web-preview' : target;
|
|
53
94
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/target-config",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Target-specific platform feature availability and effective config helpers for mpgd.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"typia": "13.0.2",
|
|
40
|
-
"@mpgd/catalog": "0.5.
|
|
41
|
-
"@mpgd/
|
|
42
|
-
"@mpgd/
|
|
40
|
+
"@mpgd/catalog": "0.5.2",
|
|
41
|
+
"@mpgd/platform": "0.8.0",
|
|
42
|
+
"@mpgd/i18n": "0.5.4"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"ttsc": "0.18.4",
|