@mpgd/target-config 0.10.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.
@@ -1,4 +1,4 @@
1
- import type { AdPlacementEntry, AdPlacements, ProductCatalog, ProductCatalogEntry } from '@mpgd/catalog';
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 { normalizeTargetIntegrationConfig, } from './runtime.js';
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 = normalizeTargetIntegrationConfig({
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 = productPlatformId(product, target);
111
- const reason = effectiveProductReason(target, config.features.iap, product, platformProductId);
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(target, targetEnabled, product, platformProductId) {
122
+ function effectiveProductReason(runtime, targetEnabled, product, platformProductId) {
122
123
  if (!targetEnabled) {
123
124
  return 'target-disabled';
124
125
  }
125
- if (target === 'verse8' && product.grant.type === 'resource') {
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 = adPlacementPlatformId(placement, target);
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 = (() => {
@@ -23,6 +24,7 @@ export const assertEffectiveTargetConfigMatrix = (() => {
23
24
  expected: "string",
24
25
  value: input["version"]
25
26
  }, _errorFactory);
27
+ const _ae0 = "(\"apps-in-toss\" | \"capacitor-android\" | \"capacitor-ios\" | \"devvit-web\" | \"microsoft-store-pwa\" | \"verse8-web\" | \"web\" | \"web-preview\")";
26
28
  const _ap1 = (input, _path, _exceptionable = true) => "boolean" === typeof input["iap"] || _assertGuard_1._assertGuard(_exceptionable, {
27
29
  method: "typia.createAssert",
28
30
  path: _path + ".iap",
@@ -53,7 +55,7 @@ export const assertEffectiveTargetConfigMatrix = (() => {
53
55
  expected: "string",
54
56
  value: input["id"]
55
57
  }, _errorFactory);
56
- const _ae0 = "({ readonly type: \"currency\"; readonly currency: \"coin\" | \"gem\"; readonly amount: number; } | { readonly type: \"entitlement\"; readonly entitlement: string; } | { readonly type: \"resource\"; readonly resource: string & MinLength<1>; readonly amount: number & ExclusiveMinimum<0> & Maximum<1.7976931348623157e+308>; })";
58
+ const _ae1 = "({ readonly type: \"currency\"; readonly currency: \"coin\" | \"gem\"; readonly amount: number; } | { readonly type: \"entitlement\"; readonly entitlement: string; } | { readonly type: \"resource\"; readonly resource: string & MinLength<1>; readonly amount: number & ExclusiveMinimum<0> & Maximum<1.7976931348623157e+308>; })";
57
59
  const _ap6 = (input, _path, _exceptionable = true) => "boolean" === typeof input["enabled"] || _assertGuard_1._assertGuard(_exceptionable, {
58
60
  method: "typia.createAssert",
59
61
  path: _path + ".enabled",
@@ -84,8 +86,8 @@ export const assertEffectiveTargetConfigMatrix = (() => {
84
86
  expected: "number",
85
87
  value: input["amount"]
86
88
  }, _errorFactory);
87
- const _ae1 = "(undefined | { readonly type: \"continue\"; readonly amount: number; } | { readonly type: \"currency\"; readonly amount: number; readonly currency: \"coin\" | \"gem\"; })";
88
- const _ae2 = "({ readonly type: \"continue\"; readonly amount: number; } | { readonly type: \"currency\"; readonly amount: number; readonly currency: \"coin\" | \"gem\"; })";
89
+ const _ae2 = "(undefined | { readonly type: \"continue\"; readonly amount: number; } | { readonly type: \"currency\"; readonly amount: number; readonly currency: \"coin\" | \"gem\"; })";
90
+ const _ae3 = "({ readonly type: \"continue\"; readonly amount: number; } | { readonly type: \"currency\"; readonly amount: number; readonly currency: \"coin\" | \"gem\"; })";
89
91
  const _ao0 = (input, _path, _exceptionable = true) => _ap0(input, _path, true && _exceptionable) && (("object" === typeof input.targets && null !== input.targets && false === Array.isArray(input.targets) || _assertGuard_1._assertGuard(_exceptionable, {
90
92
  method: "typia.createAssert",
91
93
  path: _path + ".targets",
@@ -121,12 +123,12 @@ export const assertEffectiveTargetConfigMatrix = (() => {
121
123
  }, _errorFactory)) && (("object" === typeof input.grant && null !== input.grant || _assertGuard_1._assertGuard(_exceptionable, {
122
124
  method: "typia.createAssert",
123
125
  path: _path + ".grant",
124
- expected: _ae0,
126
+ expected: _ae1,
125
127
  value: input.grant
126
128
  }, _errorFactory)) && _au0(input.grant, _path + ".grant", true && _exceptionable) || _assertGuard_1._assertGuard(_exceptionable, {
127
129
  method: "typia.createAssert",
128
130
  path: _path + ".grant",
129
- expected: _ae0,
131
+ expected: _ae1,
130
132
  value: input.grant
131
133
  }, _errorFactory)) && _ap6(input, _path, true && _exceptionable) && _ap7(input, _path, true && _exceptionable) && (undefined === input.platformProductId || "string" === typeof input.platformProductId || _assertGuard_1._assertGuard(_exceptionable, {
132
134
  method: "typia.createAssert",
@@ -206,12 +208,12 @@ export const assertEffectiveTargetConfigMatrix = (() => {
206
208
  }, _errorFactory)) && (undefined === input.reward || ("object" === typeof input.reward && null !== input.reward || _assertGuard_1._assertGuard(_exceptionable, {
207
209
  method: "typia.createAssert",
208
210
  path: _path + ".reward",
209
- expected: _ae1,
211
+ expected: _ae2,
210
212
  value: input.reward
211
213
  }, _errorFactory)) && _au1(input.reward, _path + ".reward", true && _exceptionable) || _assertGuard_1._assertGuard(_exceptionable, {
212
214
  method: "typia.createAssert",
213
215
  path: _path + ".reward",
214
- expected: _ae1,
216
+ expected: _ae2,
215
217
  value: input.reward
216
218
  }, _errorFactory)) && (("object" === typeof input.frequencyCap && null !== input.frequencyCap || _assertGuard_1._assertGuard(_exceptionable, {
217
219
  method: "typia.createAssert",
@@ -273,10 +275,10 @@ export const assertEffectiveTargetConfigMatrix = (() => {
273
275
  path: _path + ".target",
274
276
  expected: "string",
275
277
  value: input.target
276
- }, _errorFactory)) && ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web-preview" === input.runtime || _assertGuard_1._assertGuard(_exceptionable, {
278
+ }, _errorFactory)) && ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web" === input.runtime || "web-preview" === input.runtime || _assertGuard_1._assertGuard(_exceptionable, {
277
279
  method: "typia.createAssert",
278
280
  path: _path + ".runtime",
279
- expected: "(\"apps-in-toss\" | \"capacitor-android\" | \"capacitor-ios\" | \"devvit-web\" | \"microsoft-store-pwa\" | \"verse8-web\" | \"web-preview\")",
281
+ expected: _ae0,
280
282
  value: input.runtime
281
283
  }, _errorFactory)) && (("object" === typeof input.release && null !== input.release || _assertGuard_1._assertGuard(_exceptionable, {
282
284
  method: "typia.createAssert",
@@ -401,10 +403,10 @@ export const assertEffectiveTargetConfigMatrix = (() => {
401
403
  expected: "(\"en\" | \"ko\")",
402
404
  value: input.fallbackLocale
403
405
  }, _errorFactory));
404
- const _ao3 = (input, _path, _exceptionable = true) => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web-preview" === input.profile || _assertGuard_1._assertGuard(_exceptionable, {
406
+ const _ao3 = (input, _path, _exceptionable = true) => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web" === input.profile || "web-preview" === input.profile || _assertGuard_1._assertGuard(_exceptionable, {
405
407
  method: "typia.createAssert",
406
408
  path: _path + ".profile",
407
- expected: "(\"app-store\" | \"apps-in-toss\" | \"devvit\" | \"google-play\" | \"microsoft-store\" | \"verse8\" | \"web-preview\")",
409
+ expected: "(\"app-store\" | \"apps-in-toss\" | \"devvit\" | \"google-play\" | \"microsoft-store\" | \"verse8\" | \"web\" | \"web-preview\")",
408
410
  value: input.profile
409
411
  }, _errorFactory);
410
412
  const _ao4 = (input, _path, _exceptionable = true) => _ap1(input, _path, true && _exceptionable) && _ap2(input, _path, true && _exceptionable) && _ap3(input, _path, true && _exceptionable) && ("boolean" === typeof input.leaderboard || _assertGuard_1._assertGuard(_exceptionable, {
@@ -534,7 +536,7 @@ export const assertEffectiveTargetConfigMatrix = (() => {
534
536
  return _assertGuard_1._assertGuard(_exceptionable, {
535
537
  method: "typia.createAssert",
536
538
  path: _path,
537
- expected: _ae0,
539
+ expected: _ae1,
538
540
  value: input
539
541
  }, _errorFactory);
540
542
  })();
@@ -547,7 +549,7 @@ export const assertEffectiveTargetConfigMatrix = (() => {
547
549
  return _assertGuard_1._assertGuard(_exceptionable, {
548
550
  method: "typia.createAssert",
549
551
  path: _path,
550
- expected: _ae2,
552
+ expected: _ae3,
551
553
  value: input
552
554
  }, _errorFactory);
553
555
  })();
@@ -568,10 +570,10 @@ export const assertEffectiveTargetConfigMatrix = (() => {
568
570
  const _io17 = input => _ip8(input) && _ip10(input) && _ip9(input);
569
571
  const _io18 = input => "number" === typeof input.cooldownSeconds && (undefined === input.maxPerSession || "number" === typeof input.maxPerSession) && (undefined === input.minStageInterval || "number" === typeof input.minStageInterval);
570
572
  const _io19 = input => "boolean" === typeof input.native && _ip6(input) && ("available" === input.reason || "capability-unsupported" === input.reason || "target-disabled" === input.reason) && (undefined === input.defaultLeaderboardId || "string" === typeof input.defaultLeaderboardId);
571
- const _io2 = input => _ip0(input) && "string" === typeof input.target && ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web-preview" === input.runtime) && ("object" === typeof input.release && null !== input.release && _io3(input.release)) && ("object" === typeof input.features && null !== input.features && _io4(input.features)) && ("object" === typeof input.capabilities && null !== input.capabilities && _io5(input.capabilities)) && ("object" === typeof input.integrations && null !== input.integrations && _io6(input.integrations)) && ("object" === typeof input.policy && null !== input.policy && _io7(input.policy)) && ("object" === typeof input.sources && null !== input.sources && _io8(input.sources)) && ("object" === typeof input.monetization && null !== input.monetization && _io9(input.monetization)) && ("object" === typeof input.ads && null !== input.ads && _io14(input.ads)) && ("object" === typeof input.leaderboard && null !== input.leaderboard && _io19(input.leaderboard)) && ("object" === typeof input.storage && null !== input.storage && _io20(input.storage)) && ("object" === typeof input.localization && null !== input.localization && _io21(input.localization));
573
+ const _io2 = input => _ip0(input) && "string" === typeof input.target && ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web" === input.runtime || "web-preview" === input.runtime) && ("object" === typeof input.release && null !== input.release && _io3(input.release)) && ("object" === typeof input.features && null !== input.features && _io4(input.features)) && ("object" === typeof input.capabilities && null !== input.capabilities && _io5(input.capabilities)) && ("object" === typeof input.integrations && null !== input.integrations && _io6(input.integrations)) && ("object" === typeof input.policy && null !== input.policy && _io7(input.policy)) && ("object" === typeof input.sources && null !== input.sources && _io8(input.sources)) && ("object" === typeof input.monetization && null !== input.monetization && _io9(input.monetization)) && ("object" === typeof input.ads && null !== input.ads && _io14(input.ads)) && ("object" === typeof input.leaderboard && null !== input.leaderboard && _io19(input.leaderboard)) && ("object" === typeof input.storage && null !== input.storage && _io20(input.storage)) && ("object" === typeof input.localization && null !== input.localization && _io21(input.localization));
572
574
  const _io20 = input => ("local" === input.support || "native" === input.support || "none" === input.support) && _ip6(input);
573
575
  const _io21 = input => _ip6(input) && ("en" === input.fallbackLocale || "ko" === input.fallbackLocale);
574
- const _io3 = input => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web-preview" === input.profile;
576
+ const _io3 = input => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web" === input.profile || "web-preview" === input.profile;
575
577
  const _io4 = input => _ip1(input) && _ip2(input) && _ip3(input) && "boolean" === typeof input.leaderboard && _ip4(input);
576
578
  const _io5 = input => ("local" === input.storage || "native" === input.storage || "none" === input.storage) && _ip4(input);
577
579
  const _io6 = input => ("approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && ("approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "unsupported" === input.presentation) && ("approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "unsupported" === input.sharing) && ("approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "unsupported" === input.inboundShare) && ("approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "unsupported" === input.notifications) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
@@ -621,6 +623,7 @@ export const assertTargetConfigMatrix = (() => {
621
623
  const _ip1 = input => "boolean" === typeof input["rewardedAds"];
622
624
  const _ip2 = input => "boolean" === typeof input["interstitialAds"];
623
625
  const _ip3 = input => "boolean" === typeof input["localization"];
626
+ const _ae0 = "(\"apps-in-toss\" | \"capacitor-android\" | \"capacitor-ios\" | \"devvit-web\" | \"microsoft-store-pwa\" | \"verse8-web\" | \"web\" | \"web-preview\")";
624
627
  const _ap0 = (input, _path, _exceptionable = true) => "boolean" === typeof input["iap"] || _assertGuard_1._assertGuard(_exceptionable, {
625
628
  method: "typia.createAssert",
626
629
  path: _path + ".iap",
@@ -708,10 +711,10 @@ export const assertTargetConfigMatrix = (() => {
708
711
  expected: "(\"fullscreen\" | \"inline-expanded\")",
709
712
  value: input.presentationMode
710
713
  }, _errorFactory));
711
- const _ao2 = (input, _path, _exceptionable = true) => ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web-preview" === input.runtime || _assertGuard_1._assertGuard(_exceptionable, {
714
+ const _ao2 = (input, _path, _exceptionable = true) => ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web" === input.runtime || "web-preview" === input.runtime || _assertGuard_1._assertGuard(_exceptionable, {
712
715
  method: "typia.createAssert",
713
716
  path: _path + ".runtime",
714
- expected: "(\"apps-in-toss\" | \"capacitor-android\" | \"capacitor-ios\" | \"devvit-web\" | \"microsoft-store-pwa\" | \"verse8-web\" | \"web-preview\")",
717
+ expected: _ae0,
715
718
  value: input.runtime
716
719
  }, _errorFactory)) && (("object" === typeof input.features && null !== input.features || _assertGuard_1._assertGuard(_exceptionable, {
717
720
  method: "typia.createAssert",
@@ -819,10 +822,10 @@ export const assertTargetConfigMatrix = (() => {
819
822
  expected: "boolean",
820
823
  value: input.native
821
824
  }, _errorFactory);
822
- const _ao8 = (input, _path, _exceptionable = true) => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web-preview" === input.profile || _assertGuard_1._assertGuard(_exceptionable, {
825
+ const _ao8 = (input, _path, _exceptionable = true) => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web" === input.profile || "web-preview" === input.profile || _assertGuard_1._assertGuard(_exceptionable, {
823
826
  method: "typia.createAssert",
824
827
  path: _path + ".profile",
825
- expected: "(\"app-store\" | \"apps-in-toss\" | \"devvit\" | \"google-play\" | \"microsoft-store\" | \"verse8\" | \"web-preview\")",
828
+ expected: "(\"app-store\" | \"apps-in-toss\" | \"devvit\" | \"google-play\" | \"microsoft-store\" | \"verse8\" | \"web\" | \"web-preview\")",
826
829
  value: input.profile
827
830
  }, _errorFactory);
828
831
  const _ao9 = (input, _path, _exceptionable = true) => ("boolean" === typeof input.externalPaymentAllowed || _assertGuard_1._assertGuard(_exceptionable, {
@@ -859,13 +862,13 @@ export const assertTargetConfigMatrix = (() => {
859
862
  return "object" === typeof value && null !== value && _io2(value);
860
863
  });
861
864
  const _io10 = input => ("approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && ("approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "unsupported" === input.presentation) && ("approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "unsupported" === input.sharing) && ("approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "unsupported" === input.inboundShare) && ("approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "unsupported" === input.notifications) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
862
- const _io2 = input => ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web-preview" === input.runtime) && ("object" === typeof input.features && null !== input.features && _io3(input.features)) && ("object" === typeof input.capabilities && null !== input.capabilities && _io4(input.capabilities)) && ("object" === typeof input.localization && null !== input.localization && _io5(input.localization)) && ("object" === typeof input.monetization && null !== input.monetization && _io6(input.monetization)) && ("object" === typeof input.leaderboard && null !== input.leaderboard && _io7(input.leaderboard)) && ("object" === typeof input.release && null !== input.release && _io8(input.release)) && ("object" === typeof input.policy && null !== input.policy && _io9(input.policy)) && (undefined === input.integrations || "object" === typeof input.integrations && null !== input.integrations && _io10(input.integrations));
865
+ const _io2 = input => ("apps-in-toss" === input.runtime || "capacitor-android" === input.runtime || "capacitor-ios" === input.runtime || "devvit-web" === input.runtime || "microsoft-store-pwa" === input.runtime || "verse8-web" === input.runtime || "web" === input.runtime || "web-preview" === input.runtime) && ("object" === typeof input.features && null !== input.features && _io3(input.features)) && ("object" === typeof input.capabilities && null !== input.capabilities && _io4(input.capabilities)) && ("object" === typeof input.localization && null !== input.localization && _io5(input.localization)) && ("object" === typeof input.monetization && null !== input.monetization && _io6(input.monetization)) && ("object" === typeof input.leaderboard && null !== input.leaderboard && _io7(input.leaderboard)) && ("object" === typeof input.release && null !== input.release && _io8(input.release)) && ("object" === typeof input.policy && null !== input.policy && _io9(input.policy)) && (undefined === input.integrations || "object" === typeof input.integrations && null !== input.integrations && _io10(input.integrations));
863
866
  const _io3 = input => _ip0(input) && _ip1(input) && _ip2(input) && "boolean" === typeof input.leaderboard && _ip3(input);
864
867
  const _io4 = input => ("local" === input.storage || "native" === input.storage || "none" === input.storage) && _ip3(input);
865
868
  const _io5 = input => "en" === input.fallbackLocale || "ko" === input.fallbackLocale;
866
869
  const _io6 = input => _ip0(input) && _ip1(input) && _ip2(input);
867
870
  const _io7 = input => "boolean" === typeof input.native;
868
- const _io8 = input => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web-preview" === input.profile;
871
+ const _io8 = input => "app-store" === input.profile || "apps-in-toss" === input.profile || "devvit" === input.profile || "google-play" === input.profile || "microsoft-store" === input.profile || "verse8" === input.profile || "web" === input.profile || "web-preview" === input.profile;
869
872
  const _io9 = input => "boolean" === typeof input.externalPaymentAllowed && "boolean" === typeof input.remoteExecutableCodeAllowed && "boolean" === typeof input.installOtherAppCTAAllowed && "boolean" === typeof input.requiresStoreReview && "boolean" === typeof input.requiresAitReview;
870
873
  const __is = input => "object" === typeof input && null !== input && _io0(input);
871
874
  let _errorFactory;
@@ -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
@@ -4,8 +4,8 @@ import type { EffectiveTargetConfig } from './effective.js';
4
4
  export type PlatformFeature = 'iap' | 'rewardedAds' | 'interstitialAds' | 'leaderboard' | 'localization';
5
5
  export type AdPlacementType = 'rewarded' | 'interstitial';
6
6
  type PlatformConfigTarget = PlatformGateway['target'];
7
- export type TargetRuntimeKind = 'web-preview' | 'microsoft-store-pwa' | 'capacitor-android' | 'capacitor-ios' | 'apps-in-toss' | 'devvit-web' | 'verse8-web';
8
- export type ReleaseProfile = 'web-preview' | 'microsoft-store' | 'google-play' | 'app-store' | 'apps-in-toss' | 'devvit' | 'verse8';
7
+ export type TargetRuntimeKind = 'web' | 'web-preview' | 'microsoft-store-pwa' | 'capacitor-android' | 'capacitor-ios' | 'apps-in-toss' | 'devvit-web' | 'verse8-web';
8
+ export type ReleaseProfile = 'web' | 'web-preview' | 'microsoft-store' | 'google-play' | 'app-store' | 'apps-in-toss' | 'devvit' | 'verse8';
9
9
  export type StorageSupport = 'local' | 'native' | 'none';
10
10
  export type TargetIntegration = 'identityUpgrade' | 'presentation' | 'sharing' | 'inboundShare' | 'notifications';
11
11
  export type IntegrationAvailabilityState = 'available' | 'disabled' | 'approval-required' | 'configuration-required' | 'unsupported';
@@ -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/dist/viewport.js CHANGED
@@ -63,6 +63,7 @@ export function targetViewportShellForRuntime(runtime) {
63
63
  case 'devvit-web':
64
64
  case 'verse8-web':
65
65
  return 'embedded-webview';
66
+ case 'web':
66
67
  case 'web-preview':
67
68
  case 'microsoft-store-pwa':
68
69
  return 'browser';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpgd/target-config",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Target-specific platform feature availability and effective config helpers for mpgd.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -37,7 +37,7 @@
37
37
  ],
38
38
  "dependencies": {
39
39
  "typia": "13.0.2",
40
- "@mpgd/catalog": "0.5.1",
40
+ "@mpgd/catalog": "0.5.2",
41
41
  "@mpgd/i18n": "0.5.4",
42
42
  "@mpgd/platform": "0.8.0"
43
43
  },