@mpgd/cli 0.55.0 → 0.57.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.js +130 -3
- package/dist/native-build-info.json +2 -2
- package/dist/native-build-target.js +2091 -220
- package/dist/notifications-starter.d.ts +29 -2
- package/dist/notifications-starter.js +63 -4
- package/package.json +18 -18
- package/templates/lite-overlay/agent/acceptance.md +1 -0
- package/templates/lite-overlay/agent/brief.md +1 -0
- package/templates/notifications-overlay/common/docs/NOTIFICATIONS.md +91 -3
- package/templates/notifications-overlay/common/src/platform/notificationBackend.ts +113 -3
- package/templates/notifications-overlay/common/src/platform/notifications.ts +19 -1
- package/templates/phaser-game/agent/acceptance.md +10 -0
- package/templates/phaser-game/agent/brief.md +12 -0
- package/templates/phaser-game/apps/target-devvit/src/server/bridge.ts +37 -0
- package/templates/phaser-game/src/env.d.ts +5 -0
- package/templates/phaser-game/src/platform/developmentServerSession.ts +104 -0
- package/templates/phaser-game/src/platform/serverSession.ts +49 -26
|
@@ -5,7 +5,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { DOMParser } from '@xmldom/xmldom';
|
|
7
7
|
import { satisfies, valid, validRange } from 'semver';
|
|
8
|
-
import { capacitorGatewayRegistersNotifications, conflictingPushPlugin, notificationsCapacitorGatewayModules, notificationsCapacitorGateways, notificationsCapacitorSupportFiles, notificationsCapacitorTemplateSupportFiles, notificationsGameDependencies, notificationsMessagingFirebaseRange, notificationsMessagingPlugin, notificationsProviderId, notificationsShellPlugins, wireCapacitorGatewayNotifications, } from './notifications-starter.js';
|
|
8
|
+
import { capacitorGatewayRegistersNotifications, conflictingPushPlugin, notificationsCapacitorGatewayModules, notificationsCapacitorGateways, notificationsCapacitorSupportFiles, notificationsCapacitorTemplateSupportFiles, notificationsCapacitorTemplateSupportImporters, notificationsGameDependencies, notificationsMessagingFirebaseRange, notificationsMessagingPlugin, notificationsProviderId, notificationsShellPlugins, sourceReferencesRelativeModule, wireCapacitorGatewayNotifications, } from './notifications-starter.js';
|
|
9
9
|
import { isNonPublicServiceHostname } from './production-target-readiness.js';
|
|
10
10
|
import { assertAndroidSettingsAppProject, assertAndroidSettingsNoAppRemap, assertIosReleaseInfoPlistExpansion, assertIosReleasePackagingSettings, assertIosReleaseProductName, assertNativeShellIdentity, hasAndroidDisplayNameResourceOverride, hasAndroidManifestSourceSetOverride, hasAndroidResourceSourceSetOverride, hasGradleIdentityMutation, hasGradleTaskAction, maskGradleStrings, readIosAppTargetId, readIosReleaseInfoPlist, stripGradleComments, } from './native-shell-identity.js';
|
|
11
11
|
const shellPath = 'apps/mobile-capacitor';
|
|
@@ -2796,9 +2796,29 @@ function planNotificationsProvider(input) {
|
|
|
2796
2796
|
// Base-template modules they import, missing from a game an earlier release created.
|
|
2797
2797
|
if (input.templateRoot !== undefined) {
|
|
2798
2798
|
for (const file of notificationsCapacitorTemplateSupportFiles) {
|
|
2799
|
-
if (readExisting(safeDestination(gameRoot, file))
|
|
2800
|
-
|
|
2799
|
+
if (readExisting(safeDestination(gameRoot, file)) !== undefined) {
|
|
2800
|
+
continue;
|
|
2801
2801
|
}
|
|
2802
|
+
const imported = notificationsCapacitorTemplateSupportImporters[file];
|
|
2803
|
+
const importerSource = imported === undefined
|
|
2804
|
+
? undefined
|
|
2805
|
+
: readExisting(safeDestination(gameRoot, imported.importer));
|
|
2806
|
+
// A game whose own importer does not import the module would never use it.
|
|
2807
|
+
if (imported !== undefined && importerSource !== undefined
|
|
2808
|
+
&& !sourceReferencesRelativeModule(importerSource, path.posix.basename(file, '.ts'))) {
|
|
2809
|
+
warnings.push(imported.warning);
|
|
2810
|
+
continue;
|
|
2811
|
+
}
|
|
2812
|
+
// The file imports a kit export an older installed package lacks.
|
|
2813
|
+
const required = imported?.requires;
|
|
2814
|
+
if (required !== undefined
|
|
2815
|
+
&& installedPackageLacksExport(gameRoot, required.packageName, required.exportName)) {
|
|
2816
|
+
const version = installedPackageVersion(gameRoot, required.packageName);
|
|
2817
|
+
throw new Error(`--providers notifications writes ${file}, which imports ${required.exportName} from `
|
|
2818
|
+
+ `${required.packageName}; the game's ${required.packageName} ${version} does not export it. `
|
|
2819
|
+
+ "Upgrade the game's kit packages (mpgd kit upgrade) first.");
|
|
2820
|
+
}
|
|
2821
|
+
files.push({ path: file, content: starterFile(input.templateRoot, file) });
|
|
2802
2822
|
}
|
|
2803
2823
|
}
|
|
2804
2824
|
warnings.push('The notification settings screen is not added to an existing game; render one from '
|
|
@@ -2905,3 +2925,110 @@ function requireString(value, label) {
|
|
|
2905
2925
|
function json(value) {
|
|
2906
2926
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
2907
2927
|
}
|
|
2928
|
+
/** Declaration files the export check reads at most: a guard against a pathological graph. */
|
|
2929
|
+
const maxDeclarationFilesChecked = 500;
|
|
2930
|
+
/** The declaration file names TypeScript pairs with a module specifier. */
|
|
2931
|
+
function declarationCandidates(base) {
|
|
2932
|
+
// A specifier that already names a declaration file is that file.
|
|
2933
|
+
if (/\.d\.[cm]?ts$/u.test(base)) {
|
|
2934
|
+
return [base];
|
|
2935
|
+
}
|
|
2936
|
+
const extension = path.extname(base);
|
|
2937
|
+
const stem = base.slice(0, base.length - extension.length);
|
|
2938
|
+
switch (extension) {
|
|
2939
|
+
case '.js':
|
|
2940
|
+
case '.ts':
|
|
2941
|
+
return [`${stem}.d.ts`];
|
|
2942
|
+
case '.mjs':
|
|
2943
|
+
case '.mts':
|
|
2944
|
+
return [`${stem}.d.mts`];
|
|
2945
|
+
case '.cjs':
|
|
2946
|
+
case '.cts':
|
|
2947
|
+
return [`${stem}.d.cts`];
|
|
2948
|
+
default:
|
|
2949
|
+
return [`${base}.d.ts`, path.join(base, 'index.d.ts')];
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
/**
|
|
2953
|
+
* Whether the game's installed `packageName` provably lacks `exportName`:
|
|
2954
|
+
* its root type declarations, and every declaration file they re-export
|
|
2955
|
+
* from through relative specifiers, at any depth, never name it. Anything
|
|
2956
|
+
* the check cannot follow passes, and the game's build then decides, as for
|
|
2957
|
+
* the adapter's settings opener: an uninstalled or unreadable package, a
|
|
2958
|
+
* module it cannot read, or an `export *` from another package.
|
|
2959
|
+
*/
|
|
2960
|
+
function installedPackageLacksExport(gameRoot, packageName, exportName) {
|
|
2961
|
+
// Only a plain identifier is searched for; anything else is not proof of absence.
|
|
2962
|
+
if (!/^[A-Za-z_$][\w$]*$/u.test(exportName)) {
|
|
2963
|
+
return false;
|
|
2964
|
+
}
|
|
2965
|
+
const packageRoot = path.join(gameRoot, 'node_modules', packageName);
|
|
2966
|
+
const manifest = readInstalledManifest(gameRoot, packageName);
|
|
2967
|
+
if (manifest === undefined) {
|
|
2968
|
+
return false;
|
|
2969
|
+
}
|
|
2970
|
+
const rootExport = typeof manifest.exports === 'object' && manifest.exports !== null
|
|
2971
|
+
? manifest.exports['.']
|
|
2972
|
+
: undefined;
|
|
2973
|
+
const rootTypes = typeof rootExport === 'object' && rootExport !== null
|
|
2974
|
+
? rootExport.types
|
|
2975
|
+
: undefined;
|
|
2976
|
+
const typesPath = typeof rootTypes === 'string' ? rootTypes : manifest.types;
|
|
2977
|
+
if (typeof typesPath !== 'string') {
|
|
2978
|
+
return false;
|
|
2979
|
+
}
|
|
2980
|
+
// Every declaration file the root re-exports from, followed through relative
|
|
2981
|
+
// `export … from` specifiers at any depth; the name is searched as text, so a
|
|
2982
|
+
// named re-export of it counts as well.
|
|
2983
|
+
const relativeFrom = /\bexport\b[^;]*?\bfrom\s*['"](\.{1,2}\/[^'"]+)['"]/gu;
|
|
2984
|
+
const packageStar = /\bexport\s*(?:type\s*)?\*\s*(?:as\s+[\w$]+\s*)?from\s*['"](?!\.{1,2}\/)[^'"]+['"]/u;
|
|
2985
|
+
const nameUsed = new RegExp(`(?<![\\w$])${exportName.replace(/\$/gu, '\\$')}(?![\\w$])`, 'u');
|
|
2986
|
+
const pending = [path.join(packageRoot, typesPath)];
|
|
2987
|
+
const visited = new Set();
|
|
2988
|
+
while (pending.length > 0) {
|
|
2989
|
+
const file = pending.pop() ?? '';
|
|
2990
|
+
if (visited.has(file)) {
|
|
2991
|
+
continue;
|
|
2992
|
+
}
|
|
2993
|
+
visited.add(file);
|
|
2994
|
+
if (visited.size > maxDeclarationFilesChecked) {
|
|
2995
|
+
return false;
|
|
2996
|
+
}
|
|
2997
|
+
let source;
|
|
2998
|
+
try {
|
|
2999
|
+
source = readExisting(file);
|
|
3000
|
+
}
|
|
3001
|
+
catch {
|
|
3002
|
+
source = undefined;
|
|
3003
|
+
}
|
|
3004
|
+
if (source === undefined || packageStar.test(source)) {
|
|
3005
|
+
// A module the check cannot read, or names from another package: do not refuse on a guess.
|
|
3006
|
+
return false;
|
|
3007
|
+
}
|
|
3008
|
+
if (nameUsed.test(source)) {
|
|
3009
|
+
return false;
|
|
3010
|
+
}
|
|
3011
|
+
for (const match of source.matchAll(relativeFrom)) {
|
|
3012
|
+
const candidates = declarationCandidates(path.join(path.dirname(file), match[1] ?? ''));
|
|
3013
|
+
pending.push(candidates.find((candidate) => existsSync(candidate)) ?? candidates[0] ?? file);
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
return true;
|
|
3017
|
+
}
|
|
3018
|
+
/** The game's installed `packageName` manifest, or `undefined` when it is missing or unreadable. */
|
|
3019
|
+
function readInstalledManifest(gameRoot, packageName) {
|
|
3020
|
+
try {
|
|
3021
|
+
const source = readExisting(path.join(gameRoot, 'node_modules', packageName, 'package.json'));
|
|
3022
|
+
return source === undefined
|
|
3023
|
+
? undefined
|
|
3024
|
+
: parseJsonObject(source, `${packageName}/package.json`);
|
|
3025
|
+
}
|
|
3026
|
+
catch {
|
|
3027
|
+
return undefined;
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
/** The installed package's version, for a message. */
|
|
3031
|
+
function installedPackageVersion(gameRoot, packageName) {
|
|
3032
|
+
const version = readInstalledManifest(gameRoot, packageName)?.version;
|
|
3033
|
+
return typeof version === 'string' ? version : 'unknown';
|
|
3034
|
+
}
|