@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.
Files changed (62) hide show
  1. package/dist/capacitor-shell-starter.d.ts +57 -1
  2. package/dist/capacitor-shell-starter.js +311 -34
  3. package/dist/command-launcher.d.ts +13 -0
  4. package/dist/command-launcher.js +24 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +149 -12
  7. package/dist/microsoft-store-submission.js +11 -6
  8. package/dist/native-build-info.json +2 -2
  9. package/dist/native-build-target.js +2413 -345
  10. package/dist/windows-host/Core/BridgeCommand.cs +17 -0
  11. package/dist/windows-host/Core/Mpgd.MicrosoftStore.Host.csproj +9 -0
  12. package/dist/windows-host/Core/NativeBridgeContracts.cs +33 -0
  13. package/dist/windows-host/Core/NativeBridgeHost.cs +162 -0
  14. package/dist/windows-host/Core/NativeBridgeOrigin.cs +19 -0
  15. package/dist/windows-host/Core/NativeBridgeProtocol.cs +335 -0
  16. package/dist/windows-host/Core/NativeBridgeRequestGate.cs +76 -0
  17. package/dist/windows-host/Core/NativeBridgeResult.cs +65 -0
  18. package/dist/windows-host/README.md +118 -0
  19. package/dist/windows-host/WinUI/DispatcherQueueBridgeDispatcher.cs +39 -0
  20. package/dist/windows-host/WinUI/WebView2DocumentTransport.cs +46 -0
  21. package/dist/windows-host/WinUI/WebView2NativeBridge.cs +185 -0
  22. package/dist/windows-host/WinUI/WindowStoreContext.cs +20 -0
  23. package/dist/windows-native-tools.d.ts +4 -0
  24. package/dist/windows-native-tools.js +21 -0
  25. package/native-tools/windows-msix/WindowsMsixAcceptance.psm1 +333 -0
  26. package/package.json +24 -14
  27. package/templates/lite-overlay/.agents/skills/use-mpgd-kit/SKILL.md +22 -0
  28. package/templates/lite-overlay/AGENTS.md +27 -0
  29. package/templates/lite-overlay/README.md +37 -0
  30. package/templates/lite-overlay/agent/acceptance.md +27 -0
  31. package/templates/lite-overlay/agent/brief.md +17 -0
  32. package/templates/lite-overlay/apps/target-devvit/README.md +134 -0
  33. package/templates/lite-overlay/docs/MPGD_KIT_WORKFLOWS.md +37 -0
  34. package/templates/lite-overlay/src/lite/tapGame.ts +77 -0
  35. package/templates/lite-overlay/src/platform/devvitEntrypoint.ts +116 -0
  36. package/templates/lite-overlay/src/platform/devvitInlineMode.css +146 -0
  37. package/templates/lite-overlay/src/runtime/createGame.ts +57 -0
  38. package/templates/phaser-game/README.md +5 -3
  39. package/templates/phaser-game/apps/target-ait/package.json +2 -2
  40. package/templates/phaser-game/apps/target-ait/src/main.ts +17 -0
  41. package/templates/phaser-game/apps/target-ait/src/runtime-config.types.ts +2 -0
  42. package/templates/phaser-game/apps/target-ait/vite.config.ts +27 -0
  43. package/templates/phaser-game/apps/target-devvit/package.json +2 -1
  44. package/templates/phaser-game/apps/target-devvit/src/server/bridge.ts +137 -18
  45. package/templates/phaser-game/apps/target-devvit/src/server/index.ts +35 -1
  46. package/templates/phaser-game/package.json +3 -1
  47. package/templates/phaser-game/pnpm-workspace.yaml +2 -0
  48. package/templates/phaser-game/src/env.d.ts +2 -0
  49. package/templates/phaser-game/src/main.ts +8 -1
  50. package/templates/phaser-game/src/platform/buildGateways/ait.ts +9 -0
  51. package/templates/phaser-game/src/platform/buildGateways/aitSandbox.ts +13 -1
  52. package/templates/phaser-game/src/platform/buildGateways/capacitorAndroid.ts +51 -2
  53. package/templates/phaser-game/src/platform/buildGateways/capacitorIos.ts +51 -2
  54. package/templates/phaser-game/src/platform/buildGateways/microsoftStore.ts +59 -26
  55. package/templates/phaser-game/src/platform/buildGateways/reddit.ts +36 -1
  56. package/templates/phaser-game/src/platform/buildGateways/verse8.ts +39 -2
  57. package/templates/phaser-game/src/platform/commerceAccountBinding.ts +79 -0
  58. package/templates/phaser-game/src/platform/commerceProducts.ts +69 -0
  59. package/templates/phaser-game/src/platform/gameServices.ts +22 -2
  60. package/templates/phaser-game/src/platform/monetizationJournal.ts +286 -0
  61. package/templates/phaser-game/src/platform/verse8Agent8Client.ts +22 -0
  62. 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 requested provider IDs; this does not install SDKs.',
1562
- ko: '쉼표로 구분한 요청 provider ID. SDK를 설치하지는 않습니다.',
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 requested provider IDs; this does not install SDKs.',
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
- console.info('File count covers managed shell files only; pnpm may also update root or shell lockfiles.');
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', 'providers',
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 files = collectTemplateFiles(gameTemplateDir).flatMap((file) => {
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
- return path.basename(relativePath) === 'gitignore'
3023
- ? path.join(path.dirname(relativePath), '.gitignore')
3024
- : relativePath;
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 command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
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 base = new URL('https://mpgd.invalid/');
451
- const url = new URL(value, base);
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;
@@ -1,5 +1,5 @@
1
1
  {
2
- "kitGitSha": "6799cf86c8d5257db83fa5f8c56c2a74b720ae73",
2
+ "kitGitSha": "926ff936dc36d2112c042185974dc3c33102377d",
3
3
  "kitDirty": false,
4
- "packageVersion": "0.46.1"
4
+ "packageVersion": "0.48.0"
5
5
  }