lecodes-cli 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +126 -57
- package/package.json +3 -3
- package/runtime/sdk-types.json +1 -1
package/dist/index.js
CHANGED
|
@@ -45212,7 +45212,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
45212
45212
|
// package.json
|
|
45213
45213
|
var package_default = {
|
|
45214
45214
|
name: "lecodes-cli",
|
|
45215
|
-
version: "0.
|
|
45215
|
+
version: "0.16.0",
|
|
45216
45216
|
dependencies: {
|
|
45217
45217
|
"@letary/chisel": "^0.6.0",
|
|
45218
45218
|
jimp: "^1.6.1"
|
|
@@ -45226,8 +45226,8 @@ var package_default = {
|
|
|
45226
45226
|
},
|
|
45227
45227
|
peerDependencies: {
|
|
45228
45228
|
"lecodes-design": "^0.8.0",
|
|
45229
|
-
"lecodes-renderer": "^0.8.
|
|
45230
|
-
"lecodes-3d-editor": "^0.
|
|
45229
|
+
"lecodes-renderer": "^0.8.3",
|
|
45230
|
+
"lecodes-3d-editor": "^0.3.0"
|
|
45231
45231
|
},
|
|
45232
45232
|
bin: {
|
|
45233
45233
|
lecodes: "dist/index.js"
|
|
@@ -46324,6 +46324,23 @@ NEXT launch. Offline it's a silent no-op — the app always launches from a loca
|
|
|
46324
46324
|
An App Store update always beats a cached OTA bundle. JS only: adding/removing native
|
|
46325
46325
|
plugins still needs a store release.
|
|
46326
46326
|
|
|
46327
|
+
Shipping an update is just \`lecodes push --publish\` — no rebuild, no store review:
|
|
46328
|
+
running apps download the new code on their next launch and run it on the launch after.
|
|
46329
|
+
|
|
46330
|
+
Shells generated before OTA support have a \`ViewController.swift\` that reads app.js from
|
|
46331
|
+
\`Bundle.main\` directly, so downloaded updates would never run — and since \`App/*.swift\`
|
|
46332
|
+
is yours, sync won't rewrite it (\`lecodes app doctor\` flags this). Replace the
|
|
46333
|
+
\`Bundle.main\` load with:
|
|
46334
|
+
|
|
46335
|
+
\`\`\`swift
|
|
46336
|
+
LeCodesUpdater.checkForUpdate()
|
|
46337
|
+
guard let code = LeCodesUpdater.activeBundle() else {
|
|
46338
|
+
print("LeCodes: bundled app.js is missing — run \`lecodes app sync\`")
|
|
46339
|
+
return
|
|
46340
|
+
}
|
|
46341
|
+
engine.run(code)
|
|
46342
|
+
\`\`\`
|
|
46343
|
+
|
|
46327
46344
|
## Config
|
|
46328
46345
|
|
|
46329
46346
|
Identity lives in \`../app.json\` (name, version, plugins, ios.bundleId / teamId / variant /
|
|
@@ -46401,6 +46418,34 @@ var ensureShellIgnored = (root, dir) => {
|
|
|
46401
46418
|
`);
|
|
46402
46419
|
log(`${c.green("updated")} .lecodesignore (+ ${dir}/)`);
|
|
46403
46420
|
};
|
|
46421
|
+
var SDK_VARIANTS = ["core", "2d", "3d", "full"];
|
|
46422
|
+
var detectEngines = (bundleJs) => {
|
|
46423
|
+
const lines = [];
|
|
46424
|
+
for (const line of bundleJs.split(`
|
|
46425
|
+
`)) {
|
|
46426
|
+
if (!line.startsWith("//"))
|
|
46427
|
+
break;
|
|
46428
|
+
lines.push(line);
|
|
46429
|
+
}
|
|
46430
|
+
const header = lines.join(`
|
|
46431
|
+
`);
|
|
46432
|
+
return { gl: !/^\/\/ gl: disable$/m.test(header), g2: /^\/\/ 2d: enable$/m.test(header) };
|
|
46433
|
+
};
|
|
46434
|
+
var resolveVariant = (requested, bundleJs, configKey = "ios.variant") => {
|
|
46435
|
+
const uses = detectEngines(bundleJs);
|
|
46436
|
+
const detected = uses.gl && uses.g2 ? "full" : uses.gl ? "3d" : uses.g2 ? "2d" : "core";
|
|
46437
|
+
if (requested === "auto")
|
|
46438
|
+
return { variant: detected, detected };
|
|
46439
|
+
const variant = requested;
|
|
46440
|
+
const missing = [
|
|
46441
|
+
uses.gl && variant !== "3d" && variant !== "full" ? "3D" : null,
|
|
46442
|
+
uses.g2 && variant !== "2d" && variant !== "full" ? "2D" : null
|
|
46443
|
+
].filter(Boolean);
|
|
46444
|
+
if (missing.length > 0) {
|
|
46445
|
+
warn(`project uses the ${missing.join(" + ")} engine but ${configKey} forces "${variant}" — those scenes won't run on device; remove ${configKey} to auto-select "${detected}".`);
|
|
46446
|
+
}
|
|
46447
|
+
return { variant, detected };
|
|
46448
|
+
};
|
|
46404
46449
|
var VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
46405
46450
|
var cmpVersion = (a, b) => {
|
|
46406
46451
|
const pa = a.split(".").map(Number);
|
|
@@ -46748,7 +46793,7 @@ validateDistributionUrl=true
|
|
|
46748
46793
|
zipStoreBase=GRADLE_USER_HOME
|
|
46749
46794
|
zipStorePath=wrapper/dists
|
|
46750
46795
|
`;
|
|
46751
|
-
var runtimeBuildGradleTemplate = (sdkVersion, pluginModules) => {
|
|
46796
|
+
var runtimeBuildGradleTemplate = (sdkVersion, pluginModules, sdkArtifact = "lecodes-sdk") => {
|
|
46752
46797
|
const deps = SDK_RUNTIME_DEPS.map((d) => `
|
|
46753
46798
|
api("${d}")`).join("");
|
|
46754
46799
|
const plugins = pluginModules.map((m) => `
|
|
@@ -46780,8 +46825,10 @@ kotlin {
|
|
|
46780
46825
|
}
|
|
46781
46826
|
|
|
46782
46827
|
dependencies {
|
|
46783
|
-
// Exact pin — the release asset URL is derived from this version (see
|
|
46784
|
-
|
|
46828
|
+
// Exact pin — the release asset URL is derived from this artifact + version (see
|
|
46829
|
+
// settings.gradle.kts). The artifact is the SDK variant sync picked (lecodes-sdk = full,
|
|
46830
|
+
// -3d / -2d / -core = smaller engine builds); every variant vends the same Kotlin API.
|
|
46831
|
+
api("io.letary:${sdkArtifact}:${sdkVersion}@aar")
|
|
46785
46832
|
// The fat AAR carries no POM, so its own dependencies ride here explicitly.${deps}${plugins}
|
|
46786
46833
|
}
|
|
46787
46834
|
`;
|
|
@@ -46831,7 +46878,7 @@ ${push ? ` ${pushNs}.PushPlugin.setForeground(foreground)
|
|
|
46831
46878
|
}
|
|
46832
46879
|
`;
|
|
46833
46880
|
};
|
|
46834
|
-
var pluginBuildGradleTemplate = (id, module, namespace, sdkVersion, dependencies, aarNames, hasConsumerRules) => {
|
|
46881
|
+
var pluginBuildGradleTemplate = (id, module, namespace, sdkVersion, dependencies, aarNames, hasConsumerRules, sdkArtifact = "lecodes-sdk") => {
|
|
46835
46882
|
const consumer = hasConsumerRules ? `
|
|
46836
46883
|
consumerProguardFiles("consumer-rules.pro")` : "";
|
|
46837
46884
|
const aars = aarNames.map((n2) => `
|
|
@@ -46866,7 +46913,9 @@ kotlin {
|
|
|
46866
46913
|
}
|
|
46867
46914
|
|
|
46868
46915
|
dependencies {
|
|
46869
|
-
|
|
46916
|
+
// Same artifact (SDK variant) as lecodes-runtime — two different variant coordinates in one
|
|
46917
|
+
// shell would put two copies of the SDK classes on the runtime classpath.
|
|
46918
|
+
implementation("io.letary:${sdkArtifact}:${sdkVersion}@aar")${sdkDeps}${aars}${manifestDeps}
|
|
46870
46919
|
}
|
|
46871
46920
|
`;
|
|
46872
46921
|
};
|
|
@@ -46898,6 +46947,14 @@ in \`settings.gradle.kts\`. \`lecodes app update\` moves the pin (or set \`app.j
|
|
|
46898
46947
|
\`android.sdk\`). The SDK AAR ships no POM, so its own dependencies are declared explicitly in
|
|
46899
46948
|
the generated runtime build file.
|
|
46900
46949
|
|
|
46950
|
+
## SDK variant
|
|
46951
|
+
|
|
46952
|
+
Sync links the smallest SDK artifact covering the engines the compiled bundle actually uses —
|
|
46953
|
+
\`lecodes-sdk\` (full: 3D+2D), \`lecodes-sdk-3d\`, \`lecodes-sdk-2d\` or \`lecodes-sdk-core\`
|
|
46954
|
+
(UI only) — so an app without 3D scenes doesn't ship Filament. If the project starts using an
|
|
46955
|
+
engine, sync switches automatically on the next run; set \`android.variant\` in \`../app.json\`
|
|
46956
|
+
to force one (needs lecodes-android-sdk >= 1.3.0; older releases ship only the full AAR).
|
|
46957
|
+
|
|
46901
46958
|
## App-local native code
|
|
46902
46959
|
|
|
46903
46960
|
Drop Kotlin files into \`app/src/main/java/\` and register them in \`MainActivity\` after the
|
|
@@ -47561,6 +47618,8 @@ if "%OS%"=="Windows_NT" endlocal
|
|
|
47561
47618
|
// src/commands/appAndroid.ts
|
|
47562
47619
|
var ANDROID_SDK_REPO = "letary/lecodes-android-sdk";
|
|
47563
47620
|
var ANDROID_SDK_MIN_VERSION = "1.2.0";
|
|
47621
|
+
var ANDROID_SDK_VARIANTS_MIN = "1.3.0";
|
|
47622
|
+
var variantArtifact = (variant) => variant === "full" ? "lecodes-sdk" : `lecodes-sdk-${variant}`;
|
|
47564
47623
|
var ANDROID_SDK_URL_DEFAULT = `https://github.com/${ANDROID_SDK_REPO}/releases/download`;
|
|
47565
47624
|
var sdkRepoUrl = () => process.env.LECODES_ANDROID_SDK_URL ?? ANDROID_SDK_URL_DEFAULT;
|
|
47566
47625
|
var ANDROID_SDK_OPTS = { repo: ANDROID_SDK_REPO, minVersion: ANDROID_SDK_MIN_VERSION, configKey: "android.sdk" };
|
|
@@ -47568,7 +47627,7 @@ var shellSdkVersionAndroid = (androidDir) => {
|
|
|
47568
47627
|
const path2 = join14(androidDir, "lecodes-runtime", "build.gradle.kts");
|
|
47569
47628
|
if (!existsSync13(path2))
|
|
47570
47629
|
return null;
|
|
47571
|
-
const m = /io\.letary:lecodes-sdk
|
|
47630
|
+
const m = /io\.letary:lecodes-sdk(?:-(?:core|2d|3d))?:(\d+\.\d+\.\d+)@aar/.exec(readFileSync13(path2, "utf8"));
|
|
47572
47631
|
return m ? m[1] : null;
|
|
47573
47632
|
};
|
|
47574
47633
|
var GRADLE_WRAPPER_JAR_URL = "https://raw.githubusercontent.com/gradle/gradle/v8.13.0/gradle/wrapper/gradle-wrapper.jar";
|
|
@@ -47601,6 +47660,10 @@ var initAndroid = async (args) => {
|
|
|
47601
47660
|
throw new CliError("android/ already exists — run `lecodes app sync` to update it.");
|
|
47602
47661
|
}
|
|
47603
47662
|
const existing = readJson(join14(root, "app.json")) ?? {};
|
|
47663
|
+
const variant = flagStr(args, "variant") ?? existing.android?.variant ?? "auto";
|
|
47664
|
+
if (variant !== "auto" && !SDK_VARIANTS.includes(variant)) {
|
|
47665
|
+
throw new CliError(`--variant must be auto, ${SDK_VARIANTS.join(", ")} (got "${variant}")`);
|
|
47666
|
+
}
|
|
47604
47667
|
const sdkFlag = flagStr(args, "sdk") ?? existing.android?.sdk;
|
|
47605
47668
|
const sdkVersion = await resolveSdkVersion(process.env.LECODES_ANDROID_SDK ?? sdkFlag ?? "latest", null, ANDROID_SDK_OPTS);
|
|
47606
47669
|
const sdk = sdkFlag === "latest" ? "latest" : sdkVersion;
|
|
@@ -47615,6 +47678,7 @@ var initAndroid = async (args) => {
|
|
|
47615
47678
|
applicationId: flagStr(args, "app-id") ?? existing.android?.applicationId ?? defaultAppId,
|
|
47616
47679
|
versionCode: existing.android?.versionCode ?? 1,
|
|
47617
47680
|
sdk,
|
|
47681
|
+
variant,
|
|
47618
47682
|
...existing.android?.signing ? { signing: existing.android.signing } : {}
|
|
47619
47683
|
}
|
|
47620
47684
|
};
|
|
@@ -47656,7 +47720,9 @@ var initAndroid = async (args) => {
|
|
|
47656
47720
|
write("app/src/main/res/values/colors.xml", COLORS_XML);
|
|
47657
47721
|
write("app/src/main/res/values/strings.xml", stringsXmlTemplate(name));
|
|
47658
47722
|
write("app/src/main/res/drawable/ic_launcher.xml", IC_LAUNCHER_XML);
|
|
47659
|
-
|
|
47723
|
+
const initVariant = variant === "auto" ? "core" : variant;
|
|
47724
|
+
const initArtifact = cmpVersion(sdkVersion, ANDROID_SDK_VARIANTS_MIN) >= 0 ? variantArtifact(initVariant) : "lecodes-sdk";
|
|
47725
|
+
write("lecodes-runtime/build.gradle.kts", runtimeBuildGradleTemplate(sdkVersion, [], initArtifact));
|
|
47660
47726
|
write("lecodes-runtime/src/main/kotlin/io/letary/lecodes/runtime/LeCodesRuntime.kt", runtimeKotlinTemplate([]));
|
|
47661
47727
|
log("");
|
|
47662
47728
|
log(`${c.green("sdk")} lecodes-android-sdk ${sdkVersion}${sdk === "latest" ? c.dim(" (android.sdk: latest — re-resolved on every sync)") : c.dim(" (pinned in app.json android.sdk — `lecodes app update` moves it)")}`);
|
|
@@ -47681,6 +47747,40 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
47681
47747
|
const linkedSdk = shellSdkVersionAndroid(androidDir);
|
|
47682
47748
|
const sdkPin = process.env.LECODES_ANDROID_SDK ?? config.android?.sdk ?? linkedSdk ?? "latest";
|
|
47683
47749
|
const sdkVersion = await resolveSdkVersion(sdkPin, linkedSdk, ANDROID_SDK_OPTS);
|
|
47750
|
+
const remotePatterns = config.resources?.remote ?? [];
|
|
47751
|
+
if (!Array.isArray(remotePatterns) || remotePatterns.some((p2) => typeof p2 !== "string")) {
|
|
47752
|
+
throw new CliError('app.json "resources.remote" must be an array of glob strings (e.g. ["videos/**"]).');
|
|
47753
|
+
}
|
|
47754
|
+
const assetsDir = join14(androidDir, "app", "src", "main", "assets");
|
|
47755
|
+
rmrf(assetsDir);
|
|
47756
|
+
mkdirSync8(assetsDir, { recursive: true });
|
|
47757
|
+
let bundleJs;
|
|
47758
|
+
let resources;
|
|
47759
|
+
if (prior) {
|
|
47760
|
+
writeFileSync10(join14(assetsDir, "app.js"), prior.bundleJs);
|
|
47761
|
+
bundleJs = prior.bundleJs;
|
|
47762
|
+
resources = prior.resources;
|
|
47763
|
+
} else {
|
|
47764
|
+
resources = await compileShell({ _: [], flags: { o: join14(assetsDir, "app.js") } }, { remotePatterns });
|
|
47765
|
+
bundleJs = readFileSync13(join14(assetsDir, "app.js"), "utf8");
|
|
47766
|
+
}
|
|
47767
|
+
const requestedVariant = config.android?.variant ?? "auto";
|
|
47768
|
+
if (requestedVariant !== "auto" && !SDK_VARIANTS.includes(requestedVariant)) {
|
|
47769
|
+
throw new CliError(`app.json android.variant must be "auto" or one of ${SDK_VARIANTS.join(", ")} (got "${requestedVariant}").`);
|
|
47770
|
+
}
|
|
47771
|
+
const { variant, detected } = resolveVariant(requestedVariant, bundleJs, "android.variant");
|
|
47772
|
+
let sdkArtifact = variantArtifact(variant);
|
|
47773
|
+
if (sdkArtifact !== "lecodes-sdk" && cmpVersion(sdkVersion, ANDROID_SDK_VARIANTS_MIN) < 0) {
|
|
47774
|
+
warn(`lecodes-android-sdk ${sdkVersion} predates the variant matrix (${ANDROID_SDK_VARIANTS_MIN}) — linking the full lecodes-sdk AAR; run \`lecodes app update\` to pick up variant builds.`);
|
|
47775
|
+
sdkArtifact = "lecodes-sdk";
|
|
47776
|
+
}
|
|
47777
|
+
const WHY = {
|
|
47778
|
+
full: "3D + 2D engines in use",
|
|
47779
|
+
"3d": "3D in use, no 2D",
|
|
47780
|
+
"2d": "2D in use, no 3D",
|
|
47781
|
+
core: "no 3D/2D engine use detected"
|
|
47782
|
+
};
|
|
47783
|
+
log(`${c.green("variant")} ${variant} → ${sdkArtifact}${requestedVariant === "auto" ? c.dim(` (auto: ${WHY[detected]})`) : c.dim(" (forced by android.variant)")}`);
|
|
47684
47784
|
const lockPath = join14(root, "plugins.lock.json");
|
|
47685
47785
|
const oldLock = readJson(lockPath)?.plugins ?? {};
|
|
47686
47786
|
const pluginSpecs = Object.entries(config.plugins ?? {});
|
|
@@ -47721,7 +47821,7 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
47721
47821
|
aarWrapperPaths.push(`:plugins:${module}:libs:${base}`);
|
|
47722
47822
|
}
|
|
47723
47823
|
const hasConsumerRules = existsSync13(join14(dest, "consumer-rules.pro"));
|
|
47724
|
-
writeFileSync10(join14(dest, "build.gradle.kts"), pluginBuildGradleTemplate(id, module, namespace, sdkVersion, android.dependencies ?? [], aarNames, hasConsumerRules));
|
|
47824
|
+
writeFileSync10(join14(dest, "build.gradle.kts"), pluginBuildGradleTemplate(id, module, namespace, sdkVersion, android.dependencies ?? [], aarNames, hasConsumerRules, sdkArtifact));
|
|
47725
47825
|
runtimePlugins.push({ id, module, register });
|
|
47726
47826
|
newLock[id] = plugin.lock;
|
|
47727
47827
|
log(`${c.green("plugin")} ${id}@${plugin.lock.version} (${plugin.lock.tag} → plugins/${module})`);
|
|
@@ -47733,23 +47833,6 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
47733
47833
|
log(`${c.yellow("removed")} android/plugins/${entry} (plugin uninstalled)`);
|
|
47734
47834
|
}
|
|
47735
47835
|
}
|
|
47736
|
-
const remotePatterns = config.resources?.remote ?? [];
|
|
47737
|
-
if (!Array.isArray(remotePatterns) || remotePatterns.some((p2) => typeof p2 !== "string")) {
|
|
47738
|
-
throw new CliError('app.json "resources.remote" must be an array of glob strings (e.g. ["videos/**"]).');
|
|
47739
|
-
}
|
|
47740
|
-
const assetsDir = join14(androidDir, "app", "src", "main", "assets");
|
|
47741
|
-
rmrf(assetsDir);
|
|
47742
|
-
mkdirSync8(assetsDir, { recursive: true });
|
|
47743
|
-
let bundleJs;
|
|
47744
|
-
let resources;
|
|
47745
|
-
if (prior) {
|
|
47746
|
-
writeFileSync10(join14(assetsDir, "app.js"), prior.bundleJs);
|
|
47747
|
-
bundleJs = prior.bundleJs;
|
|
47748
|
-
resources = prior.resources;
|
|
47749
|
-
} else {
|
|
47750
|
-
resources = await compileShell({ _: [], flags: { o: join14(assetsDir, "app.js") } }, { remotePatterns });
|
|
47751
|
-
bundleJs = readFileSync13(join14(assetsDir, "app.js"), "utf8");
|
|
47752
|
-
}
|
|
47753
47836
|
const sdkWhy = sdkPin === "latest" ? "latest" : config.android?.sdk ? "pinned by android.sdk" : "from the shell — set android.sdk or run `lecodes app update`";
|
|
47754
47837
|
log(`${c.green("sdk")} lecodes-android-sdk ${sdkVersion}${c.dim(` (${sdkWhy})`)}`);
|
|
47755
47838
|
const preload = /^\/\/ preload: (.*)$/m.exec(bundleJs)?.[1].split(";").map((s2) => s2.trim()).filter(Boolean) ?? [];
|
|
@@ -47792,7 +47875,7 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
47792
47875
|
writeFileSync10(join14(androidDir, "settings.gradle.kts"), settingsGradleTemplate(slugify(config.name ?? basename4(root)), modules, aarWrapperPaths, sdkRepoUrl()));
|
|
47793
47876
|
writeFileSync10(join14(androidDir, "build.gradle.kts"), rootBuildGradleTemplate([...gradlePlugins].map(([id, version]) => ({ id, version }))));
|
|
47794
47877
|
writeFileSync10(join14(androidDir, "gradle.properties"), GRADLE_PROPERTIES);
|
|
47795
|
-
writeFileSync10(join14(androidDir, "lecodes-runtime", "build.gradle.kts"), runtimeBuildGradleTemplate(sdkVersion, modules));
|
|
47878
|
+
writeFileSync10(join14(androidDir, "lecodes-runtime", "build.gradle.kts"), runtimeBuildGradleTemplate(sdkVersion, modules, sdkArtifact));
|
|
47796
47879
|
const runtimeKt = join14(androidDir, "lecodes-runtime", "src", "main", "kotlin", "io", "letary", "lecodes", "runtime", "LeCodesRuntime.kt");
|
|
47797
47880
|
mkdirSync8(dirname10(runtimeKt), { recursive: true });
|
|
47798
47881
|
writeFileSync10(runtimeKt, runtimeKotlinTemplate(runtimePlugins, shellUuid));
|
|
@@ -47963,6 +48046,9 @@ var doctorAndroidChecks = async (root, config, check) => {
|
|
|
47963
48046
|
check(javaMajor >= 17, `JDK ${javaMajor || "not found"}`, "install JDK 17+ (Android Studio ships one)");
|
|
47964
48047
|
const hasSdkHome = !!(process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT) || existsSync13(join14(androidDir, "local.properties"));
|
|
47965
48048
|
check(hasSdkHome, "Android SDK location", "set ANDROID_HOME or create android/local.properties");
|
|
48049
|
+
const requestedVariant = config.android?.variant ?? "auto";
|
|
48050
|
+
const validVariant = requestedVariant === "auto" || SDK_VARIANTS.includes(requestedVariant);
|
|
48051
|
+
check(validVariant, `android.variant "${requestedVariant}"`, `use "auto" or one of ${SDK_VARIANTS.join(", ")}`);
|
|
47966
48052
|
const wrapperJar = join14(androidDir, "gradle", "wrapper", "gradle-wrapper.jar");
|
|
47967
48053
|
check(existsSync13(wrapperJar) && statSync2(wrapperJar).size > 0, "Gradle wrapper jar", `run \`gradle wrapper --gradle-version ${GRADLE_VERSION}\` in android/ (or let Android Studio repair it)`);
|
|
47968
48054
|
check(existsSync13(join14(androidDir, "app", "src", "main", "assets", "app.js")), "Bundled app.js", "run `lecodes app sync`");
|
|
@@ -48464,7 +48550,6 @@ Built with LeCodes Desktop ${version}.
|
|
|
48464
48550
|
// src/commands/app.ts
|
|
48465
48551
|
var SDK_REPO = "letary/lecodes-ios-sdk";
|
|
48466
48552
|
var SDK_MIN_VERSION = "1.2.0";
|
|
48467
|
-
var SDK_VARIANTS = ["core", "2d", "3d", "full"];
|
|
48468
48553
|
var SDK_IDENTITY_VERSION = "1.6.0";
|
|
48469
48554
|
var shellSdkVersion = (iosDir) => {
|
|
48470
48555
|
const path2 = join17(iosDir, "LeCodesRuntime", "Package.swift");
|
|
@@ -48547,33 +48632,6 @@ var appInit = async (args) => {
|
|
|
48547
48632
|
log(` ${c.bold("open ios/App.xcodeproj")} then run on your device from Xcode`);
|
|
48548
48633
|
log(` App icon: set app.json "icon" to a square ≥1024px image — sync renders every size (or drop a PNG into App/Assets.xcassets/AppIcon.appiconset/)`);
|
|
48549
48634
|
};
|
|
48550
|
-
var detectEngines = (bundleJs) => {
|
|
48551
|
-
const lines = [];
|
|
48552
|
-
for (const line of bundleJs.split(`
|
|
48553
|
-
`)) {
|
|
48554
|
-
if (!line.startsWith("//"))
|
|
48555
|
-
break;
|
|
48556
|
-
lines.push(line);
|
|
48557
|
-
}
|
|
48558
|
-
const header = lines.join(`
|
|
48559
|
-
`);
|
|
48560
|
-
return { gl: !/^\/\/ gl: disable$/m.test(header), g2: /^\/\/ 2d: enable$/m.test(header) };
|
|
48561
|
-
};
|
|
48562
|
-
var resolveVariant = (requested, bundleJs) => {
|
|
48563
|
-
const uses = detectEngines(bundleJs);
|
|
48564
|
-
const detected = uses.gl && uses.g2 ? "full" : uses.gl ? "3d" : uses.g2 ? "2d" : "core";
|
|
48565
|
-
if (requested === "auto")
|
|
48566
|
-
return { variant: detected, detected };
|
|
48567
|
-
const variant = requested;
|
|
48568
|
-
const missing = [
|
|
48569
|
-
uses.gl && variant !== "3d" && variant !== "full" ? "3D" : null,
|
|
48570
|
-
uses.g2 && variant !== "2d" && variant !== "full" ? "2D" : null
|
|
48571
|
-
].filter(Boolean);
|
|
48572
|
-
if (missing.length > 0) {
|
|
48573
|
-
warn(`project uses the ${missing.join(" + ")} engine but ios.variant forces "${variant}" — those scenes won't run on device; remove ios.variant to auto-select "${detected}".`);
|
|
48574
|
-
}
|
|
48575
|
-
return { variant, detected };
|
|
48576
|
-
};
|
|
48577
48635
|
var ensureSdkResourcesBundle = async (sdkVersion) => {
|
|
48578
48636
|
const override = process.env.LECODES_SDK_RESOURCES;
|
|
48579
48637
|
if (override) {
|
|
@@ -48771,6 +48829,14 @@ var syncIos = async (root, config) => {
|
|
|
48771
48829
|
writeFileSync13(join17(iosDir, "App", "Info.plist"), infoPlistTemplate(mergedKeys, updateUrl));
|
|
48772
48830
|
if (updateUrl)
|
|
48773
48831
|
log(`${c.green("update")} OTA source ${updateUrl} — checked natively at launch, new code applies next launch`);
|
|
48832
|
+
else if (!config.update) {
|
|
48833
|
+
let manifest = null;
|
|
48834
|
+
try {
|
|
48835
|
+
manifest = readManifest(root);
|
|
48836
|
+
} catch {}
|
|
48837
|
+
if (manifest)
|
|
48838
|
+
note(`tip: add "update": true to app.json for over-the-air JS updates — ship with \`lecodes push --publish\`, no store release`);
|
|
48839
|
+
}
|
|
48774
48840
|
if (pluginSpecs.length > 0 || existsSync16(lockPath))
|
|
48775
48841
|
writeJson(lockPath, { plugins: newLock });
|
|
48776
48842
|
const pbxPath = join17(iosDir, "App.xcodeproj", "project.pbxproj");
|
|
@@ -49086,6 +49152,9 @@ var doctorIosChecks = async (root, config, check) => {
|
|
|
49086
49152
|
if (config.update) {
|
|
49087
49153
|
const plist = readFileSync15(join17(root, "ios", "App", "Info.plist"), "utf8");
|
|
49088
49154
|
check(plist.includes("<key>LeCodesUpdateURL</key>"), "OTA update URL in Info.plist", "run `lecodes app sync`", false);
|
|
49155
|
+
const appDir = join17(root, "ios", "App");
|
|
49156
|
+
const callsUpdater = readdirSync7(appDir).some((f3) => f3.endsWith(".swift") && readFileSync15(join17(appDir, f3), "utf8").includes("LeCodesUpdater.activeBundle"));
|
|
49157
|
+
check(callsUpdater, "App code launches via LeCodesUpdater", `no App/*.swift calls LeCodesUpdater.activeBundle() — downloaded updates would never run; see "Over-the-air updates" in ios/README.md for the ViewController snippet`, false);
|
|
49089
49158
|
}
|
|
49090
49159
|
const asc = readJson(join17(homedir6(), ".lecodes", "asc.json"));
|
|
49091
49160
|
check(!!asc?.keyPath, "App Store Connect API key configured", "pass --key-path/--key-id/--issuer-id to `lecodes app upload` once to store it", false);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lecodes-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@letary/chisel": "^0.6.0",
|
|
6
6
|
"jimp": "^1.6.1"
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"lecodes-design": "^0.8.0",
|
|
17
|
-
"lecodes-renderer": "^0.8.
|
|
18
|
-
"lecodes-3d-editor": "^0.
|
|
17
|
+
"lecodes-renderer": "^0.8.3",
|
|
18
|
+
"lecodes-3d-editor": "^0.3.0"
|
|
19
19
|
},
|
|
20
20
|
"bin": {
|
|
21
21
|
"lecodes": "dist/index.js"
|