@mpgd/cli 0.54.0 → 0.54.1
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/index.js +61 -22
- package/dist/kit-upgrade.js +103 -4
- package/dist/legal-site-output.d.ts +12 -0
- package/dist/legal-site-output.js +226 -0
- package/dist/native-build-info.json +2 -2
- package/dist/native-build-target.js +96 -14
- package/package.json +16 -16
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { buildAssetPacks } from './asset-pack-build.js';
|
|
|
12
12
|
import { verifyAssetPackDelivery } from './asset-pack-verify.js';
|
|
13
13
|
import { buildAssetPackTarget } from './asset-pack-target.js';
|
|
14
14
|
import { publishAssetPacks } from './asset-pack-publish.js';
|
|
15
|
+
import { assertLegalProjectPath, publishLegalSiteFiles } from './legal-site-output.js';
|
|
15
16
|
import { assertAssetPackTargetPolicy } from '@mpgd/target-config/asset-packs';
|
|
16
17
|
import { materializeCapacitorShellStarter, planCapacitorShellStarter, } from './capacitor-shell-starter.js';
|
|
17
18
|
import { doctorNativeDeployment, initializeDeployConfig, parseDeployTargets, planNativeDeployment, readNativeDeploymentPlan, writeNativeDeploymentPlan, } from './deploy-planning.js';
|
|
@@ -1818,7 +1819,10 @@ const targetCommand = defineI18n({
|
|
|
1818
1819
|
action: 'build',
|
|
1819
1820
|
target,
|
|
1820
1821
|
profile,
|
|
1821
|
-
env: createTargetCommandEnv(ctx.values, {
|
|
1822
|
+
env: createTargetCommandEnv(ctx.values, {
|
|
1823
|
+
nativeBuildTarget: target,
|
|
1824
|
+
requireSourceRevision: true,
|
|
1825
|
+
}),
|
|
1822
1826
|
...(variant === undefined ? {} : { variant }),
|
|
1823
1827
|
});
|
|
1824
1828
|
},
|
|
@@ -2448,7 +2452,7 @@ const targetCommand = defineI18n({
|
|
|
2448
2452
|
run: (ctx) => {
|
|
2449
2453
|
const aitVariant = readOptionalString(ctx.values['ait-variant']);
|
|
2450
2454
|
const iosVariant = readOptionalString(ctx.values['ios-variant']);
|
|
2451
|
-
const env = createTargetCommandEnv(ctx.values);
|
|
2455
|
+
const env = createTargetCommandEnv(ctx.values, { requireSourceRevision: true });
|
|
2452
2456
|
runTargetMatrix({
|
|
2453
2457
|
action: 'build',
|
|
2454
2458
|
targets: parseTargetList(readOptionalString(ctx.values.targets), env),
|
|
@@ -2774,9 +2778,13 @@ function resolveLegalCommandOptions(values) {
|
|
|
2774
2778
|
function buildLegalSite(input) {
|
|
2775
2779
|
const legalDir = path.resolve(process.cwd(), input.legalDir);
|
|
2776
2780
|
const outDir = path.resolve(process.cwd(), input.outDir);
|
|
2781
|
+
assertLegalProjectPath('legal-dir', legalDir);
|
|
2782
|
+
assertLegalProjectPath('out-dir', outDir);
|
|
2777
2783
|
const outputs = createLegalSiteOutputs(legalDir, outDir);
|
|
2778
2784
|
if (input.check) {
|
|
2785
|
+
assertLegalProjectPath('out-dir', outDir);
|
|
2779
2786
|
const stale = outputs.filter((output) => {
|
|
2787
|
+
assertLegalProjectPath('out-dir', output.file);
|
|
2780
2788
|
if (!existsSync(output.file)) {
|
|
2781
2789
|
return true;
|
|
2782
2790
|
}
|
|
@@ -2792,29 +2800,24 @@ function buildLegalSite(input) {
|
|
|
2792
2800
|
outDir,
|
|
2793
2801
|
};
|
|
2794
2802
|
}
|
|
2795
|
-
|
|
2796
|
-
mkdirSync(path.dirname(output.file), { recursive: true });
|
|
2797
|
-
writeFileSync(output.file, output.content);
|
|
2798
|
-
}
|
|
2803
|
+
publishLegalSiteFiles(outDir, outputs);
|
|
2799
2804
|
return {
|
|
2800
2805
|
outDir,
|
|
2801
2806
|
};
|
|
2802
2807
|
}
|
|
2803
2808
|
function createLegalSiteOutputs(legalDir, outDir) {
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
throw new Error(`legal-dir must be inside the project root: ${legalDir}`);
|
|
2808
|
-
}
|
|
2809
|
-
if (relativeOutDir.startsWith('..') || path.isAbsolute(relativeOutDir)) {
|
|
2810
|
-
throw new Error(`out-dir must be inside the project root: ${outDir}`);
|
|
2811
|
-
}
|
|
2812
|
-
const sourceRoot = toTemplatePath(relativeLegalDir || '.');
|
|
2809
|
+
assertLegalProjectPath('legal-dir', legalDir);
|
|
2810
|
+
assertLegalProjectPath('out-dir', outDir);
|
|
2811
|
+
const sourceRoot = toTemplatePath(path.relative(process.cwd(), legalDir) || '.');
|
|
2813
2812
|
const outputs = legalPageSlugs.map((slug) => {
|
|
2814
2813
|
const sourceFile = path.join(legalDir, `${slug}.html`);
|
|
2814
|
+
// existsSync and readFileSync follow a page symlink. Check the file
|
|
2815
|
+
// itself, not only the legal directory, immediately before reading it.
|
|
2816
|
+
assertLegalProjectPath('legal-dir', sourceFile);
|
|
2815
2817
|
if (!existsSync(sourceFile)) {
|
|
2816
2818
|
throw new Error(`Missing legal page source: ${sourceFile}`);
|
|
2817
2819
|
}
|
|
2820
|
+
assertLegalProjectPath('legal-dir', sourceFile);
|
|
2818
2821
|
return {
|
|
2819
2822
|
file: path.join(outDir, slug, 'index.html'),
|
|
2820
2823
|
content: normalizeLegalHtml(readFileSync(sourceFile, 'utf8'), sourceFile),
|
|
@@ -3347,7 +3350,11 @@ function createTargetCommandEnv(values, options = {}) {
|
|
|
3347
3350
|
});
|
|
3348
3351
|
const env = {
|
|
3349
3352
|
...process.env,
|
|
3350
|
-
|
|
3353
|
+
// Release provenance is recorded only by build commands. Smoke, doctor,
|
|
3354
|
+
// icons, and submission preflight must still run on an exported game tree.
|
|
3355
|
+
...createGameOwnedReleaseEnv(gameRoot, process.env, {
|
|
3356
|
+
requireSourceRevision: options.requireSourceRevision === true,
|
|
3357
|
+
}),
|
|
3351
3358
|
MPGD_PLATFORM_TARGETS_FILE: preparedTargetsFile,
|
|
3352
3359
|
...(targetConfigExtensionsFile === undefined
|
|
3353
3360
|
? {}
|
|
@@ -3450,10 +3457,9 @@ function resolveTargetConfigExtensionsFile(gameRoot, configuredFile) {
|
|
|
3450
3457
|
const gameOwnedFile = path.join(gameRoot, 'mpgd.target-config.json');
|
|
3451
3458
|
return existsSync(gameOwnedFile) ? gameOwnedFile : undefined;
|
|
3452
3459
|
}
|
|
3453
|
-
function createGameOwnedReleaseEnv(gameRoot, baseEnv) {
|
|
3460
|
+
function createGameOwnedReleaseEnv(gameRoot, baseEnv, options) {
|
|
3454
3461
|
const monetizationFiles = resolveGameOwnedMonetizationFiles(gameRoot, baseEnv);
|
|
3455
|
-
const sourceGitSha =
|
|
3456
|
-
?? readSourceGitSha(gameRoot);
|
|
3462
|
+
const sourceGitSha = resolveCommandSourceGitSha(gameRoot, baseEnv, options.requireSourceRevision);
|
|
3457
3463
|
const appVersion = readOptionalString(baseEnv.APP_VERSION)
|
|
3458
3464
|
?? readGamePackageVersion(gameRoot);
|
|
3459
3465
|
const notificationTopicsFile = readConfiguredPath(baseEnv.MPGD_NOTIFICATION_TOPICS_FILE);
|
|
@@ -3464,7 +3470,7 @@ function createGameOwnedReleaseEnv(gameRoot, baseEnv) {
|
|
|
3464
3470
|
...(notificationTopicsFile === undefined
|
|
3465
3471
|
? {}
|
|
3466
3472
|
: { MPGD_NOTIFICATION_TOPICS_FILE: path.resolve(gameRoot, notificationTopicsFile) }),
|
|
3467
|
-
MPGD_SOURCE_GIT_SHA: sourceGitSha,
|
|
3473
|
+
...(sourceGitSha === undefined ? {} : { MPGD_SOURCE_GIT_SHA: sourceGitSha }),
|
|
3468
3474
|
...(appVersion === undefined ? {} : { APP_VERSION: appVersion }),
|
|
3469
3475
|
};
|
|
3470
3476
|
}
|
|
@@ -3499,15 +3505,48 @@ function readConfiguredPath(value) {
|
|
|
3499
3505
|
const normalized = value?.trim();
|
|
3500
3506
|
return normalized === undefined || normalized.length === 0 ? undefined : normalized;
|
|
3501
3507
|
}
|
|
3508
|
+
function resolveCommandSourceGitSha(gameRoot, baseEnv, requireSourceRevision) {
|
|
3509
|
+
const configuredSourceGitSha = readOptionalString(baseEnv.MPGD_SOURCE_GIT_SHA);
|
|
3510
|
+
if (requireSourceRevision) {
|
|
3511
|
+
return configuredSourceGitSha === undefined
|
|
3512
|
+
? readSourceGitSha(gameRoot)
|
|
3513
|
+
: requireSourceGitSha(configuredSourceGitSha);
|
|
3514
|
+
}
|
|
3515
|
+
if (configuredSourceGitSha !== undefined) {
|
|
3516
|
+
return isSourceGitSha(configuredSourceGitSha) ? configuredSourceGitSha : undefined;
|
|
3517
|
+
}
|
|
3518
|
+
const detectedSourceGitSha = readGitHead(gameRoot);
|
|
3519
|
+
return detectedSourceGitSha !== undefined && isSourceGitSha(detectedSourceGitSha)
|
|
3520
|
+
? detectedSourceGitSha
|
|
3521
|
+
: undefined;
|
|
3522
|
+
}
|
|
3502
3523
|
function readSourceGitSha(gameRoot) {
|
|
3524
|
+
const head = readGitHead(gameRoot);
|
|
3525
|
+
if (head === undefined) {
|
|
3526
|
+
throw new Error(`Failed to resolve the game source Git revision for ${gameRoot}. `
|
|
3527
|
+
+ 'Set MPGD_SOURCE_GIT_SHA to its lowercase 40-character commit SHA.');
|
|
3528
|
+
}
|
|
3529
|
+
return requireSourceGitSha(head);
|
|
3530
|
+
}
|
|
3531
|
+
function readGitHead(gameRoot) {
|
|
3503
3532
|
const result = spawnSync('git', ['-C', gameRoot, 'rev-parse', 'HEAD'], {
|
|
3504
3533
|
encoding: 'utf8',
|
|
3505
3534
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
3506
3535
|
});
|
|
3507
3536
|
if (result.error !== undefined || result.status !== 0) {
|
|
3508
|
-
return
|
|
3537
|
+
return undefined;
|
|
3509
3538
|
}
|
|
3510
|
-
|
|
3539
|
+
const head = result.stdout.trim();
|
|
3540
|
+
return head.length === 0 ? undefined : head;
|
|
3541
|
+
}
|
|
3542
|
+
function requireSourceGitSha(value) {
|
|
3543
|
+
if (!isSourceGitSha(value)) {
|
|
3544
|
+
throw new Error('MPGD_SOURCE_GIT_SHA must be a lowercase 40-character game source SHA.');
|
|
3545
|
+
}
|
|
3546
|
+
return value;
|
|
3547
|
+
}
|
|
3548
|
+
function isSourceGitSha(value) {
|
|
3549
|
+
return /^[0-9a-f]{40}$/u.test(value);
|
|
3511
3550
|
}
|
|
3512
3551
|
function readGamePackageVersion(gameRoot) {
|
|
3513
3552
|
const packageFile = path.join(gameRoot, 'package.json');
|
package/dist/kit-upgrade.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFile as execFileCallback, spawnSync } from 'node:child_process';
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
3
|
-
import { existsSync, lstatSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { existsSync, lstatSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { promisify } from 'node:util';
|
|
6
6
|
import { compare, intersects, minVersion, satisfies, valid, validRange } from 'semver';
|
|
@@ -154,6 +154,9 @@ export function applyKitUpgrade(plan, runLockfileUpdate = updatePnpmLockfile) {
|
|
|
154
154
|
...plan.manifestDigests,
|
|
155
155
|
...plan.lockfileDigests,
|
|
156
156
|
})) {
|
|
157
|
+
// Re-check links before the digest read. readFileSync follows a symlink,
|
|
158
|
+
// so a same-bytes swap would otherwise look unchanged.
|
|
159
|
+
assertOwnedUpgradePath(upgradeWriteAnchor(plan, file), file);
|
|
157
160
|
const current = readFileSync(file, 'utf8');
|
|
158
161
|
if (digest(current) !== expected) {
|
|
159
162
|
throw new Error('File changed after upgrade planning: ' + file);
|
|
@@ -176,9 +179,11 @@ export function applyKitUpgrade(plan, runLockfileUpdate = updatePnpmLockfile) {
|
|
|
176
179
|
section[update.packageName] = update.next;
|
|
177
180
|
parsed[update.section] = section;
|
|
178
181
|
}
|
|
179
|
-
|
|
182
|
+
writeUpgradeFile(plan, manifest, stringifyLike(source, parsed));
|
|
180
183
|
}
|
|
181
184
|
for (const root of plan.workspaceRoots) {
|
|
185
|
+
const lockfile = path.join(root, 'pnpm-lock.yaml');
|
|
186
|
+
assertOwnedUpgradePath(upgradeWriteAnchor(plan, lockfile), lockfile);
|
|
182
187
|
runLockfileUpdate(root);
|
|
183
188
|
}
|
|
184
189
|
}
|
|
@@ -186,7 +191,7 @@ export function applyKitUpgrade(plan, runLockfileUpdate = updatePnpmLockfile) {
|
|
|
186
191
|
const restoreFailures = [];
|
|
187
192
|
for (const [file, original] of snapshots) {
|
|
188
193
|
try {
|
|
189
|
-
|
|
194
|
+
writeUpgradeFile(plan, file, original);
|
|
190
195
|
}
|
|
191
196
|
catch (restoreError) {
|
|
192
197
|
restoreFailures.push(file + ': ' + formatError(restoreError));
|
|
@@ -473,6 +478,100 @@ function stringifyLike(original, value) {
|
|
|
473
478
|
return JSON.stringify(value, null, indent).replaceAll('\n', newline)
|
|
474
479
|
+ (original.endsWith('\n') ? newline : '');
|
|
475
480
|
}
|
|
481
|
+
function upgradeWriteAnchor(plan, file) {
|
|
482
|
+
const resolved = path.resolve(file);
|
|
483
|
+
let anchor = plan.gameRoot;
|
|
484
|
+
while (!inside(anchor, resolved)) {
|
|
485
|
+
const parent = path.dirname(anchor);
|
|
486
|
+
if (parent === anchor) {
|
|
487
|
+
throw new Error('Refusing to write outside the planned upgrade directory: ' + file);
|
|
488
|
+
}
|
|
489
|
+
anchor = parent;
|
|
490
|
+
}
|
|
491
|
+
// In-game files used to return plan.gameRoot before this check. A game
|
|
492
|
+
// directory or parent swapped for a symlink after planning then skipped
|
|
493
|
+
// lstat/realpath, and assertOwnedUpgradePath only inspects children.
|
|
494
|
+
let anchorStat;
|
|
495
|
+
try {
|
|
496
|
+
anchorStat = lstatSync(anchor);
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
throw new Error('Refusing to write through a symbolic link: ' + anchor, { cause: error });
|
|
500
|
+
}
|
|
501
|
+
if (anchorStat.isSymbolicLink()) {
|
|
502
|
+
throw new Error('Refusing to write through a symbolic link: ' + anchor);
|
|
503
|
+
}
|
|
504
|
+
const anchorReal = realpathSync(anchor);
|
|
505
|
+
// Compare with the game root captured at planning time. A fresh realpath of
|
|
506
|
+
// both sides would follow a parent swapped for a symlink and look consistent.
|
|
507
|
+
if (!inside(anchorReal, plan.gameRoot)
|
|
508
|
+
&& path.resolve(anchorReal) !== path.resolve(plan.gameRoot)) {
|
|
509
|
+
throw new Error('Refusing to write through a symbolic link: ' + anchor);
|
|
510
|
+
}
|
|
511
|
+
return anchor;
|
|
512
|
+
}
|
|
513
|
+
function assertOwnedUpgradePath(anchor, file) {
|
|
514
|
+
const resolved = path.resolve(file);
|
|
515
|
+
if (!inside(anchor, resolved)) {
|
|
516
|
+
throw new Error('Refusing to write outside the planned upgrade directory: ' + file);
|
|
517
|
+
}
|
|
518
|
+
const relative = path.relative(anchor, resolved);
|
|
519
|
+
const parts = relative.split(path.sep).filter((part) => part !== '' && part !== '.');
|
|
520
|
+
let current = anchor;
|
|
521
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
522
|
+
const part = parts[index];
|
|
523
|
+
if (part === undefined) {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
current = path.join(current, part);
|
|
527
|
+
const isFinal = index === parts.length - 1;
|
|
528
|
+
let stat;
|
|
529
|
+
try {
|
|
530
|
+
stat = lstatSync(current);
|
|
531
|
+
}
|
|
532
|
+
catch (error) {
|
|
533
|
+
if (isErrno(error, 'ENOENT') && isFinal) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
throw new Error('Upgrade file disappeared before write: ' + file, { cause: error });
|
|
537
|
+
}
|
|
538
|
+
if (stat.isSymbolicLink()) {
|
|
539
|
+
throw new Error('Refusing to write through a symbolic link: ' + current);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (!inside(realpathSync(anchor), realpathSync(resolved))) {
|
|
543
|
+
throw new Error('Refusing to write through a symbolic link: ' + file);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function writeUpgradeFile(plan, file, source) {
|
|
547
|
+
const anchor = upgradeWriteAnchor(plan, file);
|
|
548
|
+
assertOwnedUpgradePath(anchor, file);
|
|
549
|
+
const temporary = `${file}.mpgd-${randomUUID()}.tmp`;
|
|
550
|
+
try {
|
|
551
|
+
let mode = 0o644;
|
|
552
|
+
try {
|
|
553
|
+
const stat = lstatSync(file);
|
|
554
|
+
if (stat.isSymbolicLink()) {
|
|
555
|
+
throw new Error('Refusing to write through a symbolic link: ' + file);
|
|
556
|
+
}
|
|
557
|
+
mode = stat.mode & 0o777;
|
|
558
|
+
}
|
|
559
|
+
catch (error) {
|
|
560
|
+
if (!isErrno(error, 'ENOENT')) {
|
|
561
|
+
throw error;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
writeFileSync(temporary, source, { flag: 'wx', mode });
|
|
565
|
+
assertOwnedUpgradePath(anchor, file);
|
|
566
|
+
renameSync(temporary, file);
|
|
567
|
+
}
|
|
568
|
+
finally {
|
|
569
|
+
rmSync(temporary, { force: true });
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function isErrno(error, code) {
|
|
573
|
+
return error !== null && typeof error === 'object' && 'code' in error && error.code === code;
|
|
574
|
+
}
|
|
476
575
|
function inside(root, candidate) {
|
|
477
576
|
const relative = path.relative(root, candidate);
|
|
478
577
|
return relative === '' || (!relative.startsWith('..' + path.sep) && relative !== '..'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface LegalSiteFile {
|
|
2
|
+
readonly file: string;
|
|
3
|
+
readonly content: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Legal-site paths are contained only after the nearest existing ancestor is
|
|
7
|
+
* canonicalized. A lexical `path.relative` check treats a symlinked `artifacts`
|
|
8
|
+
* directory as inside the project while later writes follow the link.
|
|
9
|
+
*/
|
|
10
|
+
export declare function assertLegalProjectPath(label: string, resolved: string): void;
|
|
11
|
+
/** Stage the site beside the destination, then publish with rename. */
|
|
12
|
+
export declare function publishLegalSiteFiles(outDir: string, outputs: readonly LegalSiteFile[]): void;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { lstatSync, mkdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Legal-site paths are contained only after the nearest existing ancestor is
|
|
6
|
+
* canonicalized. A lexical `path.relative` check treats a symlinked `artifacts`
|
|
7
|
+
* directory as inside the project while later writes follow the link.
|
|
8
|
+
*/
|
|
9
|
+
export function assertLegalProjectPath(label, resolved) {
|
|
10
|
+
const lexicalRoot = process.cwd();
|
|
11
|
+
const lexical = path.relative(lexicalRoot, resolved);
|
|
12
|
+
if (lexical.startsWith('..') || path.isAbsolute(lexical)) {
|
|
13
|
+
throw new Error(`${label} must be inside the project root: ${resolved}`);
|
|
14
|
+
}
|
|
15
|
+
assertNoLegalSymlink(lexicalRoot, resolved, label);
|
|
16
|
+
const canonicalRoot = realpathSync(lexicalRoot);
|
|
17
|
+
const canonical = realpathBestEffort(resolved);
|
|
18
|
+
const canonicalRelative = path.relative(canonicalRoot, canonical);
|
|
19
|
+
if (canonicalRelative.startsWith('..') || path.isAbsolute(canonicalRelative)) {
|
|
20
|
+
throw new Error(`${label} must be inside the project root: ${resolved}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Stage the site beside the destination, then publish with rename. */
|
|
24
|
+
export function publishLegalSiteFiles(outDir, outputs) {
|
|
25
|
+
assertLegalProjectPath('out-dir', outDir);
|
|
26
|
+
// A temp dir on the project root is a different filesystem when out-dir is a
|
|
27
|
+
// mount or sits under a bind-mounted artifacts directory. Rename then fails
|
|
28
|
+
// with EXDEV. Stage on the destination filesystem instead.
|
|
29
|
+
const staging = path.join(legalStagingParent(outDir), `.mpgd-legal-${randomUUID()}`);
|
|
30
|
+
let publishedDirectory = false;
|
|
31
|
+
try {
|
|
32
|
+
for (const output of outputs) {
|
|
33
|
+
const relative = path.relative(outDir, output.file);
|
|
34
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
35
|
+
throw new Error(`Legal site output escapes the output directory: ${output.file}`);
|
|
36
|
+
}
|
|
37
|
+
const staged = path.join(staging, relative);
|
|
38
|
+
mkdirSync(path.dirname(staged), { recursive: true });
|
|
39
|
+
writeFileSync(staged, output.content, { flag: 'wx' });
|
|
40
|
+
}
|
|
41
|
+
assertLegalProjectPath('out-dir', outDir);
|
|
42
|
+
let existing;
|
|
43
|
+
try {
|
|
44
|
+
existing = lstatSync(outDir);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (!isErrno(error, 'ENOENT')) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (existing?.isSymbolicLink() === true) {
|
|
52
|
+
throw new Error(`Refusing to write legal site output through a symbolic link: ${outDir}`);
|
|
53
|
+
}
|
|
54
|
+
if (existing === undefined) {
|
|
55
|
+
ensureLegalDirectory(path.dirname(outDir));
|
|
56
|
+
assertLegalProjectPath('out-dir', outDir);
|
|
57
|
+
renameSync(staging, outDir);
|
|
58
|
+
publishedDirectory = true;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!existing.isDirectory()) {
|
|
62
|
+
throw new Error(`Legal site output path is not a directory: ${outDir}`);
|
|
63
|
+
}
|
|
64
|
+
for (const output of outputs) {
|
|
65
|
+
assertNoLegalSymlink(process.cwd(), output.file, 'out-dir');
|
|
66
|
+
ensureLegalDirectory(path.dirname(output.file));
|
|
67
|
+
assertNoLegalSymlink(process.cwd(), output.file, 'out-dir');
|
|
68
|
+
renameSync(path.join(staging, path.relative(outDir, output.file)), output.file);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
if (!publishedDirectory) {
|
|
73
|
+
rmSync(staging, { recursive: true, force: true });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Parent for the staging directory. An existing out-dir may itself be a mount,
|
|
79
|
+
* so stage inside it. A missing out-dir is created on its nearest existing
|
|
80
|
+
* ancestor, which is the filesystem the later rename must stay on.
|
|
81
|
+
*/
|
|
82
|
+
function legalStagingParent(outDir) {
|
|
83
|
+
const existing = lstatIfPresent(outDir);
|
|
84
|
+
if (existing !== undefined) {
|
|
85
|
+
if (existing.isSymbolicLink()) {
|
|
86
|
+
throw new Error(`Refusing to write legal site output through a symbolic link: ${outDir}`);
|
|
87
|
+
}
|
|
88
|
+
if (!existing.isDirectory()) {
|
|
89
|
+
throw new Error(`Legal site output path is not a directory: ${outDir}`);
|
|
90
|
+
}
|
|
91
|
+
return outDir;
|
|
92
|
+
}
|
|
93
|
+
let current = path.dirname(outDir);
|
|
94
|
+
for (;;) {
|
|
95
|
+
const stat = lstatIfPresent(current);
|
|
96
|
+
if (stat !== undefined) {
|
|
97
|
+
if (stat.isSymbolicLink()) {
|
|
98
|
+
throw new Error(`Refusing to write legal site output through a symbolic link: ${current}`);
|
|
99
|
+
}
|
|
100
|
+
if (!stat.isDirectory()) {
|
|
101
|
+
throw new Error(`Legal site output path is not a directory: ${current}`);
|
|
102
|
+
}
|
|
103
|
+
return current;
|
|
104
|
+
}
|
|
105
|
+
const parent = path.dirname(current);
|
|
106
|
+
if (parent === current) {
|
|
107
|
+
throw new Error(`out-dir must be inside the project root: ${outDir}`);
|
|
108
|
+
}
|
|
109
|
+
current = parent;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function lstatIfPresent(target) {
|
|
113
|
+
try {
|
|
114
|
+
return lstatSync(target);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (isErrno(error, 'ENOENT')) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Resolve symlinks for the longest existing ancestor, keeping the remainder. */
|
|
124
|
+
function realpathBestEffort(target) {
|
|
125
|
+
// lstat-based existence stops the walk at dangling symlinks, so realpath
|
|
126
|
+
// fails closed on them instead of lexically skipping the link.
|
|
127
|
+
const exists = (candidate) => {
|
|
128
|
+
try {
|
|
129
|
+
lstatSync(candidate);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
let existing = target;
|
|
137
|
+
while (!exists(existing)) {
|
|
138
|
+
const parent = path.dirname(existing);
|
|
139
|
+
if (parent === existing) {
|
|
140
|
+
return existing;
|
|
141
|
+
}
|
|
142
|
+
existing = parent;
|
|
143
|
+
}
|
|
144
|
+
let real;
|
|
145
|
+
try {
|
|
146
|
+
real = realpathSync(existing);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
throw new Error(`Legal site path resolves through a broken symbolic link: ${target}`, {
|
|
150
|
+
cause: error,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return existing === target ? real : path.resolve(real, path.relative(existing, target));
|
|
154
|
+
}
|
|
155
|
+
function assertNoLegalSymlink(root, target, label) {
|
|
156
|
+
const relative = path.relative(root, target);
|
|
157
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
158
|
+
throw new Error(`${label} must be inside the project root: ${target}`);
|
|
159
|
+
}
|
|
160
|
+
const verb = label === 'legal-dir' ? 'read legal sources' : 'write legal site output';
|
|
161
|
+
let current = root;
|
|
162
|
+
for (const part of relative.split(path.sep)) {
|
|
163
|
+
if (part === '' || part === '.') {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
current = path.join(current, part);
|
|
167
|
+
let stat;
|
|
168
|
+
try {
|
|
169
|
+
stat = lstatSync(current);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (isErrno(error, 'ENOENT')) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
if (stat.isSymbolicLink()) {
|
|
178
|
+
throw new Error(`Refusing to ${verb} through a symbolic link: ${current}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function ensureLegalDirectory(directory) {
|
|
183
|
+
const root = process.cwd();
|
|
184
|
+
const relative = path.relative(root, directory);
|
|
185
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
186
|
+
throw new Error(`out-dir must be inside the project root: ${directory}`);
|
|
187
|
+
}
|
|
188
|
+
if (relative === '') {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
let current = root;
|
|
192
|
+
for (const part of relative.split(path.sep)) {
|
|
193
|
+
if (part === '' || part === '.') {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
current = path.join(current, part);
|
|
197
|
+
let stat;
|
|
198
|
+
try {
|
|
199
|
+
stat = lstatSync(current);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
if (!isErrno(error, 'ENOENT')) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
mkdirSync(current);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
catch (mkdirError) {
|
|
210
|
+
if (!isErrno(mkdirError, 'EEXIST')) {
|
|
211
|
+
throw mkdirError;
|
|
212
|
+
}
|
|
213
|
+
stat = lstatSync(current);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (stat.isSymbolicLink()) {
|
|
217
|
+
throw new Error(`Refusing to write legal site output through a symbolic link: ${current}`);
|
|
218
|
+
}
|
|
219
|
+
if (!stat.isDirectory()) {
|
|
220
|
+
throw new Error(`Legal site output path is not a directory: ${current}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function isErrno(error, code) {
|
|
225
|
+
return error !== null && typeof error === 'object' && 'code' in error && error.code === code;
|
|
226
|
+
}
|
|
@@ -9502,9 +9502,21 @@ var assertReleaseManifestStructure = /* @__PURE__ */ (() => {
|
|
|
9502
9502
|
};
|
|
9503
9503
|
})();
|
|
9504
9504
|
var fullGitShaPattern = /^[0-9a-f]{40}$/u;
|
|
9505
|
+
var sha256DigestPattern = /^[0-9a-f]{64}$/u;
|
|
9505
9506
|
function assertReleaseManifest(input) {
|
|
9506
9507
|
const manifest = assertReleaseManifestStructure(input);
|
|
9508
|
+
if (!fullGitShaPattern.test(manifest.gitSha)) {
|
|
9509
|
+
throw new TypeError("Release manifest gitSha must be a lowercase 40-character SHA.");
|
|
9510
|
+
}
|
|
9511
|
+
if (!fullGitShaPattern.test(manifest.kitGitSha)) {
|
|
9512
|
+
throw new TypeError("Release manifest kitGitSha must be a lowercase 40-character SHA.");
|
|
9513
|
+
}
|
|
9507
9514
|
for (const [target2, entry] of Object.entries(manifest.targets)) {
|
|
9515
|
+
assertSha256Digest(entry.effectiveConfig.digest, `Release manifest ${target2} effectiveConfig.digest`);
|
|
9516
|
+
assertSha256Digest(entry.iconManifest.digest, `Release manifest ${target2} iconManifest.digest`);
|
|
9517
|
+
assertSha256Digest(entry.iconManifest.sourceSha256, `Release manifest ${target2} iconManifest.sourceSha256`);
|
|
9518
|
+
assertSha256Digest(entry.iconManifest.sharedConfigSha256, `Release manifest ${target2} iconManifest.sharedConfigSha256`);
|
|
9519
|
+
assertSha256Digest(entry.iconManifest.renderConfigSha256, `Release manifest ${target2} iconManifest.renderConfigSha256`);
|
|
9508
9520
|
const delivery = entry.nativeDelivery;
|
|
9509
9521
|
if (delivery === void 0) {
|
|
9510
9522
|
continue;
|
|
@@ -9519,9 +9531,6 @@ function assertReleaseManifest(input) {
|
|
|
9519
9531
|
throw new TypeError(`Release manifest production native delivery is unsigned: ${target2}.`);
|
|
9520
9532
|
}
|
|
9521
9533
|
}
|
|
9522
|
-
if (!fullGitShaPattern.test(manifest.kitGitSha)) {
|
|
9523
|
-
throw new TypeError("Release manifest kitGitSha must be a lowercase 40-character SHA.");
|
|
9524
|
-
}
|
|
9525
9534
|
if (manifest.releaseIdentity !== void 0) {
|
|
9526
9535
|
const releaseIdentity = createMpgdReleaseIdentity({
|
|
9527
9536
|
gameVersion: manifest.releaseIdentity.gameVersion,
|
|
@@ -9543,6 +9552,11 @@ function assertReleaseManifest(input) {
|
|
|
9543
9552
|
}
|
|
9544
9553
|
return manifest;
|
|
9545
9554
|
}
|
|
9555
|
+
function assertSha256Digest(value, label) {
|
|
9556
|
+
if (!sha256DigestPattern.test(value)) {
|
|
9557
|
+
throw new TypeError(`${label} must be a lowercase 64-character SHA-256 digest.`);
|
|
9558
|
+
}
|
|
9559
|
+
}
|
|
9546
9560
|
|
|
9547
9561
|
// node_modules/.cache/mpgd-native-build/tools/target/release-manifest-lock.js
|
|
9548
9562
|
import { randomUUID } from "node:crypto";
|
|
@@ -9641,7 +9655,7 @@ function canRecoverLock(lockFile) {
|
|
|
9641
9655
|
// node_modules/.cache/mpgd-native-build/tools/target/generate-release-manifest.js
|
|
9642
9656
|
var __typia_transform__accessExpressionAsString6 = _accessExpressionAsString_110._accessExpressionAsString;
|
|
9643
9657
|
var assertProductCatalog = /* @__PURE__ */ (() => {
|
|
9644
|
-
const _ae0 = '({ readonly type: "currency"; readonly currency: string & MinLength<1>; readonly amount:
|
|
9658
|
+
const _ae0 = '({ readonly type: "currency"; readonly currency: string & MinLength<1>; readonly amount: PositiveLedgerAmount; } | { readonly type: "entitlement"; readonly entitlement: string; } | { readonly type: "resource"; readonly resource: string & MinLength<1>; readonly amount: number & ExclusiveMinimum<0> & Maximum<1.7976931348623157e+308>; })';
|
|
9645
9659
|
const _ao0 = (input, _path, _exceptionable = true) => ("string" === typeof input.version || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9646
9660
|
method: "typia.createAssert",
|
|
9647
9661
|
path: _path + ".version",
|
|
@@ -9739,10 +9753,25 @@ var assertProductCatalog = /* @__PURE__ */ (() => {
|
|
|
9739
9753
|
path: _path + ".currency",
|
|
9740
9754
|
expected: "(string & MinLength<1>)",
|
|
9741
9755
|
value: input.currency
|
|
9742
|
-
}, _errorFactory)) && ("number" === typeof input.amount || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9756
|
+
}, _errorFactory)) && ("number" === typeof input.amount && (1 <= input.amount || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9743
9757
|
method: "typia.createAssert",
|
|
9744
9758
|
path: _path + ".amount",
|
|
9745
|
-
expected: "number",
|
|
9759
|
+
expected: "number & Minimum<1>",
|
|
9760
|
+
value: input.amount
|
|
9761
|
+
}, _errorFactory)) && (input.amount <= 9007199254740991 || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9762
|
+
method: "typia.createAssert",
|
|
9763
|
+
path: _path + ".amount",
|
|
9764
|
+
expected: "number & Maximum<9007199254740991>",
|
|
9765
|
+
value: input.amount
|
|
9766
|
+
}, _errorFactory)) && (input.amount % 1 === 0 || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9767
|
+
method: "typia.createAssert",
|
|
9768
|
+
path: _path + ".amount",
|
|
9769
|
+
expected: "number & MultipleOf<1>",
|
|
9770
|
+
value: input.amount
|
|
9771
|
+
}, _errorFactory)) || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9772
|
+
method: "typia.createAssert",
|
|
9773
|
+
path: _path + ".amount",
|
|
9774
|
+
expected: "(number & Minimum<1> & Maximum<9007199254740991> & MultipleOf<1>)",
|
|
9746
9775
|
value: input.amount
|
|
9747
9776
|
}, _errorFactory));
|
|
9748
9777
|
const _ao3 = (input, _path, _exceptionable = true) => ("entitlement" === input.type || _assertGuard_19._assertGuard(_exceptionable, {
|
|
@@ -9815,7 +9844,7 @@ var assertProductCatalog = /* @__PURE__ */ (() => {
|
|
|
9815
9844
|
})();
|
|
9816
9845
|
const _io0 = (input) => "string" === typeof input.version && (void 0 === input.currencies || Array.isArray(input.currencies) && (1 <= input.currencies.length && input.currencies.every((elem) => "string" === typeof elem && 1 <= elem.length))) && (Array.isArray(input.products) && input.products.every((elem) => "object" === typeof elem && null !== elem && _io1(elem)));
|
|
9817
9846
|
const _io1 = (input) => "string" === typeof input.id && ("consumable" === input.type || "non_consumable" === input.type || "subscription" === input.type) && ("object" === typeof input.grant && null !== input.grant && _iu0(input.grant)) && ("object" === typeof input.platformProductIds && null !== input.platformProductIds && false === Array.isArray(input.platformProductIds) && _io5(input.platformProductIds));
|
|
9818
|
-
const _io2 = (input) => "currency" === input.type && ("string" === typeof input.currency && 1 <= input.currency.length) && "number" === typeof input.amount;
|
|
9847
|
+
const _io2 = (input) => "currency" === input.type && ("string" === typeof input.currency && 1 <= input.currency.length) && ("number" === typeof input.amount && (1 <= input.amount && input.amount <= 9007199254740991 && input.amount % 1 === 0));
|
|
9819
9848
|
const _io3 = (input) => "entitlement" === input.type && "string" === typeof input.entitlement;
|
|
9820
9849
|
const _io4 = (input) => "resource" === input.type && ("string" === typeof input.resource && 1 <= input.resource.length) && ("number" === typeof input.amount && (0 < input.amount && input.amount <= 17976931348623157e292));
|
|
9821
9850
|
const _io5 = (input) => Object.keys(input).every((key) => {
|
|
@@ -9855,16 +9884,31 @@ var assertProductCatalog = /* @__PURE__ */ (() => {
|
|
|
9855
9884
|
};
|
|
9856
9885
|
})();
|
|
9857
9886
|
var assertAdPlacements = /* @__PURE__ */ (() => {
|
|
9858
|
-
const _ip0 = (input) => "number" === typeof input["amount"];
|
|
9887
|
+
const _ip0 = (input) => "number" === typeof input["amount"] && (1 <= input["amount"] && input["amount"] <= 9007199254740991 && input["amount"] % 1 === 0);
|
|
9859
9888
|
const _ae0 = '(AdPlacementEntryBase & { readonly type: "banner" | "interstitial"; readonly reward?: never; } | AdPlacementEntryBase & { readonly type: "rewarded"; readonly reward?: AdReward; })';
|
|
9860
|
-
const _ae1 = '(undefined | { readonly type: "continue"; readonly amount:
|
|
9861
|
-
const _ap0 = (input, _path, _exceptionable = true) => "number" === typeof input["amount"] || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9889
|
+
const _ae1 = '(undefined | { readonly type: "continue"; readonly amount: PositiveLedgerAmount; } | { readonly type: "currency"; readonly amount: PositiveLedgerAmount; readonly currency: string & MinLength<1>; })';
|
|
9890
|
+
const _ap0 = (input, _path, _exceptionable = true) => "number" === typeof input["amount"] && (1 <= input["amount"] || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9862
9891
|
method: "typia.createAssert",
|
|
9863
9892
|
path: _path + ".amount",
|
|
9864
|
-
expected: "number",
|
|
9893
|
+
expected: "number & Minimum<1>",
|
|
9894
|
+
value: input["amount"]
|
|
9895
|
+
}, _errorFactory)) && (input["amount"] <= 9007199254740991 || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9896
|
+
method: "typia.createAssert",
|
|
9897
|
+
path: _path + ".amount",
|
|
9898
|
+
expected: "number & Maximum<9007199254740991>",
|
|
9899
|
+
value: input["amount"]
|
|
9900
|
+
}, _errorFactory)) && (input["amount"] % 1 === 0 || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9901
|
+
method: "typia.createAssert",
|
|
9902
|
+
path: _path + ".amount",
|
|
9903
|
+
expected: "number & MultipleOf<1>",
|
|
9904
|
+
value: input["amount"]
|
|
9905
|
+
}, _errorFactory)) || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9906
|
+
method: "typia.createAssert",
|
|
9907
|
+
path: _path + ".amount",
|
|
9908
|
+
expected: "(number & Minimum<1> & Maximum<9007199254740991> & MultipleOf<1>)",
|
|
9865
9909
|
value: input["amount"]
|
|
9866
9910
|
}, _errorFactory);
|
|
9867
|
-
const _ae2 = '({ readonly type: "continue"; readonly amount:
|
|
9911
|
+
const _ae2 = '({ readonly type: "continue"; readonly amount: PositiveLedgerAmount; } | { readonly type: "currency"; readonly amount: PositiveLedgerAmount; readonly currency: string & MinLength<1>; })';
|
|
9868
9912
|
const _ao0 = (input, _path, _exceptionable = true) => ("string" === typeof input.version || _assertGuard_19._assertGuard(_exceptionable, {
|
|
9869
9913
|
method: "typia.createAssert",
|
|
9870
9914
|
path: _path + ".version",
|
|
@@ -10373,9 +10417,47 @@ function readSdkMajor(envValue, metadataValue) {
|
|
|
10373
10417
|
function getSourceGitSha(kitGitSha) {
|
|
10374
10418
|
const configuredGitSha = readOptionalString2(process.env.MPGD_SOURCE_GIT_SHA);
|
|
10375
10419
|
if (configuredGitSha !== void 0) {
|
|
10376
|
-
return configuredGitSha;
|
|
10420
|
+
return requireFullGitSha(configuredGitSha, "MPGD_SOURCE_GIT_SHA");
|
|
10377
10421
|
}
|
|
10378
|
-
|
|
10422
|
+
if (isInRepoKitBuild()) {
|
|
10423
|
+
return inRepoKitSourceGitSha(kitGitSha);
|
|
10424
|
+
}
|
|
10425
|
+
throw new Error("MPGD_SOURCE_GIT_SHA is required for a downstream game build and must be a lowercase 40-character SHA. Refusing to record the kit revision as the game revision.");
|
|
10426
|
+
}
|
|
10427
|
+
function inRepoKitSourceGitSha(kitGitSha) {
|
|
10428
|
+
return requireFullGitSha(kitGitSha, "in-repo kit source Git SHA");
|
|
10429
|
+
}
|
|
10430
|
+
function isInRepoKitBuild() {
|
|
10431
|
+
if (process.env.MPGD_NATIVE_PACKAGED_BUILD === "1") {
|
|
10432
|
+
return false;
|
|
10433
|
+
}
|
|
10434
|
+
const targetsFile = readOptionalString2(process.env.MPGD_PLATFORM_TARGETS_FILE);
|
|
10435
|
+
if (targetsFile === void 0) {
|
|
10436
|
+
return true;
|
|
10437
|
+
}
|
|
10438
|
+
return isInsideDirectory(resolveKitRoot(), targetsFile);
|
|
10439
|
+
}
|
|
10440
|
+
function isInsideDirectory(root, candidate) {
|
|
10441
|
+
let resolvedRoot;
|
|
10442
|
+
try {
|
|
10443
|
+
resolvedRoot = realpathSync6(root);
|
|
10444
|
+
} catch {
|
|
10445
|
+
return false;
|
|
10446
|
+
}
|
|
10447
|
+
const resolvedCandidate = resolve12(candidate);
|
|
10448
|
+
let comparable = resolvedCandidate;
|
|
10449
|
+
try {
|
|
10450
|
+
comparable = realpathSync6(resolvedCandidate);
|
|
10451
|
+
} catch {
|
|
10452
|
+
}
|
|
10453
|
+
const rel = relative9(resolvedRoot, comparable);
|
|
10454
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute8(rel);
|
|
10455
|
+
}
|
|
10456
|
+
function requireFullGitSha(value, label) {
|
|
10457
|
+
if (!/^[0-9a-f]{40}$/u.test(value)) {
|
|
10458
|
+
throw new Error(`${label} must be a lowercase 40-character SHA.`);
|
|
10459
|
+
}
|
|
10460
|
+
return value;
|
|
10379
10461
|
}
|
|
10380
10462
|
function resolveKitGitSha() {
|
|
10381
10463
|
if (process.env.MPGD_NATIVE_PACKAGED_BUILD === "1") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/cli",
|
|
3
|
-
"version": "0.54.
|
|
3
|
+
"version": "0.54.1",
|
|
4
4
|
"description": "Gunshi CLI for mpgd-kit starter generation and target workflow orchestration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"parse5": "7.3.0",
|
|
71
71
|
"postcss": "8.5.28",
|
|
72
72
|
"postcss-value-parser": "4.2.0",
|
|
73
|
-
"@mpgd/catalog": "0.10.
|
|
74
|
-
"@mpgd/platform": "0.27.
|
|
73
|
+
"@mpgd/catalog": "0.10.6",
|
|
74
|
+
"@mpgd/platform": "0.27.1",
|
|
75
75
|
"@mpgd/phaser-assets": "0.9.1",
|
|
76
|
-
"@mpgd/target-config": "0.23.
|
|
76
|
+
"@mpgd/target-config": "0.23.6"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@types/node": "^24.0.0",
|
|
@@ -81,18 +81,18 @@
|
|
|
81
81
|
"@types/yauzl": "3.4.0",
|
|
82
82
|
"ttsc": "0.32.1",
|
|
83
83
|
"typescript": "7.0.2",
|
|
84
|
-
"@mpgd/adapter-
|
|
85
|
-
"@mpgd/adapter-
|
|
86
|
-
"@mpgd/adapter-
|
|
87
|
-
"@mpgd/adapter-verse8": "0.7.
|
|
88
|
-
"@mpgd/bridge": "0.14.
|
|
89
|
-
"@mpgd/
|
|
90
|
-
"@mpgd/
|
|
91
|
-
"@mpgd/capacitor-play-billing": "0.3.
|
|
92
|
-
"@mpgd/capacitor-storekit": "0.3.
|
|
93
|
-
"@mpgd/game-
|
|
94
|
-
"@mpgd/
|
|
95
|
-
"@mpgd/
|
|
84
|
+
"@mpgd/adapter-browser": "0.11.6",
|
|
85
|
+
"@mpgd/adapter-capacitor": "0.12.2",
|
|
86
|
+
"@mpgd/adapter-ait": "0.20.2",
|
|
87
|
+
"@mpgd/adapter-verse8": "0.7.6",
|
|
88
|
+
"@mpgd/bridge": "0.14.3",
|
|
89
|
+
"@mpgd/analytics": "0.4.15",
|
|
90
|
+
"@mpgd/adapter-devvit": "0.13.4",
|
|
91
|
+
"@mpgd/capacitor-play-billing": "0.3.6",
|
|
92
|
+
"@mpgd/capacitor-storekit": "0.3.6",
|
|
93
|
+
"@mpgd/game-runtime": "0.7.6",
|
|
94
|
+
"@mpgd/game-services": "0.27.1",
|
|
95
|
+
"@mpgd/i18n": "0.6.20",
|
|
96
96
|
"@mpgd/lite-shell": "0.1.0"
|
|
97
97
|
},
|
|
98
98
|
"main": "./dist/index.js",
|