@mpgd/cli 0.59.0 → 0.61.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/capacitor-shell-starter.d.ts +24 -0
- package/dist/capacitor-shell-starter.js +100 -8
- package/dist/crash-reporting-starter.d.ts +99 -0
- package/dist/crash-reporting-starter.js +271 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +221 -14
- package/dist/ios-ipa-inspection.js +120 -1
- package/dist/native-build-info.json +2 -2
- package/dist/native-build-target.js +1617 -1185
- package/dist/native-deploy-run.d.ts +6 -0
- package/dist/native-deploy-run.js +19 -1
- package/dist/native-deploy-submission.d.ts +20 -1
- package/dist/native-deploy-submission.js +94 -7
- package/dist/native-shell-ios-push-files.d.ts +9 -0
- package/dist/native-shell-ios-push-files.js +65 -0
- package/dist/native-shell-store-policy.d.ts +109 -0
- package/dist/native-shell-store-policy.js +553 -7
- package/dist/play-internal-submission.d.ts +40 -4
- package/dist/play-internal-submission.js +215 -48
- package/dist/play-publisher-port.d.ts +26 -1
- package/dist/play-release-options.d.ts +97 -0
- package/dist/play-release-options.js +307 -0
- package/dist/play-release-promote.d.ts +59 -0
- package/dist/play-release-promote.js +235 -0
- package/dist/play-release-rollout.d.ts +57 -0
- package/dist/play-release-rollout.js +237 -0
- package/dist/play-sdk-adapter.js +26 -3
- package/dist/release-state.d.ts +6 -0
- package/dist/release-state.js +8 -0
- package/package.json +17 -17
- package/templates/phaser-game/apps/target-ait/package.json +2 -2
- package/templates/phaser-game/package.json +1 -1
- package/templates/phaser-game/vite.runtime-target-config.ts +4 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// node_modules/.cache/mpgd-native-build/tools/target/build-target.js
|
|
2
2
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
3
|
-
import { cpSync as cpSync4, existsSync as
|
|
3
|
+
import { cpSync as cpSync4, existsSync as existsSync27, lstatSync as lstatSync15, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync5, readdirSync as readdirSync9, readFileSync as readFileSync26, realpathSync as realpathSync10, rmSync as rmSync12, statSync as statSync7, writeFileSync as writeFileSync18 } from "node:fs";
|
|
4
4
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
5
5
|
import { basename as basename5, dirname as dirname12, join as join16, relative as relative13, resolve as resolve18 } from "node:path";
|
|
6
6
|
import { loadEnv } from "vite";
|
|
@@ -43,8 +43,8 @@ var knownMediaTypes = /* @__PURE__ */ new Map([
|
|
|
43
43
|
["aac", { mediaType: "audio/aac", defaultMethod: "store" }],
|
|
44
44
|
["flac", { mediaType: "audio/flac", defaultMethod: "store" }]
|
|
45
45
|
]);
|
|
46
|
-
function phaserPackMediaTypeForPath(
|
|
47
|
-
const extension =
|
|
46
|
+
function phaserPackMediaTypeForPath(path12) {
|
|
47
|
+
const extension = path12.slice(path12.lastIndexOf(".") + 1).toLowerCase();
|
|
48
48
|
return knownMediaTypes.get(extension) ?? null;
|
|
49
49
|
}
|
|
50
50
|
function parsePhaserPackEntryPath(input) {
|
|
@@ -677,9 +677,9 @@ var manifestFileName = "asset-pack-delivery.json";
|
|
|
677
677
|
var stagingSequence = 0;
|
|
678
678
|
var sha256Of = (data) => createHash("sha256").update(data).digest("hex");
|
|
679
679
|
function realpathBestEffort(target2) {
|
|
680
|
-
const exists = (
|
|
680
|
+
const exists = (path12) => {
|
|
681
681
|
try {
|
|
682
|
-
lstatSync(
|
|
682
|
+
lstatSync(path12);
|
|
683
683
|
return true;
|
|
684
684
|
} catch {
|
|
685
685
|
return false;
|
|
@@ -915,11 +915,11 @@ function buildAssetPacks(options) {
|
|
|
915
915
|
`, "utf8");
|
|
916
916
|
validatePhaserPackDeliveryManifest(JSON.parse(manifestBytes.toString("utf8")));
|
|
917
917
|
const outputRecords = [];
|
|
918
|
-
for (const [
|
|
919
|
-
const target2 = join(outPath,
|
|
918
|
+
for (const [path12, data] of outputs) {
|
|
919
|
+
const target2 = join(outPath, path12);
|
|
920
920
|
if (!existsSync(target2)) {
|
|
921
921
|
outputRecords.push({
|
|
922
|
-
path:
|
|
922
|
+
path: path12,
|
|
923
923
|
bytes: data.length,
|
|
924
924
|
sha256: sha256Of(data),
|
|
925
925
|
action: "written",
|
|
@@ -931,13 +931,13 @@ function buildAssetPacks(options) {
|
|
|
931
931
|
try {
|
|
932
932
|
existing = readFileSync(target2);
|
|
933
933
|
} catch {
|
|
934
|
-
throw new Error(`Output path is not a readable file: ${
|
|
934
|
+
throw new Error(`Output path is not a readable file: ${path12}`);
|
|
935
935
|
}
|
|
936
936
|
if (!existing.equals(data)) {
|
|
937
|
-
throw new Error(`Output path already holds different bytes (immutable conflict): ${
|
|
937
|
+
throw new Error(`Output path already holds different bytes (immutable conflict): ${path12}. Change the pack content or revision, or build into a new directory.`);
|
|
938
938
|
}
|
|
939
939
|
outputRecords.push({
|
|
940
|
-
path:
|
|
940
|
+
path: path12,
|
|
941
941
|
bytes: data.length,
|
|
942
942
|
sha256: sha256Of(data),
|
|
943
943
|
action: "unchanged",
|
|
@@ -1566,7 +1566,7 @@ var positiveIntegerOption = (failures, name, value) => {
|
|
|
1566
1566
|
};
|
|
1567
1567
|
var VerifyDeadlineError = class extends Error {
|
|
1568
1568
|
};
|
|
1569
|
-
var streamSha256 = async (
|
|
1569
|
+
var streamSha256 = async (path12, handle, hasher, deadline) => {
|
|
1570
1570
|
let bytes = 0;
|
|
1571
1571
|
const stream = handle.createReadStream({
|
|
1572
1572
|
highWaterMark: STREAM_CHUNK_BYTES,
|
|
@@ -1586,7 +1586,7 @@ var streamSha256 = async (path10, handle, hasher, deadline) => {
|
|
|
1586
1586
|
if (error instanceof VerifyDeadlineError) {
|
|
1587
1587
|
throw error;
|
|
1588
1588
|
}
|
|
1589
|
-
throw new Error(`Could not read ${
|
|
1589
|
+
throw new Error(`Could not read ${path12}: ${errorText(error)}`);
|
|
1590
1590
|
} finally {
|
|
1591
1591
|
clearTimeout(timer);
|
|
1592
1592
|
}
|
|
@@ -1802,20 +1802,20 @@ var readManifestCapped = async (manifestPath, cap, deadline) => {
|
|
|
1802
1802
|
}
|
|
1803
1803
|
return Buffer.concat(chunks);
|
|
1804
1804
|
};
|
|
1805
|
-
var readExact = async (
|
|
1805
|
+
var readExact = async (path12, handle, bytes, deadline) => {
|
|
1806
1806
|
const buffer = Buffer.alloc(bytes);
|
|
1807
1807
|
let received = 0;
|
|
1808
1808
|
while (received < bytes) {
|
|
1809
1809
|
const { bytesRead } = await deadline.race(handle.read(buffer, received, bytes - received, received));
|
|
1810
1810
|
if (bytesRead === 0) {
|
|
1811
|
-
throw new Error(`Archive shrank while being read: ${
|
|
1811
|
+
throw new Error(`Archive shrank while being read: ${path12}`);
|
|
1812
1812
|
}
|
|
1813
1813
|
received += bytesRead;
|
|
1814
1814
|
}
|
|
1815
1815
|
const tail = Buffer.alloc(1);
|
|
1816
1816
|
const { bytesRead: tailBytes } = await deadline.race(handle.read(tail, 0, 1, bytes));
|
|
1817
1817
|
if (tailBytes !== 0) {
|
|
1818
|
-
throw new Error(`Archive grew while being read: ${
|
|
1818
|
+
throw new Error(`Archive grew while being read: ${path12}`);
|
|
1819
1819
|
}
|
|
1820
1820
|
return buffer;
|
|
1821
1821
|
};
|
|
@@ -1882,7 +1882,7 @@ async function verifyAssetPackDelivery(options) {
|
|
|
1882
1882
|
positiveIntegerOption(failures, "maxEntryBytes", maxEntryBytes),
|
|
1883
1883
|
positiveIntegerOption(failures, "maxExpandedBytes", maxExpandedBytes),
|
|
1884
1884
|
...Object.entries(hostLimits ?? {}).map(([name, value]) => positiveIntegerOption(failures, `--${name.replace(/[A-Z]/gu, (letter) => `-${letter.toLowerCase()}`)}`, value))
|
|
1885
|
-
].every((
|
|
1885
|
+
].every((valid3) => valid3);
|
|
1886
1886
|
const startedAt = performance.now();
|
|
1887
1887
|
const deadlineBreached = () => {
|
|
1888
1888
|
if (performance.now() - startedAt <= verifyTimeoutMs) {
|
|
@@ -2269,9 +2269,9 @@ var assetPackTargetNamespace = "mpgd-asset-packs";
|
|
|
2269
2269
|
var assetPackTargetManifestName = "asset-pack-delivery.json";
|
|
2270
2270
|
var assetPackTargetPolicyName = "target-policy.json";
|
|
2271
2271
|
var digest = (bytes) => createHash3("sha256").update(bytes).digest("hex");
|
|
2272
|
-
async function fileDigest(
|
|
2272
|
+
async function fileDigest(path12) {
|
|
2273
2273
|
const hash = createHash3("sha256");
|
|
2274
|
-
for await (const chunk of createReadStream(
|
|
2274
|
+
for await (const chunk of createReadStream(path12)) {
|
|
2275
2275
|
hash.update(chunk);
|
|
2276
2276
|
}
|
|
2277
2277
|
return hash.digest("hex");
|
|
@@ -2280,8 +2280,8 @@ function inside(parent, child) {
|
|
|
2280
2280
|
const step = relative3(parent, child);
|
|
2281
2281
|
return step === "" || !isAbsolute3(step) && step !== ".." && !step.startsWith(`..${sep3}`);
|
|
2282
2282
|
}
|
|
2283
|
-
async function noSymlink(
|
|
2284
|
-
let current = resolve3(
|
|
2283
|
+
async function noSymlink(path12) {
|
|
2284
|
+
let current = resolve3(path12);
|
|
2285
2285
|
while (true) {
|
|
2286
2286
|
const stat2 = await lstat2(current).catch((error) => {
|
|
2287
2287
|
if (error.code === "ENOENT") {
|
|
@@ -2292,7 +2292,7 @@ async function noSymlink(path10) {
|
|
|
2292
2292
|
if (stat2?.isSymbolicLink()) {
|
|
2293
2293
|
const systemAlias = process.platform === "darwin" && (current === "/var" && await realpath2(current) === "/private/var" || current === "/tmp" && await realpath2(current) === "/private/tmp");
|
|
2294
2294
|
if (!systemAlias) {
|
|
2295
|
-
throw new Error(`Asset target path must not traverse a symbolic link: ${
|
|
2295
|
+
throw new Error(`Asset target path must not traverse a symbolic link: ${path12}`);
|
|
2296
2296
|
}
|
|
2297
2297
|
}
|
|
2298
2298
|
const parent = dirname2(current);
|
|
@@ -2302,12 +2302,12 @@ async function noSymlink(path10) {
|
|
|
2302
2302
|
current = parent;
|
|
2303
2303
|
}
|
|
2304
2304
|
}
|
|
2305
|
-
async function canonicalOutput(
|
|
2306
|
-
let ancestor =
|
|
2305
|
+
async function canonicalOutput(path12) {
|
|
2306
|
+
let ancestor = path12;
|
|
2307
2307
|
while (true) {
|
|
2308
2308
|
try {
|
|
2309
2309
|
const canonical = await realpath2(ancestor);
|
|
2310
|
-
return resolve3(canonical, relative3(ancestor,
|
|
2310
|
+
return resolve3(canonical, relative3(ancestor, path12));
|
|
2311
2311
|
} catch (error) {
|
|
2312
2312
|
if (error.code !== "ENOENT") {
|
|
2313
2313
|
throw error;
|
|
@@ -2459,18 +2459,18 @@ async function assertAssetPackTargetArtifact(report, artifactRoot, namespacePath
|
|
|
2459
2459
|
while (pending.length) {
|
|
2460
2460
|
const directory = pending.pop();
|
|
2461
2461
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
2462
|
-
const
|
|
2462
|
+
const path12 = join3(directory, entry.name);
|
|
2463
2463
|
if (++count > 1e5 || entry.isSymbolicLink()) {
|
|
2464
2464
|
throw new Error("Asset artifact inventory exceeds its limit or contains a symbolic link");
|
|
2465
2465
|
}
|
|
2466
2466
|
if (entry.isDirectory()) {
|
|
2467
|
-
pending.push(
|
|
2467
|
+
pending.push(path12);
|
|
2468
2468
|
} else if (entry.isFile()) {
|
|
2469
|
-
if (inside(namespace,
|
|
2470
|
-
namespaceBytes += (await lstat2(
|
|
2469
|
+
if (inside(namespace, path12)) {
|
|
2470
|
+
namespaceBytes += (await lstat2(path12)).size;
|
|
2471
2471
|
}
|
|
2472
|
-
if (remoteHashes.has(await fileDigest(
|
|
2473
|
-
throw new Error(`Remote-only asset object is present in the packaged artifact: ${relative3(root,
|
|
2472
|
+
if (remoteHashes.has(await fileDigest(path12))) {
|
|
2473
|
+
throw new Error(`Remote-only asset object is present in the packaged artifact: ${relative3(root, path12)}`);
|
|
2474
2474
|
}
|
|
2475
2475
|
} else {
|
|
2476
2476
|
throw new Error("Asset artifact contains a non-regular entry");
|
|
@@ -2512,14 +2512,14 @@ function expectedNamespace(artifact, namespace) {
|
|
|
2512
2512
|
}
|
|
2513
2513
|
}
|
|
2514
2514
|
async function assertAssetPackNativeArtifact(report, artifact) {
|
|
2515
|
-
const
|
|
2516
|
-
const stat2 = await lstat3(
|
|
2515
|
+
const path12 = resolve4(artifact);
|
|
2516
|
+
const stat2 = await lstat3(path12);
|
|
2517
2517
|
if (stat2.isSymbolicLink()) {
|
|
2518
2518
|
throw new Error("Native asset artifact must not be a symbolic link");
|
|
2519
2519
|
}
|
|
2520
2520
|
if (stat2.isDirectory()) {
|
|
2521
2521
|
const candidates = [];
|
|
2522
|
-
const pending = [
|
|
2522
|
+
const pending = [path12];
|
|
2523
2523
|
let entries = 0;
|
|
2524
2524
|
while (pending.length) {
|
|
2525
2525
|
const directory = pending.pop();
|
|
@@ -2531,17 +2531,17 @@ async function assertAssetPackNativeArtifact(report, artifact) {
|
|
|
2531
2531
|
if (entry.isDirectory()) {
|
|
2532
2532
|
pending.push(file);
|
|
2533
2533
|
} else if (entry.name === assetPackTargetManifestName && basename(directory) === assetPackTargetNamespace) {
|
|
2534
|
-
candidates.push(relative4(
|
|
2534
|
+
candidates.push(relative4(path12, directory));
|
|
2535
2535
|
}
|
|
2536
2536
|
}
|
|
2537
2537
|
}
|
|
2538
2538
|
if (candidates.length !== 1) {
|
|
2539
2539
|
throw new Error("Native asset artifact requires exactly one packaged pack namespace");
|
|
2540
2540
|
}
|
|
2541
|
-
if (!expectedNamespace(
|
|
2541
|
+
if (!expectedNamespace(path12, candidates[0].replaceAll("\\", "/") + "/")) {
|
|
2542
2542
|
throw new Error("Native asset namespace is outside the platform web bundle");
|
|
2543
2543
|
}
|
|
2544
|
-
await assertAssetPackTargetArtifact(report,
|
|
2544
|
+
await assertAssetPackTargetArtifact(report, path12, candidates[0]);
|
|
2545
2545
|
return;
|
|
2546
2546
|
}
|
|
2547
2547
|
if (!stat2.isFile() || stat2.size > 2 * 1024 ** 3) {
|
|
@@ -2552,7 +2552,7 @@ async function assertAssetPackNativeArtifact(report, artifact) {
|
|
|
2552
2552
|
const files = /* @__PURE__ */ new Map();
|
|
2553
2553
|
let expanded = 0;
|
|
2554
2554
|
let entryCount = 0;
|
|
2555
|
-
const archive = await openPromise(
|
|
2555
|
+
const archive = await openPromise(path12, {
|
|
2556
2556
|
lazyEntries: true,
|
|
2557
2557
|
strictFileNames: true,
|
|
2558
2558
|
validateEntrySizes: true
|
|
@@ -2600,7 +2600,7 @@ async function assertAssetPackNativeArtifact(report, artifact) {
|
|
|
2600
2600
|
throw new Error("Native asset package requires exactly one packaged pack namespace");
|
|
2601
2601
|
}
|
|
2602
2602
|
const namespace = namespaces[0];
|
|
2603
|
-
if (!expectedNamespace(
|
|
2603
|
+
if (!expectedNamespace(path12, namespace)) {
|
|
2604
2604
|
throw new Error("Native asset namespace is outside the platform web bundle");
|
|
2605
2605
|
}
|
|
2606
2606
|
const namespaceBytes = [...files].filter(([name]) => name.startsWith(namespace)).reduce((sum, [, file]) => sum + file.bytes, 0);
|
|
@@ -2942,8 +2942,8 @@ function resolveSecureGamePath(gameRoot, configuredPath) {
|
|
|
2942
2942
|
}
|
|
2943
2943
|
return real;
|
|
2944
2944
|
}
|
|
2945
|
-
function toGameRelativePath(gameRoot,
|
|
2946
|
-
return relative5(realpathSync3(gameRoot), realpathSync3(
|
|
2945
|
+
function toGameRelativePath(gameRoot, path12) {
|
|
2946
|
+
return relative5(realpathSync3(gameRoot), realpathSync3(path12)).split("\\").join("/");
|
|
2947
2947
|
}
|
|
2948
2948
|
function readAppIconConfig(input, label) {
|
|
2949
2949
|
assertRecord(input, label);
|
|
@@ -2964,9 +2964,9 @@ function readVariants(input, label) {
|
|
|
2964
2964
|
assertRecord(input, label);
|
|
2965
2965
|
const variants = {};
|
|
2966
2966
|
for (const name of variantNames) {
|
|
2967
|
-
const
|
|
2968
|
-
if (
|
|
2969
|
-
variants[name] =
|
|
2967
|
+
const path12 = readOptionalString(input[name], `${label}.${name}`);
|
|
2968
|
+
if (path12 !== void 0) {
|
|
2969
|
+
variants[name] = path12;
|
|
2970
2970
|
}
|
|
2971
2971
|
}
|
|
2972
2972
|
for (const key of Object.keys(input)) {
|
|
@@ -3008,38 +3008,38 @@ import sharp from "sharp";
|
|
|
3008
3008
|
var pngSignature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
3009
3009
|
var maximumDimension = 8192;
|
|
3010
3010
|
var maximumPixels = maximumDimension * maximumDimension;
|
|
3011
|
-
async function validateBrandImage(
|
|
3012
|
-
const bytes = readFileSync4(
|
|
3011
|
+
async function validateBrandImage(path12, options) {
|
|
3012
|
+
const bytes = readFileSync4(path12);
|
|
3013
3013
|
const format = sniffFormat(bytes);
|
|
3014
3014
|
if (format === "png" && hasPngChunk(bytes, "acTL")) {
|
|
3015
|
-
throw new Error(`Animated or multi-page brand images are not supported: ${
|
|
3015
|
+
throw new Error(`Animated or multi-page brand images are not supported: ${path12}`);
|
|
3016
3016
|
}
|
|
3017
3017
|
const warnings = format === "svg" ? validateSvg(bytes, options.strict) : [];
|
|
3018
3018
|
let metadata;
|
|
3019
3019
|
try {
|
|
3020
3020
|
metadata = await sharp(bytes, { animated: true, limitInputPixels: maximumPixels }).metadata();
|
|
3021
3021
|
} catch (error) {
|
|
3022
|
-
throw new Error(`Invalid brand image ${
|
|
3022
|
+
throw new Error(`Invalid brand image ${path12}: ${formatError2(error)}`);
|
|
3023
3023
|
}
|
|
3024
3024
|
const width = metadata.width;
|
|
3025
3025
|
const height = metadata.height;
|
|
3026
3026
|
if (width === void 0 || height === void 0 || width < 1 || height < 1) {
|
|
3027
|
-
throw new Error(`Brand image has no usable dimensions: ${
|
|
3027
|
+
throw new Error(`Brand image has no usable dimensions: ${path12}`);
|
|
3028
3028
|
}
|
|
3029
3029
|
if (width !== height) {
|
|
3030
|
-
throw new Error(`Brand image must be square, got ${width}x${height}: ${
|
|
3030
|
+
throw new Error(`Brand image must be square, got ${width}x${height}: ${path12}`);
|
|
3031
3031
|
}
|
|
3032
3032
|
if (width > maximumDimension || height > maximumDimension) {
|
|
3033
|
-
throw new Error(`Brand image exceeds ${maximumDimension}x${maximumDimension}: ${
|
|
3033
|
+
throw new Error(`Brand image exceeds ${maximumDimension}x${maximumDimension}: ${path12}`);
|
|
3034
3034
|
}
|
|
3035
3035
|
if ((metadata.pages ?? 1) > 1) {
|
|
3036
|
-
throw new Error(`Animated or multi-page brand images are not supported: ${
|
|
3036
|
+
throw new Error(`Animated or multi-page brand images are not supported: ${path12}`);
|
|
3037
3037
|
}
|
|
3038
3038
|
if (format === "png" && options.minimumSize !== void 0 && width < options.minimumSize) {
|
|
3039
|
-
throw new Error(`PNG brand image must be at least ${options.minimumSize}x${options.minimumSize}; got ${width}x${height}: ${
|
|
3039
|
+
throw new Error(`PNG brand image must be at least ${options.minimumSize}x${options.minimumSize}; got ${width}x${height}: ${path12}`);
|
|
3040
3040
|
}
|
|
3041
3041
|
return {
|
|
3042
|
-
path:
|
|
3042
|
+
path: path12,
|
|
3043
3043
|
bytes,
|
|
3044
3044
|
format,
|
|
3045
3045
|
width,
|
|
@@ -3464,28 +3464,28 @@ async function verifyGeneratedTargetIcons(result) {
|
|
|
3464
3464
|
}
|
|
3465
3465
|
assertManifestOutputsMatchProfile(result);
|
|
3466
3466
|
for (const output of result.manifest.outputs) {
|
|
3467
|
-
const
|
|
3468
|
-
const bytes = readFileSync5(
|
|
3467
|
+
const path12 = resolve6(result.outputDir, output.path.slice("icons/".length));
|
|
3468
|
+
const bytes = readFileSync5(path12);
|
|
3469
3469
|
if (sha256(bytes) !== output.sha256) {
|
|
3470
|
-
throw new Error(`Stale generated icon output: ${
|
|
3470
|
+
throw new Error(`Stale generated icon output: ${path12}`);
|
|
3471
3471
|
}
|
|
3472
3472
|
let metadata;
|
|
3473
3473
|
try {
|
|
3474
3474
|
metadata = await sharp2(bytes).metadata();
|
|
3475
3475
|
} catch {
|
|
3476
|
-
throw new Error(`Generated icon is not a decodable PNG: ${
|
|
3476
|
+
throw new Error(`Generated icon is not a decodable PNG: ${path12}`);
|
|
3477
3477
|
}
|
|
3478
3478
|
if (metadata.format !== "png" || metadata.width !== output.width || metadata.height !== output.height || (metadata.pages ?? 1) !== 1) {
|
|
3479
|
-
throw new Error(`Generated icon must be a ${output.width}x${output.height} single-page PNG: ${
|
|
3479
|
+
throw new Error(`Generated icon must be a ${output.width}x${output.height} single-page PNG: ${path12}`);
|
|
3480
3480
|
}
|
|
3481
3481
|
if (await pixelSha256(bytes) !== output.pixelSha256) {
|
|
3482
|
-
throw new Error(`Generated icon pixel digest mismatch: ${
|
|
3482
|
+
throw new Error(`Generated icon pixel digest mismatch: ${path12}`);
|
|
3483
3483
|
}
|
|
3484
3484
|
if (output.opaque && !await isPngOpaque(bytes)) {
|
|
3485
|
-
throw new Error(`Generated icon expected to be opaque: ${
|
|
3485
|
+
throw new Error(`Generated icon expected to be opaque: ${path12}`);
|
|
3486
3486
|
}
|
|
3487
3487
|
if (result.profile.id === "devvit" && bytes.byteLength > devvitIconMaximumBytes) {
|
|
3488
|
-
throw new Error(`Devvit marketing icon must be at most ${devvitIconMaximumBytes} bytes: ${
|
|
3488
|
+
throw new Error(`Devvit marketing icon must be at most ${devvitIconMaximumBytes} bytes: ${path12}`);
|
|
3489
3489
|
}
|
|
3490
3490
|
}
|
|
3491
3491
|
}
|
|
@@ -3497,13 +3497,13 @@ async function resolveOutputImage(input) {
|
|
|
3497
3497
|
}
|
|
3498
3498
|
async function loadVariantSources(gameRoot, appIcon, strict) {
|
|
3499
3499
|
const entries = await Promise.all(brandImageVariants.map(async (variant) => {
|
|
3500
|
-
const
|
|
3501
|
-
if (
|
|
3500
|
+
const path12 = appIcon.variants?.[variant];
|
|
3501
|
+
if (path12 === void 0) {
|
|
3502
3502
|
return void 0;
|
|
3503
3503
|
}
|
|
3504
3504
|
return [
|
|
3505
3505
|
variant,
|
|
3506
|
-
await validateBrandImage(resolveSecureGamePath(gameRoot,
|
|
3506
|
+
await validateBrandImage(resolveSecureGamePath(gameRoot, path12), { strict })
|
|
3507
3507
|
];
|
|
3508
3508
|
}));
|
|
3509
3509
|
return Object.fromEntries(entries.filter((entry) => entry !== void 0));
|
|
@@ -3548,14 +3548,14 @@ function assertManifestOutputsMatchProfile(result) {
|
|
|
3548
3548
|
throw new Error(`Generated icon output count does not match ${result.profile.id} profile.`);
|
|
3549
3549
|
}
|
|
3550
3550
|
for (const expected of expectedOutputs) {
|
|
3551
|
-
const
|
|
3552
|
-
const matches = result.manifest.outputs.filter((output2) => output2.path ===
|
|
3551
|
+
const path12 = `icons/${expected.file}`;
|
|
3552
|
+
const matches = result.manifest.outputs.filter((output2) => output2.path === path12);
|
|
3553
3553
|
if (matches.length !== 1) {
|
|
3554
|
-
throw new Error(`Generated icon manifest must contain exactly one ${
|
|
3554
|
+
throw new Error(`Generated icon manifest must contain exactly one ${path12} output.`);
|
|
3555
3555
|
}
|
|
3556
3556
|
const output = matches[0];
|
|
3557
3557
|
if (output === void 0 || output.target !== result.target || output.purpose !== expected.purpose || output.width !== expected.width || output.height !== expected.height || output.format !== "png" || output.opaque !== expected.opaque || !/^[0-9a-f]{64}$/u.test(output.sha256) || !/^[0-9a-f]{64}$/u.test(output.pixelSha256)) {
|
|
3558
|
-
throw new Error(`Generated icon manifest output does not match profile: ${
|
|
3558
|
+
throw new Error(`Generated icon manifest output does not match profile: ${path12}`);
|
|
3559
3559
|
}
|
|
3560
3560
|
}
|
|
3561
3561
|
}
|
|
@@ -3833,8 +3833,8 @@ function indexHtmlLinksExistingManifest(indexFile, manifests) {
|
|
|
3833
3833
|
}
|
|
3834
3834
|
function rootManifestNameFromHref(href) {
|
|
3835
3835
|
const pathEnd = href.search(/[?#]/u);
|
|
3836
|
-
const
|
|
3837
|
-
const rootRelativePath =
|
|
3836
|
+
const path12 = (pathEnd < 0 ? href : href.slice(0, pathEnd)).trim();
|
|
3837
|
+
const rootRelativePath = path12.startsWith("./") ? path12.slice(2) : path12.startsWith("/") ? path12.slice(1) : path12;
|
|
3838
3838
|
return rootRelativePath.length > 0 && !rootRelativePath.includes("/") && !rootRelativePath.includes("\\") && installableManifestNames.has(rootRelativePath.toLowerCase()) ? rootRelativePath : void 0;
|
|
3839
3839
|
}
|
|
3840
3840
|
function readHtmlAttribute(tag, expectedName) {
|
|
@@ -4196,25 +4196,25 @@ function assertExistingWebOutputsAreGeneratedArtifacts(outputs) {
|
|
|
4196
4196
|
}
|
|
4197
4197
|
}
|
|
4198
4198
|
function isPathWithin(root, candidate) {
|
|
4199
|
-
const
|
|
4200
|
-
return
|
|
4199
|
+
const path12 = relative7(root, candidate);
|
|
4200
|
+
return path12 === "" || path12 !== ".." && !path12.startsWith(`..${sep4}`) && !isAbsolute5(path12);
|
|
4201
4201
|
}
|
|
4202
4202
|
function pathsOverlap(first, second) {
|
|
4203
4203
|
return isPathWithin(first, second) || isPathWithin(second, first);
|
|
4204
4204
|
}
|
|
4205
|
-
function canonicalizeWebArtifactOutput(
|
|
4206
|
-
const status = lstatIfPresent(
|
|
4205
|
+
function canonicalizeWebArtifactOutput(path12) {
|
|
4206
|
+
const status = lstatIfPresent(path12);
|
|
4207
4207
|
if (status?.isSymbolicLink() === true) {
|
|
4208
|
-
throw new Error(`Web artifact output must not be a symbolic link: ${
|
|
4208
|
+
throw new Error(`Web artifact output must not be a symbolic link: ${path12}`);
|
|
4209
4209
|
}
|
|
4210
4210
|
if (status !== void 0 && !status.isDirectory()) {
|
|
4211
|
-
throw new Error(`Web artifact output must be a directory when it already exists: ${
|
|
4211
|
+
throw new Error(`Web artifact output must be a directory when it already exists: ${path12}`);
|
|
4212
4212
|
}
|
|
4213
|
-
return canonicalizeThroughExistingAncestor(
|
|
4213
|
+
return canonicalizeThroughExistingAncestor(path12);
|
|
4214
4214
|
}
|
|
4215
|
-
function lstatIfPresent(
|
|
4215
|
+
function lstatIfPresent(path12) {
|
|
4216
4216
|
try {
|
|
4217
|
-
return lstatSync3(
|
|
4217
|
+
return lstatSync3(path12);
|
|
4218
4218
|
} catch (error) {
|
|
4219
4219
|
if (error.code === "ENOENT") {
|
|
4220
4220
|
return void 0;
|
|
@@ -4222,14 +4222,14 @@ function lstatIfPresent(path10) {
|
|
|
4222
4222
|
throw error;
|
|
4223
4223
|
}
|
|
4224
4224
|
}
|
|
4225
|
-
function canonicalizeThroughExistingAncestor(
|
|
4226
|
-
const normalizedPath = resolve7(
|
|
4225
|
+
function canonicalizeThroughExistingAncestor(path12) {
|
|
4226
|
+
const normalizedPath = resolve7(path12);
|
|
4227
4227
|
const suffix = [];
|
|
4228
4228
|
let existingAncestor = normalizedPath;
|
|
4229
4229
|
while (!existsSync5(existingAncestor)) {
|
|
4230
4230
|
const parent = dirname4(existingAncestor);
|
|
4231
4231
|
if (parent === existingAncestor) {
|
|
4232
|
-
throw new Error(`Cannot resolve an existing ancestor for web output: ${
|
|
4232
|
+
throw new Error(`Cannot resolve an existing ancestor for web output: ${path12}`);
|
|
4233
4233
|
}
|
|
4234
4234
|
suffix.unshift(basename2(existingAncestor));
|
|
4235
4235
|
existingAncestor = parent;
|
|
@@ -4285,18 +4285,18 @@ function stageWrapperIcon(result, wrapperApp) {
|
|
|
4285
4285
|
}
|
|
4286
4286
|
async function stageNativeIconResources(result, shellApp) {
|
|
4287
4287
|
const snapshots = /* @__PURE__ */ new Map();
|
|
4288
|
-
const write = (
|
|
4289
|
-
if (!snapshots.has(
|
|
4290
|
-
snapshots.set(
|
|
4288
|
+
const write = (path12, contents) => {
|
|
4289
|
+
if (!snapshots.has(path12)) {
|
|
4290
|
+
snapshots.set(path12, existsSync6(path12) ? readFileSync7(path12) : void 0);
|
|
4291
4291
|
}
|
|
4292
|
-
mkdirSync4(dirname5(
|
|
4293
|
-
writeFileSync4(
|
|
4292
|
+
mkdirSync4(dirname5(path12), { recursive: true });
|
|
4293
|
+
writeFileSync4(path12, contents);
|
|
4294
4294
|
};
|
|
4295
|
-
const remove = (
|
|
4296
|
-
if (!snapshots.has(
|
|
4297
|
-
snapshots.set(
|
|
4295
|
+
const remove = (path12) => {
|
|
4296
|
+
if (!snapshots.has(path12)) {
|
|
4297
|
+
snapshots.set(path12, existsSync6(path12) ? readFileSync7(path12) : void 0);
|
|
4298
4298
|
}
|
|
4299
|
-
rmSync4(
|
|
4299
|
+
rmSync4(path12, { force: true });
|
|
4300
4300
|
};
|
|
4301
4301
|
if (result.profile.id === "android-adaptive") {
|
|
4302
4302
|
await stageAndroid(result, shellApp, write, remove);
|
|
@@ -4304,11 +4304,11 @@ async function stageNativeIconResources(result, shellApp) {
|
|
|
4304
4304
|
stageIos(result, shellApp, write);
|
|
4305
4305
|
}
|
|
4306
4306
|
return () => {
|
|
4307
|
-
for (const [
|
|
4307
|
+
for (const [path12, contents] of [...snapshots.entries()].reverse()) {
|
|
4308
4308
|
if (contents === void 0) {
|
|
4309
|
-
rmSync4(
|
|
4309
|
+
rmSync4(path12, { force: true });
|
|
4310
4310
|
} else {
|
|
4311
|
-
writeFileSync4(
|
|
4311
|
+
writeFileSync4(path12, contents);
|
|
4312
4312
|
}
|
|
4313
4313
|
}
|
|
4314
4314
|
};
|
|
@@ -4381,7 +4381,7 @@ function stageWebManifest(result, gameDist, manifestSourceDirectory) {
|
|
|
4381
4381
|
stagedPath,
|
|
4382
4382
|
publicWebManifestPath,
|
|
4383
4383
|
publicJsonManifestPath
|
|
4384
|
-
].find((
|
|
4384
|
+
].find((path12) => existsSync6(path12));
|
|
4385
4385
|
const manifest = manifestPath !== void 0 ? readWebManifest(manifestPath) : {
|
|
4386
4386
|
name: basename3(result.gameRoot),
|
|
4387
4387
|
short_name: basename3(result.gameRoot),
|
|
@@ -4404,10 +4404,10 @@ function stageWebManifest(result, gameDist, manifestSourceDirectory) {
|
|
|
4404
4404
|
}
|
|
4405
4405
|
ensureInstallableWebManifestLink(gameDist);
|
|
4406
4406
|
}
|
|
4407
|
-
function readWebManifest(
|
|
4408
|
-
const parsed = JSON.parse(readFileSync7(
|
|
4407
|
+
function readWebManifest(path12) {
|
|
4408
|
+
const parsed = JSON.parse(readFileSync7(path12, "utf8"));
|
|
4409
4409
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
4410
|
-
throw new Error(`Web app manifest must contain a JSON object: ${
|
|
4410
|
+
throw new Error(`Web app manifest must contain a JSON object: ${path12}`);
|
|
4411
4411
|
}
|
|
4412
4412
|
return parsed;
|
|
4413
4413
|
}
|
|
@@ -4426,8 +4426,8 @@ function androidAdaptiveXml(hasMonochrome) {
|
|
|
4426
4426
|
</adaptive-icon>
|
|
4427
4427
|
`;
|
|
4428
4428
|
}
|
|
4429
|
-
async function resizePng(
|
|
4430
|
-
return sharp3(
|
|
4429
|
+
async function resizePng(path12, size) {
|
|
4430
|
+
return sharp3(path12).resize(size, size, { kernel: sharp3.kernel.lanczos3 }).png({ compressionLevel: 9, effort: 10 }).toBuffer();
|
|
4431
4431
|
}
|
|
4432
4432
|
function cacheOutputPath(result, output) {
|
|
4433
4433
|
return resolve8(result.outputDir, basename3(output.path));
|
|
@@ -4566,10 +4566,10 @@ function instantOrNaN(at) {
|
|
|
4566
4566
|
function isNotificationTimestamp(at) {
|
|
4567
4567
|
return !Number.isNaN(instantOrNaN(at));
|
|
4568
4568
|
}
|
|
4569
|
-
function notificationTimeFieldIssue(value, fields,
|
|
4569
|
+
function notificationTimeFieldIssue(value, fields, path12 = "") {
|
|
4570
4570
|
if (Array.isArray(value)) {
|
|
4571
4571
|
for (const [index, item] of value.entries()) {
|
|
4572
|
-
const issue = notificationTimeFieldIssue(item, fields, `${
|
|
4572
|
+
const issue = notificationTimeFieldIssue(item, fields, `${path12}[${index}]`);
|
|
4573
4573
|
if (issue !== void 0) {
|
|
4574
4574
|
return issue;
|
|
4575
4575
|
}
|
|
@@ -4584,7 +4584,7 @@ function notificationTimeFieldIssue(value, fields, path10 = "") {
|
|
|
4584
4584
|
continue;
|
|
4585
4585
|
}
|
|
4586
4586
|
const field = value[key];
|
|
4587
|
-
const at =
|
|
4587
|
+
const at = path12 === "" ? key : `${path12}.${key}`;
|
|
4588
4588
|
if (typeof format !== "string") {
|
|
4589
4589
|
const issue = notificationTimeFieldIssue(field, format, at);
|
|
4590
4590
|
if (issue !== void 0) {
|
|
@@ -8010,7 +8010,8 @@ var targetIntegrations = [
|
|
|
8010
8010
|
"presentation",
|
|
8011
8011
|
"sharing",
|
|
8012
8012
|
"inboundShare",
|
|
8013
|
-
"notifications"
|
|
8013
|
+
"notifications",
|
|
8014
|
+
"reviews"
|
|
8014
8015
|
];
|
|
8015
8016
|
var integrationUpperBoundsByRuntime = {
|
|
8016
8017
|
"crazygames-web": {
|
|
@@ -8018,42 +8019,48 @@ var integrationUpperBoundsByRuntime = {
|
|
|
8018
8019
|
presentation: "available",
|
|
8019
8020
|
sharing: "unsupported",
|
|
8020
8021
|
inboundShare: "unsupported",
|
|
8021
|
-
notifications: "unsupported"
|
|
8022
|
+
notifications: "unsupported",
|
|
8023
|
+
reviews: "disabled"
|
|
8022
8024
|
},
|
|
8023
8025
|
"oneplay-web": {
|
|
8024
8026
|
identityUpgrade: "unsupported",
|
|
8025
8027
|
presentation: "available",
|
|
8026
8028
|
sharing: "unsupported",
|
|
8027
8029
|
inboundShare: "unsupported",
|
|
8028
|
-
notifications: "unsupported"
|
|
8030
|
+
notifications: "unsupported",
|
|
8031
|
+
reviews: "available"
|
|
8029
8032
|
},
|
|
8030
8033
|
"tiktok-minigame": {
|
|
8031
8034
|
identityUpgrade: "unsupported",
|
|
8032
8035
|
presentation: "available",
|
|
8033
8036
|
sharing: "available",
|
|
8034
8037
|
inboundShare: "unsupported",
|
|
8035
|
-
notifications: "unsupported"
|
|
8038
|
+
notifications: "unsupported",
|
|
8039
|
+
reviews: "disabled"
|
|
8036
8040
|
},
|
|
8037
8041
|
"verse8-web": {
|
|
8038
8042
|
identityUpgrade: "unsupported",
|
|
8039
8043
|
presentation: "available",
|
|
8040
8044
|
sharing: "unsupported",
|
|
8041
8045
|
inboundShare: "unsupported",
|
|
8042
|
-
notifications: "unsupported"
|
|
8046
|
+
notifications: "unsupported",
|
|
8047
|
+
reviews: "available"
|
|
8043
8048
|
},
|
|
8044
8049
|
"web-preview": {
|
|
8045
8050
|
identityUpgrade: "disabled",
|
|
8046
8051
|
presentation: "available",
|
|
8047
8052
|
sharing: "available",
|
|
8048
8053
|
inboundShare: "available",
|
|
8049
|
-
notifications: "unsupported"
|
|
8054
|
+
notifications: "unsupported",
|
|
8055
|
+
reviews: "disabled"
|
|
8050
8056
|
},
|
|
8051
8057
|
"wechat-minigame": {
|
|
8052
8058
|
identityUpgrade: "unsupported",
|
|
8053
8059
|
presentation: "available",
|
|
8054
8060
|
sharing: "available",
|
|
8055
8061
|
inboundShare: "unsupported",
|
|
8056
|
-
notifications: "unsupported"
|
|
8062
|
+
notifications: "unsupported",
|
|
8063
|
+
reviews: "disabled"
|
|
8057
8064
|
}
|
|
8058
8065
|
};
|
|
8059
8066
|
var integrationAvailabilityStateValues = [
|
|
@@ -8077,6 +8084,7 @@ var defaultTargetIntegrationConfig = {
|
|
|
8077
8084
|
sharing: "disabled",
|
|
8078
8085
|
inboundShare: "disabled",
|
|
8079
8086
|
notifications: "unsupported",
|
|
8087
|
+
reviews: "disabled",
|
|
8080
8088
|
presentationMode: "fullscreen"
|
|
8081
8089
|
};
|
|
8082
8090
|
var integrationAvailabilityStateSet = new Set(integrationAvailabilityStates);
|
|
@@ -8091,6 +8099,7 @@ function normalizeTargetIntegrationConfig(config2) {
|
|
|
8091
8099
|
sharing: normalizeIntegrationAvailabilityState(config2.sharing, defaultTargetIntegrationConfig.sharing),
|
|
8092
8100
|
inboundShare: normalizeIntegrationAvailabilityState(config2.inboundShare, defaultTargetIntegrationConfig.inboundShare),
|
|
8093
8101
|
notifications: normalizeIntegrationAvailabilityState(config2.notifications, defaultTargetIntegrationConfig.notifications),
|
|
8102
|
+
reviews: normalizeIntegrationAvailabilityState(config2.reviews, "disabled"),
|
|
8094
8103
|
presentationMode: normalizePresentationMode(config2.presentationMode)
|
|
8095
8104
|
};
|
|
8096
8105
|
}
|
|
@@ -8418,10 +8427,10 @@ function assertCrazyGamesArtifact(root) {
|
|
|
8418
8427
|
let bytes = 0;
|
|
8419
8428
|
function visit(directory) {
|
|
8420
8429
|
for (const name of readdirSync2(directory)) {
|
|
8421
|
-
const
|
|
8422
|
-
const stat2 = lstatSync5(
|
|
8430
|
+
const path12 = join8(directory, name);
|
|
8431
|
+
const stat2 = lstatSync5(path12);
|
|
8423
8432
|
if (stat2.isDirectory()) {
|
|
8424
|
-
visit(
|
|
8433
|
+
visit(path12);
|
|
8425
8434
|
} else if (stat2.isFile()) {
|
|
8426
8435
|
files += 1;
|
|
8427
8436
|
bytes += stat2.size;
|
|
@@ -8436,8 +8445,8 @@ function assertCrazyGamesArtifact(root) {
|
|
|
8436
8445
|
}
|
|
8437
8446
|
const index = readFileSync8(join8(root, "index.html"), "utf8");
|
|
8438
8447
|
for (const match of index.matchAll(/\b(?:src|href)\s*=\s*(?:["']([^"']+)["']|([^\s"'`=<>]+))/giu)) {
|
|
8439
|
-
const
|
|
8440
|
-
if (
|
|
8448
|
+
const path12 = match[1] ?? match[2];
|
|
8449
|
+
if (path12?.startsWith("/") || /^https?:/iu.test(path12 ?? "")) {
|
|
8441
8450
|
throw new Error("CrazyGames index assets must use relative paths.");
|
|
8442
8451
|
}
|
|
8443
8452
|
}
|
|
@@ -8449,9 +8458,9 @@ import { existsSync as existsSync7, readFileSync as readFileSync9, writeFileSync
|
|
|
8449
8458
|
import { join as join9 } from "node:path";
|
|
8450
8459
|
var onePlayFrameAncestors = "https://*.onestore.co.kr https://*.onestore.net";
|
|
8451
8460
|
function writeOnePlayHostingHeaders(root) {
|
|
8452
|
-
const
|
|
8453
|
-
if (!existsSync7(
|
|
8454
|
-
writeFileSync5(
|
|
8461
|
+
const path12 = join9(root, "_headers");
|
|
8462
|
+
if (!existsSync7(path12)) {
|
|
8463
|
+
writeFileSync5(path12, `/*
|
|
8455
8464
|
Content-Security-Policy: frame-ancestors ${onePlayFrameAncestors}
|
|
8456
8465
|
`);
|
|
8457
8466
|
}
|
|
@@ -8946,8 +8955,8 @@ function readConfiguredPath(value) {
|
|
|
8946
8955
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
8947
8956
|
import { resolve as resolve9 } from "node:path";
|
|
8948
8957
|
import { pathToFileURL } from "node:url";
|
|
8949
|
-
function readJsonFile(
|
|
8950
|
-
return JSON.parse(readFileSync10(resolve9(
|
|
8958
|
+
function readJsonFile(path12) {
|
|
8959
|
+
return JSON.parse(readFileSync10(resolve9(path12), "utf8"));
|
|
8951
8960
|
}
|
|
8952
8961
|
function isCliEntrypoint(metaUrl) {
|
|
8953
8962
|
const scriptPath = process.argv[1];
|
|
@@ -9101,20 +9110,20 @@ function listMiniGameArtifactFiles(artifactRoot) {
|
|
|
9101
9110
|
throw new Error("Mini-game artifact traversal lost its current directory.");
|
|
9102
9111
|
}
|
|
9103
9112
|
for (const entry of readdirSync3(directory, { withFileTypes: true })) {
|
|
9104
|
-
const
|
|
9105
|
-
const stat2 = lstatSync6(
|
|
9113
|
+
const path12 = resolve10(directory, entry.name);
|
|
9114
|
+
const stat2 = lstatSync6(path12);
|
|
9106
9115
|
if (stat2.isSymbolicLink()) {
|
|
9107
|
-
throw new Error(`Mini-game artifacts must not contain symbolic links: ${
|
|
9116
|
+
throw new Error(`Mini-game artifacts must not contain symbolic links: ${path12}`);
|
|
9108
9117
|
}
|
|
9109
|
-
const artifactPath = toArtifactRelativePath(root,
|
|
9118
|
+
const artifactPath = toArtifactRelativePath(root, path12);
|
|
9110
9119
|
assertMiniGameArtifactPathAllowed(artifactPath);
|
|
9111
9120
|
artifactPaths.push(artifactPath);
|
|
9112
9121
|
if (stat2.isDirectory()) {
|
|
9113
|
-
pending.push(
|
|
9122
|
+
pending.push(path12);
|
|
9114
9123
|
continue;
|
|
9115
9124
|
}
|
|
9116
9125
|
if (!stat2.isFile()) {
|
|
9117
|
-
throw new Error(`Mini-game artifacts must contain regular files only: ${
|
|
9126
|
+
throw new Error(`Mini-game artifacts must contain regular files only: ${path12}`);
|
|
9118
9127
|
}
|
|
9119
9128
|
files.push({ path: artifactPath, bytes: stat2.size });
|
|
9120
9129
|
}
|
|
@@ -9124,22 +9133,22 @@ function listMiniGameArtifactFiles(artifactRoot) {
|
|
|
9124
9133
|
return left.path < right.path ? -1 : left.path > right.path ? 1 : 0;
|
|
9125
9134
|
});
|
|
9126
9135
|
}
|
|
9127
|
-
function assertMiniGameArtifactRelativePath(
|
|
9128
|
-
const segments =
|
|
9129
|
-
if (
|
|
9130
|
-
throw new Error(`${label} must be a safe artifact-relative path: ${
|
|
9136
|
+
function assertMiniGameArtifactRelativePath(path12, label) {
|
|
9137
|
+
const segments = path12.split("/");
|
|
9138
|
+
if (path12.length === 0 || path12.includes("\\") || path12.startsWith("/") || /^[A-Za-z]:/u.test(path12) || isAbsolute6(path12) || segments.some((segment) => segment.length === 0 || segment === "." || segment === "..") || segments.some((segment) => /[. ]$/u.test(segment) || /[<>:"|?*\u0000-\u001f]/u.test(segment) || /^(?:con|prn|aux|nul|clock\$|conin\$|conout\$|com[1-9\u00b9\u00b2\u00b3]|lpt[1-9\u00b9\u00b2\u00b3])(?:\..*)?$/iu.test(segment))) {
|
|
9139
|
+
throw new Error(`${label} must be a safe artifact-relative path: ${path12}`);
|
|
9131
9140
|
}
|
|
9132
9141
|
}
|
|
9133
9142
|
function assertMiniGameArtifactPathsPortable(paths) {
|
|
9134
9143
|
const seen = /* @__PURE__ */ new Map();
|
|
9135
|
-
for (const
|
|
9136
|
-
assertMiniGameArtifactRelativePath(
|
|
9137
|
-
const portableKey = miniGamePortablePathKey(
|
|
9144
|
+
for (const path12 of paths) {
|
|
9145
|
+
assertMiniGameArtifactRelativePath(path12, "Mini-game artifact path");
|
|
9146
|
+
const portableKey = miniGamePortablePathKey(path12);
|
|
9138
9147
|
const previous = seen.get(portableKey);
|
|
9139
9148
|
if (previous !== void 0) {
|
|
9140
|
-
throw new Error(`Mini-game artifact paths collide on portable filesystems: ${previous}, ${
|
|
9149
|
+
throw new Error(`Mini-game artifact paths collide on portable filesystems: ${previous}, ${path12}.`);
|
|
9141
9150
|
}
|
|
9142
|
-
seen.set(portableKey,
|
|
9151
|
+
seen.set(portableKey, path12);
|
|
9143
9152
|
}
|
|
9144
9153
|
}
|
|
9145
9154
|
function readMiniGameSubpackages(gameConfig) {
|
|
@@ -9176,40 +9185,40 @@ function assertSubpackageRoots(subpackages) {
|
|
|
9176
9185
|
}
|
|
9177
9186
|
}
|
|
9178
9187
|
}
|
|
9179
|
-
function resolveArtifactPath2(root,
|
|
9180
|
-
const resolved = resolve10(root,
|
|
9188
|
+
function resolveArtifactPath2(root, path12) {
|
|
9189
|
+
const resolved = resolve10(root, path12);
|
|
9181
9190
|
const relativePath = relative8(root, resolved);
|
|
9182
9191
|
if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${sep5}`) || isAbsolute6(relativePath)) {
|
|
9183
|
-
throw new Error(`Mini-game path escapes its artifact root: ${
|
|
9192
|
+
throw new Error(`Mini-game path escapes its artifact root: ${path12}`);
|
|
9184
9193
|
}
|
|
9185
9194
|
try {
|
|
9186
9195
|
const stat2 = lstatSync6(resolved);
|
|
9187
9196
|
if (stat2.isSymbolicLink()) {
|
|
9188
|
-
throw new Error(`Mini-game path must not be a symbolic link: ${
|
|
9197
|
+
throw new Error(`Mini-game path must not be a symbolic link: ${path12}`);
|
|
9189
9198
|
}
|
|
9190
9199
|
} catch (error) {
|
|
9191
|
-
throw new Error(`Mini-game subpackage root does not exist: ${
|
|
9200
|
+
throw new Error(`Mini-game subpackage root does not exist: ${path12} (${formatError4(error)})`);
|
|
9192
9201
|
}
|
|
9193
9202
|
return resolved;
|
|
9194
9203
|
}
|
|
9195
|
-
function toArtifactRelativePath(root,
|
|
9196
|
-
const artifactPath = relative8(root,
|
|
9204
|
+
function toArtifactRelativePath(root, path12) {
|
|
9205
|
+
const artifactPath = relative8(root, path12).replaceAll("\\", "/");
|
|
9197
9206
|
assertMiniGameArtifactRelativePath(artifactPath, "Mini-game artifact file");
|
|
9198
9207
|
return artifactPath;
|
|
9199
9208
|
}
|
|
9200
|
-
function isInsideRoot(
|
|
9201
|
-
return
|
|
9209
|
+
function isInsideRoot(path12, root) {
|
|
9210
|
+
return path12 === root || path12.startsWith(`${root}/`);
|
|
9202
9211
|
}
|
|
9203
|
-
function miniGamePortablePathKey(
|
|
9204
|
-
return
|
|
9212
|
+
function miniGamePortablePathKey(path12) {
|
|
9213
|
+
return path12.normalize("NFC").toLowerCase();
|
|
9205
9214
|
}
|
|
9206
9215
|
function assertWithinBudget(actual, maximum, label) {
|
|
9207
9216
|
if (actual > maximum) {
|
|
9208
9217
|
throw new Error(`Mini-game ${label} exceeds its package budget: ${String(actual)} > ${String(maximum)} bytes.`);
|
|
9209
9218
|
}
|
|
9210
9219
|
}
|
|
9211
|
-
function assertMiniGameArtifactPathAllowed(
|
|
9212
|
-
const segments =
|
|
9220
|
+
function assertMiniGameArtifactPathAllowed(path12) {
|
|
9221
|
+
const segments = path12.split("/");
|
|
9213
9222
|
const fileName = segments.at(-1) ?? "";
|
|
9214
9223
|
const normalizedFileName = fileName.toLowerCase();
|
|
9215
9224
|
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
@@ -9223,16 +9232,16 @@ function assertMiniGameArtifactPathAllowed(path10) {
|
|
|
9223
9232
|
"tests"
|
|
9224
9233
|
]);
|
|
9225
9234
|
if (normalizedSegments.some((segment) => forbiddenSegments.has(segment))) {
|
|
9226
|
-
throw new Error(`Mini-game artifact contains a forbidden development path: ${
|
|
9235
|
+
throw new Error(`Mini-game artifact contains a forbidden development path: ${path12}`);
|
|
9227
9236
|
}
|
|
9228
9237
|
if (normalizedFileName === ".ds_store" || normalizedFileName === ".env" || normalizedFileName.startsWith(".env.") || normalizedFileName === ".npmrc" || normalizedFileName === "credentials.json" || normalizedFileName === "project.private.config.json" || /^service-account.*\.json$/iu.test(fileName) || /\.(?:map|jsx|ts|tsx|mts|cts|pem|key|p12|pfx)$/iu.test(fileName)) {
|
|
9229
|
-
throw new Error(`Mini-game artifact contains a forbidden development or credential file: ${
|
|
9238
|
+
throw new Error(`Mini-game artifact contains a forbidden development or credential file: ${path12}`);
|
|
9230
9239
|
}
|
|
9231
9240
|
if (/\.(?:html?|css|svg)$/iu.test(fileName)) {
|
|
9232
|
-
throw new Error(`Mini-game artifact contains a browser-only asset: ${
|
|
9241
|
+
throw new Error(`Mini-game artifact contains a browser-only asset: ${path12}`);
|
|
9233
9242
|
}
|
|
9234
9243
|
if (/\.(?:aac|m4a|mp3|ogg|opus|wav|webm)$/iu.test(fileName)) {
|
|
9235
|
-
throw new Error(`Mini-game Canvas MVP does not support audio assets yet: ${
|
|
9244
|
+
throw new Error(`Mini-game Canvas MVP does not support audio assets yet: ${path12}`);
|
|
9236
9245
|
}
|
|
9237
9246
|
}
|
|
9238
9247
|
function isRecord3(input) {
|
|
@@ -9667,6 +9676,11 @@ var assertPlatformTargetsConfig = /* @__PURE__ */ (() => {
|
|
|
9667
9676
|
path: _path + ".notifications",
|
|
9668
9677
|
expected: _ae0,
|
|
9669
9678
|
value: input.notifications
|
|
9679
|
+
}, _errorFactory)) && (void 0 === input.reviews || "action-required" === input.reviews || "approval-required" === input.reviews || "available" === input.reviews || "configuration-required" === input.reviews || "disabled" === input.reviews || "temporarily-unavailable" === input.reviews || "unsupported" === input.reviews || _assertGuard_16._assertGuard(_exceptionable, {
|
|
9680
|
+
method: "typia.createAssert",
|
|
9681
|
+
path: _path + ".reviews",
|
|
9682
|
+
expected: _ae0,
|
|
9683
|
+
value: input.reviews
|
|
9670
9684
|
}, _errorFactory)) && (void 0 === input.presentationMode || "fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode || _assertGuard_16._assertGuard(_exceptionable, {
|
|
9671
9685
|
method: "typia.createAssert",
|
|
9672
9686
|
path: _path + ".presentationMode",
|
|
@@ -9792,7 +9806,7 @@ var assertPlatformTargetsConfig = /* @__PURE__ */ (() => {
|
|
|
9792
9806
|
return "packaged" === value || "remote" === value;
|
|
9793
9807
|
});
|
|
9794
9808
|
const _io5 = (input) => (void 0 === input.appName || "string" === typeof input.appName) && (void 0 === input.displayName || "string" === typeof input.displayName) && (void 0 === input.primaryColor || "string" === typeof input.primaryColor) && (void 0 === input.packageId || "string" === typeof input.packageId) && (void 0 === input.bundleId || "string" === typeof input.bundleId) && (void 0 === input.sdkMajor || "number" === typeof input.sdkMajor) && (void 0 === input.iosDeviceFamily || "iphone" === input.iosDeviceFamily || "universal" === input.iosDeviceFamily);
|
|
9795
|
-
const _io6 = (input) => (void 0 === input.identityUpgrade || "action-required" === input.identityUpgrade || "approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "temporarily-unavailable" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && (void 0 === input.presentation || "action-required" === input.presentation || "approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "temporarily-unavailable" === input.presentation || "unsupported" === input.presentation) && (void 0 === input.sharing || "action-required" === input.sharing || "approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "temporarily-unavailable" === input.sharing || "unsupported" === input.sharing) && (void 0 === input.inboundShare || "action-required" === input.inboundShare || "approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "temporarily-unavailable" === input.inboundShare || "unsupported" === input.inboundShare) && (void 0 === input.notifications || "action-required" === input.notifications || "approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "temporarily-unavailable" === input.notifications || "unsupported" === input.notifications) && (void 0 === input.presentationMode || "fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
|
|
9809
|
+
const _io6 = (input) => (void 0 === input.identityUpgrade || "action-required" === input.identityUpgrade || "approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "temporarily-unavailable" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && (void 0 === input.presentation || "action-required" === input.presentation || "approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "temporarily-unavailable" === input.presentation || "unsupported" === input.presentation) && (void 0 === input.sharing || "action-required" === input.sharing || "approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "temporarily-unavailable" === input.sharing || "unsupported" === input.sharing) && (void 0 === input.inboundShare || "action-required" === input.inboundShare || "approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "temporarily-unavailable" === input.inboundShare || "unsupported" === input.inboundShare) && (void 0 === input.notifications || "action-required" === input.notifications || "approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "temporarily-unavailable" === input.notifications || "unsupported" === input.notifications) && (void 0 === input.reviews || "action-required" === input.reviews || "approval-required" === input.reviews || "available" === input.reviews || "configuration-required" === input.reviews || "disabled" === input.reviews || "temporarily-unavailable" === input.reviews || "unsupported" === input.reviews) && (void 0 === input.presentationMode || "fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
|
|
9796
9810
|
const _io7 = (input) => (void 0 === input.profile || "string" === typeof input.profile) && (void 0 === input.source || "string" === typeof input.source) && (void 0 === input.backgroundColor || "string" === typeof input.backgroundColor) && (void 0 === input.externalUrl || "string" === typeof input.externalUrl) && (void 0 === input.variants || "object" === typeof input.variants && null !== input.variants && false === Array.isArray(input.variants) && _io8(input.variants));
|
|
9797
9811
|
const _io8 = (input) => (void 0 === input.maskable || "string" === typeof input.maskable) && (void 0 === input.androidForeground || "string" === typeof input.androidForeground) && (void 0 === input.monochrome || "string" === typeof input.monochrome) && (void 0 === input.background || "string" === typeof input.background);
|
|
9798
9812
|
const _io9 = (input) => (void 0 === input.withBackButton || "boolean" === typeof input.withBackButton) && (void 0 === input.withHomeButton || "boolean" === typeof input.withHomeButton) && (void 0 === input.withTitle || "boolean" === typeof input.withTitle) && (void 0 === input.transparentBackground || "boolean" === typeof input.transparentBackground) && (void 0 === input.theme || "dark" === input.theme || "light" === input.theme);
|
|
@@ -9838,19 +9852,19 @@ var effectiveTargetConfigOutputDirEnv = "MPGD_EFFECTIVE_TARGET_CONFIG_OUTPUT_DIR
|
|
|
9838
9852
|
var targetIntegrationConfigKeys = /* @__PURE__ */ new Set([...targetIntegrations, "presentationMode"]);
|
|
9839
9853
|
var integrationAvailabilityStateSet2 = new Set(integrationAvailabilityStates);
|
|
9840
9854
|
var presentationModeSet2 = new Set(presentationModes);
|
|
9841
|
-
function platformTargetsFilePath(
|
|
9842
|
-
return resolve11(
|
|
9855
|
+
function platformTargetsFilePath(path12 = process.env[platformTargetsFileEnv] ?? "mpgd.targets.json") {
|
|
9856
|
+
return resolve11(path12);
|
|
9843
9857
|
}
|
|
9844
|
-
function loadPlatformTargetsConfig(
|
|
9845
|
-
const resolvedPath = platformTargetsFilePath(
|
|
9858
|
+
function loadPlatformTargetsConfig(path12 = platformTargetsFilePath()) {
|
|
9859
|
+
const resolvedPath = platformTargetsFilePath(path12);
|
|
9846
9860
|
return {
|
|
9847
9861
|
path: resolvedPath,
|
|
9848
9862
|
baseDir: dirname6(resolvedPath),
|
|
9849
9863
|
config: assertPlatformTargetsConfigShape(readJsonFile(resolvedPath))
|
|
9850
9864
|
};
|
|
9851
9865
|
}
|
|
9852
|
-
function resolveFromPlatformTargetsBase(baseDir,
|
|
9853
|
-
return isAbsolute7(
|
|
9866
|
+
function resolveFromPlatformTargetsBase(baseDir, path12) {
|
|
9867
|
+
return isAbsolute7(path12) ? path12 : resolve11(baseDir, path12);
|
|
9854
9868
|
}
|
|
9855
9869
|
function releaseManifestPath(baseDir = dirname6(platformTargetsFilePath())) {
|
|
9856
9870
|
return resolveFromPlatformTargetsBase(baseDir, process.env[releaseManifestFileEnv] ?? "artifacts/release-manifest.json");
|
|
@@ -10169,6 +10183,7 @@ var assertTargetConfigMatrix = /* @__PURE__ */ (() => {
|
|
|
10169
10183
|
const _av1 = /* @__PURE__ */ new Set(["app-store", "apps-in-toss", "crazygames", "devvit", "google-play", "microsoft-store", "oneplay", "tiktok-minigame", "verse8", "web", "web-preview", "wechat-minigame"]);
|
|
10170
10184
|
const _ae1 = '("app-store" | "apps-in-toss" | "crazygames" | "devvit" | "google-play" | "microsoft-store" | "oneplay" | "tiktok-minigame" | "verse8" | "web" | "web-preview" | "wechat-minigame")';
|
|
10171
10185
|
const _ae2 = '("action-required" | "approval-required" | "available" | "configuration-required" | "disabled" | "temporarily-unavailable" | "unsupported")';
|
|
10186
|
+
const _ae3 = '("action-required" | "approval-required" | "available" | "configuration-required" | "disabled" | "temporarily-unavailable" | "unsupported" | undefined)';
|
|
10172
10187
|
const _ao0 = (input, _path, _exceptionable = true) => ("string" === typeof input.version || _assertGuard_17._assertGuard(_exceptionable, {
|
|
10173
10188
|
method: "typia.createAssert",
|
|
10174
10189
|
path: _path + ".version",
|
|
@@ -10226,6 +10241,11 @@ var assertTargetConfigMatrix = /* @__PURE__ */ (() => {
|
|
|
10226
10241
|
path: _path + ".notifications",
|
|
10227
10242
|
expected: _ae2,
|
|
10228
10243
|
value: input.notifications
|
|
10244
|
+
}, _errorFactory)) && (void 0 === input.reviews || "action-required" === input.reviews || "approval-required" === input.reviews || "available" === input.reviews || "configuration-required" === input.reviews || "disabled" === input.reviews || "temporarily-unavailable" === input.reviews || "unsupported" === input.reviews || _assertGuard_17._assertGuard(_exceptionable, {
|
|
10245
|
+
method: "typia.createAssert",
|
|
10246
|
+
path: _path + ".reviews",
|
|
10247
|
+
expected: _ae3,
|
|
10248
|
+
value: input.reviews
|
|
10229
10249
|
}, _errorFactory)) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode || _assertGuard_17._assertGuard(_exceptionable, {
|
|
10230
10250
|
method: "typia.createAssert",
|
|
10231
10251
|
path: _path + ".presentationMode",
|
|
@@ -10402,7 +10422,7 @@ var assertTargetConfigMatrix = /* @__PURE__ */ (() => {
|
|
|
10402
10422
|
return true;
|
|
10403
10423
|
return "object" === typeof value && null !== value && _io2(value);
|
|
10404
10424
|
});
|
|
10405
|
-
const _io10 = (input) => ("action-required" === input.identityUpgrade || "approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "temporarily-unavailable" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && ("action-required" === input.presentation || "approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "temporarily-unavailable" === input.presentation || "unsupported" === input.presentation) && ("action-required" === input.sharing || "approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "temporarily-unavailable" === input.sharing || "unsupported" === input.sharing) && ("action-required" === input.inboundShare || "approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "temporarily-unavailable" === input.inboundShare || "unsupported" === input.inboundShare) && ("action-required" === input.notifications || "approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "temporarily-unavailable" === input.notifications || "unsupported" === input.notifications) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
|
|
10425
|
+
const _io10 = (input) => ("action-required" === input.identityUpgrade || "approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "temporarily-unavailable" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && ("action-required" === input.presentation || "approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "temporarily-unavailable" === input.presentation || "unsupported" === input.presentation) && ("action-required" === input.sharing || "approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "temporarily-unavailable" === input.sharing || "unsupported" === input.sharing) && ("action-required" === input.inboundShare || "approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "temporarily-unavailable" === input.inboundShare || "unsupported" === input.inboundShare) && ("action-required" === input.notifications || "approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "temporarily-unavailable" === input.notifications || "unsupported" === input.notifications) && (void 0 === input.reviews || "action-required" === input.reviews || "approval-required" === input.reviews || "available" === input.reviews || "configuration-required" === input.reviews || "disabled" === input.reviews || "temporarily-unavailable" === input.reviews || "unsupported" === input.reviews) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
|
|
10406
10426
|
const _io2 = (input) => true === _iv0.has(input.runtime) && ("object" === typeof input.features && null !== input.features && _io3(input.features)) && ("object" === typeof input.capabilities && null !== input.capabilities && _io4(input.capabilities)) && ("object" === typeof input.localization && null !== input.localization && _io5(input.localization)) && ("object" === typeof input.monetization && null !== input.monetization && _io6(input.monetization)) && ("object" === typeof input.leaderboard && null !== input.leaderboard && _io7(input.leaderboard)) && ("object" === typeof input.release && null !== input.release && _io8(input.release)) && ("object" === typeof input.policy && null !== input.policy && _io9(input.policy)) && (void 0 === input.integrations || "object" === typeof input.integrations && null !== input.integrations && _io10(input.integrations));
|
|
10407
10427
|
const _io3 = (input) => _ip0(input) && (void 0 === input.subscriptions || "boolean" === typeof input.subscriptions) && _ip1(input) && _ip2(input) && _ip3(input) && "boolean" === typeof input.leaderboard && (void 0 === input.nativeLeaderboard || "boolean" === typeof input.nativeLeaderboard) && (void 0 === input.remoteLeaderboard || "boolean" === typeof input.remoteLeaderboard) && _ip4(input);
|
|
10408
10428
|
const _io4 = (input) => ("local" === input.storage || "native" === input.storage || "none" === input.storage) && _ip4(input);
|
|
@@ -10474,6 +10494,7 @@ var assertTargetConfigExtensions = /* @__PURE__ */ (() => {
|
|
|
10474
10494
|
const _av1 = /* @__PURE__ */ new Set(["app-store", "apps-in-toss", "crazygames", "devvit", "google-play", "microsoft-store", "oneplay", "tiktok-minigame", "verse8", "web", "web-preview", "wechat-minigame"]);
|
|
10475
10495
|
const _ae1 = '("app-store" | "apps-in-toss" | "crazygames" | "devvit" | "google-play" | "microsoft-store" | "oneplay" | "tiktok-minigame" | "verse8" | "web" | "web-preview" | "wechat-minigame")';
|
|
10476
10496
|
const _ae2 = '("action-required" | "approval-required" | "available" | "configuration-required" | "disabled" | "temporarily-unavailable" | "unsupported")';
|
|
10497
|
+
const _ae3 = '("action-required" | "approval-required" | "available" | "configuration-required" | "disabled" | "temporarily-unavailable" | "unsupported" | undefined)';
|
|
10477
10498
|
const _ao0 = (input, _path, _exceptionable = true) => (1 === input.schemaVersion || _assertGuard_17._assertGuard(_exceptionable, {
|
|
10478
10499
|
method: "typia.createAssert",
|
|
10479
10500
|
path: _path + ".schemaVersion",
|
|
@@ -10531,6 +10552,11 @@ var assertTargetConfigExtensions = /* @__PURE__ */ (() => {
|
|
|
10531
10552
|
path: _path + ".notifications",
|
|
10532
10553
|
expected: _ae2,
|
|
10533
10554
|
value: input.notifications
|
|
10555
|
+
}, _errorFactory)) && (void 0 === input.reviews || "action-required" === input.reviews || "approval-required" === input.reviews || "available" === input.reviews || "configuration-required" === input.reviews || "disabled" === input.reviews || "temporarily-unavailable" === input.reviews || "unsupported" === input.reviews || _assertGuard_17._assertGuard(_exceptionable, {
|
|
10556
|
+
method: "typia.createAssert",
|
|
10557
|
+
path: _path + ".reviews",
|
|
10558
|
+
expected: _ae3,
|
|
10559
|
+
value: input.reviews
|
|
10534
10560
|
}, _errorFactory)) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode || _assertGuard_17._assertGuard(_exceptionable, {
|
|
10535
10561
|
method: "typia.createAssert",
|
|
10536
10562
|
path: _path + ".presentationMode",
|
|
@@ -10707,7 +10733,7 @@ var assertTargetConfigExtensions = /* @__PURE__ */ (() => {
|
|
|
10707
10733
|
return true;
|
|
10708
10734
|
return "object" === typeof value && null !== value && _io2(value);
|
|
10709
10735
|
});
|
|
10710
|
-
const _io10 = (input) => ("action-required" === input.identityUpgrade || "approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "temporarily-unavailable" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && ("action-required" === input.presentation || "approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "temporarily-unavailable" === input.presentation || "unsupported" === input.presentation) && ("action-required" === input.sharing || "approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "temporarily-unavailable" === input.sharing || "unsupported" === input.sharing) && ("action-required" === input.inboundShare || "approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "temporarily-unavailable" === input.inboundShare || "unsupported" === input.inboundShare) && ("action-required" === input.notifications || "approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "temporarily-unavailable" === input.notifications || "unsupported" === input.notifications) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
|
|
10736
|
+
const _io10 = (input) => ("action-required" === input.identityUpgrade || "approval-required" === input.identityUpgrade || "available" === input.identityUpgrade || "configuration-required" === input.identityUpgrade || "disabled" === input.identityUpgrade || "temporarily-unavailable" === input.identityUpgrade || "unsupported" === input.identityUpgrade) && ("action-required" === input.presentation || "approval-required" === input.presentation || "available" === input.presentation || "configuration-required" === input.presentation || "disabled" === input.presentation || "temporarily-unavailable" === input.presentation || "unsupported" === input.presentation) && ("action-required" === input.sharing || "approval-required" === input.sharing || "available" === input.sharing || "configuration-required" === input.sharing || "disabled" === input.sharing || "temporarily-unavailable" === input.sharing || "unsupported" === input.sharing) && ("action-required" === input.inboundShare || "approval-required" === input.inboundShare || "available" === input.inboundShare || "configuration-required" === input.inboundShare || "disabled" === input.inboundShare || "temporarily-unavailable" === input.inboundShare || "unsupported" === input.inboundShare) && ("action-required" === input.notifications || "approval-required" === input.notifications || "available" === input.notifications || "configuration-required" === input.notifications || "disabled" === input.notifications || "temporarily-unavailable" === input.notifications || "unsupported" === input.notifications) && (void 0 === input.reviews || "action-required" === input.reviews || "approval-required" === input.reviews || "available" === input.reviews || "configuration-required" === input.reviews || "disabled" === input.reviews || "temporarily-unavailable" === input.reviews || "unsupported" === input.reviews) && ("fullscreen" === input.presentationMode || "inline-expanded" === input.presentationMode);
|
|
10711
10737
|
const _io2 = (input) => true === _iv0.has(input.runtime) && ("object" === typeof input.features && null !== input.features && _io3(input.features)) && ("object" === typeof input.capabilities && null !== input.capabilities && _io4(input.capabilities)) && ("object" === typeof input.localization && null !== input.localization && _io5(input.localization)) && ("object" === typeof input.monetization && null !== input.monetization && _io6(input.monetization)) && ("object" === typeof input.leaderboard && null !== input.leaderboard && _io7(input.leaderboard)) && ("object" === typeof input.release && null !== input.release && _io8(input.release)) && ("object" === typeof input.policy && null !== input.policy && _io9(input.policy)) && (void 0 === input.integrations || "object" === typeof input.integrations && null !== input.integrations && _io10(input.integrations));
|
|
10712
10738
|
const _io3 = (input) => _ip0(input) && (void 0 === input.subscriptions || "boolean" === typeof input.subscriptions) && _ip1(input) && _ip2(input) && _ip3(input) && "boolean" === typeof input.leaderboard && (void 0 === input.nativeLeaderboard || "boolean" === typeof input.nativeLeaderboard) && (void 0 === input.remoteLeaderboard || "boolean" === typeof input.remoteLeaderboard) && _ip4(input);
|
|
10713
10739
|
const _io4 = (input) => ("local" === input.storage || "native" === input.storage || "none" === input.storage) && _ip4(input);
|
|
@@ -10927,14 +10953,14 @@ function writeEffectiveTargetConfigs(options = {}) {
|
|
|
10927
10953
|
writeFileSync6(indexPath, indexContent);
|
|
10928
10954
|
return index;
|
|
10929
10955
|
}
|
|
10930
|
-
function readExistingArtifactIndex(
|
|
10931
|
-
if (!existsSync8(
|
|
10956
|
+
function readExistingArtifactIndex(path12, version) {
|
|
10957
|
+
if (!existsSync8(path12)) {
|
|
10932
10958
|
return {
|
|
10933
10959
|
version,
|
|
10934
10960
|
artifacts: []
|
|
10935
10961
|
};
|
|
10936
10962
|
}
|
|
10937
|
-
const parsed = JSON.parse(readFileSync12(
|
|
10963
|
+
const parsed = JSON.parse(readFileSync12(path12, "utf8"));
|
|
10938
10964
|
if (parsed.version !== version) {
|
|
10939
10965
|
return {
|
|
10940
10966
|
version,
|
|
@@ -10945,14 +10971,14 @@ function readExistingArtifactIndex(path10, version) {
|
|
|
10945
10971
|
}
|
|
10946
10972
|
function writeEffectiveTargetConfig(target2, config2, outputDir) {
|
|
10947
10973
|
assertDeploymentTargetName(target2);
|
|
10948
|
-
const
|
|
10974
|
+
const path12 = join10(outputDir, `${target2}.json`);
|
|
10949
10975
|
const content = `${JSON.stringify(config2, null, 2)}
|
|
10950
10976
|
`;
|
|
10951
|
-
mkdirSync5(dirname7(
|
|
10952
|
-
writeFileSync6(
|
|
10977
|
+
mkdirSync5(dirname7(path12), { recursive: true });
|
|
10978
|
+
writeFileSync6(path12, content);
|
|
10953
10979
|
return {
|
|
10954
10980
|
target: target2,
|
|
10955
|
-
path:
|
|
10981
|
+
path: path12,
|
|
10956
10982
|
digest: sha2562(content),
|
|
10957
10983
|
version: config2.version
|
|
10958
10984
|
};
|
|
@@ -12088,51 +12114,51 @@ function readNativeVersionEvidence(target2) {
|
|
|
12088
12114
|
return {};
|
|
12089
12115
|
}
|
|
12090
12116
|
function readIconManifestEvidence(artifactPath) {
|
|
12091
|
-
const
|
|
12092
|
-
if (
|
|
12117
|
+
const path12 = readOptionalString2(process.env.MPGD_ICON_MANIFEST_PATH);
|
|
12118
|
+
if (path12 === void 0) {
|
|
12093
12119
|
throw new Error("MPGD_ICON_MANIFEST_PATH is required when generating a release manifest.");
|
|
12094
12120
|
}
|
|
12095
|
-
const bytes = readFileBytes(
|
|
12121
|
+
const bytes = readFileBytes(path12);
|
|
12096
12122
|
const parsed = JSON.parse(bytes.toString("utf8"));
|
|
12097
12123
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
12098
|
-
throw new Error(`Invalid icon manifest: ${
|
|
12124
|
+
throw new Error(`Invalid icon manifest: ${path12}`);
|
|
12099
12125
|
}
|
|
12100
12126
|
const manifest = parsed;
|
|
12101
12127
|
const canonicalSource = manifest.canonicalSource;
|
|
12102
12128
|
if (typeof canonicalSource !== "object" || canonicalSource === null || Array.isArray(canonicalSource)) {
|
|
12103
|
-
throw new Error(`Invalid icon manifest canonicalSource: ${
|
|
12129
|
+
throw new Error(`Invalid icon manifest canonicalSource: ${path12}`);
|
|
12104
12130
|
}
|
|
12105
12131
|
const canonicalSourceRecord = canonicalSource;
|
|
12106
12132
|
return {
|
|
12107
12133
|
path: requirePortableArtifactPath(artifactPath),
|
|
12108
12134
|
digest: createHash8("sha256").update(bytes).digest("hex"),
|
|
12109
|
-
sourceSha256: requireManifestString(canonicalSourceRecord, "sha256",
|
|
12110
|
-
sharedConfigSha256: requireManifestString(manifest, "sharedConfigSha256",
|
|
12111
|
-
renderConfigSha256: requireManifestString(manifest, "renderConfigSha256",
|
|
12112
|
-
generatorVersion: requireManifestString(manifest, "generatorVersion",
|
|
12113
|
-
targetProfile: requireManifestString(manifest, "targetProfile",
|
|
12114
|
-
targetProfileVersion: requireManifestString(manifest, "targetProfileVersion",
|
|
12135
|
+
sourceSha256: requireManifestString(canonicalSourceRecord, "sha256", path12),
|
|
12136
|
+
sharedConfigSha256: requireManifestString(manifest, "sharedConfigSha256", path12),
|
|
12137
|
+
renderConfigSha256: requireManifestString(manifest, "renderConfigSha256", path12),
|
|
12138
|
+
generatorVersion: requireManifestString(manifest, "generatorVersion", path12),
|
|
12139
|
+
targetProfile: requireManifestString(manifest, "targetProfile", path12),
|
|
12140
|
+
targetProfileVersion: requireManifestString(manifest, "targetProfileVersion", path12)
|
|
12115
12141
|
};
|
|
12116
12142
|
}
|
|
12117
|
-
function requirePortableArtifactPath(
|
|
12118
|
-
const normalized =
|
|
12143
|
+
function requirePortableArtifactPath(path12) {
|
|
12144
|
+
const normalized = path12.replaceAll("\\", "/");
|
|
12119
12145
|
const segments = normalized.split("/");
|
|
12120
|
-
if (normalized.length === 0 || isAbsolute8(
|
|
12121
|
-
throw new Error(`Invalid icon manifest artifact path: ${
|
|
12146
|
+
if (normalized.length === 0 || isAbsolute8(path12) || isAbsolute8(normalized) || /^[A-Za-z]:\//u.test(normalized) || segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")) {
|
|
12147
|
+
throw new Error(`Invalid icon manifest artifact path: ${path12}`);
|
|
12122
12148
|
}
|
|
12123
12149
|
return normalized;
|
|
12124
12150
|
}
|
|
12125
|
-
function readFileBytes(
|
|
12151
|
+
function readFileBytes(path12) {
|
|
12126
12152
|
try {
|
|
12127
|
-
return readFileSync14(
|
|
12153
|
+
return readFileSync14(path12);
|
|
12128
12154
|
} catch (error) {
|
|
12129
|
-
throw new Error(`Failed to read icon manifest ${
|
|
12155
|
+
throw new Error(`Failed to read icon manifest ${path12}: ${formatError5(error)}`);
|
|
12130
12156
|
}
|
|
12131
12157
|
}
|
|
12132
|
-
function requireManifestString(record2, key,
|
|
12158
|
+
function requireManifestString(record2, key, path12) {
|
|
12133
12159
|
const value = record2[key];
|
|
12134
12160
|
if (typeof value !== "string" || value.length === 0) {
|
|
12135
|
-
throw new Error(`Invalid icon manifest ${key}: ${
|
|
12161
|
+
throw new Error(`Invalid icon manifest ${key}: ${path12}`);
|
|
12136
12162
|
}
|
|
12137
12163
|
return value;
|
|
12138
12164
|
}
|
|
@@ -12214,15 +12240,15 @@ function makeEffectiveConfigPathsPortable(manifest, baseDir) {
|
|
|
12214
12240
|
]))
|
|
12215
12241
|
});
|
|
12216
12242
|
}
|
|
12217
|
-
function toPortablePath(baseDir,
|
|
12218
|
-
if (!isAbsolute8(
|
|
12219
|
-
return
|
|
12243
|
+
function toPortablePath(baseDir, path12) {
|
|
12244
|
+
if (!isAbsolute8(path12)) {
|
|
12245
|
+
return path12;
|
|
12220
12246
|
}
|
|
12221
|
-
const relativePath = relative9(baseDir,
|
|
12247
|
+
const relativePath = relative9(baseDir, path12);
|
|
12222
12248
|
if (relativePath.length > 0 && !relativePath.startsWith("..") && !isAbsolute8(relativePath)) {
|
|
12223
12249
|
return relativePath;
|
|
12224
12250
|
}
|
|
12225
|
-
return
|
|
12251
|
+
return path12;
|
|
12226
12252
|
}
|
|
12227
12253
|
function createBuildId() {
|
|
12228
12254
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -12622,20 +12648,20 @@ function listPrecacheEntries(artifactRoot) {
|
|
|
12622
12648
|
throw new Error("PWA artifact traversal lost its directory.");
|
|
12623
12649
|
}
|
|
12624
12650
|
for (const entry of readdirSync4(directory, { withFileTypes: true })) {
|
|
12625
|
-
const
|
|
12651
|
+
const path12 = resolve13(directory, entry.name);
|
|
12626
12652
|
if (entry.isSymbolicLink()) {
|
|
12627
|
-
throw new Error(`PWA artifact must not contain symbolic links: ${
|
|
12653
|
+
throw new Error(`PWA artifact must not contain symbolic links: ${path12}`);
|
|
12628
12654
|
}
|
|
12629
12655
|
if (entry.isDirectory()) {
|
|
12630
|
-
pendingDirectories.push(
|
|
12656
|
+
pendingDirectories.push(path12);
|
|
12631
12657
|
} else if (entry.isFile()) {
|
|
12632
|
-
files.push(
|
|
12658
|
+
files.push(path12);
|
|
12633
12659
|
}
|
|
12634
12660
|
}
|
|
12635
12661
|
}
|
|
12636
|
-
return files.filter((
|
|
12637
|
-
url: toPrecacheUrl(artifactRoot,
|
|
12638
|
-
source: readFileSync15(
|
|
12662
|
+
return files.filter((path12) => !path12.endsWith(".map") && !path12.endsWith(`${sep6}pwa-release.json`) && !path12.endsWith(`${sep6}service-worker.js`)).map((path12) => ({
|
|
12663
|
+
url: toPrecacheUrl(artifactRoot, path12),
|
|
12664
|
+
source: readFileSync15(path12)
|
|
12639
12665
|
})).sort((left, right) => compareCodeUnits(left.url, right.url));
|
|
12640
12666
|
}
|
|
12641
12667
|
function normalizePrecacheEntries(entries) {
|
|
@@ -12659,8 +12685,8 @@ function normalizePrecacheUrls(urls) {
|
|
|
12659
12685
|
}
|
|
12660
12686
|
return normalized.sort(compareCodeUnits);
|
|
12661
12687
|
}
|
|
12662
|
-
function toPrecacheUrl(root,
|
|
12663
|
-
const portablePath = relative10(root,
|
|
12688
|
+
function toPrecacheUrl(root, path12) {
|
|
12689
|
+
const portablePath = relative10(root, path12).split(sep6).join("/");
|
|
12664
12690
|
return assertMicrosoftStorePwaPrecacheUrl(`./${portablePath}`);
|
|
12665
12691
|
}
|
|
12666
12692
|
function requireGameSpecificPwaId(value) {
|
|
@@ -13061,23 +13087,23 @@ function pathsOverlap2(first, second) {
|
|
|
13061
13087
|
return isPathWithin2(first, second) || isPathWithin2(second, first);
|
|
13062
13088
|
}
|
|
13063
13089
|
function isPathWithin2(root, candidate) {
|
|
13064
|
-
const
|
|
13065
|
-
return
|
|
13090
|
+
const path12 = relative11(root, candidate);
|
|
13091
|
+
return path12 === "" || path12 !== ".." && !path12.startsWith(`..${sep7}`) && !isAbsolute9(path12);
|
|
13066
13092
|
}
|
|
13067
|
-
function portablePathComparisonKey(
|
|
13068
|
-
const portablePath =
|
|
13093
|
+
function portablePathComparisonKey(path12) {
|
|
13094
|
+
const portablePath = path12.replaceAll("\\", "/").split("/").map((segment) => {
|
|
13069
13095
|
return segment === "." || segment === ".." ? segment : segment.replace(/[. ]+$/u, "");
|
|
13070
13096
|
}).join("/");
|
|
13071
13097
|
return canonicalizeThroughExistingAncestor2(portablePath).normalize("NFC").toLowerCase();
|
|
13072
13098
|
}
|
|
13073
|
-
function canonicalizeThroughExistingAncestor2(
|
|
13074
|
-
const normalizedPath = resolve15(
|
|
13099
|
+
function canonicalizeThroughExistingAncestor2(path12) {
|
|
13100
|
+
const normalizedPath = resolve15(path12);
|
|
13075
13101
|
const suffix = [];
|
|
13076
13102
|
let existingAncestor = normalizedPath;
|
|
13077
13103
|
while (!existsSync12(existingAncestor)) {
|
|
13078
13104
|
const parent = dirname8(existingAncestor);
|
|
13079
13105
|
if (parent === existingAncestor) {
|
|
13080
|
-
throw new Error(`Cannot resolve an existing ancestor for mini-game output: ${
|
|
13106
|
+
throw new Error(`Cannot resolve an existing ancestor for mini-game output: ${path12}`);
|
|
13081
13107
|
}
|
|
13082
13108
|
suffix.unshift(basename4(existingAncestor));
|
|
13083
13109
|
existingAncestor = parent;
|
|
@@ -13131,8 +13157,8 @@ function cleanupMiniGameArtifactBackup(backupRoot, removeDirectory = removeMiniG
|
|
|
13131
13157
|
reportWarning(`The new mini-game artifact is active, but its prior backup could not be removed: ${backupRoot} (${formatError6(error)}). Remove this backup manually.`);
|
|
13132
13158
|
}
|
|
13133
13159
|
}
|
|
13134
|
-
function removeMiniGameArtifactBackupDirectory(
|
|
13135
|
-
rmSync6(
|
|
13160
|
+
function removeMiniGameArtifactBackupDirectory(path12) {
|
|
13161
|
+
rmSync6(path12, { force: true, maxRetries: 3, recursive: true, retryDelay: 100 });
|
|
13136
13162
|
}
|
|
13137
13163
|
function assertMiniGameRequiredFiles(artifactRoot) {
|
|
13138
13164
|
for (const file of [
|
|
@@ -13172,17 +13198,17 @@ function assertMiniGameJavaScriptSafety(artifactRoot, forbiddenMarkers, forbidde
|
|
|
13172
13198
|
}
|
|
13173
13199
|
}
|
|
13174
13200
|
}
|
|
13175
|
-
function assertMiniGameJavaScriptAstSafety(source,
|
|
13201
|
+
function assertMiniGameJavaScriptAstSafety(source, path12, forbiddenGlobals) {
|
|
13176
13202
|
let ast;
|
|
13177
13203
|
try {
|
|
13178
13204
|
ast = parse(source, {
|
|
13179
13205
|
ecmaVersion: "latest",
|
|
13180
|
-
sourceType:
|
|
13206
|
+
sourceType: path12.toLowerCase().endsWith(".mjs") ? "module" : "script",
|
|
13181
13207
|
allowHashBang: true,
|
|
13182
13208
|
allowReturnOutsideFunction: true
|
|
13183
13209
|
});
|
|
13184
13210
|
} catch (error) {
|
|
13185
|
-
throw new Error(`Mini-game ${
|
|
13211
|
+
throw new Error(`Mini-game ${path12} is not valid JavaScript: ${formatError6(error)}`);
|
|
13186
13212
|
}
|
|
13187
13213
|
const scopeAnalysis = createMiniGameScopeAnalysis(ast);
|
|
13188
13214
|
const ancestors = [];
|
|
@@ -13197,7 +13223,7 @@ function assertMiniGameJavaScriptAstSafety(source, path10, forbiddenGlobals) {
|
|
|
13197
13223
|
if (!isAstRecord(input)) {
|
|
13198
13224
|
return;
|
|
13199
13225
|
}
|
|
13200
|
-
assertSafeNode(input, ancestors,
|
|
13226
|
+
assertSafeNode(input, ancestors, path12, scopeAnalysis, forbiddenGlobals);
|
|
13201
13227
|
for (const [key, value] of Object.entries(input)) {
|
|
13202
13228
|
if (key !== "start" && key !== "end" && key !== "loc" && key !== "range") {
|
|
13203
13229
|
ancestors.push({ node: input, childKey: key });
|
|
@@ -13207,57 +13233,57 @@ function assertMiniGameJavaScriptAstSafety(source, path10, forbiddenGlobals) {
|
|
|
13207
13233
|
}
|
|
13208
13234
|
}
|
|
13209
13235
|
}
|
|
13210
|
-
function assertSafeNode(node, ancestors,
|
|
13236
|
+
function assertSafeNode(node, ancestors, path12, scopeAnalysis, forbiddenGlobals) {
|
|
13211
13237
|
if (node.type === "ImportExpression") {
|
|
13212
|
-
throw new Error(`Mini-game ${
|
|
13238
|
+
throw new Error(`Mini-game ${path12} contains forbidden dynamic import.`);
|
|
13213
13239
|
}
|
|
13214
13240
|
const parent = ancestors.at(-1)?.node;
|
|
13215
13241
|
if (forbiddenGlobals.size > 0 && isMiniGameProtectedIntrinsicMutation(node, ancestors, scopeAnalysis)) {
|
|
13216
|
-
throw new Error(`Mini-game ${
|
|
13242
|
+
throw new Error(`Mini-game ${path12} contains forbidden protected intrinsic mutation.`);
|
|
13217
13243
|
}
|
|
13218
13244
|
if (isMiniGameFunctionNode(node) && (parent?.type === "MethodDefinition" && parent.value === node || parent?.type === "PropertyDefinition" && parent.value === node || parent?.type === "Property" && parent.value === node) && readMiniGameFunctionReturnValues(node).some((value) => {
|
|
13219
13245
|
return isReturnedDynamicCodeConstructorSource(value, ancestors, scopeAnalysis);
|
|
13220
13246
|
})) {
|
|
13221
|
-
throw new Error(`Mini-game ${
|
|
13247
|
+
throw new Error(`Mini-game ${path12} contains forbidden dynamic-code constructor.`);
|
|
13222
13248
|
}
|
|
13223
13249
|
if (node.type === "Identifier" && typeof node.name === "string" && isExecutableIdentifierReference(ancestors)) {
|
|
13224
13250
|
const scope = scopeAnalysis.scopeByNode.get(node) ?? scopeAnalysis.programScope;
|
|
13225
13251
|
const binding = resolveMiniGameBinding(node.name, scope);
|
|
13226
13252
|
if (binding === void 0 && forbiddenGlobals.has(node.name)) {
|
|
13227
|
-
throw new Error(`Mini-game ${
|
|
13253
|
+
throw new Error(`Mini-game ${path12} contains forbidden platform global ${node.name}.`);
|
|
13228
13254
|
}
|
|
13229
13255
|
if (binding !== void 0 && isInvocationArgument(node, ancestors) && (scopeAnalysis.dynamicCodeConstructorAliases.has(binding) || scopeAnalysis.dynamicCodeConstructorContainers.has(binding) || scopeAnalysis.dynamicCodeConstructorFactories.has(binding) || scopeAnalysis.dynamicCodeConstructorContainerFactories.has(binding))) {
|
|
13230
|
-
throw new Error(`Mini-game ${
|
|
13256
|
+
throw new Error(`Mini-game ${path12} contains forbidden dynamic-code constructor.`);
|
|
13231
13257
|
}
|
|
13232
13258
|
if (node.name === "eval") {
|
|
13233
|
-
throw new Error(`Mini-game ${
|
|
13259
|
+
throw new Error(`Mini-game ${path12} contains forbidden eval.`);
|
|
13234
13260
|
}
|
|
13235
13261
|
if (node.name === "Function") {
|
|
13236
|
-
throw new Error(`Mini-game ${
|
|
13262
|
+
throw new Error(`Mini-game ${path12} contains forbidden Function constructor.`);
|
|
13237
13263
|
}
|
|
13238
13264
|
if (node.name === "importScripts" && !isTypeofReference(node, ancestors)) {
|
|
13239
|
-
throw new Error(`Mini-game ${
|
|
13265
|
+
throw new Error(`Mini-game ${path12} contains forbidden importScripts.`);
|
|
13240
13266
|
}
|
|
13241
13267
|
}
|
|
13242
13268
|
if (node.type === "MemberExpression") {
|
|
13243
13269
|
const propertyNames = readMiniGameMemberNames(node, ancestors, scopeAnalysis);
|
|
13244
13270
|
if (node.computed === true && propertyNames.size === 0 && isGlobalObjectAliasSource(node.object, ancestors, scopeAnalysis) && !isMiniGameSymbolValue(node.property, ancestors, scopeAnalysis)) {
|
|
13245
|
-
throw new Error(`Mini-game ${
|
|
13271
|
+
throw new Error(`Mini-game ${path12} contains forbidden computed global read.`);
|
|
13246
13272
|
}
|
|
13247
13273
|
const forbiddenPlatformGlobal = [...propertyNames].find((propertyName) => {
|
|
13248
13274
|
return forbiddenGlobals.has(propertyName);
|
|
13249
13275
|
});
|
|
13250
13276
|
if (forbiddenPlatformGlobal !== void 0) {
|
|
13251
|
-
throw new Error(`Mini-game ${
|
|
13277
|
+
throw new Error(`Mini-game ${path12} contains forbidden platform global ${forbiddenPlatformGlobal}.`);
|
|
13252
13278
|
}
|
|
13253
13279
|
const forbiddenDynamicCodeProperty = [...propertyNames].find((propertyName) => {
|
|
13254
13280
|
return ["eval", "Function", "importScripts"].includes(propertyName);
|
|
13255
13281
|
});
|
|
13256
13282
|
if (forbiddenDynamicCodeProperty !== void 0 && (node.computed === true || isGlobalObjectAliasSource(node.object, ancestors, scopeAnalysis)) && !isTypeofReference(node, ancestors)) {
|
|
13257
|
-
throw new Error(`Mini-game ${
|
|
13283
|
+
throw new Error(`Mini-game ${path12} contains forbidden ${forbiddenDynamicCodeProperty}.`);
|
|
13258
13284
|
}
|
|
13259
13285
|
if (isInvocationArgument(node, ancestors) && isDynamicCodeConstructorSource(node, ancestors, scopeAnalysis)) {
|
|
13260
|
-
throw new Error(`Mini-game ${
|
|
13286
|
+
throw new Error(`Mini-game ${path12} contains forbidden dynamic-code constructor.`);
|
|
13261
13287
|
}
|
|
13262
13288
|
}
|
|
13263
13289
|
if (node.type === "Property") {
|
|
@@ -13267,17 +13293,17 @@ function assertSafeNode(node, ancestors, path10, scopeAnalysis, forbiddenGlobals
|
|
|
13267
13293
|
return forbiddenGlobals.has(propertyName);
|
|
13268
13294
|
});
|
|
13269
13295
|
if (isObjectPatternProperty && forbiddenPlatformGlobal !== void 0) {
|
|
13270
|
-
throw new Error(`Mini-game ${
|
|
13296
|
+
throw new Error(`Mini-game ${path12} contains forbidden platform global ${forbiddenPlatformGlobal}.`);
|
|
13271
13297
|
}
|
|
13272
13298
|
if (isGlobalObjectDestructuring(ancestors, scopeAnalysis)) {
|
|
13273
13299
|
if (node.computed === true) {
|
|
13274
|
-
throw new Error(`Mini-game ${
|
|
13300
|
+
throw new Error(`Mini-game ${path12} contains forbidden computed destructuring.`);
|
|
13275
13301
|
}
|
|
13276
13302
|
const forbiddenDynamicCodeProperty = [...propertyNames].find((propertyName) => {
|
|
13277
13303
|
return ["eval", "Function", "importScripts"].includes(propertyName);
|
|
13278
13304
|
});
|
|
13279
13305
|
if (forbiddenDynamicCodeProperty !== void 0) {
|
|
13280
|
-
throw new Error(`Mini-game ${
|
|
13306
|
+
throw new Error(`Mini-game ${path12} contains forbidden ${forbiddenDynamicCodeProperty} destructuring.`);
|
|
13281
13307
|
}
|
|
13282
13308
|
}
|
|
13283
13309
|
}
|
|
@@ -13286,35 +13312,35 @@ function assertSafeNode(node, ancestors, path10, scopeAnalysis, forbiddenGlobals
|
|
|
13286
13312
|
const arguments_ = Array.isArray(node.arguments) ? node.arguments : [];
|
|
13287
13313
|
const firstArgument = arguments_[0];
|
|
13288
13314
|
if (isDynamicCodeConstructorInvocation(node.callee, arguments_, ancestors, scopeAnalysis)) {
|
|
13289
|
-
throw new Error(`Mini-game ${
|
|
13315
|
+
throw new Error(`Mini-game ${path12} contains forbidden dynamic-code constructor.`);
|
|
13290
13316
|
}
|
|
13291
13317
|
if (isUnknownComputedGlobalMember(node.callee, ancestors, scopeAnalysis)) {
|
|
13292
|
-
throw new Error(`Mini-game ${
|
|
13318
|
+
throw new Error(`Mini-game ${path12} contains forbidden computed global call.`);
|
|
13293
13319
|
}
|
|
13294
13320
|
if (isReflectiveDynamicCodeGlobalRead(node, ancestors, scopeAnalysis, forbiddenGlobals)) {
|
|
13295
|
-
throw new Error(`Mini-game ${
|
|
13321
|
+
throw new Error(`Mini-game ${path12} contains forbidden reflective global lookup.`);
|
|
13296
13322
|
}
|
|
13297
13323
|
if (calleeNames.has("createElement") && resolveMiniGameStaticStrings(firstArgument, ancestors, scopeAnalysis).has("script")) {
|
|
13298
|
-
throw new Error(`Mini-game ${
|
|
13324
|
+
throw new Error(`Mini-game ${path12} contains forbidden script element creation.`);
|
|
13299
13325
|
}
|
|
13300
13326
|
}
|
|
13301
13327
|
if (node.type === "NewExpression" && isAstRecord(node.callee)) {
|
|
13302
13328
|
const calleeNames = readMiniGameMemberNames(node.callee, ancestors, scopeAnalysis);
|
|
13303
13329
|
if (isDynamicCodeConstructorSource(node.callee, ancestors, scopeAnalysis)) {
|
|
13304
|
-
throw new Error(`Mini-game ${
|
|
13330
|
+
throw new Error(`Mini-game ${path12} contains forbidden dynamic-code constructor.`);
|
|
13305
13331
|
}
|
|
13306
13332
|
if (isUnknownComputedGlobalMember(node.callee, ancestors, scopeAnalysis)) {
|
|
13307
|
-
throw new Error(`Mini-game ${
|
|
13333
|
+
throw new Error(`Mini-game ${path12} contains forbidden computed global construction.`);
|
|
13308
13334
|
}
|
|
13309
13335
|
const forbiddenWorker = [...calleeNames].find((calleeName) => {
|
|
13310
13336
|
return calleeName === "Worker" || calleeName === "SharedWorker";
|
|
13311
13337
|
});
|
|
13312
13338
|
if (forbiddenWorker !== void 0) {
|
|
13313
|
-
throw new Error(`Mini-game ${
|
|
13339
|
+
throw new Error(`Mini-game ${path12} contains forbidden ${forbiddenWorker} construction.`);
|
|
13314
13340
|
}
|
|
13315
13341
|
}
|
|
13316
13342
|
if (node.type === "TaggedTemplateExpression" && isDynamicCodeConstructorSource(node.tag, ancestors, scopeAnalysis)) {
|
|
13317
|
-
throw new Error(`Mini-game ${
|
|
13343
|
+
throw new Error(`Mini-game ${path12} contains forbidden dynamic-code constructor.`);
|
|
13318
13344
|
}
|
|
13319
13345
|
}
|
|
13320
13346
|
function isInvocationArgument(node, ancestors) {
|
|
@@ -15165,10 +15191,10 @@ function createEvidence(input, files, effectiveTargetConfig, iconManifest, packa
|
|
|
15165
15191
|
files
|
|
15166
15192
|
};
|
|
15167
15193
|
}
|
|
15168
|
-
function requireEvidenceFile(artifactRoot, files,
|
|
15169
|
-
const file = files.find((candidate) => candidate.path ===
|
|
15170
|
-
if (file === void 0 || !existsSync12(join11(artifactRoot,
|
|
15171
|
-
throw new Error(`Mini-game artifact is missing required evidence file: ${
|
|
15194
|
+
function requireEvidenceFile(artifactRoot, files, path12) {
|
|
15195
|
+
const file = files.find((candidate) => candidate.path === path12);
|
|
15196
|
+
if (file === void 0 || !existsSync12(join11(artifactRoot, path12))) {
|
|
15197
|
+
throw new Error(`Mini-game artifact is missing required evidence file: ${path12}`);
|
|
15172
15198
|
}
|
|
15173
15199
|
return file;
|
|
15174
15200
|
}
|
|
@@ -15242,9 +15268,9 @@ function verifyNamedDigest(artifactRoot, reference, expectedPath, label) {
|
|
|
15242
15268
|
throw new Error(`Mini-game artifact ${label} digest mismatch.`);
|
|
15243
15269
|
}
|
|
15244
15270
|
}
|
|
15245
|
-
function readJson(
|
|
15271
|
+
function readJson(path12, label) {
|
|
15246
15272
|
try {
|
|
15247
|
-
return JSON.parse(readFileSync16(
|
|
15273
|
+
return JSON.parse(readFileSync16(path12, "utf8"));
|
|
15248
15274
|
} catch (error) {
|
|
15249
15275
|
throw new Error(`${label} is unreadable: ${formatError6(error)}`);
|
|
15250
15276
|
}
|
|
@@ -15311,8 +15337,8 @@ function assertWechatAppId(appId, production) {
|
|
|
15311
15337
|
throw new Error("WeChat Mini Game app id must be a valid AppID or the staging placeholder.");
|
|
15312
15338
|
}
|
|
15313
15339
|
}
|
|
15314
|
-
function writeJson(
|
|
15315
|
-
writeFileSync11(
|
|
15340
|
+
function writeJson(path12, input) {
|
|
15341
|
+
writeFileSync11(path12, `${JSON.stringify(input, null, 2)}
|
|
15316
15342
|
`);
|
|
15317
15343
|
}
|
|
15318
15344
|
|
|
@@ -15444,7 +15470,7 @@ function isProcessAlive(pid) {
|
|
|
15444
15470
|
}
|
|
15445
15471
|
|
|
15446
15472
|
// node_modules/.cache/mpgd-native-build/tools/target/native-build-execution.js
|
|
15447
|
-
import { existsSync as
|
|
15473
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync4, readdirSync as readdirSync8, rmSync as rmSync11, statSync as statSync6 } from "node:fs";
|
|
15448
15474
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
15449
15475
|
import { dirname as dirname11, isAbsolute as isAbsolute12, join as join15 } from "node:path";
|
|
15450
15476
|
|
|
@@ -16248,9 +16274,14 @@ function applyCapacitorShellCsp(webDir) {
|
|
|
16248
16274
|
}
|
|
16249
16275
|
|
|
16250
16276
|
// node_modules/.cache/mpgd-native-build/tools/target/native-store-policy.js
|
|
16251
|
-
import { existsSync as
|
|
16277
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "node:fs";
|
|
16252
16278
|
import { dirname as dirname9, join as join13 } from "node:path";
|
|
16253
16279
|
|
|
16280
|
+
// node_modules/.cache/mpgd-native-build/packages/cli/src/crash-reporting-starter.js
|
|
16281
|
+
import { existsSync as existsSync19, lstatSync as lstatSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync15 } from "node:fs";
|
|
16282
|
+
import path7 from "node:path";
|
|
16283
|
+
import { satisfies, valid, validRange } from "semver";
|
|
16284
|
+
|
|
16254
16285
|
// node_modules/.cache/mpgd-native-build/packages/cli/src/native-shell-identity.js
|
|
16255
16286
|
function assertAndroidSettingsAppProject(source) {
|
|
16256
16287
|
const clean = stripGradleComments(source);
|
|
@@ -16620,238 +16651,615 @@ function readBracedText(source, opening) {
|
|
|
16620
16651
|
throw new Error("Existing native project block is incomplete.");
|
|
16621
16652
|
}
|
|
16622
16653
|
|
|
16623
|
-
// node_modules/.cache/mpgd-native-build/packages/cli/src/
|
|
16624
|
-
|
|
16625
|
-
|
|
16626
|
-
|
|
16627
|
-
|
|
16628
|
-
|
|
16629
|
-
|
|
16630
|
-
|
|
16631
|
-
|
|
16632
|
-
|
|
16633
|
-
|
|
16634
|
-
|
|
16635
|
-
|
|
16636
|
-
|
|
16637
|
-
}
|
|
16638
|
-
|
|
16639
|
-
|
|
16640
|
-
|
|
16641
|
-
function lacksExportComplianceKey(plist) {
|
|
16642
|
-
return readPlistTopLevelValue(plist, "ITSAppUsesNonExemptEncryption") === void 0;
|
|
16643
|
-
}
|
|
16644
|
-
function requires32BitArm(capabilitiesXml) {
|
|
16645
|
-
return /<string>\s*armv7\s*<\/string>/u.test(capabilitiesXml);
|
|
16646
|
-
}
|
|
16647
|
-
function readPlistTopLevelValue(plist, key) {
|
|
16648
|
-
const masked = plist.replace(/<!--[\s\S]*?-->/gu, (comment) => comment.replace(/[^\n]/gu, " "));
|
|
16649
|
-
const marker = new RegExp(`<key>\\s*${escapeRegExp(key)}\\s*</key>\\s*`, "u").exec(masked);
|
|
16650
|
-
if (marker === null) {
|
|
16651
|
-
return void 0;
|
|
16652
|
-
}
|
|
16653
|
-
const start = marker.index + marker[0].length;
|
|
16654
|
-
const open2 = /^<([A-Za-z]+)\s*(\/?)>/u.exec(masked.slice(start));
|
|
16655
|
-
if (open2 === null) {
|
|
16656
|
-
throw new Error(`Info.plist key ${key} has no readable value.`);
|
|
16657
|
-
}
|
|
16658
|
-
const tag = open2[1] ?? "";
|
|
16659
|
-
if (open2[2] === "/") {
|
|
16660
|
-
const end = start + open2[0].length;
|
|
16661
|
-
return { start, end, xml: plist.slice(start, end) };
|
|
16662
|
-
}
|
|
16663
|
-
let depth = 0;
|
|
16664
|
-
const tags = new RegExp(`<(/?)${tag}\\b[^>]*?(/?)>`, "gu");
|
|
16665
|
-
tags.lastIndex = start;
|
|
16666
|
-
for (let match = tags.exec(masked); match !== null; match = tags.exec(masked)) {
|
|
16667
|
-
if (match[2] === "/") {
|
|
16668
|
-
continue;
|
|
16669
|
-
}
|
|
16670
|
-
depth += match[1] === "/" ? -1 : 1;
|
|
16671
|
-
if (depth === 0) {
|
|
16672
|
-
const end = match.index + match[0].length;
|
|
16673
|
-
return { start, end, xml: plist.slice(start, end) };
|
|
16674
|
-
}
|
|
16675
|
-
}
|
|
16676
|
-
throw new Error(`Info.plist key ${key} has an unclosed value.`);
|
|
16677
|
-
}
|
|
16678
|
-
function escapeRegExp(value) {
|
|
16679
|
-
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
16680
|
-
}
|
|
16681
|
-
var nativeShellOrientations = ["portrait", "landscape", "any"];
|
|
16682
|
-
function readGameNativeOrientation(gameConfig) {
|
|
16683
|
-
if (!isRecord5(gameConfig) || gameConfig.native === void 0) {
|
|
16684
|
-
return void 0;
|
|
16685
|
-
}
|
|
16686
|
-
if (!isRecord5(gameConfig.native)) {
|
|
16687
|
-
throw new Error("mpgd.game.json native must be an object when present.");
|
|
16688
|
-
}
|
|
16689
|
-
for (const key of Object.keys(gameConfig.native)) {
|
|
16690
|
-
if (key !== "orientation") {
|
|
16691
|
-
throw new Error(`mpgd.game.json native.${key} is not supported.`);
|
|
16692
|
-
}
|
|
16693
|
-
}
|
|
16694
|
-
const orientation = gameConfig.native.orientation;
|
|
16695
|
-
if (orientation === void 0) {
|
|
16696
|
-
return void 0;
|
|
16697
|
-
}
|
|
16698
|
-
if (!nativeShellOrientations.includes(orientation)) {
|
|
16699
|
-
throw new Error("mpgd.game.json native.orientation must be 'portrait', 'landscape' or 'any'.");
|
|
16700
|
-
}
|
|
16701
|
-
return orientation;
|
|
16702
|
-
}
|
|
16703
|
-
function readIosDeviceFamily(metadata) {
|
|
16704
|
-
if (!isRecord5(metadata) || metadata.iosDeviceFamily === void 0) {
|
|
16705
|
-
return void 0;
|
|
16706
|
-
}
|
|
16707
|
-
if (metadata.iosDeviceFamily !== "universal" && metadata.iosDeviceFamily !== "iphone") {
|
|
16708
|
-
throw new Error("ios metadata.iosDeviceFamily must be 'universal' or 'iphone'.");
|
|
16709
|
-
}
|
|
16710
|
-
return metadata.iosDeviceFamily;
|
|
16711
|
-
}
|
|
16712
|
-
var iosPortrait = "UIInterfaceOrientationPortrait";
|
|
16713
|
-
var iosPortraitUpsideDown = "UIInterfaceOrientationPortraitUpsideDown";
|
|
16714
|
-
var iosLandscape = [
|
|
16715
|
-
"UIInterfaceOrientationLandscapeLeft",
|
|
16716
|
-
"UIInterfaceOrientationLandscapeRight"
|
|
16717
|
-
];
|
|
16718
|
-
var iosIpadOrientations = [
|
|
16719
|
-
iosPortrait,
|
|
16720
|
-
iosPortraitUpsideDown,
|
|
16721
|
-
...iosLandscape
|
|
16722
|
-
];
|
|
16723
|
-
function readPlistStrings(plist, key) {
|
|
16724
|
-
const value = readPlistTopLevelValue(plist, key);
|
|
16725
|
-
if (value === void 0) {
|
|
16726
|
-
return void 0;
|
|
16727
|
-
}
|
|
16728
|
-
return [...value.xml.matchAll(/<string>\s*([^<]*?)\s*<\/string>/gu)].map((match) => match[1] ?? "");
|
|
16729
|
-
}
|
|
16730
|
-
function inspectIosInfoPlistOrientation(plist, orientation, deviceFamily) {
|
|
16731
|
-
const issues = [];
|
|
16732
|
-
if (orientation !== void 0) {
|
|
16733
|
-
const listed = readPlistStrings(plist, "UISupportedInterfaceOrientations");
|
|
16734
|
-
const iphone = listed ?? iosIpadOrientations;
|
|
16735
|
-
const portrait = iphone.some((value) => value === iosPortrait || value === iosPortraitUpsideDown);
|
|
16736
|
-
const landscape = iphone.some((value) => iosLandscape.includes(value));
|
|
16737
|
-
const matchesByOrientation = {
|
|
16738
|
-
portrait: portrait && !landscape,
|
|
16739
|
-
landscape: landscape && !portrait,
|
|
16740
|
-
any: portrait && landscape
|
|
16741
|
-
};
|
|
16742
|
-
const matches = matchesByOrientation[orientation];
|
|
16743
|
-
if (!matches) {
|
|
16744
|
-
issues.push({
|
|
16745
|
-
level: "error",
|
|
16746
|
-
message: `iOS Info.plist UISupportedInterfaceOrientations (${listed === void 0 ? "key missing, so every orientation" : iphone.join(", ") || "none"}) does not match mpgd.game.json native.orientation "${orientation}".`
|
|
16747
|
-
});
|
|
16748
|
-
}
|
|
16749
|
-
}
|
|
16750
|
-
if (deviceFamily === "universal") {
|
|
16751
|
-
const ipad = readPlistStrings(plist, "UISupportedInterfaceOrientations~ipad") ?? readPlistStrings(plist, "UISupportedInterfaceOrientations") ?? iosIpadOrientations;
|
|
16752
|
-
if (iosIpadOrientations.some((value) => !ipad.includes(value))) {
|
|
16753
|
-
issues.push({
|
|
16754
|
-
level: "warning",
|
|
16755
|
-
message: "iOS Info.plist iPad orientations (UISupportedInterfaceOrientations~ipad, or UISupportedInterfaceOrientations when that key is absent) do not list all four; Apple asks iPad apps to support every orientation (TN3192) and deprecated UIRequiresFullScreen in iPadOS 26."
|
|
16756
|
-
});
|
|
16757
|
-
}
|
|
16758
|
-
}
|
|
16759
|
-
return issues;
|
|
16760
|
-
}
|
|
16761
|
-
function iosTargetedDeviceFamily(family) {
|
|
16762
|
-
return family === "iphone" ? "1" : "1,2";
|
|
16763
|
-
}
|
|
16764
|
-
function readIosAppReleaseDeviceFamily(project) {
|
|
16765
|
-
for (const id of readAppTargetConfigurationIds(project)) {
|
|
16766
|
-
const settings = locatePbxBuildSettings(project, id);
|
|
16767
|
-
if (settings.name !== "Release") {
|
|
16768
|
-
continue;
|
|
16769
|
-
}
|
|
16770
|
-
const value = /\bTARGETED_DEVICE_FAMILY\s*=\s*([^;]+);/u.exec(project.slice(settings.start, settings.end))?.[1];
|
|
16771
|
-
return value?.trim().replace(/^"(.*)"$/u, "$1").replace(/\s+/gu, "");
|
|
16772
|
-
}
|
|
16773
|
-
return void 0;
|
|
16774
|
-
}
|
|
16775
|
-
function inspectIosProjectDeviceFamily(project, family) {
|
|
16776
|
-
if (family === void 0) {
|
|
16777
|
-
return [];
|
|
16778
|
-
}
|
|
16779
|
-
const actual = readIosAppReleaseDeviceFamily(project);
|
|
16780
|
-
const expected = iosTargetedDeviceFamily(family);
|
|
16781
|
-
if (actual === expected) {
|
|
16782
|
-
return [];
|
|
16783
|
-
}
|
|
16784
|
-
return [{
|
|
16785
|
-
level: "error",
|
|
16786
|
-
message: `iOS App target Release TARGETED_DEVICE_FAMILY is ${actual ?? "unset"}, but mpgd.targets.json ios metadata.iosDeviceFamily "${family}" needs "${expected}".`
|
|
16787
|
-
}];
|
|
16788
|
-
}
|
|
16789
|
-
var androidOrientationValues = {
|
|
16790
|
-
portrait: ["portrait", "sensorPortrait", "userPortrait", "reversePortrait"],
|
|
16791
|
-
landscape: ["landscape", "sensorLandscape", "userLandscape", "reverseLandscape"],
|
|
16792
|
-
any: ["unspecified", "user", "sensor", "fullSensor", "fullUser"]
|
|
16654
|
+
// node_modules/.cache/mpgd-native-build/packages/cli/src/notifications-starter.js
|
|
16655
|
+
var notificationsMessagingPlugin = "@capacitor-firebase/messaging";
|
|
16656
|
+
var notificationsGameDependencies = Object.freeze({
|
|
16657
|
+
[notificationsMessagingPlugin]: "8.5.2",
|
|
16658
|
+
"@capacitor/local-notifications": "8.3.1",
|
|
16659
|
+
firebase: "12.19.0"
|
|
16660
|
+
});
|
|
16661
|
+
var notificationsShellPlugins = Object.freeze([
|
|
16662
|
+
notificationsMessagingPlugin,
|
|
16663
|
+
"@capacitor/local-notifications"
|
|
16664
|
+
]);
|
|
16665
|
+
var gatewayImport = {
|
|
16666
|
+
anchor: "import type { RuntimeConfig } from '../runtimeDetector';\n",
|
|
16667
|
+
replacement: [
|
|
16668
|
+
"import { createStarterCapacitorNotifications } from '../capacitorNotifications';",
|
|
16669
|
+
"import type { RuntimeConfig } from '../runtimeDetector';",
|
|
16670
|
+
""
|
|
16671
|
+
].join("\n")
|
|
16793
16672
|
};
|
|
16794
|
-
|
|
16795
|
-
|
|
16796
|
-
|
|
16797
|
-
|
|
16798
|
-
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
|
|
16802
|
-
|
|
16803
|
-
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
|
|
16809
|
-
|
|
16810
|
-
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
}
|
|
16834
|
-
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
|
|
16845
|
-
|
|
16846
|
-
|
|
16847
|
-
|
|
16848
|
-
|
|
16849
|
-
|
|
16850
|
-
|
|
16851
|
-
}
|
|
16852
|
-
|
|
16853
|
-
|
|
16854
|
-
|
|
16673
|
+
var gatewayProviders = (platform) => ({
|
|
16674
|
+
anchor: " const providers = createStoreProviders(runtime, () => gateway);\n",
|
|
16675
|
+
replacement: [
|
|
16676
|
+
" const providers = [",
|
|
16677
|
+
" ...createStoreProviders(runtime, () => gateway),",
|
|
16678
|
+
" // Notifications v2 (FCM and local reminders); `notifications/topics.json`",
|
|
16679
|
+
" // maps the topics, and the shell needs the two plugins",
|
|
16680
|
+
" // (`mpgd target init capacitor --providers notifications`).",
|
|
16681
|
+
` ...(await createStarterCapacitorNotifications('${platform}', runtime.configTarget)),`,
|
|
16682
|
+
" ];",
|
|
16683
|
+
""
|
|
16684
|
+
].join("\n")
|
|
16685
|
+
});
|
|
16686
|
+
var commonEdits = {
|
|
16687
|
+
"src/platform/buildGateways/capacitorAndroid.ts": [gatewayImport, gatewayProviders("android")],
|
|
16688
|
+
"src/platform/buildGateways/capacitorIos.ts": [gatewayImport, gatewayProviders("ios")],
|
|
16689
|
+
"src/platform/buildGateways/reddit.ts": [
|
|
16690
|
+
{
|
|
16691
|
+
anchor: " createDevvitCommerceProducts,\n createDevvitPlatformGateway,\n",
|
|
16692
|
+
replacement: [
|
|
16693
|
+
" createDevvitCommerceProducts,",
|
|
16694
|
+
" createDevvitNotificationsBackend,",
|
|
16695
|
+
" createDevvitPlatformGateway,",
|
|
16696
|
+
""
|
|
16697
|
+
].join("\n")
|
|
16698
|
+
},
|
|
16699
|
+
{
|
|
16700
|
+
anchor: "import { createDevvitWebPaymentsClient } from '@mpgd/adapter-devvit/web';\n",
|
|
16701
|
+
replacement: [
|
|
16702
|
+
"import {",
|
|
16703
|
+
" createDevvitWebLoginPrompt,",
|
|
16704
|
+
" createDevvitWebPaymentsClient,",
|
|
16705
|
+
"} from '@mpgd/adapter-devvit/web';",
|
|
16706
|
+
""
|
|
16707
|
+
].join("\n")
|
|
16708
|
+
},
|
|
16709
|
+
{
|
|
16710
|
+
anchor: "import type { RuntimeConfig } from '../runtimeDetector';\n",
|
|
16711
|
+
replacement: [
|
|
16712
|
+
"import { setStarterHostedNotificationBackend } from '../notificationBackend';",
|
|
16713
|
+
"import { starterNotificationTopics } from '../notifications';",
|
|
16714
|
+
"import type { RuntimeConfig } from '../runtimeDetector';",
|
|
16715
|
+
""
|
|
16716
|
+
].join("\n")
|
|
16717
|
+
},
|
|
16718
|
+
{
|
|
16719
|
+
anchor: " ...(commerce === undefined ? {} : { commerce }),\n",
|
|
16720
|
+
replacement: [
|
|
16721
|
+
" ...(commerce === undefined ? {} : { commerce }),",
|
|
16722
|
+
" // Notifications v2: the game-rendered opt-in the server bridge serves",
|
|
16723
|
+
" // (a gated beta: `integrations.notifications` stays approval-required",
|
|
16724
|
+
" // until Reddit approves the app), and Reddit login for a logged-out",
|
|
16725
|
+
" // player, who must log in before opting in.",
|
|
16726
|
+
" ...notificationOptions(runtime),",
|
|
16727
|
+
" loginPrompt: createDevvitWebLoginPrompt(),",
|
|
16728
|
+
""
|
|
16729
|
+
].join("\n")
|
|
16730
|
+
},
|
|
16731
|
+
{
|
|
16732
|
+
anchor: "function createCommerceOptions(): DevvitGatewayCommerceOptions | undefined {\n",
|
|
16733
|
+
replacement: [
|
|
16734
|
+
"function notificationOptions(",
|
|
16735
|
+
" runtime: RuntimeConfig,",
|
|
16736
|
+
"): Pick<Parameters<typeof createDevvitPlatformGateway>[0], 'notifications'> {",
|
|
16737
|
+
" const topics = starterNotificationTopics(runtime.configTarget).map((topic) => topic.id);",
|
|
16738
|
+
" if (topics.length === 0) {",
|
|
16739
|
+
" return {};",
|
|
16740
|
+
" }",
|
|
16741
|
+
" // The runtime's backend is the Devvit server (consent records, reminders, notices for the",
|
|
16742
|
+
" // logged-in Reddit user), over the same server bridge as the gateway; created on first use.",
|
|
16743
|
+
" setStarterHostedNotificationBackend(runtime.configTarget, () =>",
|
|
16744
|
+
" createDevvitNotificationsBackend({ appVersion: runtime.appVersion, buildId: runtime.buildId }));",
|
|
16745
|
+
" return { notifications: { topics } };",
|
|
16746
|
+
"}",
|
|
16747
|
+
"",
|
|
16748
|
+
"function createCommerceOptions(): DevvitGatewayCommerceOptions | undefined {",
|
|
16749
|
+
""
|
|
16750
|
+
].join("\n")
|
|
16751
|
+
}
|
|
16752
|
+
],
|
|
16753
|
+
"apps/target-devvit/src/server/index.ts": [
|
|
16754
|
+
{
|
|
16755
|
+
anchor: "import { context, createServer, getServerPort, payments, reddit, redis } from '@devvit/web/server';\n",
|
|
16756
|
+
replacement: [
|
|
16757
|
+
"import {",
|
|
16758
|
+
" context,",
|
|
16759
|
+
" createServer,",
|
|
16760
|
+
" getServerPort,",
|
|
16761
|
+
" notifications,",
|
|
16762
|
+
" payments,",
|
|
16763
|
+
" reddit,",
|
|
16764
|
+
" redis,",
|
|
16765
|
+
"} from '@devvit/web/server';",
|
|
16766
|
+
""
|
|
16767
|
+
].join("\n")
|
|
16768
|
+
},
|
|
16769
|
+
{
|
|
16770
|
+
anchor: [
|
|
16771
|
+
"import {",
|
|
16772
|
+
" createDevvitCommerceBridgeProducts,",
|
|
16773
|
+
" createDevvitCommerceV2BridgeHandler,",
|
|
16774
|
+
"} from '@mpgd/adapter-devvit/server';",
|
|
16775
|
+
""
|
|
16776
|
+
].join("\n"),
|
|
16777
|
+
replacement: [
|
|
16778
|
+
"import {",
|
|
16779
|
+
" createDevvitCommerceBridgeProducts,",
|
|
16780
|
+
" createDevvitCommerceV2BridgeHandler,",
|
|
16781
|
+
" createDevvitNotificationService,",
|
|
16782
|
+
" createDevvitNotificationsBackendBridgeHandler,",
|
|
16783
|
+
" createDevvitNotificationsV2BridgeHandler,",
|
|
16784
|
+
"} from '@mpgd/adapter-devvit/server';",
|
|
16785
|
+
""
|
|
16786
|
+
].join("\n")
|
|
16787
|
+
},
|
|
16788
|
+
{
|
|
16789
|
+
anchor: "import type { ProductCatalog } from '@mpgd/catalog';\n",
|
|
16790
|
+
replacement: [
|
|
16791
|
+
"import { resolveNotificationTopicsForTarget, type NotificationTopicCatalog, type ProductCatalog } from '@mpgd/catalog';",
|
|
16792
|
+
"import { assertNotificationDeployment } from '@mpgd/platform/notifications';",
|
|
16793
|
+
""
|
|
16794
|
+
].join("\n")
|
|
16795
|
+
},
|
|
16796
|
+
{
|
|
16797
|
+
anchor: "import devvitManifest from '../../devvit.json';\n",
|
|
16798
|
+
replacement: [
|
|
16799
|
+
"import notificationDeploymentJson from '../../../../notifications/deployment.json';",
|
|
16800
|
+
"import notificationTopicsJson from '../../../../notifications/topics.json';",
|
|
16801
|
+
"import devvitManifest from '../../devvit.json';",
|
|
16802
|
+
""
|
|
16803
|
+
].join("\n")
|
|
16804
|
+
},
|
|
16805
|
+
{
|
|
16806
|
+
anchor: [
|
|
16807
|
+
"const handleBridgeRequest = createDevvitBridgeHandler({",
|
|
16808
|
+
" redis,",
|
|
16809
|
+
" currentPlayerId,",
|
|
16810
|
+
" currentDisplayName,",
|
|
16811
|
+
" storageKeyNamespace: gameName,",
|
|
16812
|
+
" ...(commerce === undefined ? {} : { commerce }),",
|
|
16813
|
+
"});",
|
|
16814
|
+
""
|
|
16815
|
+
].join("\n"),
|
|
16816
|
+
replacement: [
|
|
16817
|
+
"/**",
|
|
16818
|
+
" * Notifications v2 (`notifications/topics.json`, mapped for the `reddit`",
|
|
16819
|
+
" * target): the game-rendered opt-in for the logged-in requester, and the",
|
|
16820
|
+
" * service that records consent and sends server reminders over the Devvit",
|
|
16821
|
+
" * notifications plugin. Devvit notifications are a gated beta: the game",
|
|
16822
|
+
" * shows them only once `integrations.notifications` is `available`.",
|
|
16823
|
+
" */",
|
|
16824
|
+
"const notificationTopicCatalog = notificationTopicsJson as NotificationTopicCatalog;",
|
|
16825
|
+
"const redditNotificationTopics = readRedditNotificationTopics();",
|
|
16826
|
+
"const notificationService: ReturnType<typeof createDevvitNotificationService>['service'] | undefined =",
|
|
16827
|
+
" redditNotificationTopics.length === 0 ? undefined : createNotificationService();",
|
|
16828
|
+
"// The opt-in is served only with the service that sends; a refused catalog turns both off.",
|
|
16829
|
+
"const notificationsBridge = notificationService === undefined",
|
|
16830
|
+
" ? undefined",
|
|
16831
|
+
" : createDevvitNotificationsV2BridgeHandler({",
|
|
16832
|
+
" notifications,",
|
|
16833
|
+
" currentUserId: currentPlayerId,",
|
|
16834
|
+
" topics: redditNotificationTopics,",
|
|
16835
|
+
" });",
|
|
16836
|
+
"// The webview runtime's backend: consent records, reminders, and notices for the request's user.",
|
|
16837
|
+
"const notificationsBackend = notificationService === undefined",
|
|
16838
|
+
" ? undefined",
|
|
16839
|
+
" : createDevvitNotificationsBackendBridgeHandler({ service: notificationService, context: () => context });",
|
|
16840
|
+
"const handleBridgeRequest = createDevvitBridgeHandler({",
|
|
16841
|
+
" redis,",
|
|
16842
|
+
" currentPlayerId,",
|
|
16843
|
+
" currentDisplayName,",
|
|
16844
|
+
" storageKeyNamespace: gameName,",
|
|
16845
|
+
" ...(commerce === undefined ? {} : { commerce }),",
|
|
16846
|
+
" ...(notificationsBridge === undefined ? {} : { notifications: notificationsBridge }),",
|
|
16847
|
+
" ...(notificationsBackend === undefined ? {} : { notificationsBackend }),",
|
|
16848
|
+
"});",
|
|
16849
|
+
""
|
|
16850
|
+
].join("\n")
|
|
16851
|
+
},
|
|
16852
|
+
{
|
|
16853
|
+
anchor: [
|
|
16854
|
+
"/**",
|
|
16855
|
+
" * The notifications v2 service (`createDevvitNotificationService` from",
|
|
16856
|
+
" * `@mpgd/adapter-devvit/server`). None until the game declares a topic",
|
|
16857
|
+
" * catalog, so the scheduler tasks below do no work.",
|
|
16858
|
+
" */",
|
|
16859
|
+
"const notificationService: Parameters<typeof handleNotificationTask>[0]['notifications'] = undefined;",
|
|
16860
|
+
""
|
|
16861
|
+
].join("\n"),
|
|
16862
|
+
replacement: [
|
|
16863
|
+
"/** The topic ids the catalog maps for Reddit; none when the catalog cannot be read. */",
|
|
16864
|
+
"function readRedditNotificationTopics(): readonly string[] {",
|
|
16865
|
+
" try {",
|
|
16866
|
+
" return resolveNotificationTopicsForTarget(notificationTopicCatalog, 'reddit').map((topic) => topic.id);",
|
|
16867
|
+
" } catch (error) {",
|
|
16868
|
+
" console.error(`devvit notifications disabled: ${errorMessage(error)}`);",
|
|
16869
|
+
" return [];",
|
|
16870
|
+
" }",
|
|
16871
|
+
"}",
|
|
16872
|
+
"",
|
|
16873
|
+
"/**",
|
|
16874
|
+
" * The notifications v2 service over Redis and the Devvit plugin; the",
|
|
16875
|
+
" * scheduler tasks below run its reminders and purges. A catalog or",
|
|
16876
|
+
" * deployment the service refuses turns notifications off, never the game",
|
|
16877
|
+
" * server.",
|
|
16878
|
+
" */",
|
|
16879
|
+
"function createNotificationService(): ReturnType<typeof createDevvitNotificationService>['service'] | undefined {",
|
|
16880
|
+
" try {",
|
|
16881
|
+
" return createDevvitNotificationService({",
|
|
16882
|
+
" redis,",
|
|
16883
|
+
" notifications,",
|
|
16884
|
+
" catalog: notificationTopicCatalog,",
|
|
16885
|
+
" deployment: assertNotificationDeployment(notificationDeploymentJson),",
|
|
16886
|
+
" }).service;",
|
|
16887
|
+
" } catch (error) {",
|
|
16888
|
+
" console.error(`devvit notifications disabled: ${errorMessage(error)}`);",
|
|
16889
|
+
" return undefined;",
|
|
16890
|
+
" }",
|
|
16891
|
+
"}",
|
|
16892
|
+
""
|
|
16893
|
+
].join("\n")
|
|
16894
|
+
}
|
|
16895
|
+
]
|
|
16896
|
+
};
|
|
16897
|
+
var phaserEdits = {
|
|
16898
|
+
"src/runtime/createGame.ts": [
|
|
16899
|
+
{
|
|
16900
|
+
anchor: "import { LobbyScene } from '../scenes/LobbyScene';\n",
|
|
16901
|
+
replacement: [
|
|
16902
|
+
"import { LobbyScene } from '../scenes/LobbyScene';",
|
|
16903
|
+
"import {",
|
|
16904
|
+
" NotificationSettingsScene,",
|
|
16905
|
+
" routeNotificationSettingsOpens,",
|
|
16906
|
+
"} from '../scenes/NotificationSettingsScene';",
|
|
16907
|
+
""
|
|
16908
|
+
].join("\n")
|
|
16909
|
+
},
|
|
16910
|
+
{
|
|
16911
|
+
anchor: " scene: [BootScene, LobbyScene, PlayScene],\n",
|
|
16912
|
+
replacement: " scene: [BootScene, LobbyScene, PlayScene, NotificationSettingsScene],\n"
|
|
16913
|
+
},
|
|
16914
|
+
{
|
|
16915
|
+
anchor: " ownGameAudio(game, input.context);\n",
|
|
16916
|
+
replacement: [
|
|
16917
|
+
" ownGameAudio(game, input.context);",
|
|
16918
|
+
" // The advertising opt-out action and consent notices open the settings screen.",
|
|
16919
|
+
" routeNotificationSettingsOpens(game, input.context);",
|
|
16920
|
+
""
|
|
16921
|
+
].join("\n")
|
|
16922
|
+
}
|
|
16923
|
+
],
|
|
16924
|
+
"src/scenes/LobbyScene.ts": [
|
|
16925
|
+
{
|
|
16926
|
+
anchor: "import { starterContextKey, type StarterContext } from '../runtime/gameContext';\n",
|
|
16927
|
+
replacement: [
|
|
16928
|
+
"import { starterContextKey, type StarterContext } from '../runtime/gameContext';",
|
|
16929
|
+
"import { notificationSettingsSceneKey } from './NotificationSettingsScene';",
|
|
16930
|
+
""
|
|
16931
|
+
].join("\n")
|
|
16932
|
+
},
|
|
16933
|
+
{
|
|
16934
|
+
anchor: " this.input.once('pointerdown', () => this.scene.start('PlayScene'));\n",
|
|
16935
|
+
replacement: [
|
|
16936
|
+
" // The settings button shows only where this target has notifications.",
|
|
16937
|
+
" const notificationsButton = context.platform.notificationsV2 === undefined",
|
|
16938
|
+
" ? undefined",
|
|
16939
|
+
" : this.add",
|
|
16940
|
+
" .text(940, 16, locale === 'ko' ? '\uC54C\uB9BC \uC124\uC815' : 'Notifications', {",
|
|
16941
|
+
" color: '#5eead4',",
|
|
16942
|
+
" fontFamily: 'Arial, sans-serif',",
|
|
16943
|
+
" fontSize: '22px',",
|
|
16944
|
+
" })",
|
|
16945
|
+
" .setOrigin(1, 0)",
|
|
16946
|
+
" .setPadding(16, 12, 16, 12)",
|
|
16947
|
+
" .setInteractive({ useHandCursor: true });",
|
|
16948
|
+
" notificationsButton?.on('pointerup', () => this.scene.start(notificationSettingsSceneKey));",
|
|
16949
|
+
" // A tap anywhere else starts the game; the scene drops this listener on shutdown.",
|
|
16950
|
+
" this.input.on('pointerdown', (_pointer: Phaser.Input.Pointer, over: Phaser.GameObjects.GameObject[]) => {",
|
|
16951
|
+
" if (notificationsButton === undefined || !over.includes(notificationsButton)) {",
|
|
16952
|
+
" this.scene.start('PlayScene');",
|
|
16953
|
+
" }",
|
|
16954
|
+
" });",
|
|
16955
|
+
""
|
|
16956
|
+
].join("\n")
|
|
16957
|
+
}
|
|
16958
|
+
]
|
|
16959
|
+
};
|
|
16960
|
+
var liteEdits = {
|
|
16961
|
+
"src/runtime/createGame.ts": [
|
|
16962
|
+
{
|
|
16963
|
+
anchor: "import { createTapGame } from '../lite/tapGame';\n",
|
|
16964
|
+
replacement: [
|
|
16965
|
+
"import { mountNotificationSettingsPanel } from '../lite/notificationSettingsPanel';",
|
|
16966
|
+
"import { createTapGame } from '../lite/tapGame';",
|
|
16967
|
+
""
|
|
16968
|
+
].join("\n")
|
|
16969
|
+
},
|
|
16970
|
+
{
|
|
16971
|
+
anchor: " const shell = createTapGame({ mount, title: '__GAME_TITLE__' });\n",
|
|
16972
|
+
replacement: [
|
|
16973
|
+
" const shell = createTapGame({ mount, title: '__GAME_TITLE__' });",
|
|
16974
|
+
" const disposeNotificationSettings = mountNotificationSettingsPanel(mount, input.context);",
|
|
16975
|
+
""
|
|
16976
|
+
].join("\n")
|
|
16977
|
+
},
|
|
16978
|
+
{
|
|
16979
|
+
anchor: " audio.dispose();\n",
|
|
16980
|
+
replacement: [" audio.dispose();", " disposeNotificationSettings();", ""].join("\n")
|
|
16981
|
+
}
|
|
16982
|
+
]
|
|
16983
|
+
};
|
|
16984
|
+
var readmeSection = [
|
|
16985
|
+
"",
|
|
16986
|
+
"## Notifications",
|
|
16987
|
+
"",
|
|
16988
|
+
"This game was created with `--providers notifications`. Its topics live in",
|
|
16989
|
+
"`notifications/topics.json` and the backend settings (`advertisingRules`,",
|
|
16990
|
+
"the advertising sender) in `notifications/deployment.json`; run",
|
|
16991
|
+
"`pnpm validate:notifications` after every change and before every release.",
|
|
16992
|
+
"Replace the sender contact placeholder in `notifications/deployment.json`",
|
|
16993
|
+
"before any advertising is sent. The notification settings screen asks for the",
|
|
16994
|
+
"OS or host permission and records reminder, advertising (\uAD11\uACE0\uC131 \uC815\uBCF4",
|
|
16995
|
+
"\uC218\uC2E0\uB3D9\uC758), and night consent through the notifications runtime. See",
|
|
16996
|
+
"`docs/NOTIFICATIONS.md` and, for Android and iOS, the mpgd-kit Firebase setup",
|
|
16997
|
+
"guide; `mpgd target init capacitor --providers notifications` installs the two",
|
|
16998
|
+
"Capacitor plugins into a game-owned shell.",
|
|
16999
|
+
""
|
|
17000
|
+
].join("\n");
|
|
17001
|
+
var notificationsCapacitorGateways = Object.freeze({
|
|
17002
|
+
android: "src/platform/buildGateways/capacitorAndroid.ts",
|
|
17003
|
+
ios: "src/platform/buildGateways/capacitorIos.ts"
|
|
17004
|
+
});
|
|
17005
|
+
var notificationsCapacitorGatewayModules = Object.freeze([
|
|
17006
|
+
"src/platform/capacitorNotifications.ts",
|
|
17007
|
+
"src/platform/notifications.ts",
|
|
17008
|
+
"src/platform/notificationBackend.ts",
|
|
17009
|
+
"src/platform/notificationSettings.ts",
|
|
17010
|
+
"src/platform/notificationOpens.ts"
|
|
17011
|
+
]);
|
|
17012
|
+
var notificationsCapacitorSupportFiles = Object.freeze([
|
|
17013
|
+
...notificationsCapacitorGatewayModules,
|
|
17014
|
+
"notifications/topics.json",
|
|
17015
|
+
"notifications/deployment.json",
|
|
17016
|
+
"tools/validate-notifications.ts",
|
|
17017
|
+
"docs/NOTIFICATIONS.md"
|
|
17018
|
+
]);
|
|
17019
|
+
var notificationsCapacitorTemplateSupportFiles = Object.freeze([
|
|
17020
|
+
"src/platform/serverSession.ts",
|
|
17021
|
+
"src/platform/developmentServerSession.ts"
|
|
17022
|
+
]);
|
|
17023
|
+
var notificationsCapacitorTemplateSupportImporters = Object.freeze({
|
|
17024
|
+
"src/platform/developmentServerSession.ts": {
|
|
17025
|
+
importer: "src/platform/serverSession.ts",
|
|
17026
|
+
requires: { packageName: "@mpgd/game-services", exportName: "createDevelopmentServerSession" },
|
|
17027
|
+
warning: "src/platform/serverSession.ts predates development notification sessions (VITE_MPGD_DEV_NOTIFICATION_SESSION); to try notifications locally, copy serverSession.ts and developmentServerSession.ts from the starter template."
|
|
17028
|
+
}
|
|
17029
|
+
});
|
|
17030
|
+
|
|
17031
|
+
// node_modules/.cache/mpgd-native-build/packages/cli/src/native-shell-store-policy.js
|
|
17032
|
+
function inspectIosInfoPlistStorePolicy(plist) {
|
|
17033
|
+
const issues = [];
|
|
17034
|
+
if (lacksExportComplianceKey(plist)) {
|
|
17035
|
+
issues.push({
|
|
17036
|
+
level: "warning",
|
|
17037
|
+
message: "iOS Info.plist has no ITSAppUsesNonExemptEncryption: App Store Connect will ask the export-compliance question for every build and TestFlight holds the build until it is answered. Add <key>ITSAppUsesNonExemptEncryption</key><false/> when the game uses only HTTPS/OS encryption (see docs/TESTFLIGHT_INTERNAL_SUBMISSION.md)."
|
|
17038
|
+
});
|
|
17039
|
+
}
|
|
17040
|
+
const capabilities = readPlistTopLevelValue(plist, "UIRequiredDeviceCapabilities");
|
|
17041
|
+
if (capabilities !== void 0 && requires32BitArm(capabilities.xml)) {
|
|
17042
|
+
issues.push({
|
|
17043
|
+
level: "warning",
|
|
17044
|
+
message: "iOS Info.plist UIRequiredDeviceCapabilities lists the 32-bit armv7; use arm64."
|
|
17045
|
+
});
|
|
17046
|
+
}
|
|
17047
|
+
return issues;
|
|
17048
|
+
}
|
|
17049
|
+
function lacksExportComplianceKey(plist) {
|
|
17050
|
+
return readPlistTopLevelValue(plist, "ITSAppUsesNonExemptEncryption") === void 0;
|
|
17051
|
+
}
|
|
17052
|
+
function requires32BitArm(capabilitiesXml) {
|
|
17053
|
+
return /<string>\s*armv7\s*<\/string>/u.test(capabilitiesXml);
|
|
17054
|
+
}
|
|
17055
|
+
function readPlistTopLevelValue(plist, key) {
|
|
17056
|
+
const masked = plist.replace(/<!--[\s\S]*?-->/gu, (comment) => comment.replace(/[^\n]/gu, " "));
|
|
17057
|
+
const marker = new RegExp(`<key>\\s*${escapeRegExp(key)}\\s*</key>\\s*`, "u").exec(masked);
|
|
17058
|
+
if (marker === null) {
|
|
17059
|
+
return void 0;
|
|
17060
|
+
}
|
|
17061
|
+
const start = marker.index + marker[0].length;
|
|
17062
|
+
const open2 = /^<([A-Za-z]+)\s*(\/?)>/u.exec(masked.slice(start));
|
|
17063
|
+
if (open2 === null) {
|
|
17064
|
+
throw new Error(`Info.plist key ${key} has no readable value.`);
|
|
17065
|
+
}
|
|
17066
|
+
const tag = open2[1] ?? "";
|
|
17067
|
+
if (open2[2] === "/") {
|
|
17068
|
+
const end = start + open2[0].length;
|
|
17069
|
+
return { start, end, xml: plist.slice(start, end) };
|
|
17070
|
+
}
|
|
17071
|
+
let depth = 0;
|
|
17072
|
+
const tags = new RegExp(`<(/?)${tag}\\b[^>]*?(/?)>`, "gu");
|
|
17073
|
+
tags.lastIndex = start;
|
|
17074
|
+
for (let match = tags.exec(masked); match !== null; match = tags.exec(masked)) {
|
|
17075
|
+
if (match[2] === "/") {
|
|
17076
|
+
continue;
|
|
17077
|
+
}
|
|
17078
|
+
depth += match[1] === "/" ? -1 : 1;
|
|
17079
|
+
if (depth === 0) {
|
|
17080
|
+
const end = match.index + match[0].length;
|
|
17081
|
+
return { start, end, xml: plist.slice(start, end) };
|
|
17082
|
+
}
|
|
17083
|
+
}
|
|
17084
|
+
throw new Error(`Info.plist key ${key} has an unclosed value.`);
|
|
17085
|
+
}
|
|
17086
|
+
function escapeRegExp(value) {
|
|
17087
|
+
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
17088
|
+
}
|
|
17089
|
+
var nativeShellOrientations = ["portrait", "landscape", "any"];
|
|
17090
|
+
function readGameNativeOrientation(gameConfig) {
|
|
17091
|
+
if (!isRecord5(gameConfig) || gameConfig.native === void 0) {
|
|
17092
|
+
return void 0;
|
|
17093
|
+
}
|
|
17094
|
+
if (!isRecord5(gameConfig.native)) {
|
|
17095
|
+
throw new Error("mpgd.game.json native must be an object when present.");
|
|
17096
|
+
}
|
|
17097
|
+
for (const key of Object.keys(gameConfig.native)) {
|
|
17098
|
+
if (key !== "orientation") {
|
|
17099
|
+
throw new Error(`mpgd.game.json native.${key} is not supported.`);
|
|
17100
|
+
}
|
|
17101
|
+
}
|
|
17102
|
+
const orientation = gameConfig.native.orientation;
|
|
17103
|
+
if (orientation === void 0) {
|
|
17104
|
+
return void 0;
|
|
17105
|
+
}
|
|
17106
|
+
if (!nativeShellOrientations.includes(orientation)) {
|
|
17107
|
+
throw new Error("mpgd.game.json native.orientation must be 'portrait', 'landscape' or 'any'.");
|
|
17108
|
+
}
|
|
17109
|
+
return orientation;
|
|
17110
|
+
}
|
|
17111
|
+
function readIosDeviceFamily(metadata) {
|
|
17112
|
+
if (!isRecord5(metadata) || metadata.iosDeviceFamily === void 0) {
|
|
17113
|
+
return void 0;
|
|
17114
|
+
}
|
|
17115
|
+
if (metadata.iosDeviceFamily !== "universal" && metadata.iosDeviceFamily !== "iphone") {
|
|
17116
|
+
throw new Error("ios metadata.iosDeviceFamily must be 'universal' or 'iphone'.");
|
|
17117
|
+
}
|
|
17118
|
+
return metadata.iosDeviceFamily;
|
|
17119
|
+
}
|
|
17120
|
+
var iosPortrait = "UIInterfaceOrientationPortrait";
|
|
17121
|
+
var iosPortraitUpsideDown = "UIInterfaceOrientationPortraitUpsideDown";
|
|
17122
|
+
var iosLandscape = [
|
|
17123
|
+
"UIInterfaceOrientationLandscapeLeft",
|
|
17124
|
+
"UIInterfaceOrientationLandscapeRight"
|
|
17125
|
+
];
|
|
17126
|
+
var iosIpadOrientations = [
|
|
17127
|
+
iosPortrait,
|
|
17128
|
+
iosPortraitUpsideDown,
|
|
17129
|
+
...iosLandscape
|
|
17130
|
+
];
|
|
17131
|
+
function readPlistStrings(plist, key) {
|
|
17132
|
+
const value = readPlistTopLevelValue(plist, key);
|
|
17133
|
+
if (value === void 0) {
|
|
17134
|
+
return void 0;
|
|
17135
|
+
}
|
|
17136
|
+
return [...value.xml.matchAll(/<string>\s*([^<]*?)\s*<\/string>/gu)].map((match) => match[1] ?? "");
|
|
17137
|
+
}
|
|
17138
|
+
function inspectIosInfoPlistOrientation(plist, orientation, deviceFamily) {
|
|
17139
|
+
const issues = [];
|
|
17140
|
+
if (orientation !== void 0) {
|
|
17141
|
+
const listed = readPlistStrings(plist, "UISupportedInterfaceOrientations");
|
|
17142
|
+
const iphone = listed ?? iosIpadOrientations;
|
|
17143
|
+
const portrait = iphone.some((value) => value === iosPortrait || value === iosPortraitUpsideDown);
|
|
17144
|
+
const landscape = iphone.some((value) => iosLandscape.includes(value));
|
|
17145
|
+
const matchesByOrientation = {
|
|
17146
|
+
portrait: portrait && !landscape,
|
|
17147
|
+
landscape: landscape && !portrait,
|
|
17148
|
+
any: portrait && landscape
|
|
17149
|
+
};
|
|
17150
|
+
const matches = matchesByOrientation[orientation];
|
|
17151
|
+
if (!matches) {
|
|
17152
|
+
issues.push({
|
|
17153
|
+
level: "error",
|
|
17154
|
+
message: `iOS Info.plist UISupportedInterfaceOrientations (${listed === void 0 ? "key missing, so every orientation" : iphone.join(", ") || "none"}) does not match mpgd.game.json native.orientation "${orientation}".`
|
|
17155
|
+
});
|
|
17156
|
+
}
|
|
17157
|
+
}
|
|
17158
|
+
if (deviceFamily === "universal") {
|
|
17159
|
+
const ipad = readPlistStrings(plist, "UISupportedInterfaceOrientations~ipad") ?? readPlistStrings(plist, "UISupportedInterfaceOrientations") ?? iosIpadOrientations;
|
|
17160
|
+
if (iosIpadOrientations.some((value) => !ipad.includes(value))) {
|
|
17161
|
+
issues.push({
|
|
17162
|
+
level: "warning",
|
|
17163
|
+
message: "iOS Info.plist iPad orientations (UISupportedInterfaceOrientations~ipad, or UISupportedInterfaceOrientations when that key is absent) do not list all four; Apple asks iPad apps to support every orientation (TN3192) and deprecated UIRequiresFullScreen in iPadOS 26."
|
|
17164
|
+
});
|
|
17165
|
+
}
|
|
17166
|
+
}
|
|
17167
|
+
return issues;
|
|
17168
|
+
}
|
|
17169
|
+
function iosTargetedDeviceFamily(family) {
|
|
17170
|
+
return family === "iphone" ? "1" : "1,2";
|
|
17171
|
+
}
|
|
17172
|
+
function readIosAppReleaseDeviceFamily(project) {
|
|
17173
|
+
for (const id of readAppTargetConfigurationIds(project)) {
|
|
17174
|
+
const settings = locatePbxBuildSettings(project, id);
|
|
17175
|
+
if (settings.name !== "Release") {
|
|
17176
|
+
continue;
|
|
17177
|
+
}
|
|
17178
|
+
const value = /\bTARGETED_DEVICE_FAMILY\s*=\s*([^;]+);/u.exec(project.slice(settings.start, settings.end))?.[1];
|
|
17179
|
+
return value?.trim().replace(/^"(.*)"$/u, "$1").replace(/\s+/gu, "");
|
|
17180
|
+
}
|
|
17181
|
+
return void 0;
|
|
17182
|
+
}
|
|
17183
|
+
function inspectIosProjectDeviceFamily(project, family) {
|
|
17184
|
+
if (family === void 0) {
|
|
17185
|
+
return [];
|
|
17186
|
+
}
|
|
17187
|
+
const actual = readIosAppReleaseDeviceFamily(project);
|
|
17188
|
+
const expected = iosTargetedDeviceFamily(family);
|
|
17189
|
+
if (actual === expected) {
|
|
17190
|
+
return [];
|
|
17191
|
+
}
|
|
17192
|
+
return [{
|
|
17193
|
+
level: "error",
|
|
17194
|
+
message: `iOS App target Release TARGETED_DEVICE_FAMILY is ${actual ?? "unset"}, but mpgd.targets.json ios metadata.iosDeviceFamily "${family}" needs "${expected}".`
|
|
17195
|
+
}];
|
|
17196
|
+
}
|
|
17197
|
+
var androidOrientationValues = {
|
|
17198
|
+
portrait: ["portrait", "sensorPortrait", "userPortrait", "reversePortrait"],
|
|
17199
|
+
landscape: ["landscape", "sensorLandscape", "userLandscape", "reverseLandscape"],
|
|
17200
|
+
any: ["unspecified", "user", "sensor", "fullSensor", "fullUser"]
|
|
17201
|
+
};
|
|
17202
|
+
function inspectAndroidManifestOrientation(manifest, orientation) {
|
|
17203
|
+
if (orientation === void 0) {
|
|
17204
|
+
return [];
|
|
17205
|
+
}
|
|
17206
|
+
const activity = findAndroidLauncherActivity(manifest);
|
|
17207
|
+
if (activity === void 0) {
|
|
17208
|
+
return [{ level: "error", message: "Android manifest has no launcher activity." }];
|
|
17209
|
+
}
|
|
17210
|
+
const value = readXmlAttribute(activity.tag, "android:screenOrientation") ?? "unspecified";
|
|
17211
|
+
const issues = [];
|
|
17212
|
+
if (!androidOrientationValues[orientation].includes(value)) {
|
|
17213
|
+
issues.push({
|
|
17214
|
+
level: "error",
|
|
17215
|
+
message: `Android launcher activity android:screenOrientation="${value}" does not match mpgd.game.json native.orientation "${orientation}".`
|
|
17216
|
+
});
|
|
17217
|
+
}
|
|
17218
|
+
const application = /<application\b[^>]*?>/u.exec(maskXmlComments(manifest))?.[0] ?? "";
|
|
17219
|
+
if (orientation !== "any" && readXmlAttribute(application, "android:appCategory") !== "game") {
|
|
17220
|
+
issues.push({
|
|
17221
|
+
level: "warning",
|
|
17222
|
+
message: 'Android <application> has no android:appCategory="game": Android 16 ignores the orientation lock on tablets and foldables for apps targeting API 36 unless they are games.'
|
|
17223
|
+
});
|
|
17224
|
+
}
|
|
17225
|
+
return issues;
|
|
17226
|
+
}
|
|
17227
|
+
function findAndroidLauncherActivity(manifest) {
|
|
17228
|
+
const elements2 = readAndroidActivityElements(manifest, "activity");
|
|
17229
|
+
const direct = elements2.find((element) => element.launcher);
|
|
17230
|
+
if (direct !== void 0) {
|
|
17231
|
+
return { start: direct.start, tag: direct.tag };
|
|
17232
|
+
}
|
|
17233
|
+
const alias = readAndroidActivityElements(manifest, "activity-alias").find((element) => element.launcher);
|
|
17234
|
+
const target2 = alias === void 0 ? void 0 : readXmlAttribute(alias.tag, "android:targetActivity");
|
|
17235
|
+
if (target2 === void 0) {
|
|
17236
|
+
return void 0;
|
|
17237
|
+
}
|
|
17238
|
+
const sameClass = (name) => name === target2 || target2.startsWith(".") && name.endsWith(target2) || name.startsWith(".") && target2.endsWith(name) || !name.includes(".") && name !== "" && target2.endsWith(`.${name}`) || !target2.includes(".") && name.endsWith(`.${target2}`);
|
|
17239
|
+
const match = elements2.filter((element) => sameClass(readXmlAttribute(element.tag, "android:name") ?? ""));
|
|
17240
|
+
return match.length === 1 && match[0] !== void 0 ? { start: match[0].start, tag: match[0].tag } : void 0;
|
|
17241
|
+
}
|
|
17242
|
+
function readAndroidActivityElements(manifest, element) {
|
|
17243
|
+
const masked = maskXmlComments(manifest);
|
|
17244
|
+
const openings = new RegExp(`<${element}(?=[\\s/>])(?:"[^"]*"|'[^']*'|[^>"'])*?(\\/?)>`, "gu");
|
|
17245
|
+
const found = [];
|
|
17246
|
+
for (const opening of masked.matchAll(openings)) {
|
|
17247
|
+
const start = opening.index ?? 0;
|
|
17248
|
+
const tagEnd = start + opening[0].length;
|
|
17249
|
+
const tag = manifest.slice(start, tagEnd);
|
|
17250
|
+
if (opening[1] === "/") {
|
|
17251
|
+
found.push({ start, tag, launcher: false });
|
|
17252
|
+
continue;
|
|
17253
|
+
}
|
|
17254
|
+
const close = masked.indexOf(`</${element}>`, tagEnd);
|
|
17255
|
+
const body = close === -1 ? "" : masked.slice(tagEnd, close);
|
|
17256
|
+
found.push({ start, tag, launcher: /android\.intent\.category\.LAUNCHER/u.test(body) });
|
|
17257
|
+
}
|
|
17258
|
+
return found;
|
|
17259
|
+
}
|
|
17260
|
+
function maskXmlComments(xml) {
|
|
17261
|
+
return xml.replace(/<!--[\s\S]*?-->/gu, (comment) => comment.replace(/[^\n]/gu, " "));
|
|
17262
|
+
}
|
|
16855
17263
|
function xmlAttribute(name) {
|
|
16856
17264
|
return new RegExp(`(\\s+)${escapeRegExp(name)}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, "u");
|
|
16857
17265
|
}
|
|
@@ -16976,164 +17384,525 @@ function findPbxObjectById(project, id) {
|
|
|
16976
17384
|
if (marker === null) {
|
|
16977
17385
|
return void 0;
|
|
16978
17386
|
}
|
|
16979
|
-
const body = readBraced(project, project.indexOf("{", marker.index));
|
|
16980
|
-
return { text: body.text, start: body.start };
|
|
16981
|
-
}
|
|
16982
|
-
function readPbxList(project, object, key) {
|
|
16983
|
-
const marker = new RegExp(`\\b${key}\\s*=\\s*\\(`, "u").exec(object.text);
|
|
16984
|
-
if (marker === null) {
|
|
17387
|
+
const body = readBraced(project, project.indexOf("{", marker.index));
|
|
17388
|
+
return { text: body.text, start: body.start };
|
|
17389
|
+
}
|
|
17390
|
+
function readPbxList(project, object, key) {
|
|
17391
|
+
const marker = new RegExp(`\\b${key}\\s*=\\s*\\(`, "u").exec(object.text);
|
|
17392
|
+
if (marker === null) {
|
|
17393
|
+
return void 0;
|
|
17394
|
+
}
|
|
17395
|
+
const start = object.start + marker.index + marker[0].length;
|
|
17396
|
+
let quote = false;
|
|
17397
|
+
for (let index = start; index < project.length; index += 1) {
|
|
17398
|
+
const character = project[index];
|
|
17399
|
+
if (quote) {
|
|
17400
|
+
if (character === "\\") {
|
|
17401
|
+
index += 1;
|
|
17402
|
+
} else if (character === '"') {
|
|
17403
|
+
quote = false;
|
|
17404
|
+
}
|
|
17405
|
+
continue;
|
|
17406
|
+
}
|
|
17407
|
+
if (character === "/" && project[index + 1] === "*") {
|
|
17408
|
+
const close = project.indexOf("*/", index + 2);
|
|
17409
|
+
index = close === -1 ? project.length : close + 1;
|
|
17410
|
+
continue;
|
|
17411
|
+
}
|
|
17412
|
+
if (character === '"') {
|
|
17413
|
+
quote = true;
|
|
17414
|
+
} else if (character === ")") {
|
|
17415
|
+
const text = project.slice(start, index);
|
|
17416
|
+
const ids = text.replace(/\/\*[^]*?\*\//gu, " ").split(",").map((entry) => /^\s*([A-F0-9]+)\b/u.exec(entry)?.[1]).filter((id) => id !== void 0);
|
|
17417
|
+
return { text, ids, end: index };
|
|
17418
|
+
}
|
|
17419
|
+
}
|
|
17420
|
+
return void 0;
|
|
17421
|
+
}
|
|
17422
|
+
var admobCapacitorPlugin = "@capacitor-community/admob";
|
|
17423
|
+
var androidAdIdPermission = "com.google.android.gms.permission.AD_ID";
|
|
17424
|
+
function shellUsesAdMob(shellPackage) {
|
|
17425
|
+
if (!isRecord5(shellPackage)) {
|
|
17426
|
+
return false;
|
|
17427
|
+
}
|
|
17428
|
+
return [shellPackage.dependencies, shellPackage.devDependencies].some((dependencies) => isRecord5(dependencies) && dependencies[admobCapacitorPlugin] !== void 0);
|
|
17429
|
+
}
|
|
17430
|
+
function adIdPermissions(manifest) {
|
|
17431
|
+
const masked = maskXmlComments(manifest);
|
|
17432
|
+
return [...masked.matchAll(/<uses-permission(?=[\s/>])[^>]*?\/?>(?:\s*<\/uses-permission>)?/gu)].filter((match) => readXmlAttribute(match[0], "android:name") === androidAdIdPermission);
|
|
17433
|
+
}
|
|
17434
|
+
function readAndroidAdIdDeclaration(manifest) {
|
|
17435
|
+
const permissions = adIdPermissions(manifest);
|
|
17436
|
+
if (permissions.length === 0) {
|
|
17437
|
+
return "absent";
|
|
17438
|
+
}
|
|
17439
|
+
return permissions.some((match) => readXmlAttribute(match[0], "tools:node") === "remove") ? "removed" : "declared";
|
|
17440
|
+
}
|
|
17441
|
+
function readGameAdvertisingIdPolicy(gameConfig) {
|
|
17442
|
+
const ads = isRecord5(gameConfig) ? gameConfig.ads : void 0;
|
|
17443
|
+
const admob = isRecord5(ads) ? ads.admob : void 0;
|
|
17444
|
+
const value = isRecord5(admob) ? admob.advertisingId : void 0;
|
|
17445
|
+
if (value === void 0 || value === "declared") {
|
|
17446
|
+
return "declared";
|
|
17447
|
+
}
|
|
17448
|
+
if (value === "removed") {
|
|
17449
|
+
return "removed";
|
|
17450
|
+
}
|
|
17451
|
+
throw new Error("mpgd.game.json ads.admob.advertisingId must be 'declared' or 'removed'.");
|
|
17452
|
+
}
|
|
17453
|
+
function inspectAndroidManifestAds(manifest, usesAds, advertisingIdPolicy = "declared") {
|
|
17454
|
+
const issues = [];
|
|
17455
|
+
const declaration = readAndroidAdIdDeclaration(manifest);
|
|
17456
|
+
if (usesAds) {
|
|
17457
|
+
const hasAppId = [...maskXmlComments(manifest).matchAll(/<meta-data\b[^>]*?\/?>/gu)].some((match) => readXmlAttribute(match[0], "android:name") === "com.google.android.gms.ads.APPLICATION_ID");
|
|
17458
|
+
if (!hasAppId) {
|
|
17459
|
+
issues.push({
|
|
17460
|
+
level: "error",
|
|
17461
|
+
message: "The shell installs AdMob but neither android/app/src/main/AndroidManifest.xml nor the release source set's manifest has com.google.android.gms.ads.APPLICATION_ID meta-data; the app crashes at launch."
|
|
17462
|
+
});
|
|
17463
|
+
}
|
|
17464
|
+
if (declaration === "removed" && advertisingIdPolicy !== "removed") {
|
|
17465
|
+
issues.push({
|
|
17466
|
+
level: "error",
|
|
17467
|
+
message: `AndroidManifest.xml removes ${androidAdIdPermission} although the shell installs AdMob: ads get a zeroed advertising ID on Android 13+ and the Play Console answer no longer matches. Replace the tools:node="remove" line with <uses-permission android:name="${androidAdIdPermission}" />, or, for a deliberate no-advertising-ID policy (for example a child-directed game), set ads.admob.advertisingId to "removed" in mpgd.game.json.`
|
|
17468
|
+
});
|
|
17469
|
+
}
|
|
17470
|
+
if (declaration !== "removed" && advertisingIdPolicy === "removed") {
|
|
17471
|
+
issues.push({
|
|
17472
|
+
level: "error",
|
|
17473
|
+
message: `mpgd.game.json ads.admob.advertisingId is "removed", but AndroidManifest.xml does not remove ${androidAdIdPermission}; add <uses-permission android:name="${androidAdIdPermission}" tools:node="remove" />.`
|
|
17474
|
+
});
|
|
17475
|
+
}
|
|
17476
|
+
} else if (declaration !== "removed") {
|
|
17477
|
+
issues.push({
|
|
17478
|
+
level: "warning",
|
|
17479
|
+
message: `The shell shows no AdMob ads, but AndroidManifest.xml does not remove ${androidAdIdPermission}; a dependency can still merge it. Add <uses-permission android:name="${androidAdIdPermission}" tools:node="remove" />.`
|
|
17480
|
+
});
|
|
17481
|
+
}
|
|
17482
|
+
return issues;
|
|
17483
|
+
}
|
|
17484
|
+
function inspectIosInfoPlistAds(plist, usesAds) {
|
|
17485
|
+
if (!usesAds) {
|
|
17486
|
+
return [];
|
|
17487
|
+
}
|
|
17488
|
+
const issues = [];
|
|
17489
|
+
if (readPlistTopLevelValue(plist, "GADApplicationIdentifier") === void 0) {
|
|
17490
|
+
issues.push({
|
|
17491
|
+
level: "error",
|
|
17492
|
+
message: "The shell installs AdMob but Info.plist has no GADApplicationIdentifier; the Google Mobile Ads SDK stops the app at launch."
|
|
17493
|
+
});
|
|
17494
|
+
}
|
|
17495
|
+
const networks = readPlistTopLevelValue(plist, "SKAdNetworkItems");
|
|
17496
|
+
if (networks === void 0 || !/cstr6suwn9\.skadnetwork/u.test(networks.xml)) {
|
|
17497
|
+
issues.push({
|
|
17498
|
+
level: "warning",
|
|
17499
|
+
message: "Info.plist SKAdNetworkItems does not list Google's cstr6suwn9.skadnetwork; copy the current list from https://developers.google.com/admob/ios/3p-skadnetworks."
|
|
17500
|
+
});
|
|
17501
|
+
}
|
|
17502
|
+
return issues;
|
|
17503
|
+
}
|
|
17504
|
+
var iosPushEntitlementsFile = "App.entitlements";
|
|
17505
|
+
var iosPushEntitlementsSetting = `App/${iosPushEntitlementsFile}`;
|
|
17506
|
+
var iosPushEntitlementsXml = [
|
|
17507
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
17508
|
+
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
17509
|
+
'<plist version="1.0">',
|
|
17510
|
+
"<dict>",
|
|
17511
|
+
" <key>aps-environment</key>",
|
|
17512
|
+
" <string>development</string>",
|
|
17513
|
+
"</dict>",
|
|
17514
|
+
"</plist>",
|
|
17515
|
+
""
|
|
17516
|
+
].join("\n");
|
|
17517
|
+
function shellUsesFirebaseMessaging(shellPackage) {
|
|
17518
|
+
if (!isRecord5(shellPackage)) {
|
|
17519
|
+
return false;
|
|
17520
|
+
}
|
|
17521
|
+
return [shellPackage.dependencies, shellPackage.devDependencies].some((dependencies) => isRecord5(dependencies) && dependencies[notificationsMessagingPlugin] !== void 0);
|
|
17522
|
+
}
|
|
17523
|
+
function stripSwiftCommentsAndStrings(source) {
|
|
17524
|
+
let output = "";
|
|
17525
|
+
let commentDepth = 0;
|
|
17526
|
+
let lineComment = false;
|
|
17527
|
+
let closing;
|
|
17528
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
17529
|
+
const character = source[index] ?? "";
|
|
17530
|
+
const next = source[index + 1] ?? "";
|
|
17531
|
+
const blank = character === "\n" ? "\n" : " ";
|
|
17532
|
+
if (lineComment) {
|
|
17533
|
+
lineComment = character !== "\n";
|
|
17534
|
+
output += blank;
|
|
17535
|
+
} else if (commentDepth > 0) {
|
|
17536
|
+
if (character === "/" && next === "*") {
|
|
17537
|
+
commentDepth += 1;
|
|
17538
|
+
output += " ";
|
|
17539
|
+
index += 1;
|
|
17540
|
+
} else if (character === "*" && next === "/") {
|
|
17541
|
+
commentDepth -= 1;
|
|
17542
|
+
output += " ";
|
|
17543
|
+
index += 1;
|
|
17544
|
+
} else {
|
|
17545
|
+
output += blank;
|
|
17546
|
+
}
|
|
17547
|
+
} else if (closing !== void 0) {
|
|
17548
|
+
if (!closing.raw && character === "\\" && next !== "" && next !== "\n") {
|
|
17549
|
+
output += " ";
|
|
17550
|
+
index += 1;
|
|
17551
|
+
} else if (source.startsWith(closing.text, index)) {
|
|
17552
|
+
output += " ".repeat(closing.text.length);
|
|
17553
|
+
index += closing.text.length - 1;
|
|
17554
|
+
closing = void 0;
|
|
17555
|
+
} else {
|
|
17556
|
+
if (character === "\n" && !closing.multiline) {
|
|
17557
|
+
closing = void 0;
|
|
17558
|
+
}
|
|
17559
|
+
output += blank;
|
|
17560
|
+
}
|
|
17561
|
+
} else if (character === "/" && next === "/") {
|
|
17562
|
+
lineComment = true;
|
|
17563
|
+
output += " ";
|
|
17564
|
+
index += 1;
|
|
17565
|
+
} else if (character === "/" && next === "*") {
|
|
17566
|
+
commentDepth = 1;
|
|
17567
|
+
output += " ";
|
|
17568
|
+
index += 1;
|
|
17569
|
+
} else {
|
|
17570
|
+
const opener = /^(#*)("""|")/u.exec(source.slice(index, index + 64));
|
|
17571
|
+
if (opener === null || opener[1] === "" && character !== '"') {
|
|
17572
|
+
output += character;
|
|
17573
|
+
continue;
|
|
17574
|
+
}
|
|
17575
|
+
const hashes = opener[1] ?? "";
|
|
17576
|
+
const quote = opener[2] ?? '"';
|
|
17577
|
+
closing = { text: `${quote}${hashes}`, multiline: quote === '"""', raw: hashes !== "" };
|
|
17578
|
+
output += " ".repeat(opener[0].length);
|
|
17579
|
+
index += opener[0].length - 1;
|
|
17580
|
+
}
|
|
17581
|
+
}
|
|
17582
|
+
return output;
|
|
17583
|
+
}
|
|
17584
|
+
function swiftFunctionBodies(code, label) {
|
|
17585
|
+
const bodies = [];
|
|
17586
|
+
for (const match of code.matchAll(new RegExp(`\\bfunc\\b[^{}]*\\b${label}\\b[^{}]*\\{`, "gu"))) {
|
|
17587
|
+
const open2 = (match.index ?? 0) + match[0].length - 1;
|
|
17588
|
+
let depth = 0;
|
|
17589
|
+
for (let index = open2; index < code.length; index += 1) {
|
|
17590
|
+
if (code[index] === "{") {
|
|
17591
|
+
depth += 1;
|
|
17592
|
+
} else if (code[index] === "}") {
|
|
17593
|
+
depth -= 1;
|
|
17594
|
+
if (depth === 0) {
|
|
17595
|
+
bodies.push(code.slice(open2 + 1, index));
|
|
17596
|
+
break;
|
|
17597
|
+
}
|
|
17598
|
+
}
|
|
17599
|
+
}
|
|
17600
|
+
}
|
|
17601
|
+
return bodies;
|
|
17602
|
+
}
|
|
17603
|
+
function swiftForwardsPushToken(source) {
|
|
17604
|
+
return swiftFunctionBodies(stripSwiftCommentsAndStrings(source), "didRegisterForRemoteNotificationsWithDeviceToken").some((body) => /\bcapacitorDidRegisterForRemoteNotifications\b|\.\s*apnsToken\s*=/u.test(body));
|
|
17605
|
+
}
|
|
17606
|
+
function swiftDeclaresSceneDelegate(source) {
|
|
17607
|
+
return /\bclass\s+\w+\s*:[^{]*\bUIWindowSceneDelegate\b/u.test(stripSwiftCommentsAndStrings(source));
|
|
17608
|
+
}
|
|
17609
|
+
function swiftForwardsColdStartNotification(source) {
|
|
17610
|
+
return /\.\s*notificationResponse\b/u.test(stripSwiftCommentsAndStrings(source));
|
|
17611
|
+
}
|
|
17612
|
+
function readPbxSetting(settings, name) {
|
|
17613
|
+
const value = new RegExp(`(?:^|[\\s;{])${name}\\s*=\\s*([^;]+);`, "u").exec(settings)?.[1];
|
|
17614
|
+
return value?.trim().replace(/^"(.*)"$/u, "$1");
|
|
17615
|
+
}
|
|
17616
|
+
function resolveIosEntitlementsSetting(value) {
|
|
17617
|
+
const relative14 = value.replace(/^\$[({](?:SRCROOT|PROJECT_DIR)[)}]\//u, "");
|
|
17618
|
+
return relative14.includes("$") || relative14 === "" ? void 0 : relative14;
|
|
17619
|
+
}
|
|
17620
|
+
var iosPushEntitlementStep = `add the Push Notifications capability to the App target in Xcode, or create ios/App/App/${iosPushEntitlementsFile} with <key>aps-environment</key><string>development</string> and set CODE_SIGN_ENTITLEMENTS = ${iosPushEntitlementsSetting} in the App target's Debug and Release build settings (Xcode signs the value from the provisioning profile, production for the App Store)`;
|
|
17621
|
+
var iosPushTokenForwardingStep = "add to the AppDelegate class: func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken) } and func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error) }";
|
|
17622
|
+
var iosPushColdStartStep = "copy forwardColdStartNotification and deliverColdStartNotification from the mpgd-kit reference shell (apps/mobile-capacitor/ios/App/App/SceneDelegate.swift) into SceneDelegate, import UserNotifications, and call forwardColdStartNotification(connectionOptions.notificationResponse) right after SceneDelegateProxy.shared.scene(scene, willConnectTo: session, options: connectionOptions)";
|
|
17623
|
+
function inspectIosPushWiring(input) {
|
|
17624
|
+
const issues = [];
|
|
17625
|
+
const guide = " (see the mpgd-kit Firebase guide, docs/FIREBASE_NOTIFICATIONS.md#4-ios).";
|
|
17626
|
+
const entitlement = inspectIosPushEntitlement(input, guide);
|
|
17627
|
+
if (entitlement !== void 0) {
|
|
17628
|
+
issues.push(entitlement);
|
|
17629
|
+
}
|
|
17630
|
+
if (!input.swiftSources.some(swiftForwardsPushToken)) {
|
|
17631
|
+
issues.push({
|
|
17632
|
+
level: "error",
|
|
17633
|
+
message: `The shell installs @capacitor-firebase/messaging, but no App Swift source forwards the APNs device token to Capacitor, so the plugin never gets an FCM token: ${iosPushTokenForwardingStep}${guide}`
|
|
17634
|
+
});
|
|
17635
|
+
}
|
|
17636
|
+
if (input.swiftSources.some(swiftDeclaresSceneDelegate) && !input.swiftSources.some(swiftForwardsColdStartNotification)) {
|
|
17637
|
+
issues.push({
|
|
17638
|
+
level: "error",
|
|
17639
|
+
message: `The shell installs @capacitor-firebase/messaging, but its iOS SceneDelegate does not forward connectionOptions.notificationResponse, so a tap on a notification while the app is not running opens the game without the notification's route: ${iosPushColdStartStep}${guide}`
|
|
17640
|
+
});
|
|
17641
|
+
}
|
|
17642
|
+
return issues;
|
|
17643
|
+
}
|
|
17644
|
+
function inspectIosPushEntitlement(input, guide) {
|
|
17645
|
+
const unverifiable = (reason) => ({
|
|
17646
|
+
level: "warning",
|
|
17647
|
+
message: `The kit cannot verify the iOS aps-environment entitlement: ${reason}; make sure the App target's Release signing includes it${guide}`
|
|
17648
|
+
});
|
|
17649
|
+
let release;
|
|
17650
|
+
try {
|
|
17651
|
+
release = readIosAppReleaseSigning(input.project);
|
|
17652
|
+
} catch {
|
|
17653
|
+
return unverifiable("the Xcode project could not be read");
|
|
17654
|
+
}
|
|
17655
|
+
if (release.conditional) {
|
|
17656
|
+
return unverifiable("CODE_SIGN_ENTITLEMENTS is set per SDK");
|
|
17657
|
+
}
|
|
17658
|
+
if (release.entitlements === void 0 && release.baseConfiguration) {
|
|
17659
|
+
return unverifiable("the Release configuration has a base xcconfig that may set CODE_SIGN_ENTITLEMENTS");
|
|
17660
|
+
}
|
|
17661
|
+
const relative14 = release.entitlements === void 0 ? void 0 : resolveIosEntitlementsSetting(release.entitlements);
|
|
17662
|
+
if (release.entitlements !== void 0 && relative14 === void 0) {
|
|
17663
|
+
return unverifiable(`CODE_SIGN_ENTITLEMENTS is ${release.entitlements}`);
|
|
17664
|
+
}
|
|
17665
|
+
const entitlements = relative14 === void 0 ? void 0 : input.readProjectFile(relative14);
|
|
17666
|
+
let value;
|
|
17667
|
+
try {
|
|
17668
|
+
value = entitlements === void 0 ? void 0 : readPlistTopLevelValue(entitlements, "aps-environment")?.xml;
|
|
17669
|
+
} catch {
|
|
17670
|
+
value = void 0;
|
|
17671
|
+
}
|
|
17672
|
+
if (value !== void 0 && /^<string>\s*(?:development|production)\s*<\/string>$/u.test(value)) {
|
|
16985
17673
|
return void 0;
|
|
16986
17674
|
}
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
16995
|
-
|
|
17675
|
+
if (value !== void 0 && /^<string>[^<]*\$[({]/u.test(value)) {
|
|
17676
|
+
return unverifiable(`aps-environment is ${value}`);
|
|
17677
|
+
}
|
|
17678
|
+
return {
|
|
17679
|
+
level: "error",
|
|
17680
|
+
message: `The shell installs @capacitor-firebase/messaging, but the iOS App target has no aps-environment entitlement in its Release configuration${release.entitlements === void 0 ? "" : ` (${release.entitlements})`}, so APNs issues no device token and no push reaches the app: ${iosPushEntitlementStep}${guide}`
|
|
17681
|
+
};
|
|
17682
|
+
}
|
|
17683
|
+
function readIosAppReleaseSigning(project) {
|
|
17684
|
+
const projectObject = findPbxObject(project, (body) => /\bisa\s*=\s*PBXProject\s*;/u.test(body));
|
|
17685
|
+
const projectListId = /\bbuildConfigurationList\s*=\s*([A-F0-9]+)\b/u.exec(projectObject?.text ?? "")?.[1];
|
|
17686
|
+
const projectList = projectListId === void 0 ? void 0 : findPbxObjectById(project, projectListId);
|
|
17687
|
+
const levels = [
|
|
17688
|
+
readAppTargetConfigurationIds(project),
|
|
17689
|
+
projectList === void 0 ? [] : readPbxList(project, projectList, "buildConfigurations")?.ids ?? []
|
|
17690
|
+
];
|
|
17691
|
+
let baseConfiguration = false;
|
|
17692
|
+
for (const ids of levels) {
|
|
17693
|
+
for (const id of ids) {
|
|
17694
|
+
const settings = locatePbxBuildSettings(project, id);
|
|
17695
|
+
if (settings.name !== "Release") {
|
|
17696
|
+
continue;
|
|
16996
17697
|
}
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
if (character === '"') {
|
|
17005
|
-
quote = true;
|
|
17006
|
-
} else if (character === ")") {
|
|
17007
|
-
const text = project.slice(start, index);
|
|
17008
|
-
const ids = text.replace(/\/\*[^]*?\*\//gu, " ").split(",").map((entry) => /^\s*([A-F0-9]+)\b/u.exec(entry)?.[1]).filter((id) => id !== void 0);
|
|
17009
|
-
return { text, ids, end: index };
|
|
17698
|
+
const body = project.slice(settings.start, settings.end);
|
|
17699
|
+
const entitlements = readPbxSetting(body, "CODE_SIGN_ENTITLEMENTS");
|
|
17700
|
+
const conditional = /\bCODE_SIGN_ENTITLEMENTS\s*\[/u.test(body);
|
|
17701
|
+
if (entitlements !== void 0 || conditional) {
|
|
17702
|
+
return baseConfiguration ? { entitlements: void 0, conditional: false, baseConfiguration } : { entitlements, conditional, baseConfiguration };
|
|
17703
|
+
}
|
|
17704
|
+
baseConfiguration ||= /\bbaseConfigurationReference\s*=/u.test(findPbxObjectById(project, id)?.text.replace(body, "") ?? "");
|
|
17010
17705
|
}
|
|
17011
17706
|
}
|
|
17012
|
-
return void 0;
|
|
17707
|
+
return { entitlements: void 0, conditional: false, baseConfiguration };
|
|
17013
17708
|
}
|
|
17014
|
-
var
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
return false;
|
|
17709
|
+
var iosFirebaseConfigFile = "GoogleService-Info.plist";
|
|
17710
|
+
function inspectIosFirebaseConfig(project) {
|
|
17711
|
+
if (iosAppBundlesResource(project, iosFirebaseConfigFile)) {
|
|
17712
|
+
return [];
|
|
17019
17713
|
}
|
|
17020
|
-
return [
|
|
17714
|
+
return [{
|
|
17715
|
+
level: "warning",
|
|
17716
|
+
message: `The shell installs @capacitor-firebase/messaging, but the iOS App target does not bundle ${iosFirebaseConfigFile}; the plugin then leaves Firebase unconfigured and push fails closed. Download it from the Firebase console and add it to the App target in Xcode.`
|
|
17717
|
+
}];
|
|
17021
17718
|
}
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17719
|
+
|
|
17720
|
+
// node_modules/.cache/mpgd-native-build/packages/cli/src/crash-reporting-starter.js
|
|
17721
|
+
var crashReportingPlugin = "@capacitor-firebase/crashlytics";
|
|
17722
|
+
var crashlyticsGradlePluginVersion = "3.0.8";
|
|
17723
|
+
var crashlyticsGradleClasspath = `com.google.firebase:firebase-crashlytics-gradle:${crashlyticsGradlePluginVersion}`;
|
|
17724
|
+
var crashlyticsGradlePluginId = "com.google.firebase.crashlytics";
|
|
17725
|
+
var androidRootGradle = "android/build.gradle";
|
|
17726
|
+
var androidAppGradle = "android/app/build.gradle";
|
|
17727
|
+
var crashReportingAndroidSteps = Object.freeze([
|
|
17728
|
+
`In android/build.gradle, add classpath '${crashlyticsGradleClasspath}' to buildscript.dependencies, next to the google-services classpath (4.4.1 or later).`,
|
|
17729
|
+
`In android/app/build.gradle, add apply plugin: '${crashlyticsGradlePluginId}' right after apply plugin: 'com.google.gms.google-services', inside the same google-services.json check.`
|
|
17730
|
+
]);
|
|
17731
|
+
var crashReportingIosSteps = Object.freeze([
|
|
17732
|
+
'Upload dSYMs for every App Store build: add the Crashlytics run script build phase ("${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run") as the last phase of the App target, or run upload-symbols after each archive; see docs/CRASH_REPORTING.md in mpgd-kit.'
|
|
17733
|
+
]);
|
|
17734
|
+
function androidShellHasCrashlytics(shellRoot) {
|
|
17735
|
+
const read = (relative14) => {
|
|
17736
|
+
const file = path7.join(shellRoot, relative14);
|
|
17737
|
+
return existsSync19(file) && lstatSync12(file).isFile() ? readFileSync20(file, "utf8") : void 0;
|
|
17738
|
+
};
|
|
17739
|
+
const root = read(androidRootGradle);
|
|
17740
|
+
const app = read(androidAppGradle);
|
|
17741
|
+
return root !== void 0 && app !== void 0 && androidRootGradleHasCrashlytics(root) && androidAppGradleHasCrashlytics(app);
|
|
17025
17742
|
}
|
|
17026
|
-
function
|
|
17027
|
-
|
|
17028
|
-
if (permissions.length === 0) {
|
|
17029
|
-
return "absent";
|
|
17030
|
-
}
|
|
17031
|
-
return permissions.some((match) => readXmlAttribute(match[0], "tools:node") === "remove") ? "removed" : "declared";
|
|
17743
|
+
function androidRootGradleHasCrashlytics(source) {
|
|
17744
|
+
return /['"]com\.google\.firebase:firebase-crashlytics-gradle:[^'"]+['"]|\bid\s*\(?\s*['"]com\.google\.firebase\.crashlytics['"]/u.test(stripGradleComments(source));
|
|
17032
17745
|
}
|
|
17033
|
-
function
|
|
17034
|
-
const
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
if (value === void 0 || value === "declared") {
|
|
17038
|
-
return "declared";
|
|
17746
|
+
function androidAppGradleHasCrashlytics(source) {
|
|
17747
|
+
const clean = stripGradleComments(source);
|
|
17748
|
+
if (/\bapply\s+plugin\s*:\s*['"]com\.google\.firebase\.crashlytics['"]/u.test(clean)) {
|
|
17749
|
+
return true;
|
|
17039
17750
|
}
|
|
17040
|
-
|
|
17041
|
-
|
|
17751
|
+
return clean.split("\n").some((line) => /\bid\s*\(?\s*['"]com\.google\.firebase\.crashlytics['"]/u.test(line) && !/\bapply\s*\(?\s*false\b/u.test(line));
|
|
17752
|
+
}
|
|
17753
|
+
function shellUsesCrashlytics(shellPackage) {
|
|
17754
|
+
if (typeof shellPackage !== "object" || shellPackage === null) {
|
|
17755
|
+
return false;
|
|
17042
17756
|
}
|
|
17043
|
-
|
|
17757
|
+
const { dependencies, devDependencies } = shellPackage;
|
|
17758
|
+
return [dependencies, devDependencies].some((entries) => typeof entries === "object" && entries !== null && entries[crashReportingPlugin] !== void 0);
|
|
17044
17759
|
}
|
|
17045
|
-
function
|
|
17760
|
+
function inspectCrashReportingShell(input) {
|
|
17761
|
+
if (!shellUsesCrashlytics(input.shellPackage)) {
|
|
17762
|
+
return [];
|
|
17763
|
+
}
|
|
17046
17764
|
const issues = [];
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
if (!hasAppId) {
|
|
17051
|
-
issues.push({
|
|
17052
|
-
level: "error",
|
|
17053
|
-
message: "The shell installs AdMob but neither android/app/src/main/AndroidManifest.xml nor the release source set's manifest has com.google.android.gms.ads.APPLICATION_ID meta-data; the app crashes at launch."
|
|
17054
|
-
});
|
|
17055
|
-
}
|
|
17056
|
-
if (declaration === "removed" && advertisingIdPolicy !== "removed") {
|
|
17765
|
+
if (input.platform === "android") {
|
|
17766
|
+
const config2 = path7.join(input.shellApp, "android/app/google-services.json");
|
|
17767
|
+
if (!existsSync19(config2) || !lstatSync12(config2).isFile() || readFileSync20(config2, "utf8").trim() === "") {
|
|
17057
17768
|
issues.push({
|
|
17058
17769
|
level: "error",
|
|
17059
|
-
message: `
|
|
17770
|
+
message: `The shell installs ${crashReportingPlugin}, but android/app/google-services.json is missing; Firebase does not start and the release reports no crashes. Download it from the Firebase console (the same file notifications use).`
|
|
17060
17771
|
});
|
|
17061
17772
|
}
|
|
17062
|
-
if (
|
|
17773
|
+
if (!androidShellHasCrashlytics(input.shellApp)) {
|
|
17063
17774
|
issues.push({
|
|
17064
17775
|
level: "error",
|
|
17065
|
-
message: `
|
|
17776
|
+
message: `The shell installs ${crashReportingPlugin}, but the Android project does not apply the Crashlytics Gradle plugin; the Crashlytics SDK stops the app at startup without the build ID it writes. ${crashReportingAndroidSteps.join(" ")}`
|
|
17066
17777
|
});
|
|
17067
17778
|
}
|
|
17068
|
-
|
|
17779
|
+
return issues;
|
|
17780
|
+
}
|
|
17781
|
+
if (input.iosProject !== void 0 && !iosAppBundlesResource(input.iosProject, "GoogleService-Info.plist")) {
|
|
17069
17782
|
issues.push({
|
|
17070
|
-
level: "
|
|
17071
|
-
message: `The shell
|
|
17783
|
+
level: "error",
|
|
17784
|
+
message: `The shell installs ${crashReportingPlugin}, but the iOS App target does not bundle GoogleService-Info.plist; Firebase does not start and the plugin still calls Crashlytics. Download it from the Firebase console and add it to the App target in Xcode.`
|
|
17072
17785
|
});
|
|
17073
17786
|
}
|
|
17074
17787
|
return issues;
|
|
17075
17788
|
}
|
|
17076
|
-
|
|
17077
|
-
|
|
17078
|
-
|
|
17789
|
+
|
|
17790
|
+
// node_modules/.cache/mpgd-native-build/packages/cli/src/native-shell-ios-push-files.js
|
|
17791
|
+
import { existsSync as existsSync20, lstatSync as lstatSync13, readdirSync as readdirSync6, readFileSync as readFileSync21 } from "node:fs";
|
|
17792
|
+
import path8 from "node:path";
|
|
17793
|
+
var maxSwiftSources = 2e3;
|
|
17794
|
+
function readIosPushWiringInput(iosProjectDirectory) {
|
|
17795
|
+
const project = readContainedFile(iosProjectDirectory, "App.xcodeproj/project.pbxproj");
|
|
17796
|
+
if (project === void 0) {
|
|
17797
|
+
return void 0;
|
|
17079
17798
|
}
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
|
|
17085
|
-
|
|
17799
|
+
return {
|
|
17800
|
+
project,
|
|
17801
|
+
readProjectFile: (relative14) => readContainedFile(iosProjectDirectory, relative14),
|
|
17802
|
+
swiftSources: listContainedSwiftFiles(iosProjectDirectory, "App").map((relative14) => readContainedFile(iosProjectDirectory, relative14) ?? "")
|
|
17803
|
+
};
|
|
17804
|
+
}
|
|
17805
|
+
function readContainedFile(root, relative14) {
|
|
17806
|
+
const file = path8.resolve(root, relative14);
|
|
17807
|
+
const within = path8.relative(root, file);
|
|
17808
|
+
if (within === "" || within.startsWith("..") || path8.isAbsolute(within)) {
|
|
17809
|
+
return void 0;
|
|
17086
17810
|
}
|
|
17087
|
-
|
|
17088
|
-
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
}
|
|
17811
|
+
let current = root;
|
|
17812
|
+
for (const segment of within.split(path8.sep)) {
|
|
17813
|
+
current = path8.join(current, segment);
|
|
17814
|
+
if (!existsSync20(current) || lstatSync13(current).isSymbolicLink()) {
|
|
17815
|
+
return void 0;
|
|
17816
|
+
}
|
|
17093
17817
|
}
|
|
17094
|
-
return
|
|
17818
|
+
return lstatSync13(file).isFile() ? readFileSync21(file, "utf8") : void 0;
|
|
17819
|
+
}
|
|
17820
|
+
function listContainedSwiftFiles(root, relativeRoot) {
|
|
17821
|
+
const pending = [relativeRoot];
|
|
17822
|
+
const files = [];
|
|
17823
|
+
while (pending.length > 0) {
|
|
17824
|
+
const relative14 = pending.pop() ?? "";
|
|
17825
|
+
const full = path8.join(root, relative14);
|
|
17826
|
+
if (!existsSync20(full) || lstatSync13(full).isSymbolicLink() || !lstatSync13(full).isDirectory()) {
|
|
17827
|
+
continue;
|
|
17828
|
+
}
|
|
17829
|
+
for (const entry of readdirSync6(full, { withFileTypes: true })) {
|
|
17830
|
+
const child = path8.join(relative14, entry.name);
|
|
17831
|
+
if (entry.isDirectory() && child !== path8.join(relativeRoot, "public")) {
|
|
17832
|
+
pending.push(child);
|
|
17833
|
+
} else if (entry.isFile() && entry.name.endsWith(".swift")) {
|
|
17834
|
+
files.push(child);
|
|
17835
|
+
if (files.length >= maxSwiftSources) {
|
|
17836
|
+
return files.sort();
|
|
17837
|
+
}
|
|
17838
|
+
}
|
|
17839
|
+
}
|
|
17840
|
+
}
|
|
17841
|
+
return files.sort();
|
|
17095
17842
|
}
|
|
17096
17843
|
|
|
17097
17844
|
// node_modules/.cache/mpgd-native-build/tools/target/native-store-policy.js
|
|
17098
17845
|
function inspectNativeStorePolicy(input) {
|
|
17099
17846
|
const gameConfig = input.gameRoot === void 0 ? void 0 : join13(input.gameRoot, "mpgd.game.json");
|
|
17100
|
-
const gameConfigJson = gameConfig !== void 0 &&
|
|
17847
|
+
const gameConfigJson = gameConfig !== void 0 && existsSync21(gameConfig) ? readJson2(gameConfig) : void 0;
|
|
17101
17848
|
const orientation = readGameNativeOrientation(gameConfigJson);
|
|
17102
17849
|
const shellPackage = join13(input.shellApp, "package.json");
|
|
17103
|
-
const
|
|
17850
|
+
const shellPackageJson = existsSync21(shellPackage) ? readJson2(shellPackage) : void 0;
|
|
17851
|
+
const usesAds = shellUsesAdMob(shellPackageJson);
|
|
17852
|
+
const usesPush = shellUsesFirebaseMessaging(shellPackageJson);
|
|
17104
17853
|
if (input.platform === "ios") {
|
|
17105
17854
|
const project = join13(input.shellApp, "ios/App/App.xcodeproj/project.pbxproj");
|
|
17106
|
-
if (!
|
|
17855
|
+
if (!existsSync21(project)) {
|
|
17107
17856
|
return [];
|
|
17108
17857
|
}
|
|
17109
|
-
const projectSource =
|
|
17858
|
+
const projectSource = readFileSync22(project, "utf8");
|
|
17110
17859
|
const deviceFamily = readIosDeviceFamily(input.metadata);
|
|
17111
17860
|
const issues = [
|
|
17112
17861
|
...inspectIosProjectDeviceFamily(projectSource, deviceFamily),
|
|
17113
17862
|
...inspectIosAppPrivacyManifest(projectSource)
|
|
17114
17863
|
];
|
|
17864
|
+
const pushInput = usesPush ? readIosPushWiringInput(dirname9(dirname9(project))) : void 0;
|
|
17865
|
+
if (pushInput !== void 0) {
|
|
17866
|
+
issues.push(...inspectIosPushWiring(pushInput), ...inspectIosFirebaseConfig(projectSource));
|
|
17867
|
+
}
|
|
17868
|
+
issues.push(...inspectCrashReportingShell({
|
|
17869
|
+
platform: "ios",
|
|
17870
|
+
shellApp: input.shellApp,
|
|
17871
|
+
shellPackage: shellPackageJson,
|
|
17872
|
+
iosProject: projectSource
|
|
17873
|
+
}));
|
|
17115
17874
|
const plist = join13(dirname9(dirname9(project)), readIosReleaseInfoPlist(projectSource));
|
|
17116
|
-
if (
|
|
17117
|
-
const plistSource =
|
|
17875
|
+
if (existsSync21(plist)) {
|
|
17876
|
+
const plistSource = readFileSync22(plist, "utf8");
|
|
17118
17877
|
issues.push(...inspectIosInfoPlistStorePolicy(plistSource), ...inspectIosInfoPlistOrientation(plistSource, orientation, deviceFamily ?? "universal"), ...inspectIosInfoPlistAds(plistSource, usesAds));
|
|
17119
17878
|
}
|
|
17120
17879
|
return issues;
|
|
17121
17880
|
}
|
|
17122
17881
|
const manifest = join13(input.shellApp, "android/app/src/main/AndroidManifest.xml");
|
|
17123
|
-
if (!
|
|
17882
|
+
if (!existsSync21(manifest)) {
|
|
17124
17883
|
return [];
|
|
17125
17884
|
}
|
|
17126
|
-
const manifestSource =
|
|
17885
|
+
const manifestSource = readFileSync22(manifest, "utf8");
|
|
17127
17886
|
const releaseManifest = join13(input.shellApp, "android/app/src/release/AndroidManifest.xml");
|
|
17128
|
-
const releaseSource =
|
|
17887
|
+
const releaseSource = existsSync21(releaseManifest) ? readFileSync22(releaseManifest, "utf8") : "";
|
|
17129
17888
|
return [
|
|
17130
17889
|
...inspectAndroidManifestOrientation(manifestSource, orientation),
|
|
17131
17890
|
...inspectAndroidManifestAds(`${manifestSource}
|
|
17132
|
-
${releaseSource}`, usesAds, usesAds ? readGameAdvertisingIdPolicy(gameConfigJson) : "declared")
|
|
17891
|
+
${releaseSource}`, usesAds, usesAds ? readGameAdvertisingIdPolicy(gameConfigJson) : "declared"),
|
|
17892
|
+
// `--providers crash-reporting`: the Firebase config file and the Gradle plugin.
|
|
17893
|
+
...inspectCrashReportingShell({
|
|
17894
|
+
platform: "android",
|
|
17895
|
+
shellApp: input.shellApp,
|
|
17896
|
+
shellPackage: shellPackageJson
|
|
17897
|
+
})
|
|
17133
17898
|
];
|
|
17134
17899
|
}
|
|
17900
|
+
function shellInstallsFirebaseMessaging(shellApp) {
|
|
17901
|
+
const shellPackage = join13(shellApp, "package.json");
|
|
17902
|
+
return existsSync21(shellPackage) && shellUsesFirebaseMessaging(readJson2(shellPackage));
|
|
17903
|
+
}
|
|
17135
17904
|
function readJson2(file) {
|
|
17136
|
-
const source =
|
|
17905
|
+
const source = readFileSync22(file, "utf8");
|
|
17137
17906
|
try {
|
|
17138
17907
|
return JSON.parse(source);
|
|
17139
17908
|
} catch (error) {
|
|
@@ -17153,14 +17922,14 @@ ${errors.map((issue) => `- ${issue.message}`).join("\n")}`);
|
|
|
17153
17922
|
|
|
17154
17923
|
// node_modules/.cache/mpgd-native-build/tools/target/native-ios-inspection.js
|
|
17155
17924
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
17156
|
-
import { existsSync as
|
|
17925
|
+
import { existsSync as existsSync22, mkdtempSync as mkdtempSync3, readFileSync as readFileSync23, rmSync as rmSync10, statSync as statSync4 } from "node:fs";
|
|
17157
17926
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
17158
|
-
import
|
|
17927
|
+
import path9 from "node:path";
|
|
17159
17928
|
function inspectSignedIosArchive(archive, input) {
|
|
17160
|
-
return inspectSignedIosApplication(
|
|
17929
|
+
return inspectSignedIosApplication(path9.join(archive, "Products/Applications/App.app"), input);
|
|
17161
17930
|
}
|
|
17162
17931
|
function inspectSignedIosIpa(ipa, input) {
|
|
17163
|
-
if (!
|
|
17932
|
+
if (!existsSync22(ipa) || !statSync4(ipa).isFile()) {
|
|
17164
17933
|
throw new Error("iOS store IPA is missing.");
|
|
17165
17934
|
}
|
|
17166
17935
|
const runner = input.runner ?? { run: runCommand2 };
|
|
@@ -17176,530 +17945,190 @@ function inspectSignedIosIpa(ipa, input) {
|
|
|
17176
17945
|
if (appManifests.length !== 1) {
|
|
17177
17946
|
throw new Error("iOS store IPA must contain exactly one app manifest.");
|
|
17178
17947
|
}
|
|
17179
|
-
const appRelative =
|
|
17180
|
-
const extracted = mkdtempSync3(
|
|
17948
|
+
const appRelative = path9.dirname(appManifests[0] ?? "");
|
|
17949
|
+
const extracted = mkdtempSync3(path9.join(tmpdir3(), "mpgd-ios-inspection-"));
|
|
17181
17950
|
try {
|
|
17182
17951
|
const result = runner.run("unzip", ["-q", ipa, "-d", extracted]);
|
|
17183
17952
|
if (result.status !== 0) {
|
|
17184
17953
|
throw new Error("iOS store IPA could not be extracted.");
|
|
17185
|
-
}
|
|
17186
|
-
return inspectSignedIosApplication(
|
|
17187
|
-
} finally {
|
|
17188
|
-
rmSync10(extracted, { recursive: true, force: true });
|
|
17189
|
-
}
|
|
17190
|
-
}
|
|
17191
|
-
function inspectSignedIosApplication(appPath, input) {
|
|
17192
|
-
const plist = path7.join(appPath, "Info.plist");
|
|
17193
|
-
if (!existsSync20(plist) || !statSync4(plist).isFile()) {
|
|
17194
|
-
throw new Error("Signed iOS app manifest is missing.");
|
|
17195
|
-
}
|
|
17196
|
-
if (!existsSync20(path7.join(appPath, "Assets.car")) || existsSync20(path7.join(appPath, "Info-Smoke.plist"))) {
|
|
17197
|
-
throw new Error("Signed iOS app contains smoke assets or omits release icons.");
|
|
17198
|
-
}
|
|
17199
|
-
const runner = input.runner ?? { run: runCommand2 };
|
|
17200
|
-
const signature = runner.run("codesign", ["--verify", "--deep", "--strict", appPath]);
|
|
17201
|
-
if (signature.status !== 0) {
|
|
17202
|
-
throw new Error("iOS app code signature could not be verified.");
|
|
17203
|
-
}
|
|
17204
|
-
const signingInfo = runner.run("codesign", ["-dv", "--verbose=4", appPath]);
|
|
17205
|
-
const signingText = `${signingInfo.stdout}
|
|
17206
|
-
${signingInfo.stderr}`;
|
|
17207
|
-
const expectedTeamLine = `TeamIdentifier=${input.expectedTeamId}`;
|
|
17208
|
-
if (signingInfo.status !== 0 || /Signature=adhoc/iu.test(signingText) || !signingText.split(/\r?\n/u).some((line) => line.trim() === expectedTeamLine)) {
|
|
17209
|
-
throw new Error("iOS app is not signed for the expected development team.");
|
|
17210
|
-
}
|
|
17211
|
-
const fields = [
|
|
17212
|
-
["bundleId", "CFBundleIdentifier", input.expectedBundleId],
|
|
17213
|
-
["marketingVersion", "CFBundleShortVersionString", input.expectedMarketingVersion],
|
|
17214
|
-
["buildNumber", "CFBundleVersion", input.expectedBuildNumber]
|
|
17215
|
-
];
|
|
17216
|
-
const observed = Object.fromEntries(fields.map(([name, key, expected]) => {
|
|
17217
|
-
const result = runner.run("/usr/libexec/PlistBuddy", ["-c", `Print :${key}`, plist]);
|
|
17218
|
-
if (result.status !== 0 || result.stdout.trim() !== expected) {
|
|
17219
|
-
throw new Error(`iOS app ${name} does not match release identity.`);
|
|
17220
|
-
}
|
|
17221
|
-
return [name, expected];
|
|
17222
|
-
}));
|
|
17223
|
-
const configFiles = [
|
|
17224
|
-
path7.join(appPath, "capacitor.config.json"),
|
|
17225
|
-
path7.join(appPath, "public/capacitor.config.json")
|
|
17226
|
-
];
|
|
17227
|
-
if (!configFiles.some((file) => existsSync20(file))) {
|
|
17228
|
-
throw new Error("Signed iOS app Capacitor configuration is missing.");
|
|
17229
|
-
}
|
|
17230
|
-
for (const configFile of configFiles) {
|
|
17231
|
-
if (existsSync20(configFile)) {
|
|
17232
|
-
assertNoDebugServer(configFile);
|
|
17233
|
-
}
|
|
17234
|
-
}
|
|
17235
|
-
return { ...observed, teamId: input.expectedTeamId, signed: true };
|
|
17236
|
-
}
|
|
17237
|
-
function assertNoDebugServer(file) {
|
|
17238
|
-
const value = JSON.parse(readFileSync21(file, "utf8"));
|
|
17239
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
17240
|
-
throw new Error("Signed iOS app has malformed Capacitor configuration.");
|
|
17241
|
-
}
|
|
17242
|
-
const config2 = value;
|
|
17243
|
-
const server = config2.server;
|
|
17244
|
-
const ios = config2.ios;
|
|
17245
|
-
if (typeof server === "object" && server !== null && "url" in server || typeof ios === "object" && ios !== null && "webContentsDebuggingEnabled" in ios && ios.webContentsDebuggingEnabled === true) {
|
|
17246
|
-
throw new Error("Signed iOS app retains a live-reload or debug bridge configuration.");
|
|
17247
|
-
}
|
|
17248
|
-
}
|
|
17249
|
-
function runCommand2(command, args) {
|
|
17250
|
-
const result = spawnSync3(command, [...args], {
|
|
17251
|
-
encoding: "utf8",
|
|
17252
|
-
env: nativeInspectionEnvironment(),
|
|
17253
|
-
maxBuffer: 4 * 1024 * 1024
|
|
17254
|
-
});
|
|
17255
|
-
if (result.error !== void 0) {
|
|
17256
|
-
throw new Error(`Required iOS inspection command is unavailable: ${command}.`);
|
|
17257
|
-
}
|
|
17258
|
-
return {
|
|
17259
|
-
status: result.status,
|
|
17260
|
-
stdout: result.stdout,
|
|
17261
|
-
stderr: result.stderr
|
|
17262
|
-
};
|
|
17263
|
-
}
|
|
17264
|
-
|
|
17265
|
-
// node_modules/.cache/mpgd-native-build/tools/target/native-ios-signing.js
|
|
17266
|
-
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
17267
|
-
import { existsSync as existsSync21, statSync as statSync5 } from "node:fs";
|
|
17268
|
-
import path8 from "node:path";
|
|
17269
|
-
function resolveIosSigningPlan(environment, mode) {
|
|
17270
|
-
const teamId = environment.MPGD_IOS_TEAM_ID?.trim();
|
|
17271
|
-
if (teamId === void 0 || !/^[A-Z0-9]{10}$/u.test(teamId)) {
|
|
17272
|
-
throw new Error("Signed iOS builds require a 10-character MPGD_IOS_TEAM_ID.");
|
|
17273
|
-
}
|
|
17274
|
-
const style = environment.MPGD_IOS_SIGNING_STYLE ?? "Automatic";
|
|
17275
|
-
if (style !== "Automatic" && style !== "Manual") {
|
|
17276
|
-
throw new Error("MPGD_IOS_SIGNING_STYLE must be Automatic or Manual.");
|
|
17277
|
-
}
|
|
17278
|
-
const identity = environment.MPGD_IOS_SIGNING_IDENTITY?.trim();
|
|
17279
|
-
const profile2 = environment.MPGD_IOS_PROVISIONING_PROFILE_SPECIFIER?.trim();
|
|
17280
|
-
if (style === "Manual" && (identity === void 0 || identity === "" || profile2 === void 0 || profile2 === "")) {
|
|
17281
|
-
throw new Error("Manual iOS signing requires host identity and provisioning profile names.");
|
|
17282
|
-
}
|
|
17283
|
-
if (style === "Automatic" && profile2 !== void 0 && profile2 !== "") {
|
|
17284
|
-
throw new Error("Automatic iOS signing must not set a manual provisioning profile.");
|
|
17285
|
-
}
|
|
17286
|
-
const archiveBuildSettings = [
|
|
17287
|
-
"CODE_SIGNING_ALLOWED=YES",
|
|
17288
|
-
`CODE_SIGN_STYLE=${style}`,
|
|
17289
|
-
`DEVELOPMENT_TEAM=${teamId}`,
|
|
17290
|
-
...identity === void 0 || identity === "" ? [] : [`CODE_SIGN_IDENTITY=${identity}`],
|
|
17291
|
-
...profile2 === void 0 || profile2 === "" ? [] : [`PROVISIONING_PROFILE_SPECIFIER=${profile2}`],
|
|
17292
|
-
...environment.MPGD_IOS_SIGNING_KEYCHAIN === void 0 ? [] : [`OTHER_CODE_SIGN_FLAGS=--keychain ${JSON.stringify(environment.MPGD_IOS_SIGNING_KEYCHAIN)}`]
|
|
17293
|
-
];
|
|
17294
|
-
if (mode !== "store-export") {
|
|
17295
|
-
return { teamId, archiveBuildSettings };
|
|
17296
|
-
}
|
|
17297
|
-
const configuredExportFile = environment.MPGD_IOS_EXPORT_OPTIONS_PLIST;
|
|
17298
|
-
if (configuredExportFile === void 0 || configuredExportFile.trim() === "") {
|
|
17299
|
-
throw new Error("iOS store export requires MPGD_IOS_EXPORT_OPTIONS_PLIST.");
|
|
17300
|
-
}
|
|
17301
|
-
const exportOptionsPlist = path8.resolve(configuredExportFile);
|
|
17302
|
-
if (!existsSync21(exportOptionsPlist) || !statSync5(exportOptionsPlist).isFile()) {
|
|
17303
|
-
throw new Error("iOS export options plist must be an existing host file.");
|
|
17304
|
-
}
|
|
17305
|
-
const method = spawnSync4("/usr/libexec/PlistBuddy", ["-c", "Print :method", exportOptionsPlist], {
|
|
17306
|
-
encoding: "utf8",
|
|
17307
|
-
maxBuffer: 1024 * 1024
|
|
17308
|
-
});
|
|
17309
|
-
if (method.error !== void 0 || method.status !== 0 || !["app-store", "app-store-connect"].includes(method.stdout.trim())) {
|
|
17310
|
-
throw new Error("iOS export options must select an App Store distribution method.");
|
|
17954
|
+
}
|
|
17955
|
+
return inspectSignedIosApplication(path9.join(extracted, appRelative), input);
|
|
17956
|
+
} finally {
|
|
17957
|
+
rmSync10(extracted, { recursive: true, force: true });
|
|
17311
17958
|
}
|
|
17312
|
-
return { teamId, archiveBuildSettings, exportOptionsPlist };
|
|
17313
17959
|
}
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
|
|
17321
|
-
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
17329
|
-
|
|
17330
|
-
|
|
17331
|
-
|
|
17332
|
-
|
|
17333
|
-
|
|
17334
|
-
|
|
17335
|
-
]);
|
|
17336
|
-
|
|
17337
|
-
|
|
17338
|
-
replacement: [
|
|
17339
|
-
"import { createStarterCapacitorNotifications } from '../capacitorNotifications';",
|
|
17340
|
-
"import type { RuntimeConfig } from '../runtimeDetector';",
|
|
17341
|
-
""
|
|
17342
|
-
].join("\n")
|
|
17343
|
-
};
|
|
17344
|
-
var gatewayProviders = (platform) => ({
|
|
17345
|
-
anchor: " const providers = createStoreProviders(runtime, () => gateway);\n",
|
|
17346
|
-
replacement: [
|
|
17347
|
-
" const providers = [",
|
|
17348
|
-
" ...createStoreProviders(runtime, () => gateway),",
|
|
17349
|
-
" // Notifications v2 (FCM and local reminders); `notifications/topics.json`",
|
|
17350
|
-
" // maps the topics, and the shell needs the two plugins",
|
|
17351
|
-
" // (`mpgd target init capacitor --providers notifications`).",
|
|
17352
|
-
` ...(await createStarterCapacitorNotifications('${platform}', runtime.configTarget)),`,
|
|
17353
|
-
" ];",
|
|
17354
|
-
""
|
|
17355
|
-
].join("\n")
|
|
17356
|
-
});
|
|
17357
|
-
var commonEdits = {
|
|
17358
|
-
"src/platform/buildGateways/capacitorAndroid.ts": [gatewayImport, gatewayProviders("android")],
|
|
17359
|
-
"src/platform/buildGateways/capacitorIos.ts": [gatewayImport, gatewayProviders("ios")],
|
|
17360
|
-
"src/platform/buildGateways/reddit.ts": [
|
|
17361
|
-
{
|
|
17362
|
-
anchor: " createDevvitCommerceProducts,\n createDevvitPlatformGateway,\n",
|
|
17363
|
-
replacement: [
|
|
17364
|
-
" createDevvitCommerceProducts,",
|
|
17365
|
-
" createDevvitNotificationsBackend,",
|
|
17366
|
-
" createDevvitPlatformGateway,",
|
|
17367
|
-
""
|
|
17368
|
-
].join("\n")
|
|
17369
|
-
},
|
|
17370
|
-
{
|
|
17371
|
-
anchor: "import { createDevvitWebPaymentsClient } from '@mpgd/adapter-devvit/web';\n",
|
|
17372
|
-
replacement: [
|
|
17373
|
-
"import {",
|
|
17374
|
-
" createDevvitWebLoginPrompt,",
|
|
17375
|
-
" createDevvitWebPaymentsClient,",
|
|
17376
|
-
"} from '@mpgd/adapter-devvit/web';",
|
|
17377
|
-
""
|
|
17378
|
-
].join("\n")
|
|
17379
|
-
},
|
|
17380
|
-
{
|
|
17381
|
-
anchor: "import type { RuntimeConfig } from '../runtimeDetector';\n",
|
|
17382
|
-
replacement: [
|
|
17383
|
-
"import { setStarterHostedNotificationBackend } from '../notificationBackend';",
|
|
17384
|
-
"import { starterNotificationTopics } from '../notifications';",
|
|
17385
|
-
"import type { RuntimeConfig } from '../runtimeDetector';",
|
|
17386
|
-
""
|
|
17387
|
-
].join("\n")
|
|
17388
|
-
},
|
|
17389
|
-
{
|
|
17390
|
-
anchor: " ...(commerce === undefined ? {} : { commerce }),\n",
|
|
17391
|
-
replacement: [
|
|
17392
|
-
" ...(commerce === undefined ? {} : { commerce }),",
|
|
17393
|
-
" // Notifications v2: the game-rendered opt-in the server bridge serves",
|
|
17394
|
-
" // (a gated beta: `integrations.notifications` stays approval-required",
|
|
17395
|
-
" // until Reddit approves the app), and Reddit login for a logged-out",
|
|
17396
|
-
" // player, who must log in before opting in.",
|
|
17397
|
-
" ...notificationOptions(runtime),",
|
|
17398
|
-
" loginPrompt: createDevvitWebLoginPrompt(),",
|
|
17399
|
-
""
|
|
17400
|
-
].join("\n")
|
|
17401
|
-
},
|
|
17402
|
-
{
|
|
17403
|
-
anchor: "function createCommerceOptions(): DevvitGatewayCommerceOptions | undefined {\n",
|
|
17404
|
-
replacement: [
|
|
17405
|
-
"function notificationOptions(",
|
|
17406
|
-
" runtime: RuntimeConfig,",
|
|
17407
|
-
"): Pick<Parameters<typeof createDevvitPlatformGateway>[0], 'notifications'> {",
|
|
17408
|
-
" const topics = starterNotificationTopics(runtime.configTarget).map((topic) => topic.id);",
|
|
17409
|
-
" if (topics.length === 0) {",
|
|
17410
|
-
" return {};",
|
|
17411
|
-
" }",
|
|
17412
|
-
" // The runtime's backend is the Devvit server (consent records, reminders, notices for the",
|
|
17413
|
-
" // logged-in Reddit user), over the same server bridge as the gateway; created on first use.",
|
|
17414
|
-
" setStarterHostedNotificationBackend(runtime.configTarget, () =>",
|
|
17415
|
-
" createDevvitNotificationsBackend({ appVersion: runtime.appVersion, buildId: runtime.buildId }));",
|
|
17416
|
-
" return { notifications: { topics } };",
|
|
17417
|
-
"}",
|
|
17418
|
-
"",
|
|
17419
|
-
"function createCommerceOptions(): DevvitGatewayCommerceOptions | undefined {",
|
|
17420
|
-
""
|
|
17421
|
-
].join("\n")
|
|
17422
|
-
}
|
|
17423
|
-
],
|
|
17424
|
-
"apps/target-devvit/src/server/index.ts": [
|
|
17425
|
-
{
|
|
17426
|
-
anchor: "import { context, createServer, getServerPort, payments, reddit, redis } from '@devvit/web/server';\n",
|
|
17427
|
-
replacement: [
|
|
17428
|
-
"import {",
|
|
17429
|
-
" context,",
|
|
17430
|
-
" createServer,",
|
|
17431
|
-
" getServerPort,",
|
|
17432
|
-
" notifications,",
|
|
17433
|
-
" payments,",
|
|
17434
|
-
" reddit,",
|
|
17435
|
-
" redis,",
|
|
17436
|
-
"} from '@devvit/web/server';",
|
|
17437
|
-
""
|
|
17438
|
-
].join("\n")
|
|
17439
|
-
},
|
|
17440
|
-
{
|
|
17441
|
-
anchor: [
|
|
17442
|
-
"import {",
|
|
17443
|
-
" createDevvitCommerceBridgeProducts,",
|
|
17444
|
-
" createDevvitCommerceV2BridgeHandler,",
|
|
17445
|
-
"} from '@mpgd/adapter-devvit/server';",
|
|
17446
|
-
""
|
|
17447
|
-
].join("\n"),
|
|
17448
|
-
replacement: [
|
|
17449
|
-
"import {",
|
|
17450
|
-
" createDevvitCommerceBridgeProducts,",
|
|
17451
|
-
" createDevvitCommerceV2BridgeHandler,",
|
|
17452
|
-
" createDevvitNotificationService,",
|
|
17453
|
-
" createDevvitNotificationsBackendBridgeHandler,",
|
|
17454
|
-
" createDevvitNotificationsV2BridgeHandler,",
|
|
17455
|
-
"} from '@mpgd/adapter-devvit/server';",
|
|
17456
|
-
""
|
|
17457
|
-
].join("\n")
|
|
17458
|
-
},
|
|
17459
|
-
{
|
|
17460
|
-
anchor: "import type { ProductCatalog } from '@mpgd/catalog';\n",
|
|
17461
|
-
replacement: [
|
|
17462
|
-
"import { resolveNotificationTopicsForTarget, type NotificationTopicCatalog, type ProductCatalog } from '@mpgd/catalog';",
|
|
17463
|
-
"import { assertNotificationDeployment } from '@mpgd/platform/notifications';",
|
|
17464
|
-
""
|
|
17465
|
-
].join("\n")
|
|
17466
|
-
},
|
|
17467
|
-
{
|
|
17468
|
-
anchor: "import devvitManifest from '../../devvit.json';\n",
|
|
17469
|
-
replacement: [
|
|
17470
|
-
"import notificationDeploymentJson from '../../../../notifications/deployment.json';",
|
|
17471
|
-
"import notificationTopicsJson from '../../../../notifications/topics.json';",
|
|
17472
|
-
"import devvitManifest from '../../devvit.json';",
|
|
17473
|
-
""
|
|
17474
|
-
].join("\n")
|
|
17475
|
-
},
|
|
17476
|
-
{
|
|
17477
|
-
anchor: [
|
|
17478
|
-
"const handleBridgeRequest = createDevvitBridgeHandler({",
|
|
17479
|
-
" redis,",
|
|
17480
|
-
" currentPlayerId,",
|
|
17481
|
-
" currentDisplayName,",
|
|
17482
|
-
" storageKeyNamespace: gameName,",
|
|
17483
|
-
" ...(commerce === undefined ? {} : { commerce }),",
|
|
17484
|
-
"});",
|
|
17485
|
-
""
|
|
17486
|
-
].join("\n"),
|
|
17487
|
-
replacement: [
|
|
17488
|
-
"/**",
|
|
17489
|
-
" * Notifications v2 (`notifications/topics.json`, mapped for the `reddit`",
|
|
17490
|
-
" * target): the game-rendered opt-in for the logged-in requester, and the",
|
|
17491
|
-
" * service that records consent and sends server reminders over the Devvit",
|
|
17492
|
-
" * notifications plugin. Devvit notifications are a gated beta: the game",
|
|
17493
|
-
" * shows them only once `integrations.notifications` is `available`.",
|
|
17494
|
-
" */",
|
|
17495
|
-
"const notificationTopicCatalog = notificationTopicsJson as NotificationTopicCatalog;",
|
|
17496
|
-
"const redditNotificationTopics = readRedditNotificationTopics();",
|
|
17497
|
-
"const notificationService: ReturnType<typeof createDevvitNotificationService>['service'] | undefined =",
|
|
17498
|
-
" redditNotificationTopics.length === 0 ? undefined : createNotificationService();",
|
|
17499
|
-
"// The opt-in is served only with the service that sends; a refused catalog turns both off.",
|
|
17500
|
-
"const notificationsBridge = notificationService === undefined",
|
|
17501
|
-
" ? undefined",
|
|
17502
|
-
" : createDevvitNotificationsV2BridgeHandler({",
|
|
17503
|
-
" notifications,",
|
|
17504
|
-
" currentUserId: currentPlayerId,",
|
|
17505
|
-
" topics: redditNotificationTopics,",
|
|
17506
|
-
" });",
|
|
17507
|
-
"// The webview runtime's backend: consent records, reminders, and notices for the request's user.",
|
|
17508
|
-
"const notificationsBackend = notificationService === undefined",
|
|
17509
|
-
" ? undefined",
|
|
17510
|
-
" : createDevvitNotificationsBackendBridgeHandler({ service: notificationService, context: () => context });",
|
|
17511
|
-
"const handleBridgeRequest = createDevvitBridgeHandler({",
|
|
17512
|
-
" redis,",
|
|
17513
|
-
" currentPlayerId,",
|
|
17514
|
-
" currentDisplayName,",
|
|
17515
|
-
" storageKeyNamespace: gameName,",
|
|
17516
|
-
" ...(commerce === undefined ? {} : { commerce }),",
|
|
17517
|
-
" ...(notificationsBridge === undefined ? {} : { notifications: notificationsBridge }),",
|
|
17518
|
-
" ...(notificationsBackend === undefined ? {} : { notificationsBackend }),",
|
|
17519
|
-
"});",
|
|
17520
|
-
""
|
|
17521
|
-
].join("\n")
|
|
17522
|
-
},
|
|
17523
|
-
{
|
|
17524
|
-
anchor: [
|
|
17525
|
-
"/**",
|
|
17526
|
-
" * The notifications v2 service (`createDevvitNotificationService` from",
|
|
17527
|
-
" * `@mpgd/adapter-devvit/server`). None until the game declares a topic",
|
|
17528
|
-
" * catalog, so the scheduler tasks below do no work.",
|
|
17529
|
-
" */",
|
|
17530
|
-
"const notificationService: Parameters<typeof handleNotificationTask>[0]['notifications'] = undefined;",
|
|
17531
|
-
""
|
|
17532
|
-
].join("\n"),
|
|
17533
|
-
replacement: [
|
|
17534
|
-
"/** The topic ids the catalog maps for Reddit; none when the catalog cannot be read. */",
|
|
17535
|
-
"function readRedditNotificationTopics(): readonly string[] {",
|
|
17536
|
-
" try {",
|
|
17537
|
-
" return resolveNotificationTopicsForTarget(notificationTopicCatalog, 'reddit').map((topic) => topic.id);",
|
|
17538
|
-
" } catch (error) {",
|
|
17539
|
-
" console.error(`devvit notifications disabled: ${errorMessage(error)}`);",
|
|
17540
|
-
" return [];",
|
|
17541
|
-
" }",
|
|
17542
|
-
"}",
|
|
17543
|
-
"",
|
|
17544
|
-
"/**",
|
|
17545
|
-
" * The notifications v2 service over Redis and the Devvit plugin; the",
|
|
17546
|
-
" * scheduler tasks below run its reminders and purges. A catalog or",
|
|
17547
|
-
" * deployment the service refuses turns notifications off, never the game",
|
|
17548
|
-
" * server.",
|
|
17549
|
-
" */",
|
|
17550
|
-
"function createNotificationService(): ReturnType<typeof createDevvitNotificationService>['service'] | undefined {",
|
|
17551
|
-
" try {",
|
|
17552
|
-
" return createDevvitNotificationService({",
|
|
17553
|
-
" redis,",
|
|
17554
|
-
" notifications,",
|
|
17555
|
-
" catalog: notificationTopicCatalog,",
|
|
17556
|
-
" deployment: assertNotificationDeployment(notificationDeploymentJson),",
|
|
17557
|
-
" }).service;",
|
|
17558
|
-
" } catch (error) {",
|
|
17559
|
-
" console.error(`devvit notifications disabled: ${errorMessage(error)}`);",
|
|
17560
|
-
" return undefined;",
|
|
17561
|
-
" }",
|
|
17562
|
-
"}",
|
|
17563
|
-
""
|
|
17564
|
-
].join("\n")
|
|
17960
|
+
function inspectSignedIosApplication(appPath, input) {
|
|
17961
|
+
const plist = path9.join(appPath, "Info.plist");
|
|
17962
|
+
if (!existsSync22(plist) || !statSync4(plist).isFile()) {
|
|
17963
|
+
throw new Error("Signed iOS app manifest is missing.");
|
|
17964
|
+
}
|
|
17965
|
+
if (!existsSync22(path9.join(appPath, "Assets.car")) || existsSync22(path9.join(appPath, "Info-Smoke.plist"))) {
|
|
17966
|
+
throw new Error("Signed iOS app contains smoke assets or omits release icons.");
|
|
17967
|
+
}
|
|
17968
|
+
const runner = input.runner ?? { run: runCommand2 };
|
|
17969
|
+
const signature = runner.run("codesign", ["--verify", "--deep", "--strict", appPath]);
|
|
17970
|
+
if (signature.status !== 0) {
|
|
17971
|
+
throw new Error("iOS app code signature could not be verified.");
|
|
17972
|
+
}
|
|
17973
|
+
const signingInfo = runner.run("codesign", ["-dv", "--verbose=4", appPath]);
|
|
17974
|
+
const signingText = `${signingInfo.stdout}
|
|
17975
|
+
${signingInfo.stderr}`;
|
|
17976
|
+
const expectedTeamLine = `TeamIdentifier=${input.expectedTeamId}`;
|
|
17977
|
+
if (signingInfo.status !== 0 || /Signature=adhoc/iu.test(signingText) || !signingText.split(/\r?\n/u).some((line) => line.trim() === expectedTeamLine)) {
|
|
17978
|
+
throw new Error("iOS app is not signed for the expected development team.");
|
|
17979
|
+
}
|
|
17980
|
+
if (input.expectedApsEnvironment !== void 0) {
|
|
17981
|
+
const entitlements = runner.run("codesign", ["-d", "--entitlements", "-", "--xml", appPath]);
|
|
17982
|
+
if (entitlements.status !== 0) {
|
|
17983
|
+
throw new Error("iOS app entitlements could not be read.");
|
|
17565
17984
|
}
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
"src/runtime/createGame.ts": [
|
|
17570
|
-
{
|
|
17571
|
-
anchor: "import { LobbyScene } from '../scenes/LobbyScene';\n",
|
|
17572
|
-
replacement: [
|
|
17573
|
-
"import { LobbyScene } from '../scenes/LobbyScene';",
|
|
17574
|
-
"import {",
|
|
17575
|
-
" NotificationSettingsScene,",
|
|
17576
|
-
" routeNotificationSettingsOpens,",
|
|
17577
|
-
"} from '../scenes/NotificationSettingsScene';",
|
|
17578
|
-
""
|
|
17579
|
-
].join("\n")
|
|
17580
|
-
},
|
|
17581
|
-
{
|
|
17582
|
-
anchor: " scene: [BootScene, LobbyScene, PlayScene],\n",
|
|
17583
|
-
replacement: " scene: [BootScene, LobbyScene, PlayScene, NotificationSettingsScene],\n"
|
|
17584
|
-
},
|
|
17585
|
-
{
|
|
17586
|
-
anchor: " ownGameAudio(game, input.context);\n",
|
|
17587
|
-
replacement: [
|
|
17588
|
-
" ownGameAudio(game, input.context);",
|
|
17589
|
-
" // The advertising opt-out action and consent notices open the settings screen.",
|
|
17590
|
-
" routeNotificationSettingsOpens(game, input.context);",
|
|
17591
|
-
""
|
|
17592
|
-
].join("\n")
|
|
17985
|
+
const problem = iosStorePushEntitlementError(readSignedApsEnvironment(entitlements.stdout));
|
|
17986
|
+
if (problem !== void 0) {
|
|
17987
|
+
throw new Error(problem);
|
|
17593
17988
|
}
|
|
17594
|
-
|
|
17595
|
-
|
|
17596
|
-
|
|
17597
|
-
|
|
17598
|
-
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
|
|
17603
|
-
|
|
17604
|
-
{
|
|
17605
|
-
anchor: " this.input.once('pointerdown', () => this.scene.start('PlayScene'));\n",
|
|
17606
|
-
replacement: [
|
|
17607
|
-
" // The settings button shows only where this target has notifications.",
|
|
17608
|
-
" const notificationsButton = context.platform.notificationsV2 === undefined",
|
|
17609
|
-
" ? undefined",
|
|
17610
|
-
" : this.add",
|
|
17611
|
-
" .text(940, 16, locale === 'ko' ? '\uC54C\uB9BC \uC124\uC815' : 'Notifications', {",
|
|
17612
|
-
" color: '#5eead4',",
|
|
17613
|
-
" fontFamily: 'Arial, sans-serif',",
|
|
17614
|
-
" fontSize: '22px',",
|
|
17615
|
-
" })",
|
|
17616
|
-
" .setOrigin(1, 0)",
|
|
17617
|
-
" .setPadding(16, 12, 16, 12)",
|
|
17618
|
-
" .setInteractive({ useHandCursor: true });",
|
|
17619
|
-
" notificationsButton?.on('pointerup', () => this.scene.start(notificationSettingsSceneKey));",
|
|
17620
|
-
" // A tap anywhere else starts the game; the scene drops this listener on shutdown.",
|
|
17621
|
-
" this.input.on('pointerdown', (_pointer: Phaser.Input.Pointer, over: Phaser.GameObjects.GameObject[]) => {",
|
|
17622
|
-
" if (notificationsButton === undefined || !over.includes(notificationsButton)) {",
|
|
17623
|
-
" this.scene.start('PlayScene');",
|
|
17624
|
-
" }",
|
|
17625
|
-
" });",
|
|
17626
|
-
""
|
|
17627
|
-
].join("\n")
|
|
17989
|
+
}
|
|
17990
|
+
const fields = [
|
|
17991
|
+
["bundleId", "CFBundleIdentifier", input.expectedBundleId],
|
|
17992
|
+
["marketingVersion", "CFBundleShortVersionString", input.expectedMarketingVersion],
|
|
17993
|
+
["buildNumber", "CFBundleVersion", input.expectedBuildNumber]
|
|
17994
|
+
];
|
|
17995
|
+
const observed = Object.fromEntries(fields.map(([name, key, expected]) => {
|
|
17996
|
+
const result = runner.run("/usr/libexec/PlistBuddy", ["-c", `Print :${key}`, plist]);
|
|
17997
|
+
if (result.status !== 0 || result.stdout.trim() !== expected) {
|
|
17998
|
+
throw new Error(`iOS app ${name} does not match release identity.`);
|
|
17628
17999
|
}
|
|
17629
|
-
|
|
17630
|
-
};
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
|
|
17640
|
-
|
|
17641
|
-
{
|
|
17642
|
-
anchor: " const shell = createTapGame({ mount, title: '__GAME_TITLE__' });\n",
|
|
17643
|
-
replacement: [
|
|
17644
|
-
" const shell = createTapGame({ mount, title: '__GAME_TITLE__' });",
|
|
17645
|
-
" const disposeNotificationSettings = mountNotificationSettingsPanel(mount, input.context);",
|
|
17646
|
-
""
|
|
17647
|
-
].join("\n")
|
|
17648
|
-
},
|
|
17649
|
-
{
|
|
17650
|
-
anchor: " audio.dispose();\n",
|
|
17651
|
-
replacement: [" audio.dispose();", " disposeNotificationSettings();", ""].join("\n")
|
|
18000
|
+
return [name, expected];
|
|
18001
|
+
}));
|
|
18002
|
+
const configFiles = [
|
|
18003
|
+
path9.join(appPath, "capacitor.config.json"),
|
|
18004
|
+
path9.join(appPath, "public/capacitor.config.json")
|
|
18005
|
+
];
|
|
18006
|
+
if (!configFiles.some((file) => existsSync22(file))) {
|
|
18007
|
+
throw new Error("Signed iOS app Capacitor configuration is missing.");
|
|
18008
|
+
}
|
|
18009
|
+
for (const configFile of configFiles) {
|
|
18010
|
+
if (existsSync22(configFile)) {
|
|
18011
|
+
assertNoDebugServer(configFile);
|
|
17652
18012
|
}
|
|
17653
|
-
]
|
|
17654
|
-
};
|
|
17655
|
-
var readmeSection = [
|
|
17656
|
-
"",
|
|
17657
|
-
"## Notifications",
|
|
17658
|
-
"",
|
|
17659
|
-
"This game was created with `--providers notifications`. Its topics live in",
|
|
17660
|
-
"`notifications/topics.json` and the backend settings (`advertisingRules`,",
|
|
17661
|
-
"the advertising sender) in `notifications/deployment.json`; run",
|
|
17662
|
-
"`pnpm validate:notifications` after every change and before every release.",
|
|
17663
|
-
"Replace the sender contact placeholder in `notifications/deployment.json`",
|
|
17664
|
-
"before any advertising is sent. The notification settings screen asks for the",
|
|
17665
|
-
"OS or host permission and records reminder, advertising (\uAD11\uACE0\uC131 \uC815\uBCF4",
|
|
17666
|
-
"\uC218\uC2E0\uB3D9\uC758), and night consent through the notifications runtime. See",
|
|
17667
|
-
"`docs/NOTIFICATIONS.md` and, for Android and iOS, the mpgd-kit Firebase setup",
|
|
17668
|
-
"guide; `mpgd target init capacitor --providers notifications` installs the two",
|
|
17669
|
-
"Capacitor plugins into a game-owned shell.",
|
|
17670
|
-
""
|
|
17671
|
-
].join("\n");
|
|
17672
|
-
var notificationsCapacitorGateways = Object.freeze({
|
|
17673
|
-
android: "src/platform/buildGateways/capacitorAndroid.ts",
|
|
17674
|
-
ios: "src/platform/buildGateways/capacitorIos.ts"
|
|
17675
|
-
});
|
|
17676
|
-
var notificationsCapacitorGatewayModules = Object.freeze([
|
|
17677
|
-
"src/platform/capacitorNotifications.ts",
|
|
17678
|
-
"src/platform/notifications.ts",
|
|
17679
|
-
"src/platform/notificationBackend.ts",
|
|
17680
|
-
"src/platform/notificationSettings.ts",
|
|
17681
|
-
"src/platform/notificationOpens.ts"
|
|
17682
|
-
]);
|
|
17683
|
-
var notificationsCapacitorSupportFiles = Object.freeze([
|
|
17684
|
-
...notificationsCapacitorGatewayModules,
|
|
17685
|
-
"notifications/topics.json",
|
|
17686
|
-
"notifications/deployment.json",
|
|
17687
|
-
"tools/validate-notifications.ts",
|
|
17688
|
-
"docs/NOTIFICATIONS.md"
|
|
17689
|
-
]);
|
|
17690
|
-
var notificationsCapacitorTemplateSupportFiles = Object.freeze([
|
|
17691
|
-
"src/platform/serverSession.ts",
|
|
17692
|
-
"src/platform/developmentServerSession.ts"
|
|
17693
|
-
]);
|
|
17694
|
-
var notificationsCapacitorTemplateSupportImporters = Object.freeze({
|
|
17695
|
-
"src/platform/developmentServerSession.ts": {
|
|
17696
|
-
importer: "src/platform/serverSession.ts",
|
|
17697
|
-
requires: { packageName: "@mpgd/game-services", exportName: "createDevelopmentServerSession" },
|
|
17698
|
-
warning: "src/platform/serverSession.ts predates development notification sessions (VITE_MPGD_DEV_NOTIFICATION_SESSION); to try notifications locally, copy serverSession.ts and developmentServerSession.ts from the starter template."
|
|
17699
18013
|
}
|
|
17700
|
-
}
|
|
18014
|
+
return { ...observed, teamId: input.expectedTeamId, signed: true };
|
|
18015
|
+
}
|
|
18016
|
+
function readSignedApsEnvironment(codesignOutput) {
|
|
18017
|
+
const start = codesignOutput.search(/<\?xml|<plist\b/u);
|
|
18018
|
+
if (start === -1) {
|
|
18019
|
+
return codesignOutput.trim() === "" ? void 0 : null;
|
|
18020
|
+
}
|
|
18021
|
+
let value;
|
|
18022
|
+
try {
|
|
18023
|
+
value = readPlistTopLevelValue(codesignOutput.slice(start), "aps-environment")?.xml;
|
|
18024
|
+
} catch {
|
|
18025
|
+
return null;
|
|
18026
|
+
}
|
|
18027
|
+
if (value === void 0) {
|
|
18028
|
+
return void 0;
|
|
18029
|
+
}
|
|
18030
|
+
return /^<string>\s*([^<]*?)\s*<\/string>$/u.exec(value)?.[1] ?? null;
|
|
18031
|
+
}
|
|
18032
|
+
function iosStorePushEntitlementError(apsEnvironment) {
|
|
18033
|
+
if (apsEnvironment === "production") {
|
|
18034
|
+
return void 0;
|
|
18035
|
+
}
|
|
18036
|
+
const fix = "Enable Push Notifications on the App ID in the Apple Developer account, regenerate the App Store provisioning profile (MPGD_IOS_PROVISIONING_PROFILE_FILE), and rebuild (docs/FIREBASE_NOTIFICATIONS.md#4-ios).";
|
|
18037
|
+
if (apsEnvironment === void 0) {
|
|
18038
|
+
return `The store IPA has no aps-environment entitlement although the shell installs @capacitor-firebase/messaging: the provisioning profile that signed it lacks the Push Notifications capability (the App ID has no push, or the profile was generated before it was enabled), so the app never gets an APNs token. ${fix}`;
|
|
18039
|
+
}
|
|
18040
|
+
if (apsEnvironment === "development") {
|
|
18041
|
+
return `The store IPA is signed with aps-environment = development although it is an App Store build: the export used a development provisioning profile, so its APNs token belongs to the sandbox and production pushes never arrive. Export with the App Store distribution profile. ${fix}`;
|
|
18042
|
+
}
|
|
18043
|
+
return `The store IPA's aps-environment entitlement is ${apsEnvironment === null ? "unreadable" : apsEnvironment}, not production, so production pushes never arrive. ${fix}`;
|
|
18044
|
+
}
|
|
18045
|
+
function assertNoDebugServer(file) {
|
|
18046
|
+
const value = JSON.parse(readFileSync23(file, "utf8"));
|
|
18047
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
18048
|
+
throw new Error("Signed iOS app has malformed Capacitor configuration.");
|
|
18049
|
+
}
|
|
18050
|
+
const config2 = value;
|
|
18051
|
+
const server = config2.server;
|
|
18052
|
+
const ios = config2.ios;
|
|
18053
|
+
if (typeof server === "object" && server !== null && "url" in server || typeof ios === "object" && ios !== null && "webContentsDebuggingEnabled" in ios && ios.webContentsDebuggingEnabled === true) {
|
|
18054
|
+
throw new Error("Signed iOS app retains a live-reload or debug bridge configuration.");
|
|
18055
|
+
}
|
|
18056
|
+
}
|
|
18057
|
+
function runCommand2(command, args) {
|
|
18058
|
+
const result = spawnSync3(command, [...args], {
|
|
18059
|
+
encoding: "utf8",
|
|
18060
|
+
env: nativeInspectionEnvironment(),
|
|
18061
|
+
maxBuffer: 4 * 1024 * 1024
|
|
18062
|
+
});
|
|
18063
|
+
if (result.error !== void 0) {
|
|
18064
|
+
throw new Error(`Required iOS inspection command is unavailable: ${command}.`);
|
|
18065
|
+
}
|
|
18066
|
+
return {
|
|
18067
|
+
status: result.status,
|
|
18068
|
+
stdout: result.stdout,
|
|
18069
|
+
stderr: result.stderr
|
|
18070
|
+
};
|
|
18071
|
+
}
|
|
18072
|
+
|
|
18073
|
+
// node_modules/.cache/mpgd-native-build/tools/target/native-ios-signing.js
|
|
18074
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
18075
|
+
import { existsSync as existsSync23, statSync as statSync5 } from "node:fs";
|
|
18076
|
+
import path10 from "node:path";
|
|
18077
|
+
function resolveIosSigningPlan(environment, mode) {
|
|
18078
|
+
const teamId = environment.MPGD_IOS_TEAM_ID?.trim();
|
|
18079
|
+
if (teamId === void 0 || !/^[A-Z0-9]{10}$/u.test(teamId)) {
|
|
18080
|
+
throw new Error("Signed iOS builds require a 10-character MPGD_IOS_TEAM_ID.");
|
|
18081
|
+
}
|
|
18082
|
+
const style = environment.MPGD_IOS_SIGNING_STYLE ?? "Automatic";
|
|
18083
|
+
if (style !== "Automatic" && style !== "Manual") {
|
|
18084
|
+
throw new Error("MPGD_IOS_SIGNING_STYLE must be Automatic or Manual.");
|
|
18085
|
+
}
|
|
18086
|
+
const identity = environment.MPGD_IOS_SIGNING_IDENTITY?.trim();
|
|
18087
|
+
const profile2 = environment.MPGD_IOS_PROVISIONING_PROFILE_SPECIFIER?.trim();
|
|
18088
|
+
if (style === "Manual" && (identity === void 0 || identity === "" || profile2 === void 0 || profile2 === "")) {
|
|
18089
|
+
throw new Error("Manual iOS signing requires host identity and provisioning profile names.");
|
|
18090
|
+
}
|
|
18091
|
+
if (style === "Automatic" && profile2 !== void 0 && profile2 !== "") {
|
|
18092
|
+
throw new Error("Automatic iOS signing must not set a manual provisioning profile.");
|
|
18093
|
+
}
|
|
18094
|
+
const archiveBuildSettings = [
|
|
18095
|
+
"CODE_SIGNING_ALLOWED=YES",
|
|
18096
|
+
`CODE_SIGN_STYLE=${style}`,
|
|
18097
|
+
`DEVELOPMENT_TEAM=${teamId}`,
|
|
18098
|
+
...identity === void 0 || identity === "" ? [] : [`CODE_SIGN_IDENTITY=${identity}`],
|
|
18099
|
+
...profile2 === void 0 || profile2 === "" ? [] : [`PROVISIONING_PROFILE_SPECIFIER=${profile2}`],
|
|
18100
|
+
...environment.MPGD_IOS_SIGNING_KEYCHAIN === void 0 ? [] : [`OTHER_CODE_SIGN_FLAGS=--keychain ${JSON.stringify(environment.MPGD_IOS_SIGNING_KEYCHAIN)}`]
|
|
18101
|
+
];
|
|
18102
|
+
if (mode !== "store-export") {
|
|
18103
|
+
return { teamId, archiveBuildSettings };
|
|
18104
|
+
}
|
|
18105
|
+
const configuredExportFile = environment.MPGD_IOS_EXPORT_OPTIONS_PLIST;
|
|
18106
|
+
if (configuredExportFile === void 0 || configuredExportFile.trim() === "") {
|
|
18107
|
+
throw new Error("iOS store export requires MPGD_IOS_EXPORT_OPTIONS_PLIST.");
|
|
18108
|
+
}
|
|
18109
|
+
const exportOptionsPlist = path10.resolve(configuredExportFile);
|
|
18110
|
+
if (!existsSync23(exportOptionsPlist) || !statSync5(exportOptionsPlist).isFile()) {
|
|
18111
|
+
throw new Error("iOS export options plist must be an existing host file.");
|
|
18112
|
+
}
|
|
18113
|
+
const method = spawnSync4("/usr/libexec/PlistBuddy", ["-c", "Print :method", exportOptionsPlist], {
|
|
18114
|
+
encoding: "utf8",
|
|
18115
|
+
maxBuffer: 1024 * 1024
|
|
18116
|
+
});
|
|
18117
|
+
if (method.error !== void 0 || method.status !== 0 || !["app-store", "app-store-connect"].includes(method.stdout.trim())) {
|
|
18118
|
+
throw new Error("iOS export options must select an App Store distribution method.");
|
|
18119
|
+
}
|
|
18120
|
+
return { teamId, archiveBuildSettings, exportOptionsPlist };
|
|
18121
|
+
}
|
|
18122
|
+
|
|
18123
|
+
// node_modules/.cache/mpgd-native-build/tools/target/native-release-identity.js
|
|
18124
|
+
import { existsSync as existsSync25, readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
|
|
18125
|
+
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join14, relative as relative12, resolve as resolve17 } from "node:path";
|
|
17701
18126
|
|
|
17702
18127
|
// node_modules/.cache/mpgd-native-build/packages/cli/src/capacitor-shell-starter.js
|
|
18128
|
+
import { chmodSync as chmodSync2, existsSync as existsSync24, lstatSync as lstatSync14, mkdirSync as mkdirSync11, readdirSync as readdirSync7, readFileSync as readFileSync24, realpathSync as realpathSync9, renameSync as renameSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync16 } from "node:fs";
|
|
18129
|
+
import path11 from "node:path";
|
|
18130
|
+
import { DOMParser as DOMParser2 } from "@xmldom/xmldom";
|
|
18131
|
+
import { satisfies as satisfies2, valid as valid2, validRange as validRange2 } from "semver";
|
|
17703
18132
|
var shellPath = "apps/mobile-capacitor";
|
|
17704
18133
|
var webPath = `${shellPath}/www`;
|
|
17705
18134
|
var javaKeywords = new Set(`
|
|
@@ -17780,7 +18209,7 @@ var androidDataExtractionRulesXml = [
|
|
|
17780
18209
|
""
|
|
17781
18210
|
].join("\n");
|
|
17782
18211
|
function assertAndroidLauncherClasses(nativeDirectory, gradle) {
|
|
17783
|
-
const application = readAndroidApplication(
|
|
18212
|
+
const application = readAndroidApplication(path11.join(nativeDirectory, "app/src/main/AndroidManifest.xml"));
|
|
17784
18213
|
if (application === void 0) {
|
|
17785
18214
|
throw new Error("Existing android project launcher activity is missing.");
|
|
17786
18215
|
}
|
|
@@ -17788,8 +18217,8 @@ function assertAndroidLauncherClasses(nativeDirectory, gradle) {
|
|
|
17788
18217
|
const manifestRoot = application.parentNode;
|
|
17789
18218
|
const manifestPackage = manifestRoot?.getAttribute("package");
|
|
17790
18219
|
const namespace = /\bnamespace\s*(?:=\s*)?["']([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)+)["']/u.exec(stripGradleComments(gradle))?.[1] ?? (manifestPackage === null || manifestPackage === "" ? void 0 : manifestPackage);
|
|
17791
|
-
const releaseFile =
|
|
17792
|
-
const release =
|
|
18220
|
+
const releaseFile = path11.join(nativeDirectory, "app/src/release/AndroidManifest.xml");
|
|
18221
|
+
const release = existsSync24(releaseFile) ? readAndroidApplication(releaseFile, false) : void 0;
|
|
17793
18222
|
if (release !== void 0) {
|
|
17794
18223
|
assertAndroidLauncherEnabled(release, "Release application");
|
|
17795
18224
|
}
|
|
@@ -17899,7 +18328,7 @@ function resolvesAndroidClass(nativeDirectory, qualified, sourceFiles, visited,
|
|
|
17899
18328
|
if (!isNativeFile(nativeDirectory, relative14)) {
|
|
17900
18329
|
continue;
|
|
17901
18330
|
}
|
|
17902
|
-
const source = stripSourceCommentsAndStrings(
|
|
18331
|
+
const source = stripSourceCommentsAndStrings(readFileSync24(path11.join(nativeDirectory, relative14), "utf8"));
|
|
17903
18332
|
const declaredPackage = /\bpackage\s+([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)+)\s*;?/u.exec(source)?.[1];
|
|
17904
18333
|
if (declaredPackage !== packageName) {
|
|
17905
18334
|
continue;
|
|
@@ -17955,15 +18384,15 @@ function listNativeFiles(nativeDirectory, relativeRoot, extension) {
|
|
|
17955
18384
|
const files = [];
|
|
17956
18385
|
while (pending.length > 0) {
|
|
17957
18386
|
const relative14 = pending.pop() ?? "";
|
|
17958
|
-
const full =
|
|
17959
|
-
if (!
|
|
18387
|
+
const full = path11.join(nativeDirectory, relative14);
|
|
18388
|
+
if (!existsSync24(full) || lstatSync14(full).isSymbolicLink()) {
|
|
17960
18389
|
continue;
|
|
17961
18390
|
}
|
|
17962
|
-
for (const entry of
|
|
18391
|
+
for (const entry of readdirSync7(full, { withFileTypes: true })) {
|
|
17963
18392
|
if (entry.isSymbolicLink()) {
|
|
17964
18393
|
continue;
|
|
17965
18394
|
}
|
|
17966
|
-
const child =
|
|
18395
|
+
const child = path11.join(relative14, entry.name);
|
|
17967
18396
|
if (entry.isDirectory()) {
|
|
17968
18397
|
pending.push(child);
|
|
17969
18398
|
} else if (entry.isFile() && entry.name.endsWith(extension)) {
|
|
@@ -18169,7 +18598,7 @@ function assertReferencedIosFiles(nativeDirectory, project, infoRelative) {
|
|
|
18169
18598
|
throw new Error(`Existing ios project is incomplete; referenced app file ${relative14} is missing.`);
|
|
18170
18599
|
}
|
|
18171
18600
|
}
|
|
18172
|
-
const info =
|
|
18601
|
+
const info = readFileSync24(path11.join(nativeDirectory, infoRelative), "utf8");
|
|
18173
18602
|
assertSceneDelegateFiles(nativeDirectory, info, "Release", compiledSources);
|
|
18174
18603
|
return compiledSources;
|
|
18175
18604
|
}
|
|
@@ -18300,7 +18729,7 @@ function readPbxGroupPath(project, parents, referenceId) {
|
|
|
18300
18729
|
const groupPath = /\bpath\s*=\s*(?:"([^"]+)"|([^;]+))\s*;/u.exec(group);
|
|
18301
18730
|
const value = (groupPath?.[1] ?? groupPath?.[2])?.trim();
|
|
18302
18731
|
if (value !== void 0) {
|
|
18303
|
-
if (value.includes("$") ||
|
|
18732
|
+
if (value.includes("$") || path11.isAbsolute(value)) {
|
|
18304
18733
|
throw new Error("Existing ios project build input group path is unsupported.");
|
|
18305
18734
|
}
|
|
18306
18735
|
parts.push(value);
|
|
@@ -18322,7 +18751,7 @@ function assertPbxFileReference(nativeDirectory, project, referenceId, parentGro
|
|
|
18322
18751
|
}
|
|
18323
18752
|
const relative14 = /\bpath\s*=\s*(?:"([^"]+)"|([^;]+))\s*;/u.exec(reference);
|
|
18324
18753
|
const filePath = (relative14?.[1] ?? relative14?.[2])?.trim();
|
|
18325
|
-
if (filePath === void 0 || filePath.includes("$") ||
|
|
18754
|
+
if (filePath === void 0 || filePath.includes("$") || path11.isAbsolute(filePath)) {
|
|
18326
18755
|
throw new Error("Existing ios project App build input path is unsupported.");
|
|
18327
18756
|
}
|
|
18328
18757
|
if (filePath === "public" || filePath === "capacitor.config.json") {
|
|
@@ -18349,19 +18778,19 @@ function assertPbxFileReference(nativeDirectory, project, referenceId, parentGro
|
|
|
18349
18778
|
return [resolved];
|
|
18350
18779
|
}
|
|
18351
18780
|
function isNativeEntry(directory, relative14) {
|
|
18352
|
-
const file =
|
|
18353
|
-
const within =
|
|
18354
|
-
if (within === "" || within.startsWith("..") ||
|
|
18781
|
+
const file = path11.resolve(directory, relative14);
|
|
18782
|
+
const within = path11.relative(directory, file);
|
|
18783
|
+
if (within === "" || within.startsWith("..") || path11.isAbsolute(within)) {
|
|
18355
18784
|
return false;
|
|
18356
18785
|
}
|
|
18357
18786
|
let current = directory;
|
|
18358
|
-
for (const segment of within.split(
|
|
18359
|
-
current =
|
|
18360
|
-
if (!
|
|
18787
|
+
for (const segment of within.split(path11.sep)) {
|
|
18788
|
+
current = path11.join(current, segment);
|
|
18789
|
+
if (!existsSync24(current) || lstatSync14(current).isSymbolicLink()) {
|
|
18361
18790
|
return false;
|
|
18362
18791
|
}
|
|
18363
18792
|
}
|
|
18364
|
-
return
|
|
18793
|
+
return lstatSync14(file).isFile() || lstatSync14(file).isDirectory();
|
|
18365
18794
|
}
|
|
18366
18795
|
function assertSceneDelegateFiles(nativeDirectory, source, label, compiledSources) {
|
|
18367
18796
|
const values = parsePlistDictionary(source, label);
|
|
@@ -18390,7 +18819,7 @@ function assertSceneDelegateFiles(nativeDirectory, source, label, compiledSource
|
|
|
18390
18819
|
if (!compiledSources.has(relative14)) {
|
|
18391
18820
|
return false;
|
|
18392
18821
|
}
|
|
18393
|
-
const text = stripSourceCommentsAndStrings(
|
|
18822
|
+
const text = stripSourceCommentsAndStrings(readFileSync24(path11.join(nativeDirectory, relative14), "utf8"));
|
|
18394
18823
|
return hasUsableTopLevelSwiftSceneDelegate(text, className);
|
|
18395
18824
|
})) {
|
|
18396
18825
|
throw new Error(`Existing ios project ${label} scene delegate ${delegate} is missing from App Sources.`);
|
|
@@ -18415,29 +18844,29 @@ function hasUsableTopLevelSwiftSceneDelegate(source, className) {
|
|
|
18415
18844
|
return false;
|
|
18416
18845
|
}
|
|
18417
18846
|
function assertAndroidManifestResources(nativeDirectory) {
|
|
18418
|
-
const manifestFiles = ["main", "release"].map((sourceSet) =>
|
|
18419
|
-
const resourceRoots = ["main", "release"].map((sourceSet) =>
|
|
18847
|
+
const manifestFiles = ["main", "release"].map((sourceSet) => path11.join(nativeDirectory, `app/src/${sourceSet}/AndroidManifest.xml`)).filter((file) => existsSync24(file));
|
|
18848
|
+
const resourceRoots = ["main", "release"].map((sourceSet) => path11.join(nativeDirectory, `app/src/${sourceSet}/res`));
|
|
18420
18849
|
const references = manifestFiles.flatMap((file) => {
|
|
18421
|
-
const manifest =
|
|
18850
|
+
const manifest = readFileSync24(file, "utf8").replace(/<!--[\s\S]*?-->/gu, "");
|
|
18422
18851
|
return [...manifest.matchAll(/(?<![\w+])@([a-z]+)\/([A-Za-z_][A-Za-z0-9_.]*)/gu)];
|
|
18423
18852
|
});
|
|
18424
18853
|
for (const reference of references) {
|
|
18425
18854
|
const type = reference[1] ?? "";
|
|
18426
18855
|
const name = reference[2] ?? "";
|
|
18427
18856
|
const found = resourceRoots.some((resourceRoot) => {
|
|
18428
|
-
if (!
|
|
18857
|
+
if (!existsSync24(resourceRoot)) {
|
|
18429
18858
|
return false;
|
|
18430
18859
|
}
|
|
18431
|
-
const folders =
|
|
18860
|
+
const folders = readdirSync7(resourceRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
18432
18861
|
return folders.some((folder) => {
|
|
18433
18862
|
const densityFallback = (type === "mipmap" || type === "drawable") && new RegExp(`^${type}-(?:ldpi|mdpi|hdpi|xhdpi|xxhdpi|xxxhdpi|nodpi|anydpi)$`, "u").test(folder);
|
|
18434
18863
|
if (folder === type || densityFallback) {
|
|
18435
|
-
return
|
|
18864
|
+
return readdirSync7(path11.join(resourceRoot, folder)).some((file) => file === `${name}.xml` || file.startsWith(`${name}.`));
|
|
18436
18865
|
}
|
|
18437
18866
|
if (folder !== "values") {
|
|
18438
18867
|
return false;
|
|
18439
18868
|
}
|
|
18440
|
-
return
|
|
18869
|
+
return readdirSync7(path11.join(resourceRoot, folder)).some((file) => file.endsWith(".xml") && readAndroidValueResource(path11.join(resourceRoot, folder, file), type, name).length > 0);
|
|
18441
18870
|
});
|
|
18442
18871
|
});
|
|
18443
18872
|
if (!found) {
|
|
@@ -18450,13 +18879,13 @@ function assertNativeDisplayName(nativeDirectory, platform, expectedDisplayName,
|
|
|
18450
18879
|
if (platform === "ios" && !isNativeFile(nativeDirectory, relative14)) {
|
|
18451
18880
|
throw new Error(`Existing ${platform} project is incomplete; native display name resource is missing.`);
|
|
18452
18881
|
}
|
|
18453
|
-
const source = platform === "ios" ?
|
|
18882
|
+
const source = platform === "ios" ? readFileSync24(path11.join(nativeDirectory, relative14), "utf8") : "";
|
|
18454
18883
|
const labels = platform === "ios" ? [parsePlistDictionary(source, "Release").get("CFBundleDisplayName")].filter((value) => value?.tagName === "string").map((value) => value?.textContent ?? "") : [];
|
|
18455
18884
|
if (platform === "ios" && (labels.length !== 1 || labels[0] !== expectedDisplayName)) {
|
|
18456
18885
|
throw new Error(`Existing ${platform} project display name differs or cannot be read safely.`);
|
|
18457
18886
|
}
|
|
18458
18887
|
if (platform === "android") {
|
|
18459
|
-
const main = readAndroidApplication(
|
|
18888
|
+
const main = readAndroidApplication(path11.join(nativeDirectory, "app/src/main/AndroidManifest.xml"));
|
|
18460
18889
|
if (main === void 0) {
|
|
18461
18890
|
throw new Error("Existing android project application label is missing.");
|
|
18462
18891
|
}
|
|
@@ -18475,8 +18904,8 @@ function assertNativeDisplayName(nativeDirectory, platform, expectedDisplayName,
|
|
|
18475
18904
|
throw new Error("Existing android project launcher label differs from the requested name.");
|
|
18476
18905
|
}
|
|
18477
18906
|
}
|
|
18478
|
-
const overlayFile =
|
|
18479
|
-
if (
|
|
18907
|
+
const overlayFile = path11.join(nativeDirectory, "app/src/release/AndroidManifest.xml");
|
|
18908
|
+
if (existsSync24(overlayFile)) {
|
|
18480
18909
|
const release = readAndroidApplication(overlayFile, false);
|
|
18481
18910
|
if (release !== void 0) {
|
|
18482
18911
|
if (hasAndroidMergerDirective(release)) {
|
|
@@ -18486,8 +18915,8 @@ function assertNativeDisplayName(nativeDirectory, platform, expectedDisplayName,
|
|
|
18486
18915
|
if (releaseLabel !== null && resolveAndroidLabel(nativeDirectory, releaseLabel) !== expectedDisplayName) {
|
|
18487
18916
|
throw new Error("Existing android Release application label differs from the requested name.");
|
|
18488
18917
|
}
|
|
18489
|
-
const appBuildFile = ["app/build.gradle", "app/build.gradle.kts"].map((relative15) =>
|
|
18490
|
-
const appGradle = appBuildFile === void 0 ? "" :
|
|
18918
|
+
const appBuildFile = ["app/build.gradle", "app/build.gradle.kts"].map((relative15) => path11.join(nativeDirectory, relative15)).find((file) => existsSync24(file));
|
|
18919
|
+
const appGradle = appBuildFile === void 0 ? "" : readFileSync24(appBuildFile, "utf8");
|
|
18491
18920
|
const manifestPackage = main.parentNode?.getAttribute("package");
|
|
18492
18921
|
const namespace = /\bnamespace\s*(?:=\s*)?["']([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)+)["']/u.exec(stripGradleComments(appGradle))?.[1] ?? (manifestPackage === null || manifestPackage === "" ? void 0 : manifestPackage);
|
|
18493
18922
|
const launcherNames = /* @__PURE__ */ new Set();
|
|
@@ -18523,21 +18952,21 @@ function assertNativeDisplayName(nativeDirectory, platform, expectedDisplayName,
|
|
|
18523
18952
|
}
|
|
18524
18953
|
}
|
|
18525
18954
|
function assertAndroidReleaseDisplayName(shellApp, expectedDisplayName) {
|
|
18526
|
-
const nativeDirectory =
|
|
18955
|
+
const nativeDirectory = path11.join(shellApp, "android");
|
|
18527
18956
|
assertAndroidManifestResources(nativeDirectory);
|
|
18528
18957
|
assertNativeDisplayName(nativeDirectory, "android", expectedDisplayName);
|
|
18529
18958
|
}
|
|
18530
18959
|
function assertAndroidReleaseLauncherIntegrity(shellApp) {
|
|
18531
|
-
const nativeDirectory =
|
|
18960
|
+
const nativeDirectory = path11.join(shellApp, "android");
|
|
18532
18961
|
const gradleRelative = requireOneNativeFile(nativeDirectory, ["app/build.gradle", "app/build.gradle.kts"], "android");
|
|
18533
|
-
const gradle =
|
|
18962
|
+
const gradle = readFileSync24(path11.join(nativeDirectory, gradleRelative), "utf8");
|
|
18534
18963
|
assertAndroidLauncherClasses(nativeDirectory, gradle);
|
|
18535
18964
|
}
|
|
18536
18965
|
function assertIosReleaseDisplayName(shellApp, expectedDisplayName) {
|
|
18537
|
-
const nativeDirectory =
|
|
18538
|
-
const projectFile =
|
|
18539
|
-
const project =
|
|
18540
|
-
const infoRelative =
|
|
18966
|
+
const nativeDirectory = path11.join(shellApp, "ios");
|
|
18967
|
+
const projectFile = path11.join(nativeDirectory, "App/App.xcodeproj/project.pbxproj");
|
|
18968
|
+
const project = readFileSync24(projectFile, "utf8");
|
|
18969
|
+
const infoRelative = path11.join("App", readIosReleaseInfoPlist(project));
|
|
18541
18970
|
if (!isNativeFile(nativeDirectory, infoRelative)) {
|
|
18542
18971
|
throw new Error("Existing ios project Release Info.plist is missing or unsafe.");
|
|
18543
18972
|
}
|
|
@@ -18547,20 +18976,20 @@ function assertIosReleaseDisplayName(shellApp, expectedDisplayName) {
|
|
|
18547
18976
|
}
|
|
18548
18977
|
function assertNoIosLocalizedDisplayNameOverride(nativeDirectory, project) {
|
|
18549
18978
|
const files = listNativeFiles(nativeDirectory, "App/App", ".strings");
|
|
18550
|
-
if (/\bInfoPlist\.strings\b/u.test(project) || isNativeFile(nativeDirectory, "App/InfoPlist.strings") || files.some((relative14) =>
|
|
18979
|
+
if (/\bInfoPlist\.strings\b/u.test(project) || isNativeFile(nativeDirectory, "App/InfoPlist.strings") || files.some((relative14) => path11.basename(relative14) === "InfoPlist.strings")) {
|
|
18551
18980
|
throw new Error("Existing ios project localized InfoPlist.strings overrides are unsupported.");
|
|
18552
18981
|
}
|
|
18553
18982
|
}
|
|
18554
18983
|
function assertIosArchiveScheme(shellApp) {
|
|
18555
|
-
const nativeDirectory =
|
|
18984
|
+
const nativeDirectory = path11.join(shellApp, "ios");
|
|
18556
18985
|
const projectRelative = "App/App.xcodeproj/project.pbxproj";
|
|
18557
18986
|
const schemeRelative = "App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme";
|
|
18558
18987
|
if (!isNativeFile(nativeDirectory, projectRelative) || !isNativeFile(nativeDirectory, schemeRelative)) {
|
|
18559
18988
|
throw new Error("Existing ios project shared App archive scheme is missing or unsafe.");
|
|
18560
18989
|
}
|
|
18561
|
-
const project =
|
|
18990
|
+
const project = readFileSync24(path11.join(nativeDirectory, projectRelative), "utf8");
|
|
18562
18991
|
const appTargetId = readIosAppTargetId(project);
|
|
18563
|
-
const schemeSource =
|
|
18992
|
+
const schemeSource = readFileSync24(path11.join(nativeDirectory, schemeRelative), "utf8");
|
|
18564
18993
|
const scheme = parseXml(schemeSource, "ios project App archive scheme").documentElement;
|
|
18565
18994
|
if (scheme?.tagName !== "Scheme") {
|
|
18566
18995
|
throw new Error("Existing ios project App archive scheme is malformed.");
|
|
@@ -18587,7 +19016,7 @@ function hasAndroidMergerDirectiveDeep(element) {
|
|
|
18587
19016
|
return hasAndroidMergerDirective(element) || childElements(element).some(hasAndroidMergerDirectiveDeep);
|
|
18588
19017
|
}
|
|
18589
19018
|
function readAndroidApplication(file, required = true) {
|
|
18590
|
-
const root = parseXml(
|
|
19019
|
+
const root = parseXml(readFileSync24(file, "utf8"), "android manifest").documentElement;
|
|
18591
19020
|
const application = root === null ? void 0 : childElements(root).find((element) => element.tagName === "application");
|
|
18592
19021
|
if (root?.tagName !== "manifest" || required && application === void 0) {
|
|
18593
19022
|
throw new Error("Existing android project manifest application is missing.");
|
|
@@ -18615,22 +19044,22 @@ function readAndroidString(nativeDirectory, key) {
|
|
|
18615
19044
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key)) {
|
|
18616
19045
|
throw new Error("Existing android project application label is unsupported.");
|
|
18617
19046
|
}
|
|
18618
|
-
const overlay =
|
|
18619
|
-
const overlayValues =
|
|
18620
|
-
const main =
|
|
18621
|
-
const mainValues =
|
|
19047
|
+
const overlay = path11.join(nativeDirectory, "app/src/release/res/values");
|
|
19048
|
+
const overlayValues = existsSync24(overlay) && lstatSync14(overlay).isDirectory() ? readdirSync7(overlay).filter((file) => file.endsWith(".xml")).flatMap((file) => readAndroidValueResource(path11.join(overlay, file), "string", key)) : [];
|
|
19049
|
+
const main = path11.join(nativeDirectory, "app/src/main/res/values");
|
|
19050
|
+
const mainValues = existsSync24(main) && lstatSync14(main).isDirectory() ? readdirSync7(main).filter((file) => file.endsWith(".xml")).flatMap((file) => readAndroidValueResource(path11.join(main, file), "string", key)) : [];
|
|
18622
19051
|
const values = overlayValues.length > 0 ? overlayValues : mainValues;
|
|
18623
19052
|
if (values.length !== 1) {
|
|
18624
19053
|
throw new Error("Existing android project application label resource is missing or ambiguous.");
|
|
18625
19054
|
}
|
|
18626
|
-
const qualified = ["main", "release"].flatMap((sourceSet) => listNativeFiles(nativeDirectory, `app/src/${sourceSet}/res`, ".xml").filter((relative14) => /^values-[^/]+$/u.test(
|
|
19055
|
+
const qualified = ["main", "release"].flatMap((sourceSet) => listNativeFiles(nativeDirectory, `app/src/${sourceSet}/res`, ".xml").filter((relative14) => /^values-[^/]+$/u.test(path11.basename(path11.dirname(relative14)))).flatMap((relative14) => readAndroidValueResource(path11.join(nativeDirectory, relative14), "string", key)));
|
|
18627
19056
|
if (qualified.some((value) => value !== values[0])) {
|
|
18628
19057
|
throw new Error("Existing android project configuration-qualified application label differs.");
|
|
18629
19058
|
}
|
|
18630
19059
|
return values[0] ?? "";
|
|
18631
19060
|
}
|
|
18632
19061
|
function readAndroidValueResource(file, type, name) {
|
|
18633
|
-
const root = parseXml(
|
|
19062
|
+
const root = parseXml(readFileSync24(file, "utf8"), "android values resource").documentElement;
|
|
18634
19063
|
if (root?.tagName !== "resources") {
|
|
18635
19064
|
throw new Error("Existing android values resource is malformed.");
|
|
18636
19065
|
}
|
|
@@ -18690,19 +19119,19 @@ function requireOneNativeFile(directory, candidates, platform) {
|
|
|
18690
19119
|
return present[0] ?? "";
|
|
18691
19120
|
}
|
|
18692
19121
|
function isNativeFile(directory, relative14) {
|
|
18693
|
-
const file =
|
|
18694
|
-
const within =
|
|
18695
|
-
if (within === "" || within.startsWith("..") ||
|
|
19122
|
+
const file = path11.resolve(directory, relative14);
|
|
19123
|
+
const within = path11.relative(directory, file);
|
|
19124
|
+
if (within === "" || within.startsWith("..") || path11.isAbsolute(within)) {
|
|
18696
19125
|
return false;
|
|
18697
19126
|
}
|
|
18698
19127
|
let current = directory;
|
|
18699
|
-
for (const segment of within.split(
|
|
18700
|
-
current =
|
|
18701
|
-
if (!
|
|
19128
|
+
for (const segment of within.split(path11.sep)) {
|
|
19129
|
+
current = path11.join(current, segment);
|
|
19130
|
+
if (!existsSync24(current) || lstatSync14(current).isSymbolicLink()) {
|
|
18702
19131
|
return false;
|
|
18703
19132
|
}
|
|
18704
19133
|
}
|
|
18705
|
-
return
|
|
19134
|
+
return lstatSync14(file).isFile();
|
|
18706
19135
|
}
|
|
18707
19136
|
var androidAdvertisingRendererService = "dev.mpgd.capacitor.AdvertisingMessagingService";
|
|
18708
19137
|
var androidMessagingPluginService = "io.capawesome.capacitorjs.plugins.firebase.messaging.MessagingService";
|
|
@@ -18747,7 +19176,7 @@ function assertNativeReleaseIdentity(input) {
|
|
|
18747
19176
|
const candidates = [
|
|
18748
19177
|
join14(input.shellApp, "android/app/build.gradle"),
|
|
18749
19178
|
join14(input.shellApp, "android/app/build.gradle.kts")
|
|
18750
|
-
].filter((file) =>
|
|
19179
|
+
].filter((file) => existsSync25(file));
|
|
18751
19180
|
if (candidates.length !== 1) {
|
|
18752
19181
|
throw new Error("Android native release requires exactly one Gradle app build file.");
|
|
18753
19182
|
}
|
|
@@ -18778,12 +19207,12 @@ function stampNativeReleaseVersions(input) {
|
|
|
18778
19207
|
const candidates = [
|
|
18779
19208
|
join14(input.stagedShellApp, "android/app/build.gradle"),
|
|
18780
19209
|
join14(input.stagedShellApp, "android/app/build.gradle.kts")
|
|
18781
|
-
].filter((file3) =>
|
|
19210
|
+
].filter((file3) => existsSync25(file3));
|
|
18782
19211
|
if (candidates.length !== 1) {
|
|
18783
19212
|
throw new Error("Android native release requires exactly one Gradle app build file.");
|
|
18784
19213
|
}
|
|
18785
19214
|
const file2 = candidates[0] ?? "";
|
|
18786
|
-
|
|
19215
|
+
writeFileSync17(file2, stampAndroidGradleVersions(readFileSync25(file2, "utf8"), {
|
|
18787
19216
|
versionCode,
|
|
18788
19217
|
versionName
|
|
18789
19218
|
}, file2));
|
|
@@ -18792,7 +19221,7 @@ function stampNativeReleaseVersions(input) {
|
|
|
18792
19221
|
const marketingVersion = requireFinalSemVer2(optional(input.environment.MPGD_TARGET_MARKETING_VERSION), "MPGD_TARGET_MARKETING_VERSION");
|
|
18793
19222
|
const buildNumber = requirePositiveInteger2(optional(input.environment.MPGD_TARGET_BUILD_NUMBER), "MPGD_TARGET_BUILD_NUMBER");
|
|
18794
19223
|
const file = join14(input.stagedShellApp, "ios/App/App.xcodeproj/project.pbxproj");
|
|
18795
|
-
|
|
19224
|
+
writeFileSync17(file, stampIosProjectVersions(readRequiredFile(file, "iOS Xcode project configuration"), { marketingVersion, buildNumber }, file));
|
|
18796
19225
|
}
|
|
18797
19226
|
function stampAndroidGradleVersions(source, versions, file) {
|
|
18798
19227
|
const end = "(?=\\s*(?:;|\\r?\\n|\\}|$))";
|
|
@@ -19054,7 +19483,7 @@ function assertAndroidAppliedScripts(appBuild, androidRoot) {
|
|
|
19054
19483
|
throw new Error("Native release preflight cannot resolve an applied Gradle script.");
|
|
19055
19484
|
}
|
|
19056
19485
|
};
|
|
19057
|
-
const rootFiles = ["build.gradle", "build.gradle.kts"].map((name) => join14(androidRoot, name)).filter((file) =>
|
|
19486
|
+
const rootFiles = ["build.gradle", "build.gradle.kts"].map((name) => join14(androidRoot, name)).filter((file) => existsSync25(file));
|
|
19058
19487
|
if (rootFiles.length !== 1) {
|
|
19059
19488
|
throw new Error("Native release preflight requires one Android root Gradle build file.");
|
|
19060
19489
|
}
|
|
@@ -19064,7 +19493,7 @@ function assertAndroidAppliedScripts(appBuild, androidRoot) {
|
|
|
19064
19493
|
if (/\b(?:afterEvaluate|projectsEvaluated)\b/u.test(rootCode) && /\b(?:project|subprojects|allprojects|android)\b/u.test(rootCode)) {
|
|
19065
19494
|
throw new Error("Native release preflight cannot resolve root Gradle app callbacks.");
|
|
19066
19495
|
}
|
|
19067
|
-
const settingsFiles = ["settings.gradle", "settings.gradle.kts"].map((name) => join14(androidRoot, name)).filter((file) =>
|
|
19496
|
+
const settingsFiles = ["settings.gradle", "settings.gradle.kts"].map((name) => join14(androidRoot, name)).filter((file) => existsSync25(file));
|
|
19068
19497
|
if (settingsFiles.length !== 1) {
|
|
19069
19498
|
throw new Error("Native release preflight requires one Android settings Gradle file.");
|
|
19070
19499
|
}
|
|
@@ -19400,10 +19829,10 @@ function stripOptionalQuotes(value) {
|
|
|
19400
19829
|
return value;
|
|
19401
19830
|
}
|
|
19402
19831
|
function readRequiredFile(file, label) {
|
|
19403
|
-
if (!
|
|
19832
|
+
if (!existsSync25(file)) {
|
|
19404
19833
|
throw new Error(`Missing ${label}: ${file}`);
|
|
19405
19834
|
}
|
|
19406
|
-
return
|
|
19835
|
+
return readFileSync25(file, "utf8");
|
|
19407
19836
|
}
|
|
19408
19837
|
function requireFinalSemVer2(value, label) {
|
|
19409
19838
|
const normalized = requireValue(value, label);
|
|
@@ -19514,7 +19943,7 @@ function androidSignedReleaseGradleArgs(environment) {
|
|
|
19514
19943
|
if (initScript === void 0 || initScript === "") {
|
|
19515
19944
|
return ["bundleRelease", "--no-daemon"];
|
|
19516
19945
|
}
|
|
19517
|
-
if (!isAbsolute12(initScript) || !
|
|
19946
|
+
if (!isAbsolute12(initScript) || !existsSync26(initScript) || !statSync6(initScript).isFile()) {
|
|
19518
19947
|
throw new Error("Android upload signing init script must be an existing absolute file.");
|
|
19519
19948
|
}
|
|
19520
19949
|
return ["bundleRelease", "--no-daemon", "--init-script", initScript];
|
|
@@ -19624,13 +20053,16 @@ function executeIosBuildWithEnvironment(input, stagedShell, environment) {
|
|
|
19624
20053
|
"-exportOptionsPlist",
|
|
19625
20054
|
requireString(signing.exportOptionsPlist, "iOS export options plist")
|
|
19626
20055
|
], environment, `${stagedShell}/ios`);
|
|
19627
|
-
const exportedIpas =
|
|
20056
|
+
const exportedIpas = readdirSync8(exportRoot).filter((name) => name.endsWith(".ipa"));
|
|
19628
20057
|
if (exportedIpas.length !== 1) {
|
|
19629
20058
|
throw new Error("iOS store export must produce exactly one IPA.");
|
|
19630
20059
|
}
|
|
19631
20060
|
releaseArtifact = `${artifactRoot}/App.ipa`;
|
|
19632
20061
|
input.copyFile(join15(exportRoot, exportedIpas[0] ?? ""), input.targetPath(releaseArtifact));
|
|
19633
|
-
inspectSignedIosIpa(input.targetPath(releaseArtifact),
|
|
20062
|
+
inspectSignedIosIpa(input.targetPath(releaseArtifact), {
|
|
20063
|
+
...expectedIosIdentity,
|
|
20064
|
+
...shellInstallsFirebaseMessaging(stagedShell) ? { expectedApsEnvironment: "production" } : {}
|
|
20065
|
+
});
|
|
19634
20066
|
} finally {
|
|
19635
20067
|
rmSync11(exportRoot, { recursive: true, force: true });
|
|
19636
20068
|
}
|
|
@@ -19742,7 +20174,7 @@ var releaseManifestEnvKeys = [
|
|
|
19742
20174
|
var platformTargets = loadPlatformTargetsConfig();
|
|
19743
20175
|
var configBaseDir = platformTargets.baseDir;
|
|
19744
20176
|
var kitLinkCheck = resolve18("tools/workspace/relink-kit-workspace.mjs");
|
|
19745
|
-
if (
|
|
20177
|
+
if (existsSync27(kitLinkCheck)) {
|
|
19746
20178
|
spawnSync5(process.execPath, [kitLinkCheck, "--warn-unless-owner", configBaseDir], {
|
|
19747
20179
|
stdio: "inherit"
|
|
19748
20180
|
});
|
|
@@ -20072,7 +20504,7 @@ try {
|
|
|
20072
20504
|
function createRuntimeTargetConfigMatrixFile(matrix) {
|
|
20073
20505
|
const directory = mkdtempSync5(join16(tmpdir5(), "mpgd-target-config-matrix-"));
|
|
20074
20506
|
const file = join16(directory, "matrix.json");
|
|
20075
|
-
|
|
20507
|
+
writeFileSync18(file, `${JSON.stringify(matrix)}
|
|
20076
20508
|
`);
|
|
20077
20509
|
return file;
|
|
20078
20510
|
}
|
|
@@ -20092,7 +20524,7 @@ function replaceDirectory(source, destination) {
|
|
|
20092
20524
|
function mirrorAitRuntimeAssets(gameApp2, wrapperApp) {
|
|
20093
20525
|
const sourceAssets = `${gameApp2}/dist/assets`;
|
|
20094
20526
|
const destinationAssets = `${wrapperApp}/public/assets`;
|
|
20095
|
-
if (
|
|
20527
|
+
if (existsSync27(sourceAssets)) {
|
|
20096
20528
|
replaceDirectory(sourceAssets, destinationAssets);
|
|
20097
20529
|
} else {
|
|
20098
20530
|
rmSync12(destinationAssets, { recursive: true, force: true });
|
|
@@ -20103,7 +20535,7 @@ async function stageTargetAssetPacks(webOutput) {
|
|
|
20103
20535
|
return;
|
|
20104
20536
|
}
|
|
20105
20537
|
const destination = join16(webOutput, assetPackTargetNamespace);
|
|
20106
|
-
if (
|
|
20538
|
+
if (existsSync27(destination)) {
|
|
20107
20539
|
throw new Error("mpgd-asset-packs is owned by the target policy; remove source/public copies from the game");
|
|
20108
20540
|
}
|
|
20109
20541
|
cpSync4(assetTargetReport.packagedDir, destination, {
|
|
@@ -20126,7 +20558,7 @@ async function writeRemoteAssetPacks() {
|
|
|
20126
20558
|
});
|
|
20127
20559
|
replaceDirectory(assetTargetReport.remoteDir, `${remoteOutput}/remote`);
|
|
20128
20560
|
mkdirSync13(remoteOutput, { recursive: true });
|
|
20129
|
-
|
|
20561
|
+
writeFileSync18(`${remoteOutput}/report.json`, JSON.stringify({
|
|
20130
20562
|
...assetTargetReport,
|
|
20131
20563
|
outDir: remoteOutput,
|
|
20132
20564
|
packagedDir: assetPackTargetNamespace,
|
|
@@ -20209,14 +20641,14 @@ function copyIosSyncSwiftPackage(shellApp, releaseArtifact, packageName, swiftPa
|
|
|
20209
20641
|
}
|
|
20210
20642
|
function rewriteIosSyncSwiftPackagePath(releaseArtifact, packageName, swiftPackageName) {
|
|
20211
20643
|
const packageFile = targetPath(`${releaseArtifact}/App/CapApp-SPM/Package.swift`);
|
|
20212
|
-
const contents =
|
|
20644
|
+
const contents = readFileSync26(packageFile, "utf8");
|
|
20213
20645
|
const originalPath = readSwiftPackagePath(packageFile, swiftPackageName);
|
|
20214
20646
|
const rewrittenPath = `../../node_modules/${packageName}`;
|
|
20215
20647
|
const marker = `.package(name: "${swiftPackageName}", path: "`;
|
|
20216
|
-
|
|
20648
|
+
writeFileSync18(packageFile, contents.replace(`${marker}${originalPath}"`, `${marker}${rewrittenPath}"`));
|
|
20217
20649
|
}
|
|
20218
20650
|
function readSwiftPackagePath(packageFile, swiftPackageName) {
|
|
20219
|
-
const contents =
|
|
20651
|
+
const contents = readFileSync26(packageFile, "utf8");
|
|
20220
20652
|
const marker = `.package(name: "${swiftPackageName}", path: "`;
|
|
20221
20653
|
const index = contents.indexOf(marker);
|
|
20222
20654
|
if (index < 0 || contents.indexOf(marker, index + marker.length) >= 0) {
|
|
@@ -20234,10 +20666,10 @@ function copyFile2(source, destination) {
|
|
|
20234
20666
|
cpSync4(source, destination);
|
|
20235
20667
|
}
|
|
20236
20668
|
function removeFilesByExtension(directory, extension) {
|
|
20237
|
-
if (!
|
|
20669
|
+
if (!existsSync27(directory)) {
|
|
20238
20670
|
return;
|
|
20239
20671
|
}
|
|
20240
|
-
for (const file of
|
|
20672
|
+
for (const file of readdirSync9(directory)) {
|
|
20241
20673
|
const target2 = `${directory}/${file}`;
|
|
20242
20674
|
if (file.endsWith(extension) && statSync7(target2).isFile()) {
|
|
20243
20675
|
rmSync12(target2, { force: true });
|
|
@@ -20249,7 +20681,7 @@ function safeArtifactFileStem(value) {
|
|
|
20249
20681
|
return stem.length === 0 ? "mpgd-kit" : stem;
|
|
20250
20682
|
}
|
|
20251
20683
|
function ensureCapacitorPlatform(shellApp, platform, commandEnv) {
|
|
20252
|
-
if (!
|
|
20684
|
+
if (!existsSync27(`${shellApp}/${platform}`)) {
|
|
20253
20685
|
run("pnpm", ["--dir", shellApp, "cap", "add", platform], commandEnv);
|
|
20254
20686
|
}
|
|
20255
20687
|
}
|
|
@@ -20273,7 +20705,7 @@ function writeManifest(target2, releaseProfile, artifact, commandEnv) {
|
|
|
20273
20705
|
function findEmbeddedIconManifestArtifactPath(artifact) {
|
|
20274
20706
|
const artifactPath = targetPath(artifact);
|
|
20275
20707
|
const fileName = "mpgd-icon-manifest.json";
|
|
20276
|
-
const matches = statSync7(artifactPath).isDirectory() ? findNamedArtifactFiles(artifactPath, fileName).map((
|
|
20708
|
+
const matches = statSync7(artifactPath).isDirectory() ? findNamedArtifactFiles(artifactPath, fileName).map((path12) => relative13(artifactPath, path12).replaceAll("\\", "/")) : listZipEntries(artifactPath).filter((entry) => basename5(entry) === fileName);
|
|
20277
20709
|
if (matches.length !== 1) {
|
|
20278
20710
|
throw new Error(`Expected exactly one ${fileName} in release artifact ${artifactPath}; found ${matches.length}.`);
|
|
20279
20711
|
}
|
|
@@ -20285,22 +20717,22 @@ function findEmbeddedIconManifestArtifactPath(artifact) {
|
|
|
20285
20717
|
}
|
|
20286
20718
|
function findNamedArtifactFiles(root, fileName) {
|
|
20287
20719
|
const matches = [];
|
|
20288
|
-
for (const entry of
|
|
20289
|
-
const
|
|
20290
|
-
const stat2 =
|
|
20720
|
+
for (const entry of readdirSync9(root)) {
|
|
20721
|
+
const path12 = join16(root, entry);
|
|
20722
|
+
const stat2 = lstatSync15(path12);
|
|
20291
20723
|
if (stat2.isSymbolicLink()) {
|
|
20292
20724
|
continue;
|
|
20293
20725
|
}
|
|
20294
20726
|
if (stat2.isDirectory()) {
|
|
20295
|
-
matches.push(...findNamedArtifactFiles(
|
|
20727
|
+
matches.push(...findNamedArtifactFiles(path12, fileName));
|
|
20296
20728
|
} else if (stat2.isFile() && entry === fileName) {
|
|
20297
|
-
matches.push(
|
|
20729
|
+
matches.push(path12);
|
|
20298
20730
|
}
|
|
20299
20731
|
}
|
|
20300
20732
|
return matches;
|
|
20301
20733
|
}
|
|
20302
|
-
function listZipEntries(
|
|
20303
|
-
const result = spawnSync5("unzip", ["-Z1",
|
|
20734
|
+
function listZipEntries(path12) {
|
|
20735
|
+
const result = spawnSync5("unzip", ["-Z1", path12], {
|
|
20304
20736
|
cwd: process.cwd(),
|
|
20305
20737
|
env: nativeInspectionEnvironment(),
|
|
20306
20738
|
encoding: "utf8"
|
|
@@ -20310,7 +20742,7 @@ function listZipEntries(path10) {
|
|
|
20310
20742
|
}
|
|
20311
20743
|
const toleratedPrefixWarning = result.status === 1 && result.stdout.trim().length > 0 && result.stderr.includes("extra bytes at beginning or within zipfile") && result.stderr.includes("(attempting to process anyway)");
|
|
20312
20744
|
if (result.status !== 0 && !toleratedPrefixWarning) {
|
|
20313
|
-
throw new Error(`Failed to list release artifact ${
|
|
20745
|
+
throw new Error(`Failed to list release artifact ${path12}: ${result.stderr.trim() || `exit ${String(result.status)}`}`);
|
|
20314
20746
|
}
|
|
20315
20747
|
return result.stdout.split("\n").filter((entry) => entry.length > 0);
|
|
20316
20748
|
}
|
|
@@ -20337,7 +20769,7 @@ function isMiniGameTarget(target2) {
|
|
|
20337
20769
|
}
|
|
20338
20770
|
function buildMiniGameBundle(bundleKind, outputDir, stagingRoot, gameApp2, profile2, commandEnv) {
|
|
20339
20771
|
const viteConfig = join16(gameApp2, "vite.minigame.config.ts");
|
|
20340
|
-
if (!
|
|
20772
|
+
if (!existsSync27(viteConfig)) {
|
|
20341
20773
|
throw new Error(`Mini-game target requires a game-owned vite.minigame.config.ts: ${viteConfig}`);
|
|
20342
20774
|
}
|
|
20343
20775
|
run("pnpm", ["exec", "vite", "build", "--config", "vite.minigame.config.ts", "--mode", profile2], {
|
|
@@ -20369,11 +20801,11 @@ function withProcessEnv(env2, keys, callback) {
|
|
|
20369
20801
|
}
|
|
20370
20802
|
}
|
|
20371
20803
|
}
|
|
20372
|
-
function targetPath(
|
|
20373
|
-
return resolveFromPlatformTargetsBase(configBaseDir,
|
|
20804
|
+
function targetPath(path12) {
|
|
20805
|
+
return resolveFromPlatformTargetsBase(configBaseDir, path12);
|
|
20374
20806
|
}
|
|
20375
20807
|
function findFileByExtension(directory, extension) {
|
|
20376
|
-
const files =
|
|
20808
|
+
const files = readdirSync9(directory).filter((file) => file.endsWith(extension)).sort();
|
|
20377
20809
|
if (files.length === 0) {
|
|
20378
20810
|
throw new Error(`Missing ${extension} artifact in ${directory}.`);
|
|
20379
20811
|
}
|