@mpgd/cli 0.46.1 → 0.48.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/capacitor-shell-starter.d.ts +57 -1
- package/dist/capacitor-shell-starter.js +311 -34
- package/dist/command-launcher.d.ts +13 -0
- package/dist/command-launcher.js +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +149 -12
- package/dist/microsoft-store-submission.js +11 -6
- package/dist/native-build-info.json +2 -2
- package/dist/native-build-target.js +2413 -345
- package/dist/windows-host/Core/BridgeCommand.cs +17 -0
- package/dist/windows-host/Core/Mpgd.MicrosoftStore.Host.csproj +9 -0
- package/dist/windows-host/Core/NativeBridgeContracts.cs +33 -0
- package/dist/windows-host/Core/NativeBridgeHost.cs +162 -0
- package/dist/windows-host/Core/NativeBridgeOrigin.cs +19 -0
- package/dist/windows-host/Core/NativeBridgeProtocol.cs +335 -0
- package/dist/windows-host/Core/NativeBridgeRequestGate.cs +76 -0
- package/dist/windows-host/Core/NativeBridgeResult.cs +65 -0
- package/dist/windows-host/README.md +118 -0
- package/dist/windows-host/WinUI/DispatcherQueueBridgeDispatcher.cs +39 -0
- package/dist/windows-host/WinUI/WebView2DocumentTransport.cs +46 -0
- package/dist/windows-host/WinUI/WebView2NativeBridge.cs +185 -0
- package/dist/windows-host/WinUI/WindowStoreContext.cs +20 -0
- package/dist/windows-native-tools.d.ts +4 -0
- package/dist/windows-native-tools.js +21 -0
- package/native-tools/windows-msix/WindowsMsixAcceptance.psm1 +333 -0
- package/package.json +24 -14
- package/templates/lite-overlay/.agents/skills/use-mpgd-kit/SKILL.md +22 -0
- package/templates/lite-overlay/AGENTS.md +27 -0
- package/templates/lite-overlay/README.md +37 -0
- package/templates/lite-overlay/agent/acceptance.md +27 -0
- package/templates/lite-overlay/agent/brief.md +17 -0
- package/templates/lite-overlay/apps/target-devvit/README.md +134 -0
- package/templates/lite-overlay/docs/MPGD_KIT_WORKFLOWS.md +37 -0
- package/templates/lite-overlay/src/lite/tapGame.ts +77 -0
- package/templates/lite-overlay/src/platform/devvitEntrypoint.ts +116 -0
- package/templates/lite-overlay/src/platform/devvitInlineMode.css +146 -0
- package/templates/lite-overlay/src/runtime/createGame.ts +57 -0
- package/templates/phaser-game/README.md +5 -3
- package/templates/phaser-game/apps/target-ait/package.json +2 -2
- package/templates/phaser-game/apps/target-ait/src/main.ts +17 -0
- package/templates/phaser-game/apps/target-ait/src/runtime-config.types.ts +2 -0
- package/templates/phaser-game/apps/target-ait/vite.config.ts +27 -0
- package/templates/phaser-game/apps/target-devvit/package.json +2 -1
- package/templates/phaser-game/apps/target-devvit/src/server/bridge.ts +137 -18
- package/templates/phaser-game/apps/target-devvit/src/server/index.ts +35 -1
- package/templates/phaser-game/package.json +3 -1
- package/templates/phaser-game/pnpm-workspace.yaml +2 -0
- package/templates/phaser-game/src/env.d.ts +2 -0
- package/templates/phaser-game/src/main.ts +8 -1
- package/templates/phaser-game/src/platform/buildGateways/ait.ts +9 -0
- package/templates/phaser-game/src/platform/buildGateways/aitSandbox.ts +13 -1
- package/templates/phaser-game/src/platform/buildGateways/capacitorAndroid.ts +51 -2
- package/templates/phaser-game/src/platform/buildGateways/capacitorIos.ts +51 -2
- package/templates/phaser-game/src/platform/buildGateways/microsoftStore.ts +59 -26
- package/templates/phaser-game/src/platform/buildGateways/reddit.ts +36 -1
- package/templates/phaser-game/src/platform/buildGateways/verse8.ts +39 -2
- package/templates/phaser-game/src/platform/commerceAccountBinding.ts +79 -0
- package/templates/phaser-game/src/platform/commerceProducts.ts +69 -0
- package/templates/phaser-game/src/platform/gameServices.ts +22 -2
- package/templates/phaser-game/src/platform/monetizationJournal.ts +286 -0
- package/templates/phaser-game/src/platform/verse8Agent8Client.ts +22 -0
- package/templates/phaser-game/vite.shared.ts +40 -1
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import i18n, { defineI18n } from '@gunshi/plugin-i18n';
|
|
|
7
7
|
import resources from '@gunshi/resources';
|
|
8
8
|
import { cli } from 'gunshi';
|
|
9
9
|
import { assertPlatformVersionLedger } from '@mpgd/target-config';
|
|
10
|
+
import { resolveNativeCommandLaunch } from './command-launcher.js';
|
|
10
11
|
import { buildAssetPacks } from './asset-pack-build.js';
|
|
11
12
|
import { verifyAssetPackDelivery } from './asset-pack-verify.js';
|
|
12
13
|
import { buildAssetPackTarget } from './asset-pack-target.js';
|
|
@@ -47,6 +48,7 @@ export { cloudflarePagesDeploymentProfiles, hostedPwaDeploymentHosts, isSupporte
|
|
|
47
48
|
export { defaultOfflinePlaytestArtifactDir, defaultOfflinePlaytestMaximumBytes, defaultOfflinePlaytestOutputDir, offlinePlaytestSchemaVersion, runOfflinePlaytestPackaging, } from './offline-playtest.js';
|
|
48
49
|
export { assertMicrosoftStorePwaCacheTransition, assertMicrosoftStorePwaPrecacheUrl, assertMicrosoftStorePwaReleaseEvidence, inspectMicrosoftStorePwaBrowserCacheTransition, microsoftStorePwaCacheSchema, readMicrosoftStorePwaBrowserReleaseEvidence, requestMicrosoftStorePwaBrowserUpdate, resolveMicrosoftStorePwaScopedCacheName, } from './microsoft-store-pwa-e2e.js';
|
|
49
50
|
export { createMicrosoftStorePackageAcceptanceRuntime, microsoftStorePackageAcceptanceSchemaVersion, parseMicrosoftStorePackageIdentity, parseWindowsAppCertificationResult, renderMicrosoftStorePackageAcceptanceMarkdown, runMicrosoftStorePackageAcceptance, } from './microsoft-store-package-acceptance.js';
|
|
51
|
+
export { getMicrosoftStoreNativeAcceptanceModulePath, getMicrosoftStoreNativeHostSourceDirectory, } from './windows-native-tools.js';
|
|
50
52
|
export { createMicrosoftStorePackageGenerationRuntime, microsoftStorePackageGeneratorEndpoint, microsoftStorePackageGeneratorSourceRevision, microsoftStorePackageGenerationSchemaVersion, renderMicrosoftStorePackageGenerationMarkdown, runMicrosoftStorePackageGeneration, } from './microsoft-store-package-generation.js';
|
|
51
53
|
export { microsoftStoreSubmissionSchemaVersion, parseMicrosoftStoreSubmissionConfig, renderMicrosoftStoreSubmissionMarkdown, runMicrosoftStoreSubmissionPreflight, } from './microsoft-store-submission.js';
|
|
52
54
|
export { assertProductionTargetReadiness, } from './production-target-readiness.js';
|
|
@@ -54,6 +56,18 @@ const sourceDir = path.dirname(fileURLToPath(import.meta.url));
|
|
|
54
56
|
const packageRoot = resolvePackageRoot(sourceDir);
|
|
55
57
|
const detectedKitRoot = resolveDefaultKitRoot();
|
|
56
58
|
const gameTemplateDir = path.resolve(packageRoot, 'templates/phaser-game');
|
|
59
|
+
const liteTemplateOverlayDir = path.resolve(packageRoot, 'templates/lite-overlay');
|
|
60
|
+
const supportedGameTemplates = ['phaser', 'lite'];
|
|
61
|
+
/** Lite renderers implemented today. dom/svg are reserved extension points in @mpgd/lite-shell. */
|
|
62
|
+
const supportedLiteRenderers = ['canvas'];
|
|
63
|
+
/** Phaser-only base template files that the lite template does not emit. */
|
|
64
|
+
const liteTemplateRemovedFiles = new Set([
|
|
65
|
+
'src/scenes/BootScene.ts',
|
|
66
|
+
'src/scenes/LobbyScene.ts',
|
|
67
|
+
'src/scenes/PlayScene.ts',
|
|
68
|
+
'src/assets/manifest.ts',
|
|
69
|
+
'src/assets/marker.svg',
|
|
70
|
+
]);
|
|
57
71
|
const cliVersion = readPackageVersion(packageRoot);
|
|
58
72
|
const recommendedMatrixTargets = 'web,microsoft-store,verse8,ait,reddit';
|
|
59
73
|
const recommendedMatrixTargetsWithoutMicrosoftStore = recommendedMatrixTargets
|
|
@@ -73,11 +87,14 @@ const mpgdTemplateDependencyPackages = [
|
|
|
73
87
|
{ name: '@mpgd/adapter-verse8', packageDir: 'adapters/verse8' },
|
|
74
88
|
{ name: '@mpgd/analytics', packageDir: 'packages/analytics' },
|
|
75
89
|
{ name: '@mpgd/bridge', packageDir: 'packages/bridge' },
|
|
90
|
+
{ name: '@mpgd/capacitor-play-billing', packageDir: 'native-plugins/capacitor-play-billing' },
|
|
91
|
+
{ name: '@mpgd/capacitor-storekit', packageDir: 'native-plugins/capacitor-storekit' },
|
|
76
92
|
{ name: '@mpgd/catalog', packageDir: 'packages/catalog' },
|
|
77
93
|
{ name: '@mpgd/cli', packageDir: 'packages/cli' },
|
|
78
94
|
{ name: '@mpgd/game-services', packageDir: 'packages/game-services' },
|
|
79
95
|
{ name: '@mpgd/game-runtime', packageDir: 'packages/game-runtime' },
|
|
80
96
|
{ name: '@mpgd/i18n', packageDir: 'packages/i18n' },
|
|
97
|
+
{ name: '@mpgd/lite-shell', packageDir: 'packages/lite-shell' },
|
|
81
98
|
{ name: '@mpgd/phaser-assets', packageDir: 'packages/phaser-assets' },
|
|
82
99
|
{ name: '@mpgd/platform', packageDir: 'packages/platform' },
|
|
83
100
|
{ name: '@mpgd/target-config', packageDir: 'packages/target-config' },
|
|
@@ -549,8 +566,26 @@ const gameCommand = defineI18n({
|
|
|
549
566
|
en: 'Include the Microsoft Store PWA target and release workflow.',
|
|
550
567
|
ko: 'Microsoft Store PWA 타깃과 출시 워크플로를 포함합니다.',
|
|
551
568
|
},
|
|
569
|
+
template: {
|
|
570
|
+
en: 'Game template: phaser (default) or lite (no Phaser, @mpgd/lite-shell).',
|
|
571
|
+
ko: '게임 템플릿: phaser(기본) 또는 lite(Phaser 없음, @mpgd/lite-shell).',
|
|
572
|
+
},
|
|
573
|
+
renderer: {
|
|
574
|
+
en: 'Lite template renderer. Only canvas is implemented today.',
|
|
575
|
+
ko: 'lite 템플릿 렌더러. 현재는 canvas만 지원합니다.',
|
|
576
|
+
},
|
|
552
577
|
}),
|
|
553
578
|
args: {
|
|
579
|
+
template: {
|
|
580
|
+
type: 'string',
|
|
581
|
+
required: false,
|
|
582
|
+
description: 'Game template: phaser (default) or lite.',
|
|
583
|
+
},
|
|
584
|
+
renderer: {
|
|
585
|
+
type: 'string',
|
|
586
|
+
required: false,
|
|
587
|
+
description: 'Lite template renderer: canvas (default).',
|
|
588
|
+
},
|
|
554
589
|
directory: {
|
|
555
590
|
type: 'positional',
|
|
556
591
|
required: true,
|
|
@@ -601,7 +636,10 @@ const gameCommand = defineI18n({
|
|
|
601
636
|
? 'workspace:*'
|
|
602
637
|
: readOptionalString(ctx.values['dependency-version']);
|
|
603
638
|
const kitPath = readGameCreateKitPath(ctx.values, ctx.values.workspace === true);
|
|
639
|
+
const { template, renderer } = readGameCreateTemplate(readOptionalString(ctx.values.template), readOptionalString(ctx.values.renderer));
|
|
604
640
|
createGameApp({
|
|
641
|
+
template,
|
|
642
|
+
...(renderer === undefined ? {} : { renderer }),
|
|
605
643
|
directory,
|
|
606
644
|
...(title === undefined ? {} : { title }),
|
|
607
645
|
...(packageName === undefined ? {} : { packageName }),
|
|
@@ -1558,8 +1596,8 @@ const targetCommand = defineI18n({
|
|
|
1558
1596
|
ko: '프로덕션 HTTPS Game Services 기본 URL.',
|
|
1559
1597
|
},
|
|
1560
1598
|
providers: {
|
|
1561
|
-
en: 'Comma-separated
|
|
1562
|
-
ko: '쉼표로 구분한
|
|
1599
|
+
en: 'Comma-separated provider IDs. play-billing (Android) and storekit (iOS) install the kit store plugin into the shell and the game, register it with cap sync, and wire an unwired template gateway; other IDs are recorded only.',
|
|
1600
|
+
ko: '쉼표로 구분한 provider ID. play-billing(Android)과 storekit(iOS)은 키트 스토어 플러그인을 셸과 게임에 설치하고 cap sync로 등록하며, 연결되지 않은 템플릿 게이트웨이를 연결합니다. 다른 ID는 기록만 합니다.',
|
|
1563
1601
|
},
|
|
1564
1602
|
}),
|
|
1565
1603
|
args: {
|
|
@@ -1607,7 +1645,7 @@ const targetCommand = defineI18n({
|
|
|
1607
1645
|
providers: {
|
|
1608
1646
|
type: 'string',
|
|
1609
1647
|
required: false,
|
|
1610
|
-
description: 'Comma-separated
|
|
1648
|
+
description: 'Comma-separated provider IDs. play-billing (Android) and storekit (iOS) install the kit store plugin into the shell and the game, register it with cap sync, and wire an unwired template gateway; other IDs are recorded only.',
|
|
1611
1649
|
},
|
|
1612
1650
|
},
|
|
1613
1651
|
run: (ctx) => {
|
|
@@ -1631,6 +1669,7 @@ const targetCommand = defineI18n({
|
|
|
1631
1669
|
gameRoot,
|
|
1632
1670
|
appId,
|
|
1633
1671
|
displayName,
|
|
1672
|
+
templateRoot: gameTemplateDir,
|
|
1634
1673
|
...(iconSource === undefined ? {} : { iconSource }),
|
|
1635
1674
|
...(backendUrl === undefined ? {} : { backendUrl }),
|
|
1636
1675
|
...(selectedProviders === undefined ? {} : {
|
|
@@ -1647,18 +1686,33 @@ const targetCommand = defineI18n({
|
|
|
1647
1686
|
for (const platform of plan.nativePlatformsToAdd) {
|
|
1648
1687
|
console.info(`${dryRun ? 'Would add' : 'Added'} native platform: ${platform}`);
|
|
1649
1688
|
}
|
|
1650
|
-
|
|
1689
|
+
for (const plugin of plan.providerPlugins) {
|
|
1690
|
+
console.info(`${dryRun ? 'Would install' : 'Installed'} ${plugin.platform} store plugin `
|
|
1691
|
+
+ `${plugin.packageName}@${plugin.version} (${plugin.id}) into the shell`
|
|
1692
|
+
+ `${plugin.versionSource === 'kit' ? ' and the game' : ''}`
|
|
1693
|
+
+ `${dryRun ? '; cap add or cap sync registers it' : ''}.`);
|
|
1694
|
+
}
|
|
1695
|
+
for (const warning of plan.warnings) {
|
|
1696
|
+
console.warn(`Warning: ${warning}`);
|
|
1697
|
+
}
|
|
1698
|
+
console.info('File count covers managed shell and game files only; pnpm may also update root or shell lockfiles.');
|
|
1651
1699
|
if (!dryRun) {
|
|
1652
1700
|
console.info('Production native builds still require release identity and signing checks.');
|
|
1653
1701
|
}
|
|
1654
1702
|
return;
|
|
1655
1703
|
}
|
|
1704
|
+
if (ctx.values.providers !== undefined) {
|
|
1705
|
+
throw new Error('--providers is only available for capacitor initialization: it installs the '
|
|
1706
|
+
+ 'play-billing (Android) and storekit (iOS) store plugins into the game-owned '
|
|
1707
|
+
+ `native shell, which ${requestedTarget} does not initialize. Run `
|
|
1708
|
+
+ '"mpgd target init capacitor --providers ..." instead.');
|
|
1709
|
+
}
|
|
1656
1710
|
const target = normalizeConfiguredBuildTarget(requestedTarget);
|
|
1657
1711
|
if (target !== 'microsoft-store') {
|
|
1658
1712
|
throw new Error(`Target initialization is only available for microsoft-store; received: ${requestedTarget}`);
|
|
1659
1713
|
}
|
|
1660
1714
|
for (const option of [
|
|
1661
|
-
'app-id', 'display-name', 'icon-source', 'backend-url',
|
|
1715
|
+
'app-id', 'display-name', 'icon-source', 'backend-url',
|
|
1662
1716
|
]) {
|
|
1663
1717
|
if (ctx.values[option] !== undefined) {
|
|
1664
1718
|
throw new Error(`--${option} is only available for capacitor initialization.`);
|
|
@@ -2737,9 +2791,88 @@ function normalizeLegalHtml(content, sourceFile) {
|
|
|
2737
2791
|
}
|
|
2738
2792
|
return content.endsWith('\n') ? content : `${content}\n`;
|
|
2739
2793
|
}
|
|
2794
|
+
function readGameCreateTemplate(template, renderer) {
|
|
2795
|
+
const resolvedTemplate = template ?? 'phaser';
|
|
2796
|
+
if (!supportedGameTemplates.includes(resolvedTemplate)) {
|
|
2797
|
+
throw new Error(`Unsupported --template ${resolvedTemplate}; expected one of: ${supportedGameTemplates.join(', ')}.`);
|
|
2798
|
+
}
|
|
2799
|
+
if (resolvedTemplate !== 'lite') {
|
|
2800
|
+
if (renderer !== undefined) {
|
|
2801
|
+
throw new Error('--renderer is only available with --template lite.');
|
|
2802
|
+
}
|
|
2803
|
+
return { template: resolvedTemplate };
|
|
2804
|
+
}
|
|
2805
|
+
const resolvedRenderer = renderer ?? 'canvas';
|
|
2806
|
+
if (!supportedLiteRenderers.includes(resolvedRenderer)) {
|
|
2807
|
+
throw new Error(`Unsupported --renderer ${resolvedRenderer}; implemented lite renderers: ${supportedLiteRenderers.join(', ')}. `
|
|
2808
|
+
+ 'dom and svg are planned LiteRenderer implementations.');
|
|
2809
|
+
}
|
|
2810
|
+
return { template: 'lite', renderer: resolvedRenderer };
|
|
2811
|
+
}
|
|
2812
|
+
/** Apply the lite overlay to base template files: drop Phaser-only files and swap renderers. */
|
|
2813
|
+
function applyLiteTemplateOverlay(baseFiles, overlayFiles) {
|
|
2814
|
+
const overlay = new Map(overlayFiles.map((file) => [file.relativePath, file]));
|
|
2815
|
+
const merged = baseFiles.flatMap((file) => {
|
|
2816
|
+
if (liteTemplateRemovedFiles.has(file.relativePath)) {
|
|
2817
|
+
return [];
|
|
2818
|
+
}
|
|
2819
|
+
const replacement = overlay.get(file.relativePath);
|
|
2820
|
+
overlay.delete(file.relativePath);
|
|
2821
|
+
if (replacement !== undefined) {
|
|
2822
|
+
return [replacement];
|
|
2823
|
+
}
|
|
2824
|
+
if (file.relativePath === 'package.json') {
|
|
2825
|
+
return [{ ...file, content: liteTemplatePackageJson(file.content) }];
|
|
2826
|
+
}
|
|
2827
|
+
if (file.relativePath === 'agent/game-manifest.json') {
|
|
2828
|
+
return [{ ...file, content: liteTemplateGameManifest(file.content) }];
|
|
2829
|
+
}
|
|
2830
|
+
if (file.relativePath === 'mpgd.targets.json') {
|
|
2831
|
+
return [{ ...file, content: liteTemplateTargets(file.content) }];
|
|
2832
|
+
}
|
|
2833
|
+
return [file];
|
|
2834
|
+
});
|
|
2835
|
+
return [...merged, ...overlay.values()];
|
|
2836
|
+
}
|
|
2837
|
+
function liteTemplateTargets(content) {
|
|
2838
|
+
const value = JSON.parse(content);
|
|
2839
|
+
const reddit = value.targets.reddit;
|
|
2840
|
+
if (reddit !== undefined) {
|
|
2841
|
+
reddit.inlineEntry = 'index.html';
|
|
2842
|
+
reddit.inlineBudget = {
|
|
2843
|
+
maxGzipKb: 40,
|
|
2844
|
+
forbidModules: ['phaser', 'matter-js'],
|
|
2845
|
+
deferredChunks: ['main.js', 'matter.js', 'assets/main-*.js', 'assets/matter-*.js'],
|
|
2846
|
+
};
|
|
2847
|
+
}
|
|
2848
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
2849
|
+
}
|
|
2850
|
+
function liteTemplatePackageJson(content) {
|
|
2851
|
+
const value = JSON.parse(content);
|
|
2852
|
+
value.description = (value.description ?? '').replace('mpgd Phaser game', 'mpgd lite (Canvas2D) game');
|
|
2853
|
+
const dependencies = { ...value.dependencies };
|
|
2854
|
+
delete dependencies.phaser;
|
|
2855
|
+
delete dependencies['@mpgd/phaser-assets'];
|
|
2856
|
+
dependencies['@mpgd/lite-shell'] = '__MPGD_DEPENDENCY_VERSION_LITE_SHELL__';
|
|
2857
|
+
value.dependencies = Object.fromEntries(Object.entries(dependencies).sort(([a], [b]) => a.localeCompare(b)));
|
|
2858
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
2859
|
+
}
|
|
2860
|
+
function liteTemplateGameManifest(content) {
|
|
2861
|
+
const value = JSON.parse(content);
|
|
2862
|
+
if (value.game !== undefined) {
|
|
2863
|
+
value.game.engine = 'lite-canvas';
|
|
2864
|
+
}
|
|
2865
|
+
value.blocks = (value.blocks ?? []).map((block) => block.id === 'assets.manifest.phaser-loader'
|
|
2866
|
+
? { id: 'render.lite-shell.canvas', owner: 'src/lite/tapGame.ts' }
|
|
2867
|
+
: block);
|
|
2868
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
2869
|
+
}
|
|
2740
2870
|
function createGameApp(input) {
|
|
2741
2871
|
const appDir = resolveAppDirectory(input.directory);
|
|
2742
2872
|
const gameName = path.basename(appDir);
|
|
2873
|
+
if (input.template === 'lite' && !input.workspace) {
|
|
2874
|
+
throw new Error('The lite template requires --workspace until @mpgd/lite-shell is published.');
|
|
2875
|
+
}
|
|
2743
2876
|
assertValidGameName(gameName);
|
|
2744
2877
|
const packageName = input.packageName ?? gameName;
|
|
2745
2878
|
assertValidPackageName(packageName);
|
|
@@ -2759,7 +2892,11 @@ function createGameApp(input) {
|
|
|
2759
2892
|
...(input.title === undefined ? {} : { title: input.title }),
|
|
2760
2893
|
microsoftStore: input.microsoftStore,
|
|
2761
2894
|
});
|
|
2762
|
-
const
|
|
2895
|
+
const baseTemplateFiles = collectTemplateFiles(gameTemplateDir);
|
|
2896
|
+
const selectedTemplateFiles = input.template === 'lite'
|
|
2897
|
+
? applyLiteTemplateOverlay(baseTemplateFiles, collectTemplateFiles(liteTemplateOverlayDir))
|
|
2898
|
+
: baseTemplateFiles;
|
|
2899
|
+
const files = selectedTemplateFiles.flatMap((file) => {
|
|
2763
2900
|
const prepared = prepareBaseGameTemplateFile({
|
|
2764
2901
|
relativePath: file.relativePath,
|
|
2765
2902
|
content: file.content,
|
|
@@ -3019,9 +3156,10 @@ function renderTemplate(content, context) {
|
|
|
3019
3156
|
return rendered;
|
|
3020
3157
|
}
|
|
3021
3158
|
function templateOutputPath(relativePath) {
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3159
|
+
const normalized = relativePath.replace(/\\/gu, '/');
|
|
3160
|
+
return path.posix.basename(normalized) === 'gitignore'
|
|
3161
|
+
? path.posix.join(path.posix.dirname(normalized), '.gitignore')
|
|
3162
|
+
: normalized;
|
|
3025
3163
|
}
|
|
3026
3164
|
function toPascalCase(value) {
|
|
3027
3165
|
return value
|
|
@@ -3488,12 +3626,11 @@ function runPnpm(args, commandEnv) {
|
|
|
3488
3626
|
if (kitPath === undefined || kitPath.length === 0) {
|
|
3489
3627
|
throw new Error('Missing MPGD_KIT_PATH. Pass --kit-path or set MPGD_KIT_PATH.');
|
|
3490
3628
|
}
|
|
3491
|
-
const
|
|
3492
|
-
const result = spawnSync(command, [...args], {
|
|
3629
|
+
const launch = resolveNativeCommandLaunch({ command: 'pnpm', args, environment: commandEnv });
|
|
3630
|
+
const result = spawnSync(launch.command, [...launch.args], {
|
|
3493
3631
|
cwd: kitPath,
|
|
3494
3632
|
env: commandEnv,
|
|
3495
3633
|
stdio: 'inherit',
|
|
3496
|
-
shell: process.platform === 'win32',
|
|
3497
3634
|
});
|
|
3498
3635
|
if (result.error !== undefined) {
|
|
3499
3636
|
throw result.error;
|
|
@@ -3,6 +3,7 @@ import { closeSync, existsSync, fstatSync, lstatSync, openSync, readFileSync, re
|
|
|
3
3
|
import { isIP } from 'node:net';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { inflateSync } from 'node:zlib';
|
|
6
|
+
import { normalizeRootRelativeRoute } from '@mpgd/platform/routes';
|
|
6
7
|
import { escapeMarkdownInline, escapeMarkdownTable, formatError, relativeOrAbsolute, } from './evidence-io.js';
|
|
7
8
|
import { isMicrosoftStoreSupportedListingLocale } from './microsoft-store-supported-locales.js';
|
|
8
9
|
export const microsoftStoreSubmissionSchemaVersion = 1;
|
|
@@ -445,14 +446,18 @@ function parseListings(input) {
|
|
|
445
446
|
}];
|
|
446
447
|
}));
|
|
447
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* An artifact-relative URL: `.` and then a root-relative route already in the
|
|
451
|
+
* form `normalizeRootRelativeRoute` from `@mpgd/platform/routes` returns, the
|
|
452
|
+
* rule share links and notification routes follow, so no client reads it as
|
|
453
|
+
* another host, even once it percent-decodes the path. The manifest ships in
|
|
454
|
+
* the artifact and the Store resolves these against the manifest's own URL,
|
|
455
|
+
* so an absolute URL is never needed.
|
|
456
|
+
*/
|
|
448
457
|
function requireManifestUrl(input, label) {
|
|
449
458
|
const value = requireNonEmptyString(input, label);
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
if (!value.startsWith('./')
|
|
453
|
-
|| url.origin !== base.origin
|
|
454
|
-
|| url.pathname.startsWith('//')
|
|
455
|
-
|| value !== `.${url.pathname}${url.search}${url.hash}`) {
|
|
459
|
+
const route = value.startsWith('./') ? value.slice(1) : undefined;
|
|
460
|
+
if (route === undefined || normalizeRootRelativeRoute(route) !== route) {
|
|
456
461
|
throw new Error(`${label} must be an artifact-relative URL beginning with ./`);
|
|
457
462
|
}
|
|
458
463
|
return value;
|