@mpgd/cli 0.47.0 → 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/command-launcher.d.ts +13 -0
- package/dist/command-launcher.js +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +126 -7
- package/dist/microsoft-store-submission.js +11 -6
- package/dist/native-build-info.json +2 -2
- package/dist/native-build-target.js +2121 -350
- 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 -16
- 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 +5 -5
- package/templates/phaser-game/apps/target-devvit/src/server/bridge.ts +137 -18
- package/templates/phaser-game/package.json +1 -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/platform/buildGateways/ait.ts +1 -1
- package/templates/phaser-game/src/platform/buildGateways/aitSandbox.ts +9 -4
- package/templates/phaser-game/src/platform/buildGateways/microsoftStore.ts +2 -5
- package/templates/phaser-game/src/platform/buildGateways/reddit.ts +1 -1
- package/templates/phaser-game/src/platform/buildGateways/verse8.ts +1 -2
- package/templates/phaser-game/src/platform/verse8Agent8Client.ts +5 -6
- package/templates/phaser-game/vite.shared.ts +40 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface NativeCommandLaunch {
|
|
2
|
+
readonly command: string;
|
|
3
|
+
readonly args: readonly string[];
|
|
4
|
+
readonly shell?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Launch pnpm directly; Windows .cmd shims require a shell and lose argument boundaries. */
|
|
7
|
+
export declare function resolveNativeCommandLaunch(input: {
|
|
8
|
+
readonly command: string;
|
|
9
|
+
readonly args: readonly string[];
|
|
10
|
+
readonly environment: NodeJS.ProcessEnv;
|
|
11
|
+
readonly platform?: NodeJS.Platform;
|
|
12
|
+
readonly nodeExecutable?: string;
|
|
13
|
+
}): NativeCommandLaunch;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Launch pnpm directly; Windows .cmd shims require a shell and lose argument boundaries. */
|
|
2
|
+
export function resolveNativeCommandLaunch(input) {
|
|
3
|
+
if ((input.platform ?? process.platform) !== 'win32') {
|
|
4
|
+
return { command: input.command, args: input.args };
|
|
5
|
+
}
|
|
6
|
+
if (input.command === './gradlew') {
|
|
7
|
+
return { command: 'gradlew.bat', args: input.args, shell: true };
|
|
8
|
+
}
|
|
9
|
+
if (input.command !== 'pnpm') {
|
|
10
|
+
return { command: input.command, args: input.args };
|
|
11
|
+
}
|
|
12
|
+
const pnpmEntry = input.environment.npm_execpath;
|
|
13
|
+
const pnpmBase = pnpmEntry?.split(/[\\/]/u).at(-1) ?? '';
|
|
14
|
+
if (pnpmEntry === undefined || !/^pnpm(?:\.exe|\.[cm]?js)$/iu.test(pnpmBase)) {
|
|
15
|
+
throw new Error('Windows builds require pnpm exec mpgd so npm_execpath resolves the pnpm executable or JavaScript entrypoint.');
|
|
16
|
+
}
|
|
17
|
+
if (/\.exe$/iu.test(pnpmEntry)) {
|
|
18
|
+
return { command: pnpmEntry, args: input.args };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
command: input.nodeExecutable ?? process.execPath,
|
|
22
|
+
args: [pnpmEntry, ...input.args],
|
|
23
|
+
};
|
|
24
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { cloudflarePagesDeploymentProfiles, hostedPwaDeploymentHosts, isSupporte
|
|
|
15
15
|
export { defaultOfflinePlaytestArtifactDir, defaultOfflinePlaytestMaximumBytes, defaultOfflinePlaytestOutputDir, offlinePlaytestSchemaVersion, runOfflinePlaytestPackaging, type OfflinePlaytestEvidence, type RunOfflinePlaytestPackagingInput, type RunOfflinePlaytestPackagingResult, } from './offline-playtest.js';
|
|
16
16
|
export { assertMicrosoftStorePwaCacheTransition, assertMicrosoftStorePwaPrecacheUrl, assertMicrosoftStorePwaReleaseEvidence, inspectMicrosoftStorePwaBrowserCacheTransition, microsoftStorePwaCacheSchema, readMicrosoftStorePwaBrowserReleaseEvidence, requestMicrosoftStorePwaBrowserUpdate, resolveMicrosoftStorePwaScopedCacheName, type AssertMicrosoftStorePwaCacheTransitionInput, type InspectMicrosoftStorePwaCacheTransitionInput, type MicrosoftStorePwaBrowserPage, type MicrosoftStorePwaCachedIndexObservation, type MicrosoftStorePwaCacheTransitionEvidence, type MicrosoftStorePwaCacheTransitionObservation, type MicrosoftStorePwaReleaseEvidence, } from './microsoft-store-pwa-e2e.js';
|
|
17
17
|
export { createMicrosoftStorePackageAcceptanceRuntime, microsoftStorePackageAcceptanceSchemaVersion, parseMicrosoftStorePackageIdentity, parseWindowsAppCertificationResult, renderMicrosoftStorePackageAcceptanceMarkdown, runMicrosoftStorePackageAcceptance, type CreateMicrosoftStorePackageAcceptanceRuntimeInput, type MicrosoftStorePackageAcceptanceEvidence, type MicrosoftStorePackageAcceptanceRuntime, type MicrosoftStorePackageIdentity, type RunMicrosoftStorePackageAcceptanceInput, } from './microsoft-store-package-acceptance.js';
|
|
18
|
+
export { getMicrosoftStoreNativeAcceptanceModulePath, getMicrosoftStoreNativeHostSourceDirectory, } from './windows-native-tools.js';
|
|
18
19
|
export { createMicrosoftStorePackageGenerationRuntime, microsoftStorePackageGeneratorEndpoint, microsoftStorePackageGeneratorSourceRevision, microsoftStorePackageGenerationSchemaVersion, renderMicrosoftStorePackageGenerationMarkdown, runMicrosoftStorePackageGeneration, type CreateMicrosoftStorePackageGenerationRuntimeInput, type MicrosoftStoreAddressResolver, type MicrosoftStorePackageGenerationEvidence, type MicrosoftStorePackageGenerationRuntime, type MicrosoftStoreResolvedAddress, type RunMicrosoftStorePackageGenerationInput, } from './microsoft-store-package-generation.js';
|
|
19
20
|
export { microsoftStoreSubmissionSchemaVersion, parseMicrosoftStoreSubmissionConfig, renderMicrosoftStoreSubmissionMarkdown, runMicrosoftStoreSubmissionPreflight, type MicrosoftStoreSubmissionConfig, type MicrosoftStoreSubmissionCommerce, type MicrosoftStoreSubmissionCommerceProduct, type MicrosoftStoreSubmissionEvidence, type RunMicrosoftStoreSubmissionPreflightInput, } from './microsoft-store-submission.js';
|
|
20
21
|
export { assertProductionTargetReadiness, type ProductionTargetReadinessInput, } from './production-target-readiness.js';
|
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
|
|
@@ -80,6 +94,7 @@ const mpgdTemplateDependencyPackages = [
|
|
|
80
94
|
{ name: '@mpgd/game-services', packageDir: 'packages/game-services' },
|
|
81
95
|
{ name: '@mpgd/game-runtime', packageDir: 'packages/game-runtime' },
|
|
82
96
|
{ name: '@mpgd/i18n', packageDir: 'packages/i18n' },
|
|
97
|
+
{ name: '@mpgd/lite-shell', packageDir: 'packages/lite-shell' },
|
|
83
98
|
{ name: '@mpgd/phaser-assets', packageDir: 'packages/phaser-assets' },
|
|
84
99
|
{ name: '@mpgd/platform', packageDir: 'packages/platform' },
|
|
85
100
|
{ name: '@mpgd/target-config', packageDir: 'packages/target-config' },
|
|
@@ -551,8 +566,26 @@ const gameCommand = defineI18n({
|
|
|
551
566
|
en: 'Include the Microsoft Store PWA target and release workflow.',
|
|
552
567
|
ko: 'Microsoft Store PWA 타깃과 출시 워크플로를 포함합니다.',
|
|
553
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
|
+
},
|
|
554
577
|
}),
|
|
555
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
|
+
},
|
|
556
589
|
directory: {
|
|
557
590
|
type: 'positional',
|
|
558
591
|
required: true,
|
|
@@ -603,7 +636,10 @@ const gameCommand = defineI18n({
|
|
|
603
636
|
? 'workspace:*'
|
|
604
637
|
: readOptionalString(ctx.values['dependency-version']);
|
|
605
638
|
const kitPath = readGameCreateKitPath(ctx.values, ctx.values.workspace === true);
|
|
639
|
+
const { template, renderer } = readGameCreateTemplate(readOptionalString(ctx.values.template), readOptionalString(ctx.values.renderer));
|
|
606
640
|
createGameApp({
|
|
641
|
+
template,
|
|
642
|
+
...(renderer === undefined ? {} : { renderer }),
|
|
607
643
|
directory,
|
|
608
644
|
...(title === undefined ? {} : { title }),
|
|
609
645
|
...(packageName === undefined ? {} : { packageName }),
|
|
@@ -2755,9 +2791,88 @@ function normalizeLegalHtml(content, sourceFile) {
|
|
|
2755
2791
|
}
|
|
2756
2792
|
return content.endsWith('\n') ? content : `${content}\n`;
|
|
2757
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
|
+
}
|
|
2758
2870
|
function createGameApp(input) {
|
|
2759
2871
|
const appDir = resolveAppDirectory(input.directory);
|
|
2760
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
|
+
}
|
|
2761
2876
|
assertValidGameName(gameName);
|
|
2762
2877
|
const packageName = input.packageName ?? gameName;
|
|
2763
2878
|
assertValidPackageName(packageName);
|
|
@@ -2777,7 +2892,11 @@ function createGameApp(input) {
|
|
|
2777
2892
|
...(input.title === undefined ? {} : { title: input.title }),
|
|
2778
2893
|
microsoftStore: input.microsoftStore,
|
|
2779
2894
|
});
|
|
2780
|
-
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) => {
|
|
2781
2900
|
const prepared = prepareBaseGameTemplateFile({
|
|
2782
2901
|
relativePath: file.relativePath,
|
|
2783
2902
|
content: file.content,
|
|
@@ -3037,9 +3156,10 @@ function renderTemplate(content, context) {
|
|
|
3037
3156
|
return rendered;
|
|
3038
3157
|
}
|
|
3039
3158
|
function templateOutputPath(relativePath) {
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3159
|
+
const normalized = relativePath.replace(/\\/gu, '/');
|
|
3160
|
+
return path.posix.basename(normalized) === 'gitignore'
|
|
3161
|
+
? path.posix.join(path.posix.dirname(normalized), '.gitignore')
|
|
3162
|
+
: normalized;
|
|
3043
3163
|
}
|
|
3044
3164
|
function toPascalCase(value) {
|
|
3045
3165
|
return value
|
|
@@ -3506,12 +3626,11 @@ function runPnpm(args, commandEnv) {
|
|
|
3506
3626
|
if (kitPath === undefined || kitPath.length === 0) {
|
|
3507
3627
|
throw new Error('Missing MPGD_KIT_PATH. Pass --kit-path or set MPGD_KIT_PATH.');
|
|
3508
3628
|
}
|
|
3509
|
-
const
|
|
3510
|
-
const result = spawnSync(command, [...args], {
|
|
3629
|
+
const launch = resolveNativeCommandLaunch({ command: 'pnpm', args, environment: commandEnv });
|
|
3630
|
+
const result = spawnSync(launch.command, [...launch.args], {
|
|
3511
3631
|
cwd: kitPath,
|
|
3512
3632
|
env: commandEnv,
|
|
3513
3633
|
stdio: 'inherit',
|
|
3514
|
-
shell: process.platform === 'win32',
|
|
3515
3634
|
});
|
|
3516
3635
|
if (result.error !== undefined) {
|
|
3517
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;
|