muon-ui 0.26.0 → 0.26.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +5 -0
  2. package/android.d.ts +4 -4
  3. package/dist/android/lib/index.cjs +13 -10
  4. package/dist/android/lib/index.cjs.map +1 -1
  5. package/dist/android/lib/index.mjs +14 -11
  6. package/dist/android/lib/index.mjs.map +1 -1
  7. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.aar +0 -0
  8. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.aar.md5 +1 -1
  9. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.aar.sha1 +1 -1
  10. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.aar.sha256 +1 -1
  11. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.aar.sha512 +1 -1
  12. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.module +10 -10
  13. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.module.md5 +1 -1
  14. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.module.sha1 +1 -1
  15. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.module.sha256 +1 -1
  16. package/dist/android/maven/dev/muon/runtime/0.1.0/runtime-0.1.0.module.sha512 +1 -1
  17. package/dist/android/maven/dev/muon/runtime/maven-metadata.xml +1 -1
  18. package/dist/android/maven/dev/muon/runtime/maven-metadata.xml.md5 +1 -1
  19. package/dist/android/maven/dev/muon/runtime/maven-metadata.xml.sha1 +1 -1
  20. package/dist/android/maven/dev/muon/runtime/maven-metadata.xml.sha256 +1 -1
  21. package/dist/android/maven/dev/muon/runtime/maven-metadata.xml.sha512 +1 -1
  22. package/dist/android/renderer/renderer.js +41 -14
  23. package/dist/android/renderer/renderer.js.map +1 -1
  24. package/dist/cli.cjs +82 -56
  25. package/dist/cli.cjs.map +1 -1
  26. package/dist/index.cjs +2 -2
  27. package/dist/index.mjs +2 -2
  28. package/dist/native/linux-amd64/muon-builder +0 -0
  29. package/dist/native/linux-amd64/muon-launcher +0 -0
  30. package/dist/native/linux-amd64/muon-runtime-helper +0 -0
  31. package/dist/native/linux-arm64/muon-builder +0 -0
  32. package/dist/native/linux-arm64/muon-launcher +0 -0
  33. package/dist/native/linux-arm64/muon-runtime-helper +0 -0
  34. package/dist/native/linux-armhf/muon-builder +0 -0
  35. package/dist/native/linux-armhf/muon-launcher +0 -0
  36. package/dist/native/linux-armhf/muon-runtime-helper +0 -0
  37. package/dist/native/windows-amd64/muon-builder.exe +0 -0
  38. package/dist/native/windows-amd64/muon-launcher.exe +0 -0
  39. package/dist/native/windows-amd64/muon-plugin-inspector.exe +0 -0
  40. package/dist/native/windows-i686/muon-builder.exe +0 -0
  41. package/dist/native/windows-i686/muon-launcher.exe +0 -0
  42. package/dist/native/windows-i686/muon-plugin-inspector.exe +0 -0
  43. package/dist/runtime/linux-amd64/libmuon-ui.so +0 -0
  44. package/dist/runtime/linux-amd64/muon-core +0 -0
  45. package/dist/runtime/linux-amd64/plugins/node-bridge.mjs +5 -5
  46. package/dist/runtime/linux-amd64/plugins/node.so +0 -0
  47. package/dist/runtime/linux-arm64/libmuon-ui.so +0 -0
  48. package/dist/runtime/linux-arm64/muon-core +0 -0
  49. package/dist/runtime/linux-arm64/plugins/node-bridge.mjs +5 -5
  50. package/dist/runtime/linux-arm64/plugins/node.so +0 -0
  51. package/dist/runtime/linux-armhf/libmuon-ui.so +0 -0
  52. package/dist/runtime/linux-armhf/muon-core +0 -0
  53. package/dist/runtime/linux-armhf/plugins/node-bridge.mjs +5 -5
  54. package/dist/runtime/linux-armhf/plugins/node.so +0 -0
  55. package/dist/runtime/windows-amd64/libcardio.dll +0 -0
  56. package/dist/runtime/windows-amd64/libmuon-ui.dll +0 -0
  57. package/dist/runtime/windows-amd64/muon-core.exe +0 -0
  58. package/dist/runtime/windows-amd64/plugins/node-bridge.mjs +5 -5
  59. package/dist/runtime/windows-amd64/plugins/node.dll +0 -0
  60. package/dist/runtime/windows-i686/libcardio.dll +0 -0
  61. package/dist/runtime/windows-i686/libmuon-ui.dll +0 -0
  62. package/dist/runtime/windows-i686/muon-core.exe +0 -0
  63. package/dist/runtime/windows-i686/plugins/node-bridge.mjs +5 -5
  64. package/dist/runtime/windows-i686/plugins/node.dll +0 -0
  65. package/dist/{vite-internals-DseKep-X.cjs → vite-internals-CueaxMaY.cjs} +4225 -1963
  66. package/dist/vite-internals-CueaxMaY.cjs.map +1 -0
  67. package/dist/vite.cjs +100 -1294
  68. package/dist/vite.cjs.map +1 -1
  69. package/dist/vite.mjs +6102 -5128
  70. package/dist/vite.mjs.map +1 -1
  71. package/images/get-started-android.png +0 -0
  72. package/muon-virtual-modules.d.ts +53 -0
  73. package/package.json +13 -13
  74. package/vite.d.ts +8 -0
  75. package/dist/vite-internals-DseKep-X.cjs.map +0 -1
package/README.md CHANGED
@@ -53,6 +53,10 @@ This lets you build modern local GUI applications with the web technology ecosys
53
53
  muon also minimizes the steps required to create a muon application, keeping the barrier to entry low.
54
54
  With the minimal setup, installing the NPM package and adding one line to the configuration file is enough to launch your first muon app.
55
55
 
56
+ WIP: And once you've created a muon application, you can deploy it directly to Android.
57
+
58
+ ![android](./images/get-started-android.png)
59
+
56
60
  ### Features
57
61
 
58
62
  - Restricts all network access through a whitelist filter, letting you completely exclude problematic content.
@@ -63,6 +67,7 @@ With the minimal setup, installing the NPM package and adding one line to the co
63
67
  - You can also build Android applications (experimental).
64
68
  - DevTools can be used. CDP (Chrome DevTools Protocol) is also supported, so remote debugging from external tools is possible.
65
69
  - Includes a plugin system. Plugin capabilities can also be restricted by a whitelist filter.
70
+ - An independent SDK supports C/C++ plugin development and distribution as prebuilt NPM packages.
66
71
  - Built-in plugins provide access to local files, open dialogs, child process launching, and window operations.
67
72
 
68
73
  ### Environment
package/android.d.ts CHANGED
@@ -14,10 +14,10 @@ export interface MuonAndroidPluginOptions {
14
14
  soname: string;
15
15
  /** Library path for each ABI selected by android.abis. */
16
16
  libraries: Partial<Record<MuonAndroidAbi, string>>;
17
- /** Allowed public function patterns; an explicit nonempty list is required. */
18
- allow: readonly string[];
19
- /** Application-owned string configuration passed to the plugin. */
20
- config?: Readonly<Record<string, string>>;
17
+ /** Ordinary shared dependencies by ABI, copied beside the plugin. */
18
+ dependencies?: Partial<Record<MuonAndroidAbi, readonly string[]>>;
19
+ /** Producer catalog JSON path, required for validate mode; resolved like libraries. */
20
+ metadata?: string;
21
21
  }
22
22
 
23
23
  /** Android application options, overriding the muon.json android section. */
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * name: muon-android
3
- * version: 0.26.0
4
- * description: Shared Android runtime and build components for muon-ui.
2
+ * name: muon-ui
3
+ * version: 0.26.47
4
+ * description: A multi-platform GUI application framework that uses CEF as its backend
5
5
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
6
  * license: MIT
7
7
  * repository.url: https://github.com/kekyo/muon-ui.git
8
- * git.commit.hash: 4bceacb2bf609778560407d23f4cba0e36315098
8
+ * git.commit.hash: 95dc2712686873c8a022483fd9abf18598019bd7
9
9
  */
10
10
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
11
11
  let node_fs_promises = require("node:fs/promises");
@@ -15,7 +15,7 @@ let funcity = require("funcity");
15
15
  let node_child_process = require("node:child_process");
16
16
  let node_fs = require("node:fs");
17
17
  let node_os = require("node:os");
18
- //#region src/command.ts
18
+ //#region android/command.ts
19
19
  /**
20
20
  * Runs a build tool without a shell and awaits process completion.
21
21
  * @param command - Executable path.
@@ -50,7 +50,7 @@ var runAndroidCommand = async (command, args, cwd, environment, output) => await
50
50
  });
51
51
  });
52
52
  //#endregion
53
- //#region src/toolchain.ts
53
+ //#region android/toolchain.ts
54
54
  var accessible = async (path, mode) => {
55
55
  try {
56
56
  await (0, node_fs_promises.access)(path, mode);
@@ -109,7 +109,7 @@ var prepareAndroid = async (options) => {
109
109
  };
110
110
  };
111
111
  //#endregion
112
- //#region src/build.ts
112
+ //#region android/build.ts
113
113
  var xml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
114
114
  var render = async (template, variables) => {
115
115
  const logs = [];
@@ -162,15 +162,17 @@ var buildAndroidApplication = async (input) => {
162
162
  await (0, node_fs_promises.copyFile)((0, node_path.join)(tools.componentsDirectory, "renderer/renderer.js"), (0, node_path.join)(frameworkAssets, "renderer.js"));
163
163
  await (0, node_fs_promises.writeFile)((0, node_path.join)(frameworkAssets, "config.json"), JSON.stringify({
164
164
  startPage: input.startPage,
165
- values: input.values
165
+ values: input.values,
166
+ plugin: input.pluginAccess
166
167
  }));
167
168
  await (0, node_fs_promises.writeFile)((0, node_path.join)(frameworkAssets, "plugins.json"), JSON.stringify({
168
169
  schemaVersion: 1,
169
- plugins: input.plugins.map(({ name, soname, allow, config }) => ({
170
+ plugins: input.plugins.map(({ name, soname, allow, config, expectedFunctions }) => ({
170
171
  name,
171
172
  soname,
172
173
  allow,
173
- config
174
+ config,
175
+ ...expectedFunctions === void 0 ? {} : { expectedFunctions }
174
176
  }))
175
177
  }));
176
178
  for (const plugin of input.plugins) for (const abi of input.abis) {
@@ -179,6 +181,7 @@ var buildAndroidApplication = async (input) => {
179
181
  const destination = (0, node_path.join)(project, "app/src/main/jniLibs", abi, plugin.soname);
180
182
  await (0, node_fs_promises.mkdir)((0, node_path.dirname)(destination), { recursive: true });
181
183
  await (0, node_fs_promises.copyFile)(library, destination);
184
+ for (const dependency of plugin.dependencies?.[abi] ?? []) await (0, node_fs_promises.copyFile)(dependency, (0, node_path.join)((0, node_path.dirname)(destination), (0, node_path.basename)(dependency)));
182
185
  }
183
186
  await (0, node_fs_promises.writeFile)((0, node_path.join)(project, "muon-build.json"), JSON.stringify({
184
187
  ...tools.toolchain,
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["spawn","access","delimiter","join","constants","resolve","readFile","dirname","homedir","mkdir","runScriptOnceToText","readFile","resolve","relative","isAbsolute","rm","cp","join","chmod","mkdir","stat","copyFile","writeFile","dirname","pathToFileURL"],"sources":["../../src/command.ts","../../src/toolchain.ts","../../src/build.ts"],"sourcesContent":["// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { spawn } from 'node:child_process';\n\n/**\n * Runs a build tool without a shell and awaits process completion.\n * @param command - Executable path.\n * @param args - Literal argument vector.\n * @param cwd - Working directory.\n * @param environment - Child environment, including any external credentials.\n * @param output - Optional progress sink; undefined captures output only.\n * @returns Captured standard output and standard error.\n */\nexport const runAndroidCommand = async (\n command: string,\n args: readonly string[],\n cwd: string,\n environment: NodeJS.ProcessEnv,\n output: ((text: string) => void) | undefined\n): Promise<string> =>\n await new Promise<string>((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n env: environment,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let captured = '';\n const receive = (chunk: Buffer) => {\n const text = chunk.toString();\n captured += text;\n output?.(text);\n };\n child.stdout.on('data', receive);\n child.stderr.on('data', receive);\n child.once('error', reject);\n child.once('close', (code, signal) => {\n if (code === 0) resolve(captured);\n else\n reject(\n new Error(`${command} failed (${signal ?? code}):\\n${captured}`)\n );\n });\n });\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { constants } from 'node:fs';\nimport { access, mkdir, readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { delimiter, dirname, join, resolve } from 'node:path';\nimport { runAndroidCommand } from './command.js';\n\n/** Versions fixed by the shipped Android component set. */\nexport interface MuonAndroidToolchain {\n /** Exact Android SDK platform package directory. */ readonly platform: string;\n /** Component schema. */ readonly schemaVersion: 1;\n /** Android Gradle plugin version. */ readonly agp: string;\n /** Wrapper version. */ readonly gradle: string;\n /** API used for compilation. */ readonly compileSdk: number;\n /** API targeted by generated applications. */ readonly targetSdk: number;\n /** Minimum installation API; see documented verification range. */ readonly minSdk: number;\n /** Required SDK Build Tools version. */ readonly buildTools: string;\n /** Minimum JDK runtime version. */ readonly javaMin: number;\n /** Highest supported JDK runtime version. */ readonly javaMax: number;\n /** Version of dev.muon:runtime. */ readonly runtimeVersion: string;\n /** ABIs included in the standard runtime. */ readonly abis: readonly string[];\n}\n\n/** Inputs for the Android environment diagnostic. */\nexport interface MuonAndroidPrepareOptions {\n /** Directory containing templates, maven, renderer and toolchain.json. */ componentsDirectory: string;\n /** Explicit SDK location, otherwise resolved from the environment or adb. */ sdkPath:\n string | undefined;\n /** Child environment. */ environment: NodeJS.ProcessEnv;\n /** Whether to download/verify the pinned Gradle distribution using its Wrapper. */ prepareGradle: boolean;\n}\n\n/** Validated tools for an Android build; no NDK or CMake is needed. */\nexport interface MuonAndroidPrepareResult {\n /** Discriminates Android from desktop preparation. */ readonly target: 'android';\n /** Absolute SDK directory. */ readonly sdkPath: string;\n /** Detected JDK major version. */ readonly javaVersion: number;\n /** Absolute Java executable. */ readonly javaPath: string;\n /** Shipped version requirements. */ readonly toolchain: MuonAndroidToolchain;\n /** Component directory used for this build. */ readonly componentsDirectory: string;\n}\n\nconst accessible = async (path: string, mode: number): Promise<boolean> => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n};\n\nconst findExecutable = async (\n name: string,\n environment: NodeJS.ProcessEnv\n): Promise<string | undefined> => {\n for (const directory of (environment.PATH ?? '')\n .split(delimiter)\n .filter(Boolean)) {\n const path = join(directory, name);\n if (await accessible(path, constants.X_OK)) return path;\n }\n return undefined;\n};\n\n/**\n * Diagnoses a Linux x64 SDK/JDK installation and optionally prepares Gradle.\n * @param options - Component location, SDK override and process environment.\n * @returns Validated tool paths and pinned versions.\n * @remarks Does not install SDK packages, accept licenses, or require a device.\n */\nexport const prepareAndroid = async (\n options: MuonAndroidPrepareOptions\n): Promise<MuonAndroidPrepareResult> => {\n if (process.platform !== 'linux' || process.arch !== 'x64') {\n throw new Error('Android builds currently support Linux x64 hosts.');\n }\n const componentsDirectory = resolve(options.componentsDirectory);\n const toolchain = JSON.parse(\n await readFile(join(componentsDirectory, 'toolchain.json'), 'utf8')\n ) as MuonAndroidToolchain;\n if (toolchain.schemaVersion !== 1)\n throw new Error('Unsupported Muon Android toolchain schema.');\n const adb = await findExecutable('adb', options.environment);\n const candidate =\n options.sdkPath ??\n options.environment.ANDROID_HOME ??\n options.environment.ANDROID_SDK_ROOT ??\n (adb === undefined ? undefined : dirname(dirname(adb)));\n if (!candidate)\n throw new Error(\n 'Android SDK not found. Set ANDROID_HOME or android.sdkPath.'\n );\n const sdkPath = resolve(candidate);\n for (const [file, packageName] of [\n [\n `platforms/${toolchain.platform}/android.jar`,\n `platforms;${toolchain.platform}`,\n ],\n ...['aapt2', 'zipalign', 'apksigner'].map((name) => [\n `build-tools/${toolchain.buildTools}/${name}`,\n `build-tools;${toolchain.buildTools}`,\n ]),\n ]) {\n if (!(await accessible(join(sdkPath, file!), constants.R_OK))) {\n throw new Error(\n `Android SDK ${sdkPath} is missing ${packageName}. Install this package using the Android CLI: android sdk install '${packageName}'. See https://developer.android.com/tools/agents/android-cli/commands/sdk`\n );\n }\n }\n const platformProperties = await readFile(\n join(sdkPath, 'platforms', toolchain.platform, 'source.properties'),\n 'utf8'\n );\n if (\n Number(\n /^AndroidVersion.ApiLevel\\s*=\\s*(\\S+)/mu.exec(platformProperties)?.[1]\n ) !== toolchain.compileSdk\n ) {\n throw new Error(\n `Android SDK platform version differs from the required API ${toolchain.compileSdk}: ${sdkPath}`\n );\n }\n const buildProperties = await readFile(\n join(sdkPath, 'build-tools', toolchain.buildTools, 'source.properties'),\n 'utf8'\n );\n if (\n /^Pkg.Revision\\s*=\\s*(\\S+)/mu.exec(buildProperties)?.[1] !==\n toolchain.buildTools\n ) {\n throw new Error(\n `Android SDK Build Tools version differs from ${toolchain.buildTools}: ${sdkPath}`\n );\n }\n const javaPath = options.environment.JAVA_HOME\n ? join(options.environment.JAVA_HOME, 'bin/java')\n : await findExecutable('java', options.environment);\n if (!javaPath || !(await accessible(javaPath, constants.X_OK))) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required. Set JAVA_HOME or add java to PATH.`\n );\n }\n const versionText = await runAndroidCommand(\n javaPath,\n ['-version'],\n componentsDirectory,\n options.environment,\n undefined\n );\n const javaVersion = Number(\n /(?:openjdk|java) version \"(\\d+)[.\"]/u.exec(versionText)?.[1]\n );\n if (\n !Number.isInteger(javaVersion) ||\n javaVersion < toolchain.javaMin ||\n javaVersion > toolchain.javaMax\n ) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required; detected ${versionText.trim()}.`\n );\n }\n if (options.prepareGradle) {\n const cache = join(homedir(), '.cache/muon/android', toolchain.gradle);\n await mkdir(cache, { recursive: true });\n const result = await runAndroidCommand(\n join(componentsDirectory, 'templates/gradlew'),\n ['--version'],\n cache,\n options.environment,\n undefined\n );\n if (!result.includes(`Gradle ${toolchain.gradle}`))\n throw new Error(\n 'Gradle Wrapper version differs from the shipped toolchain.'\n );\n }\n return {\n target: 'android',\n sdkPath,\n javaVersion,\n javaPath,\n toolchain,\n componentsDirectory,\n };\n};\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport {\n chmod,\n copyFile,\n cp,\n mkdir,\n readFile,\n rm,\n stat,\n writeFile,\n} from 'node:fs/promises';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { runScriptOnceToText, type FunCityLogEntry } from 'funcity';\nimport { runAndroidCommand } from './command.js';\nimport { prepareAndroid } from './toolchain.js';\n\n/** ABI shipped by the Muon Android runtime. */\nexport type MuonAndroidAbi = 'arm64-v8a' | 'x86_64';\n\n/** Normalized package-owned plugin entry. */\nexport interface MuonAndroidPackagedPlugin {\n /** Logical capability name. */ readonly name: string;\n /** Packaged ELF soname. */ readonly soname: string;\n /** Explicitly allowed public function patterns. */ readonly allow: readonly string[];\n /** Application-owned plugin configuration. */ readonly config: readonly {\n readonly key: string;\n readonly value: string;\n }[];\n /** Absolute prebuilt library path for each selected ABI. */ readonly libraries: Readonly<\n Partial<Record<MuonAndroidAbi, string>>\n >;\n}\n\n/** Explicit inputs used by the Android package builder. */\nexport interface MuonAndroidApplicationInput {\n /** Packaged Muon Android components. */ componentsDirectory: string;\n /** Directory containing previously built web assets. */ assetsDirectory: string;\n /** Relative URL path prefix under the trusted asset host. */ assetPath: string;\n /** Trusted HTTPS entry URL. */ startPage: string;\n /** Application identifier independent of Muon's Java namespace. */ applicationId: string;\n /** Launcher label. */ label: string;\n /** Monotonic Android update number. */ versionCode: number;\n /** User-facing version. */ versionName: string;\n /** Selected runtime ABIs. */ abis: readonly MuonAndroidAbi[];\n /** Manifest permissions, already normalized by the public build boundary. */ permissions: readonly string[];\n /** Values returned by muon.environments.getConfigValues. */ values: Readonly<\n Record<string, string>\n >;\n /** Explicit prebuilt plugins; an empty array builds a standard app. */ plugins: readonly MuonAndroidPackagedPlugin[];\n /** Optional PNG icon already converted by the public build boundary. */ icon:\n string | undefined;\n /** Owned directory for generated Gradle sources and intermediates. */ projectDirectory: string;\n /** Destination for APKs and result metadata. */ outputDirectory: string;\n /** SDK override. */ sdkPath: string | undefined;\n /** Debug package or unsigned release package. */ variant:\n 'debug' | 'release';\n /** Process environment. */ environment: NodeJS.ProcessEnv;\n /** Progress sink, or undefined for a quiet build. */ output:\n ((text: string) => void) | undefined;\n}\n\n/** Android APK result, without desktop launcher or CEF fields. */\nexport interface MuonAndroidApplicationResult {\n /** Target discriminator. */ readonly target: 'android';\n /** Absolute APK path. */ readonly packagePath: string;\n /** Generated Gradle project for diagnostics. */ readonly projectDirectory: string;\n /** Android variant. */ readonly variant: 'debug' | 'release';\n /** Included native ABIs. */ readonly abis: readonly MuonAndroidAbi[];\n /** Application identifier. */ readonly applicationId: string;\n /** Update version. */ readonly versionCode: number;\n /** Display version. */ readonly versionName: string;\n /** Actual signing state. */ readonly signing:\n 'debug' | 'unsigned' | 'release';\n}\n\nconst xml = (value: string): string =>\n value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;');\n\nconst render = async (\n template: string,\n variables: ReadonlyMap<string, unknown>\n): Promise<string> => {\n const logs: FunCityLogEntry[] = [];\n const value = await runScriptOnceToText(await readFile(template, 'utf8'), {\n sourceId: template,\n variables,\n logs,\n });\n if (value === undefined || logs.some((log) => log.type === 'error')) {\n throw new Error(\n `Cannot render Android template ${template}: ${JSON.stringify(logs)}`\n );\n }\n return value;\n};\n\n/**\n * Builds a self-contained APK from the shipped AAR and prebuilt web assets.\n * @param input - Explicit application, artifact and toolchain inputs.\n * @returns The APK path and its actual variant/signing state.\n * @remarks Does not run Vite, compile native code or infer a repository root.\n */\nexport const buildAndroidApplication = async (\n input: MuonAndroidApplicationInput\n): Promise<MuonAndroidApplicationResult> => {\n const tools = await prepareAndroid({\n componentsDirectory: input.componentsDirectory,\n sdkPath: input.sdkPath,\n environment: input.environment,\n prepareGradle: false,\n });\n const project = resolve(input.projectDirectory);\n const assetRelative = relative(resolve(input.assetsDirectory), project);\n if (\n assetRelative === '' ||\n (!assetRelative.startsWith('..') && !isAbsolute(assetRelative))\n ) {\n throw new Error(\n 'The generated Android project must be outside the web assets directory.'\n );\n }\n if (\n isAbsolute(input.assetPath) ||\n input.assetPath\n .split(/[\\\\/]/u)\n .some((part) => part === '..' || part === 'muon')\n ) {\n throw new Error(\n 'Android assetPath must be relative and must not use the reserved muon directory.'\n );\n }\n await rm(project, { recursive: true, force: true });\n await cp(join(tools.componentsDirectory, 'templates'), project, {\n recursive: true,\n });\n await chmod(join(project, 'gradlew'), 0o755);\n const assets = join(project, 'app/src/main/assets');\n await mkdir(assets, { recursive: true });\n await cp(input.assetsDirectory, join(assets, input.assetPath), {\n recursive: true,\n dereference: true,\n });\n const frameworkAssets = join(assets, 'muon');\n try {\n await stat(frameworkAssets);\n throw new Error('Web assets must not contain the reserved muon directory.');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n }\n await mkdir(frameworkAssets, { recursive: true });\n await cp(\n join(tools.componentsDirectory, 'licenses'),\n join(frameworkAssets, 'licenses'),\n { recursive: true }\n );\n await copyFile(\n join(tools.componentsDirectory, 'renderer/renderer.js'),\n join(frameworkAssets, 'renderer.js')\n );\n await writeFile(\n join(frameworkAssets, 'config.json'),\n JSON.stringify({ startPage: input.startPage, values: input.values })\n );\n await writeFile(\n join(frameworkAssets, 'plugins.json'),\n JSON.stringify({\n schemaVersion: 1,\n plugins: input.plugins.map(({ name, soname, allow, config }) => ({\n name,\n soname,\n allow,\n config,\n })),\n })\n );\n for (const plugin of input.plugins) {\n for (const abi of input.abis) {\n const library = plugin.libraries[abi];\n if (!library)\n throw new Error(`${plugin.name} is missing its ${abi} library.`);\n const destination = join(\n project,\n 'app/src/main/jniLibs',\n abi,\n plugin.soname\n );\n await mkdir(dirname(destination), { recursive: true });\n await copyFile(library, destination);\n }\n }\n await writeFile(\n join(project, 'muon-build.json'),\n JSON.stringify(\n {\n ...tools.toolchain,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n abis: input.abis,\n maven: pathToFileURL(join(tools.componentsDirectory, 'maven')).href,\n },\n null,\n 2\n )\n );\n await writeFile(\n join(project, 'app/src/main/AndroidManifest.xml'),\n await render(\n join(project, 'AndroidManifest.xml.fc'),\n new Map([['permissions', input.permissions.map(xml)]])\n )\n );\n const resources = join(project, 'app/src/main/res');\n await mkdir(join(resources, 'values'), { recursive: true });\n await writeFile(\n join(resources, 'values/strings.xml'),\n await render(\n join(project, 'strings.xml.fc'),\n new Map([\n [\n 'label',\n xml(input.label.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')),\n ],\n ])\n )\n );\n if (input.icon !== undefined) {\n await rm(join(resources, 'mipmap/ic_launcher.xml'));\n await copyFile(input.icon, join(resources, 'mipmap/ic_launcher.png'));\n }\n await runAndroidCommand(\n join(project, 'gradlew'),\n [\n '--no-daemon',\n '--console=plain',\n input.variant === 'debug' ? ':app:assembleDebug' : ':app:assembleRelease',\n ],\n project,\n {\n ...input.environment,\n ANDROID_HOME: tools.sdkPath,\n ANDROID_SDK_ROOT: tools.sdkPath,\n },\n input.output\n );\n const name =\n input.variant === 'debug' ? 'app-debug.apk' : 'app-release-unsigned.apk';\n const packagePath = join(\n resolve(input.outputDirectory),\n `${input.applicationId}-${input.versionCode}-${input.variant}.apk`\n );\n await mkdir(dirname(packagePath), { recursive: true });\n await copyFile(\n join(project, 'app/build/outputs/apk', input.variant, name),\n packagePath\n );\n const result: MuonAndroidApplicationResult = {\n target: 'android',\n packagePath,\n projectDirectory: project,\n variant: input.variant,\n abis: input.abis,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n signing: input.variant === 'debug' ? 'debug' : 'unsigned',\n };\n await writeFile(\n `${packagePath}.json`,\n JSON.stringify(result, null, 2) + '\\n'\n );\n return result;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["spawn","access","delimiter","join","constants","resolve","readFile","dirname","homedir","mkdir","runScriptOnceToText","readFile","resolve","relative","isAbsolute","rm","cp","join","chmod","mkdir","stat","copyFile","writeFile","dirname","basename","pathToFileURL"],"sources":["../../android/command.ts","../../android/toolchain.ts","../../android/build.ts"],"sourcesContent":["// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { spawn } from \"node:child_process\";\n\n/**\n * Runs a build tool without a shell and awaits process completion.\n * @param command - Executable path.\n * @param args - Literal argument vector.\n * @param cwd - Working directory.\n * @param environment - Child environment, including any external credentials.\n * @param output - Optional progress sink; undefined captures output only.\n * @returns Captured standard output and standard error.\n */\nexport const runAndroidCommand = async (\n command: string,\n args: readonly string[],\n cwd: string,\n environment: NodeJS.ProcessEnv,\n output: ((text: string) => void) | undefined,\n): Promise<string> =>\n await new Promise<string>((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n env: environment,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n let captured = \"\";\n const receive = (chunk: Buffer) => {\n const text = chunk.toString();\n captured += text;\n output?.(text);\n };\n child.stdout.on(\"data\", receive);\n child.stderr.on(\"data\", receive);\n child.once(\"error\", reject);\n child.once(\"close\", (code, signal) => {\n if (code === 0) resolve(captured);\n else\n reject(\n new Error(`${command} failed (${signal ?? code}):\\n${captured}`),\n );\n });\n });\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { constants } from \"node:fs\";\nimport { access, mkdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { delimiter, dirname, join, resolve } from \"node:path\";\nimport { runAndroidCommand } from \"./command.js\";\n\n/** Versions fixed by the shipped Android component set. */\nexport interface MuonAndroidToolchain {\n /** Exact Android SDK platform package directory. */ readonly platform: string;\n /** Component schema. */ readonly schemaVersion: 1;\n /** Android Gradle plugin version. */ readonly agp: string;\n /** Wrapper version. */ readonly gradle: string;\n /** API used for compilation. */ readonly compileSdk: number;\n /** API targeted by generated applications. */ readonly targetSdk: number;\n /** Minimum installation API; see documented verification range. */ readonly minSdk: number;\n /** Required SDK Build Tools version. */ readonly buildTools: string;\n /** Minimum JDK runtime version. */ readonly javaMin: number;\n /** Highest supported JDK runtime version. */ readonly javaMax: number;\n /** Version of dev.muon:runtime. */ readonly runtimeVersion: string;\n /** ABIs included in the standard runtime. */ readonly abis: readonly string[];\n}\n\n/** Inputs for the Android environment diagnostic. */\nexport interface MuonAndroidPrepareOptions {\n /** Directory containing templates, maven, renderer and toolchain.json. */ componentsDirectory: string;\n /** Explicit SDK location, otherwise resolved from the environment or adb. */ sdkPath:\n string | undefined;\n /** Child environment. */ environment: NodeJS.ProcessEnv;\n /** Whether to download/verify the pinned Gradle distribution using its Wrapper. */ prepareGradle: boolean;\n}\n\n/** Validated tools for an Android build; no NDK or CMake is needed. */\nexport interface MuonAndroidPrepareResult {\n /** Discriminates Android from desktop preparation. */ readonly target: \"android\";\n /** Absolute SDK directory. */ readonly sdkPath: string;\n /** Detected JDK major version. */ readonly javaVersion: number;\n /** Absolute Java executable. */ readonly javaPath: string;\n /** Shipped version requirements. */ readonly toolchain: MuonAndroidToolchain;\n /** Component directory used for this build. */ readonly componentsDirectory: string;\n}\n\nconst accessible = async (path: string, mode: number): Promise<boolean> => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n};\n\nconst findExecutable = async (\n name: string,\n environment: NodeJS.ProcessEnv,\n): Promise<string | undefined> => {\n for (const directory of (environment.PATH ?? \"\")\n .split(delimiter)\n .filter(Boolean)) {\n const path = join(directory, name);\n if (await accessible(path, constants.X_OK)) return path;\n }\n return undefined;\n};\n\n/**\n * Diagnoses a Linux x64 SDK/JDK installation and optionally prepares Gradle.\n * @param options - Component location, SDK override and process environment.\n * @returns Validated tool paths and pinned versions.\n * @remarks Does not install SDK packages, accept licenses, or require a device.\n */\nexport const prepareAndroid = async (\n options: MuonAndroidPrepareOptions,\n): Promise<MuonAndroidPrepareResult> => {\n if (process.platform !== \"linux\" || process.arch !== \"x64\") {\n throw new Error(\"Android builds currently support Linux x64 hosts.\");\n }\n const componentsDirectory = resolve(options.componentsDirectory);\n const toolchain = JSON.parse(\n await readFile(join(componentsDirectory, \"toolchain.json\"), \"utf8\"),\n ) as MuonAndroidToolchain;\n if (toolchain.schemaVersion !== 1)\n throw new Error(\"Unsupported Muon Android toolchain schema.\");\n const adb = await findExecutable(\"adb\", options.environment);\n const candidate =\n options.sdkPath ??\n options.environment.ANDROID_HOME ??\n options.environment.ANDROID_SDK_ROOT ??\n (adb === undefined ? undefined : dirname(dirname(adb)));\n if (!candidate)\n throw new Error(\n \"Android SDK not found. Set ANDROID_HOME or android.sdkPath.\",\n );\n const sdkPath = resolve(candidate);\n for (const [file, packageName] of [\n [\n `platforms/${toolchain.platform}/android.jar`,\n `platforms;${toolchain.platform}`,\n ],\n ...[\"aapt2\", \"zipalign\", \"apksigner\"].map((name) => [\n `build-tools/${toolchain.buildTools}/${name}`,\n `build-tools;${toolchain.buildTools}`,\n ]),\n ]) {\n if (!(await accessible(join(sdkPath, file!), constants.R_OK))) {\n throw new Error(\n `Android SDK ${sdkPath} is missing ${packageName}. Install this package using the Android CLI: android sdk install '${packageName}'. See https://developer.android.com/tools/agents/android-cli/commands/sdk`,\n );\n }\n }\n const platformProperties = await readFile(\n join(sdkPath, \"platforms\", toolchain.platform, \"source.properties\"),\n \"utf8\",\n );\n if (\n Number(\n /^AndroidVersion.ApiLevel\\s*=\\s*(\\S+)/mu.exec(platformProperties)?.[1],\n ) !== toolchain.compileSdk\n ) {\n throw new Error(\n `Android SDK platform version differs from the required API ${toolchain.compileSdk}: ${sdkPath}`,\n );\n }\n const buildProperties = await readFile(\n join(sdkPath, \"build-tools\", toolchain.buildTools, \"source.properties\"),\n \"utf8\",\n );\n if (\n /^Pkg.Revision\\s*=\\s*(\\S+)/mu.exec(buildProperties)?.[1] !==\n toolchain.buildTools\n ) {\n throw new Error(\n `Android SDK Build Tools version differs from ${toolchain.buildTools}: ${sdkPath}`,\n );\n }\n const javaPath = options.environment.JAVA_HOME\n ? join(options.environment.JAVA_HOME, \"bin/java\")\n : await findExecutable(\"java\", options.environment);\n if (!javaPath || !(await accessible(javaPath, constants.X_OK))) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required. Set JAVA_HOME or add java to PATH.`,\n );\n }\n const versionText = await runAndroidCommand(\n javaPath,\n [\"-version\"],\n componentsDirectory,\n options.environment,\n undefined,\n );\n const javaVersion = Number(\n /(?:openjdk|java) version \"(\\d+)[.\"]/u.exec(versionText)?.[1],\n );\n if (\n !Number.isInteger(javaVersion) ||\n javaVersion < toolchain.javaMin ||\n javaVersion > toolchain.javaMax\n ) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required; detected ${versionText.trim()}.`,\n );\n }\n if (options.prepareGradle) {\n const cache = join(homedir(), \".cache/muon/android\", toolchain.gradle);\n await mkdir(cache, { recursive: true });\n const result = await runAndroidCommand(\n join(componentsDirectory, \"templates/gradlew\"),\n [\"--version\"],\n cache,\n options.environment,\n undefined,\n );\n if (!result.includes(`Gradle ${toolchain.gradle}`))\n throw new Error(\n \"Gradle Wrapper version differs from the shipped toolchain.\",\n );\n }\n return {\n target: \"android\",\n sdkPath,\n javaVersion,\n javaPath,\n toolchain,\n componentsDirectory,\n };\n};\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport {\n chmod,\n copyFile,\n cp,\n mkdir,\n readFile,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport {\n basename,\n dirname,\n isAbsolute,\n join,\n relative,\n resolve,\n} from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { runScriptOnceToText, type FunCityLogEntry } from \"funcity\";\nimport { runAndroidCommand } from \"./command.js\";\nimport { prepareAndroid } from \"./toolchain.js\";\n\n/** ABI shipped by the Muon Android runtime. */\nexport type MuonAndroidAbi = \"arm64-v8a\" | \"x86_64\";\n\n/** Package-owned plugin exposure and built-in function policy. */\nexport type MuonAndroidPluginAccess = {\n /** Whether the trusted main frame may use the bridge. */ readonly enabled: boolean;\n /** Allowed built-in public function paths. */ readonly internalAllow: readonly string[];\n} & (\n | { /** Global API exposure mode. */ readonly mode: \"simple\" }\n | {\n /** Virtual-module exposure mode. */ readonly mode: \"validate\";\n /** Capabilities generated by the same build as the application bundle. */ readonly capabilities: readonly {\n /** Opaque capability id. */ readonly id: string;\n /** Allowed public function paths. */ readonly allow: readonly string[];\n }[];\n }\n);\n\n/** Normalized package-owned plugin entry. */\nexport interface MuonAndroidPackagedPlugin {\n /** Ordinary shared libraries copied beside the plugin for each ABI. */ readonly dependencies?: Readonly<\n Partial<Record<MuonAndroidAbi, readonly string[]>>\n >;\n /** Logical capability name. */ readonly name: string;\n /** Packaged ELF soname. */ readonly soname: string;\n /** Explicitly allowed public function patterns. */ readonly allow: readonly string[];\n /** Producer catalog after applying the allow policy, checked when loading. */ readonly expectedFunctions?: readonly string[];\n /** Application-owned plugin configuration. */ readonly config: readonly {\n readonly key: string;\n readonly value: string;\n }[];\n /** Absolute prebuilt library path for each selected ABI. */ readonly libraries: Readonly<\n Partial<Record<MuonAndroidAbi, string>>\n >;\n}\n\n/** Explicit inputs used by the Android package builder. */\nexport interface MuonAndroidApplicationInput {\n /** Packaged Muon Android components. */ componentsDirectory: string;\n /** Directory containing previously built web assets. */ assetsDirectory: string;\n /** Relative URL path prefix under the trusted asset host. */ assetPath: string;\n /** Trusted HTTPS entry URL. */ startPage: string;\n /** Application identifier independent of Muon's Java namespace. */ applicationId: string;\n /** Launcher label. */ label: string;\n /** Monotonic Android update number. */ versionCode: number;\n /** User-facing version. */ versionName: string;\n /** Selected runtime ABIs. */ abis: readonly MuonAndroidAbi[];\n /** Manifest permissions, already normalized by the public build boundary. */ permissions: readonly string[];\n /** Values returned by muon.environments.getConfigValues. */ values: Readonly<\n Record<string, string>\n >;\n /** Explicit prebuilt plugins; an empty array builds a standard app. */ plugins: readonly MuonAndroidPackagedPlugin[];\n /** Validated common plugin access settings. */ pluginAccess: MuonAndroidPluginAccess;\n /** Optional PNG icon already converted by the public build boundary. */ icon:\n string | undefined;\n /** Owned directory for generated Gradle sources and intermediates. */ projectDirectory: string;\n /** Destination for APKs and result metadata. */ outputDirectory: string;\n /** SDK override. */ sdkPath: string | undefined;\n /** Debug package or unsigned release package. */ variant:\n \"debug\" | \"release\";\n /** Process environment. */ environment: NodeJS.ProcessEnv;\n /** Progress sink, or undefined for a quiet build. */ output:\n ((text: string) => void) | undefined;\n}\n\n/** Android APK result, without desktop launcher or CEF fields. */\nexport interface MuonAndroidApplicationResult {\n /** Target discriminator. */ readonly target: \"android\";\n /** Absolute APK path. */ readonly packagePath: string;\n /** Generated Gradle project for diagnostics. */ readonly projectDirectory: string;\n /** Android variant. */ readonly variant: \"debug\" | \"release\";\n /** Included native ABIs. */ readonly abis: readonly MuonAndroidAbi[];\n /** Application identifier. */ readonly applicationId: string;\n /** Update version. */ readonly versionCode: number;\n /** Display version. */ readonly versionName: string;\n /** Actual signing state. */ readonly signing:\n \"debug\" | \"unsigned\" | \"release\";\n}\n\nconst xml = (value: string): string =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&apos;\");\n\nconst render = async (\n template: string,\n variables: ReadonlyMap<string, unknown>,\n): Promise<string> => {\n const logs: FunCityLogEntry[] = [];\n const value = await runScriptOnceToText(await readFile(template, \"utf8\"), {\n sourceId: template,\n variables,\n logs,\n });\n if (value === undefined || logs.some((log) => log.type === \"error\")) {\n throw new Error(\n `Cannot render Android template ${template}: ${JSON.stringify(logs)}`,\n );\n }\n return value;\n};\n\n/**\n * Builds a self-contained APK from the shipped AAR and prebuilt web assets.\n * @param input - Explicit application, artifact and toolchain inputs.\n * @returns The APK path and its actual variant/signing state.\n * @remarks Does not run Vite, compile native code or infer a repository root.\n */\nexport const buildAndroidApplication = async (\n input: MuonAndroidApplicationInput,\n): Promise<MuonAndroidApplicationResult> => {\n const tools = await prepareAndroid({\n componentsDirectory: input.componentsDirectory,\n sdkPath: input.sdkPath,\n environment: input.environment,\n prepareGradle: false,\n });\n const project = resolve(input.projectDirectory);\n const assetRelative = relative(resolve(input.assetsDirectory), project);\n if (\n assetRelative === \"\" ||\n (!assetRelative.startsWith(\"..\") && !isAbsolute(assetRelative))\n ) {\n throw new Error(\n \"The generated Android project must be outside the web assets directory.\",\n );\n }\n if (\n isAbsolute(input.assetPath) ||\n input.assetPath\n .split(/[\\\\/]/u)\n .some((part) => part === \"..\" || part === \"muon\")\n ) {\n throw new Error(\n \"Android assetPath must be relative and must not use the reserved muon directory.\",\n );\n }\n await rm(project, { recursive: true, force: true });\n await cp(join(tools.componentsDirectory, \"templates\"), project, {\n recursive: true,\n });\n await chmod(join(project, \"gradlew\"), 0o755);\n const assets = join(project, \"app/src/main/assets\");\n await mkdir(assets, { recursive: true });\n await cp(input.assetsDirectory, join(assets, input.assetPath), {\n recursive: true,\n dereference: true,\n });\n const frameworkAssets = join(assets, \"muon\");\n try {\n await stat(frameworkAssets);\n throw new Error(\"Web assets must not contain the reserved muon directory.\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n await mkdir(frameworkAssets, { recursive: true });\n await cp(\n join(tools.componentsDirectory, \"licenses\"),\n join(frameworkAssets, \"licenses\"),\n { recursive: true },\n );\n await copyFile(\n join(tools.componentsDirectory, \"renderer/renderer.js\"),\n join(frameworkAssets, \"renderer.js\"),\n );\n await writeFile(\n join(frameworkAssets, \"config.json\"),\n JSON.stringify({\n startPage: input.startPage,\n values: input.values,\n plugin: input.pluginAccess,\n }),\n );\n await writeFile(\n join(frameworkAssets, \"plugins.json\"),\n JSON.stringify({\n schemaVersion: 1,\n plugins: input.plugins.map(\n ({ name, soname, allow, config, expectedFunctions }) => ({\n name,\n soname,\n allow,\n config,\n ...(expectedFunctions === undefined ? {} : { expectedFunctions }),\n }),\n ),\n }),\n );\n for (const plugin of input.plugins) {\n for (const abi of input.abis) {\n const library = plugin.libraries[abi];\n if (!library)\n throw new Error(`${plugin.name} is missing its ${abi} library.`);\n const destination = join(\n project,\n \"app/src/main/jniLibs\",\n abi,\n plugin.soname,\n );\n await mkdir(dirname(destination), { recursive: true });\n await copyFile(library, destination);\n for (const dependency of plugin.dependencies?.[abi] ?? [])\n await copyFile(\n dependency,\n join(dirname(destination), basename(dependency)),\n );\n }\n }\n await writeFile(\n join(project, \"muon-build.json\"),\n JSON.stringify(\n {\n ...tools.toolchain,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n abis: input.abis,\n maven: pathToFileURL(join(tools.componentsDirectory, \"maven\")).href,\n },\n null,\n 2,\n ),\n );\n await writeFile(\n join(project, \"app/src/main/AndroidManifest.xml\"),\n await render(\n join(project, \"AndroidManifest.xml.fc\"),\n new Map([[\"permissions\", input.permissions.map(xml)]]),\n ),\n );\n const resources = join(project, \"app/src/main/res\");\n await mkdir(join(resources, \"values\"), { recursive: true });\n await writeFile(\n join(resources, \"values/strings.xml\"),\n await render(\n join(project, \"strings.xml.fc\"),\n new Map([\n [\n \"label\",\n xml(input.label.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll('\"', '\\\\\"')),\n ],\n ]),\n ),\n );\n if (input.icon !== undefined) {\n await rm(join(resources, \"mipmap/ic_launcher.xml\"));\n await copyFile(input.icon, join(resources, \"mipmap/ic_launcher.png\"));\n }\n await runAndroidCommand(\n join(project, \"gradlew\"),\n [\n \"--no-daemon\",\n \"--console=plain\",\n input.variant === \"debug\" ? \":app:assembleDebug\" : \":app:assembleRelease\",\n ],\n project,\n {\n ...input.environment,\n ANDROID_HOME: tools.sdkPath,\n ANDROID_SDK_ROOT: tools.sdkPath,\n },\n input.output,\n );\n const name =\n input.variant === \"debug\" ? \"app-debug.apk\" : \"app-release-unsigned.apk\";\n const packagePath = join(\n resolve(input.outputDirectory),\n `${input.applicationId}-${input.versionCode}-${input.variant}.apk`,\n );\n await mkdir(dirname(packagePath), { recursive: true });\n await copyFile(\n join(project, \"app/build/outputs/apk\", input.variant, name),\n packagePath,\n );\n const result: MuonAndroidApplicationResult = {\n target: \"android\",\n packagePath,\n projectDirectory: project,\n variant: input.variant,\n abis: input.abis,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n signing: input.variant === \"debug\" ? \"debug\" : \"unsigned\",\n };\n await writeFile(\n `${packagePath}.json`,\n JSON.stringify(result, null, 2) + \"\\n\",\n );\n return result;\n};\n"],"mappings":"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"}
@@ -1,20 +1,20 @@
1
1
  /*!
2
- * name: muon-android
3
- * version: 0.26.0
4
- * description: Shared Android runtime and build components for muon-ui.
2
+ * name: muon-ui
3
+ * version: 0.26.47
4
+ * description: A multi-platform GUI application framework that uses CEF as its backend
5
5
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
6
  * license: MIT
7
7
  * repository.url: https://github.com/kekyo/muon-ui.git
8
- * git.commit.hash: 4bceacb2bf609778560407d23f4cba0e36315098
8
+ * git.commit.hash: 95dc2712686873c8a022483fd9abf18598019bd7
9
9
  */
10
10
  import { access, chmod, copyFile, cp, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
11
- import { delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
11
+ import { basename, delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
12
12
  import { pathToFileURL } from "node:url";
13
13
  import { runScriptOnceToText } from "funcity";
14
14
  import { spawn } from "node:child_process";
15
15
  import { constants } from "node:fs";
16
16
  import { homedir } from "node:os";
17
- //#region src/command.ts
17
+ //#region android/command.ts
18
18
  /**
19
19
  * Runs a build tool without a shell and awaits process completion.
20
20
  * @param command - Executable path.
@@ -49,7 +49,7 @@ var runAndroidCommand = async (command, args, cwd, environment, output) => await
49
49
  });
50
50
  });
51
51
  //#endregion
52
- //#region src/toolchain.ts
52
+ //#region android/toolchain.ts
53
53
  var accessible = async (path, mode) => {
54
54
  try {
55
55
  await access(path, mode);
@@ -108,7 +108,7 @@ var prepareAndroid = async (options) => {
108
108
  };
109
109
  };
110
110
  //#endregion
111
- //#region src/build.ts
111
+ //#region android/build.ts
112
112
  var xml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
113
113
  var render = async (template, variables) => {
114
114
  const logs = [];
@@ -161,15 +161,17 @@ var buildAndroidApplication = async (input) => {
161
161
  await copyFile(join(tools.componentsDirectory, "renderer/renderer.js"), join(frameworkAssets, "renderer.js"));
162
162
  await writeFile(join(frameworkAssets, "config.json"), JSON.stringify({
163
163
  startPage: input.startPage,
164
- values: input.values
164
+ values: input.values,
165
+ plugin: input.pluginAccess
165
166
  }));
166
167
  await writeFile(join(frameworkAssets, "plugins.json"), JSON.stringify({
167
168
  schemaVersion: 1,
168
- plugins: input.plugins.map(({ name, soname, allow, config }) => ({
169
+ plugins: input.plugins.map(({ name, soname, allow, config, expectedFunctions }) => ({
169
170
  name,
170
171
  soname,
171
172
  allow,
172
- config
173
+ config,
174
+ ...expectedFunctions === void 0 ? {} : { expectedFunctions }
173
175
  }))
174
176
  }));
175
177
  for (const plugin of input.plugins) for (const abi of input.abis) {
@@ -178,6 +180,7 @@ var buildAndroidApplication = async (input) => {
178
180
  const destination = join(project, "app/src/main/jniLibs", abi, plugin.soname);
179
181
  await mkdir(dirname(destination), { recursive: true });
180
182
  await copyFile(library, destination);
183
+ for (const dependency of plugin.dependencies?.[abi] ?? []) await copyFile(dependency, join(dirname(destination), basename(dependency)));
181
184
  }
182
185
  await writeFile(join(project, "muon-build.json"), JSON.stringify({
183
186
  ...tools.toolchain,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/command.ts","../../src/toolchain.ts","../../src/build.ts"],"sourcesContent":["// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { spawn } from 'node:child_process';\n\n/**\n * Runs a build tool without a shell and awaits process completion.\n * @param command - Executable path.\n * @param args - Literal argument vector.\n * @param cwd - Working directory.\n * @param environment - Child environment, including any external credentials.\n * @param output - Optional progress sink; undefined captures output only.\n * @returns Captured standard output and standard error.\n */\nexport const runAndroidCommand = async (\n command: string,\n args: readonly string[],\n cwd: string,\n environment: NodeJS.ProcessEnv,\n output: ((text: string) => void) | undefined\n): Promise<string> =>\n await new Promise<string>((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n env: environment,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let captured = '';\n const receive = (chunk: Buffer) => {\n const text = chunk.toString();\n captured += text;\n output?.(text);\n };\n child.stdout.on('data', receive);\n child.stderr.on('data', receive);\n child.once('error', reject);\n child.once('close', (code, signal) => {\n if (code === 0) resolve(captured);\n else\n reject(\n new Error(`${command} failed (${signal ?? code}):\\n${captured}`)\n );\n });\n });\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { constants } from 'node:fs';\nimport { access, mkdir, readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { delimiter, dirname, join, resolve } from 'node:path';\nimport { runAndroidCommand } from './command.js';\n\n/** Versions fixed by the shipped Android component set. */\nexport interface MuonAndroidToolchain {\n /** Exact Android SDK platform package directory. */ readonly platform: string;\n /** Component schema. */ readonly schemaVersion: 1;\n /** Android Gradle plugin version. */ readonly agp: string;\n /** Wrapper version. */ readonly gradle: string;\n /** API used for compilation. */ readonly compileSdk: number;\n /** API targeted by generated applications. */ readonly targetSdk: number;\n /** Minimum installation API; see documented verification range. */ readonly minSdk: number;\n /** Required SDK Build Tools version. */ readonly buildTools: string;\n /** Minimum JDK runtime version. */ readonly javaMin: number;\n /** Highest supported JDK runtime version. */ readonly javaMax: number;\n /** Version of dev.muon:runtime. */ readonly runtimeVersion: string;\n /** ABIs included in the standard runtime. */ readonly abis: readonly string[];\n}\n\n/** Inputs for the Android environment diagnostic. */\nexport interface MuonAndroidPrepareOptions {\n /** Directory containing templates, maven, renderer and toolchain.json. */ componentsDirectory: string;\n /** Explicit SDK location, otherwise resolved from the environment or adb. */ sdkPath:\n string | undefined;\n /** Child environment. */ environment: NodeJS.ProcessEnv;\n /** Whether to download/verify the pinned Gradle distribution using its Wrapper. */ prepareGradle: boolean;\n}\n\n/** Validated tools for an Android build; no NDK or CMake is needed. */\nexport interface MuonAndroidPrepareResult {\n /** Discriminates Android from desktop preparation. */ readonly target: 'android';\n /** Absolute SDK directory. */ readonly sdkPath: string;\n /** Detected JDK major version. */ readonly javaVersion: number;\n /** Absolute Java executable. */ readonly javaPath: string;\n /** Shipped version requirements. */ readonly toolchain: MuonAndroidToolchain;\n /** Component directory used for this build. */ readonly componentsDirectory: string;\n}\n\nconst accessible = async (path: string, mode: number): Promise<boolean> => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n};\n\nconst findExecutable = async (\n name: string,\n environment: NodeJS.ProcessEnv\n): Promise<string | undefined> => {\n for (const directory of (environment.PATH ?? '')\n .split(delimiter)\n .filter(Boolean)) {\n const path = join(directory, name);\n if (await accessible(path, constants.X_OK)) return path;\n }\n return undefined;\n};\n\n/**\n * Diagnoses a Linux x64 SDK/JDK installation and optionally prepares Gradle.\n * @param options - Component location, SDK override and process environment.\n * @returns Validated tool paths and pinned versions.\n * @remarks Does not install SDK packages, accept licenses, or require a device.\n */\nexport const prepareAndroid = async (\n options: MuonAndroidPrepareOptions\n): Promise<MuonAndroidPrepareResult> => {\n if (process.platform !== 'linux' || process.arch !== 'x64') {\n throw new Error('Android builds currently support Linux x64 hosts.');\n }\n const componentsDirectory = resolve(options.componentsDirectory);\n const toolchain = JSON.parse(\n await readFile(join(componentsDirectory, 'toolchain.json'), 'utf8')\n ) as MuonAndroidToolchain;\n if (toolchain.schemaVersion !== 1)\n throw new Error('Unsupported Muon Android toolchain schema.');\n const adb = await findExecutable('adb', options.environment);\n const candidate =\n options.sdkPath ??\n options.environment.ANDROID_HOME ??\n options.environment.ANDROID_SDK_ROOT ??\n (adb === undefined ? undefined : dirname(dirname(adb)));\n if (!candidate)\n throw new Error(\n 'Android SDK not found. Set ANDROID_HOME or android.sdkPath.'\n );\n const sdkPath = resolve(candidate);\n for (const [file, packageName] of [\n [\n `platforms/${toolchain.platform}/android.jar`,\n `platforms;${toolchain.platform}`,\n ],\n ...['aapt2', 'zipalign', 'apksigner'].map((name) => [\n `build-tools/${toolchain.buildTools}/${name}`,\n `build-tools;${toolchain.buildTools}`,\n ]),\n ]) {\n if (!(await accessible(join(sdkPath, file!), constants.R_OK))) {\n throw new Error(\n `Android SDK ${sdkPath} is missing ${packageName}. Install this package using the Android CLI: android sdk install '${packageName}'. See https://developer.android.com/tools/agents/android-cli/commands/sdk`\n );\n }\n }\n const platformProperties = await readFile(\n join(sdkPath, 'platforms', toolchain.platform, 'source.properties'),\n 'utf8'\n );\n if (\n Number(\n /^AndroidVersion.ApiLevel\\s*=\\s*(\\S+)/mu.exec(platformProperties)?.[1]\n ) !== toolchain.compileSdk\n ) {\n throw new Error(\n `Android SDK platform version differs from the required API ${toolchain.compileSdk}: ${sdkPath}`\n );\n }\n const buildProperties = await readFile(\n join(sdkPath, 'build-tools', toolchain.buildTools, 'source.properties'),\n 'utf8'\n );\n if (\n /^Pkg.Revision\\s*=\\s*(\\S+)/mu.exec(buildProperties)?.[1] !==\n toolchain.buildTools\n ) {\n throw new Error(\n `Android SDK Build Tools version differs from ${toolchain.buildTools}: ${sdkPath}`\n );\n }\n const javaPath = options.environment.JAVA_HOME\n ? join(options.environment.JAVA_HOME, 'bin/java')\n : await findExecutable('java', options.environment);\n if (!javaPath || !(await accessible(javaPath, constants.X_OK))) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required. Set JAVA_HOME or add java to PATH.`\n );\n }\n const versionText = await runAndroidCommand(\n javaPath,\n ['-version'],\n componentsDirectory,\n options.environment,\n undefined\n );\n const javaVersion = Number(\n /(?:openjdk|java) version \"(\\d+)[.\"]/u.exec(versionText)?.[1]\n );\n if (\n !Number.isInteger(javaVersion) ||\n javaVersion < toolchain.javaMin ||\n javaVersion > toolchain.javaMax\n ) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required; detected ${versionText.trim()}.`\n );\n }\n if (options.prepareGradle) {\n const cache = join(homedir(), '.cache/muon/android', toolchain.gradle);\n await mkdir(cache, { recursive: true });\n const result = await runAndroidCommand(\n join(componentsDirectory, 'templates/gradlew'),\n ['--version'],\n cache,\n options.environment,\n undefined\n );\n if (!result.includes(`Gradle ${toolchain.gradle}`))\n throw new Error(\n 'Gradle Wrapper version differs from the shipped toolchain.'\n );\n }\n return {\n target: 'android',\n sdkPath,\n javaVersion,\n javaPath,\n toolchain,\n componentsDirectory,\n };\n};\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport {\n chmod,\n copyFile,\n cp,\n mkdir,\n readFile,\n rm,\n stat,\n writeFile,\n} from 'node:fs/promises';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { runScriptOnceToText, type FunCityLogEntry } from 'funcity';\nimport { runAndroidCommand } from './command.js';\nimport { prepareAndroid } from './toolchain.js';\n\n/** ABI shipped by the Muon Android runtime. */\nexport type MuonAndroidAbi = 'arm64-v8a' | 'x86_64';\n\n/** Normalized package-owned plugin entry. */\nexport interface MuonAndroidPackagedPlugin {\n /** Logical capability name. */ readonly name: string;\n /** Packaged ELF soname. */ readonly soname: string;\n /** Explicitly allowed public function patterns. */ readonly allow: readonly string[];\n /** Application-owned plugin configuration. */ readonly config: readonly {\n readonly key: string;\n readonly value: string;\n }[];\n /** Absolute prebuilt library path for each selected ABI. */ readonly libraries: Readonly<\n Partial<Record<MuonAndroidAbi, string>>\n >;\n}\n\n/** Explicit inputs used by the Android package builder. */\nexport interface MuonAndroidApplicationInput {\n /** Packaged Muon Android components. */ componentsDirectory: string;\n /** Directory containing previously built web assets. */ assetsDirectory: string;\n /** Relative URL path prefix under the trusted asset host. */ assetPath: string;\n /** Trusted HTTPS entry URL. */ startPage: string;\n /** Application identifier independent of Muon's Java namespace. */ applicationId: string;\n /** Launcher label. */ label: string;\n /** Monotonic Android update number. */ versionCode: number;\n /** User-facing version. */ versionName: string;\n /** Selected runtime ABIs. */ abis: readonly MuonAndroidAbi[];\n /** Manifest permissions, already normalized by the public build boundary. */ permissions: readonly string[];\n /** Values returned by muon.environments.getConfigValues. */ values: Readonly<\n Record<string, string>\n >;\n /** Explicit prebuilt plugins; an empty array builds a standard app. */ plugins: readonly MuonAndroidPackagedPlugin[];\n /** Optional PNG icon already converted by the public build boundary. */ icon:\n string | undefined;\n /** Owned directory for generated Gradle sources and intermediates. */ projectDirectory: string;\n /** Destination for APKs and result metadata. */ outputDirectory: string;\n /** SDK override. */ sdkPath: string | undefined;\n /** Debug package or unsigned release package. */ variant:\n 'debug' | 'release';\n /** Process environment. */ environment: NodeJS.ProcessEnv;\n /** Progress sink, or undefined for a quiet build. */ output:\n ((text: string) => void) | undefined;\n}\n\n/** Android APK result, without desktop launcher or CEF fields. */\nexport interface MuonAndroidApplicationResult {\n /** Target discriminator. */ readonly target: 'android';\n /** Absolute APK path. */ readonly packagePath: string;\n /** Generated Gradle project for diagnostics. */ readonly projectDirectory: string;\n /** Android variant. */ readonly variant: 'debug' | 'release';\n /** Included native ABIs. */ readonly abis: readonly MuonAndroidAbi[];\n /** Application identifier. */ readonly applicationId: string;\n /** Update version. */ readonly versionCode: number;\n /** Display version. */ readonly versionName: string;\n /** Actual signing state. */ readonly signing:\n 'debug' | 'unsigned' | 'release';\n}\n\nconst xml = (value: string): string =>\n value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;');\n\nconst render = async (\n template: string,\n variables: ReadonlyMap<string, unknown>\n): Promise<string> => {\n const logs: FunCityLogEntry[] = [];\n const value = await runScriptOnceToText(await readFile(template, 'utf8'), {\n sourceId: template,\n variables,\n logs,\n });\n if (value === undefined || logs.some((log) => log.type === 'error')) {\n throw new Error(\n `Cannot render Android template ${template}: ${JSON.stringify(logs)}`\n );\n }\n return value;\n};\n\n/**\n * Builds a self-contained APK from the shipped AAR and prebuilt web assets.\n * @param input - Explicit application, artifact and toolchain inputs.\n * @returns The APK path and its actual variant/signing state.\n * @remarks Does not run Vite, compile native code or infer a repository root.\n */\nexport const buildAndroidApplication = async (\n input: MuonAndroidApplicationInput\n): Promise<MuonAndroidApplicationResult> => {\n const tools = await prepareAndroid({\n componentsDirectory: input.componentsDirectory,\n sdkPath: input.sdkPath,\n environment: input.environment,\n prepareGradle: false,\n });\n const project = resolve(input.projectDirectory);\n const assetRelative = relative(resolve(input.assetsDirectory), project);\n if (\n assetRelative === '' ||\n (!assetRelative.startsWith('..') && !isAbsolute(assetRelative))\n ) {\n throw new Error(\n 'The generated Android project must be outside the web assets directory.'\n );\n }\n if (\n isAbsolute(input.assetPath) ||\n input.assetPath\n .split(/[\\\\/]/u)\n .some((part) => part === '..' || part === 'muon')\n ) {\n throw new Error(\n 'Android assetPath must be relative and must not use the reserved muon directory.'\n );\n }\n await rm(project, { recursive: true, force: true });\n await cp(join(tools.componentsDirectory, 'templates'), project, {\n recursive: true,\n });\n await chmod(join(project, 'gradlew'), 0o755);\n const assets = join(project, 'app/src/main/assets');\n await mkdir(assets, { recursive: true });\n await cp(input.assetsDirectory, join(assets, input.assetPath), {\n recursive: true,\n dereference: true,\n });\n const frameworkAssets = join(assets, 'muon');\n try {\n await stat(frameworkAssets);\n throw new Error('Web assets must not contain the reserved muon directory.');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n }\n await mkdir(frameworkAssets, { recursive: true });\n await cp(\n join(tools.componentsDirectory, 'licenses'),\n join(frameworkAssets, 'licenses'),\n { recursive: true }\n );\n await copyFile(\n join(tools.componentsDirectory, 'renderer/renderer.js'),\n join(frameworkAssets, 'renderer.js')\n );\n await writeFile(\n join(frameworkAssets, 'config.json'),\n JSON.stringify({ startPage: input.startPage, values: input.values })\n );\n await writeFile(\n join(frameworkAssets, 'plugins.json'),\n JSON.stringify({\n schemaVersion: 1,\n plugins: input.plugins.map(({ name, soname, allow, config }) => ({\n name,\n soname,\n allow,\n config,\n })),\n })\n );\n for (const plugin of input.plugins) {\n for (const abi of input.abis) {\n const library = plugin.libraries[abi];\n if (!library)\n throw new Error(`${plugin.name} is missing its ${abi} library.`);\n const destination = join(\n project,\n 'app/src/main/jniLibs',\n abi,\n plugin.soname\n );\n await mkdir(dirname(destination), { recursive: true });\n await copyFile(library, destination);\n }\n }\n await writeFile(\n join(project, 'muon-build.json'),\n JSON.stringify(\n {\n ...tools.toolchain,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n abis: input.abis,\n maven: pathToFileURL(join(tools.componentsDirectory, 'maven')).href,\n },\n null,\n 2\n )\n );\n await writeFile(\n join(project, 'app/src/main/AndroidManifest.xml'),\n await render(\n join(project, 'AndroidManifest.xml.fc'),\n new Map([['permissions', input.permissions.map(xml)]])\n )\n );\n const resources = join(project, 'app/src/main/res');\n await mkdir(join(resources, 'values'), { recursive: true });\n await writeFile(\n join(resources, 'values/strings.xml'),\n await render(\n join(project, 'strings.xml.fc'),\n new Map([\n [\n 'label',\n xml(input.label.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"')),\n ],\n ])\n )\n );\n if (input.icon !== undefined) {\n await rm(join(resources, 'mipmap/ic_launcher.xml'));\n await copyFile(input.icon, join(resources, 'mipmap/ic_launcher.png'));\n }\n await runAndroidCommand(\n join(project, 'gradlew'),\n [\n '--no-daemon',\n '--console=plain',\n input.variant === 'debug' ? ':app:assembleDebug' : ':app:assembleRelease',\n ],\n project,\n {\n ...input.environment,\n ANDROID_HOME: tools.sdkPath,\n ANDROID_SDK_ROOT: tools.sdkPath,\n },\n input.output\n );\n const name =\n input.variant === 'debug' ? 'app-debug.apk' : 'app-release-unsigned.apk';\n const packagePath = join(\n resolve(input.outputDirectory),\n `${input.applicationId}-${input.versionCode}-${input.variant}.apk`\n );\n await mkdir(dirname(packagePath), { recursive: true });\n await copyFile(\n join(project, 'app/build/outputs/apk', input.variant, name),\n packagePath\n );\n const result: MuonAndroidApplicationResult = {\n target: 'android',\n packagePath,\n projectDirectory: project,\n variant: input.variant,\n abis: input.abis,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n signing: input.variant === 'debug' ? 'debug' : 'unsigned',\n };\n await writeFile(\n `${packagePath}.json`,\n JSON.stringify(result, null, 2) + '\\n'\n );\n return result;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../android/command.ts","../../android/toolchain.ts","../../android/build.ts"],"sourcesContent":["// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { spawn } from \"node:child_process\";\n\n/**\n * Runs a build tool without a shell and awaits process completion.\n * @param command - Executable path.\n * @param args - Literal argument vector.\n * @param cwd - Working directory.\n * @param environment - Child environment, including any external credentials.\n * @param output - Optional progress sink; undefined captures output only.\n * @returns Captured standard output and standard error.\n */\nexport const runAndroidCommand = async (\n command: string,\n args: readonly string[],\n cwd: string,\n environment: NodeJS.ProcessEnv,\n output: ((text: string) => void) | undefined,\n): Promise<string> =>\n await new Promise<string>((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n env: environment,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n let captured = \"\";\n const receive = (chunk: Buffer) => {\n const text = chunk.toString();\n captured += text;\n output?.(text);\n };\n child.stdout.on(\"data\", receive);\n child.stderr.on(\"data\", receive);\n child.once(\"error\", reject);\n child.once(\"close\", (code, signal) => {\n if (code === 0) resolve(captured);\n else\n reject(\n new Error(`${command} failed (${signal ?? code}):\\n${captured}`),\n );\n });\n });\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport { constants } from \"node:fs\";\nimport { access, mkdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { delimiter, dirname, join, resolve } from \"node:path\";\nimport { runAndroidCommand } from \"./command.js\";\n\n/** Versions fixed by the shipped Android component set. */\nexport interface MuonAndroidToolchain {\n /** Exact Android SDK platform package directory. */ readonly platform: string;\n /** Component schema. */ readonly schemaVersion: 1;\n /** Android Gradle plugin version. */ readonly agp: string;\n /** Wrapper version. */ readonly gradle: string;\n /** API used for compilation. */ readonly compileSdk: number;\n /** API targeted by generated applications. */ readonly targetSdk: number;\n /** Minimum installation API; see documented verification range. */ readonly minSdk: number;\n /** Required SDK Build Tools version. */ readonly buildTools: string;\n /** Minimum JDK runtime version. */ readonly javaMin: number;\n /** Highest supported JDK runtime version. */ readonly javaMax: number;\n /** Version of dev.muon:runtime. */ readonly runtimeVersion: string;\n /** ABIs included in the standard runtime. */ readonly abis: readonly string[];\n}\n\n/** Inputs for the Android environment diagnostic. */\nexport interface MuonAndroidPrepareOptions {\n /** Directory containing templates, maven, renderer and toolchain.json. */ componentsDirectory: string;\n /** Explicit SDK location, otherwise resolved from the environment or adb. */ sdkPath:\n string | undefined;\n /** Child environment. */ environment: NodeJS.ProcessEnv;\n /** Whether to download/verify the pinned Gradle distribution using its Wrapper. */ prepareGradle: boolean;\n}\n\n/** Validated tools for an Android build; no NDK or CMake is needed. */\nexport interface MuonAndroidPrepareResult {\n /** Discriminates Android from desktop preparation. */ readonly target: \"android\";\n /** Absolute SDK directory. */ readonly sdkPath: string;\n /** Detected JDK major version. */ readonly javaVersion: number;\n /** Absolute Java executable. */ readonly javaPath: string;\n /** Shipped version requirements. */ readonly toolchain: MuonAndroidToolchain;\n /** Component directory used for this build. */ readonly componentsDirectory: string;\n}\n\nconst accessible = async (path: string, mode: number): Promise<boolean> => {\n try {\n await access(path, mode);\n return true;\n } catch {\n return false;\n }\n};\n\nconst findExecutable = async (\n name: string,\n environment: NodeJS.ProcessEnv,\n): Promise<string | undefined> => {\n for (const directory of (environment.PATH ?? \"\")\n .split(delimiter)\n .filter(Boolean)) {\n const path = join(directory, name);\n if (await accessible(path, constants.X_OK)) return path;\n }\n return undefined;\n};\n\n/**\n * Diagnoses a Linux x64 SDK/JDK installation and optionally prepares Gradle.\n * @param options - Component location, SDK override and process environment.\n * @returns Validated tool paths and pinned versions.\n * @remarks Does not install SDK packages, accept licenses, or require a device.\n */\nexport const prepareAndroid = async (\n options: MuonAndroidPrepareOptions,\n): Promise<MuonAndroidPrepareResult> => {\n if (process.platform !== \"linux\" || process.arch !== \"x64\") {\n throw new Error(\"Android builds currently support Linux x64 hosts.\");\n }\n const componentsDirectory = resolve(options.componentsDirectory);\n const toolchain = JSON.parse(\n await readFile(join(componentsDirectory, \"toolchain.json\"), \"utf8\"),\n ) as MuonAndroidToolchain;\n if (toolchain.schemaVersion !== 1)\n throw new Error(\"Unsupported Muon Android toolchain schema.\");\n const adb = await findExecutable(\"adb\", options.environment);\n const candidate =\n options.sdkPath ??\n options.environment.ANDROID_HOME ??\n options.environment.ANDROID_SDK_ROOT ??\n (adb === undefined ? undefined : dirname(dirname(adb)));\n if (!candidate)\n throw new Error(\n \"Android SDK not found. Set ANDROID_HOME or android.sdkPath.\",\n );\n const sdkPath = resolve(candidate);\n for (const [file, packageName] of [\n [\n `platforms/${toolchain.platform}/android.jar`,\n `platforms;${toolchain.platform}`,\n ],\n ...[\"aapt2\", \"zipalign\", \"apksigner\"].map((name) => [\n `build-tools/${toolchain.buildTools}/${name}`,\n `build-tools;${toolchain.buildTools}`,\n ]),\n ]) {\n if (!(await accessible(join(sdkPath, file!), constants.R_OK))) {\n throw new Error(\n `Android SDK ${sdkPath} is missing ${packageName}. Install this package using the Android CLI: android sdk install '${packageName}'. See https://developer.android.com/tools/agents/android-cli/commands/sdk`,\n );\n }\n }\n const platformProperties = await readFile(\n join(sdkPath, \"platforms\", toolchain.platform, \"source.properties\"),\n \"utf8\",\n );\n if (\n Number(\n /^AndroidVersion.ApiLevel\\s*=\\s*(\\S+)/mu.exec(platformProperties)?.[1],\n ) !== toolchain.compileSdk\n ) {\n throw new Error(\n `Android SDK platform version differs from the required API ${toolchain.compileSdk}: ${sdkPath}`,\n );\n }\n const buildProperties = await readFile(\n join(sdkPath, \"build-tools\", toolchain.buildTools, \"source.properties\"),\n \"utf8\",\n );\n if (\n /^Pkg.Revision\\s*=\\s*(\\S+)/mu.exec(buildProperties)?.[1] !==\n toolchain.buildTools\n ) {\n throw new Error(\n `Android SDK Build Tools version differs from ${toolchain.buildTools}: ${sdkPath}`,\n );\n }\n const javaPath = options.environment.JAVA_HOME\n ? join(options.environment.JAVA_HOME, \"bin/java\")\n : await findExecutable(\"java\", options.environment);\n if (!javaPath || !(await accessible(javaPath, constants.X_OK))) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required. Set JAVA_HOME or add java to PATH.`,\n );\n }\n const versionText = await runAndroidCommand(\n javaPath,\n [\"-version\"],\n componentsDirectory,\n options.environment,\n undefined,\n );\n const javaVersion = Number(\n /(?:openjdk|java) version \"(\\d+)[.\"]/u.exec(versionText)?.[1],\n );\n if (\n !Number.isInteger(javaVersion) ||\n javaVersion < toolchain.javaMin ||\n javaVersion > toolchain.javaMax\n ) {\n throw new Error(\n `JDK ${toolchain.javaMin}–${toolchain.javaMax} is required; detected ${versionText.trim()}.`,\n );\n }\n if (options.prepareGradle) {\n const cache = join(homedir(), \".cache/muon/android\", toolchain.gradle);\n await mkdir(cache, { recursive: true });\n const result = await runAndroidCommand(\n join(componentsDirectory, \"templates/gradlew\"),\n [\"--version\"],\n cache,\n options.environment,\n undefined,\n );\n if (!result.includes(`Gradle ${toolchain.gradle}`))\n throw new Error(\n \"Gradle Wrapper version differs from the shipped toolchain.\",\n );\n }\n return {\n target: \"android\",\n sdkPath,\n javaVersion,\n javaPath,\n toolchain,\n componentsDirectory,\n };\n};\n","// muon - Multi-platform GUI application framework that uses CEF as its backend\n// Copyright (c) Kouji Matsui. (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/muon-ui\n\nimport {\n chmod,\n copyFile,\n cp,\n mkdir,\n readFile,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport {\n basename,\n dirname,\n isAbsolute,\n join,\n relative,\n resolve,\n} from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { runScriptOnceToText, type FunCityLogEntry } from \"funcity\";\nimport { runAndroidCommand } from \"./command.js\";\nimport { prepareAndroid } from \"./toolchain.js\";\n\n/** ABI shipped by the Muon Android runtime. */\nexport type MuonAndroidAbi = \"arm64-v8a\" | \"x86_64\";\n\n/** Package-owned plugin exposure and built-in function policy. */\nexport type MuonAndroidPluginAccess = {\n /** Whether the trusted main frame may use the bridge. */ readonly enabled: boolean;\n /** Allowed built-in public function paths. */ readonly internalAllow: readonly string[];\n} & (\n | { /** Global API exposure mode. */ readonly mode: \"simple\" }\n | {\n /** Virtual-module exposure mode. */ readonly mode: \"validate\";\n /** Capabilities generated by the same build as the application bundle. */ readonly capabilities: readonly {\n /** Opaque capability id. */ readonly id: string;\n /** Allowed public function paths. */ readonly allow: readonly string[];\n }[];\n }\n);\n\n/** Normalized package-owned plugin entry. */\nexport interface MuonAndroidPackagedPlugin {\n /** Ordinary shared libraries copied beside the plugin for each ABI. */ readonly dependencies?: Readonly<\n Partial<Record<MuonAndroidAbi, readonly string[]>>\n >;\n /** Logical capability name. */ readonly name: string;\n /** Packaged ELF soname. */ readonly soname: string;\n /** Explicitly allowed public function patterns. */ readonly allow: readonly string[];\n /** Producer catalog after applying the allow policy, checked when loading. */ readonly expectedFunctions?: readonly string[];\n /** Application-owned plugin configuration. */ readonly config: readonly {\n readonly key: string;\n readonly value: string;\n }[];\n /** Absolute prebuilt library path for each selected ABI. */ readonly libraries: Readonly<\n Partial<Record<MuonAndroidAbi, string>>\n >;\n}\n\n/** Explicit inputs used by the Android package builder. */\nexport interface MuonAndroidApplicationInput {\n /** Packaged Muon Android components. */ componentsDirectory: string;\n /** Directory containing previously built web assets. */ assetsDirectory: string;\n /** Relative URL path prefix under the trusted asset host. */ assetPath: string;\n /** Trusted HTTPS entry URL. */ startPage: string;\n /** Application identifier independent of Muon's Java namespace. */ applicationId: string;\n /** Launcher label. */ label: string;\n /** Monotonic Android update number. */ versionCode: number;\n /** User-facing version. */ versionName: string;\n /** Selected runtime ABIs. */ abis: readonly MuonAndroidAbi[];\n /** Manifest permissions, already normalized by the public build boundary. */ permissions: readonly string[];\n /** Values returned by muon.environments.getConfigValues. */ values: Readonly<\n Record<string, string>\n >;\n /** Explicit prebuilt plugins; an empty array builds a standard app. */ plugins: readonly MuonAndroidPackagedPlugin[];\n /** Validated common plugin access settings. */ pluginAccess: MuonAndroidPluginAccess;\n /** Optional PNG icon already converted by the public build boundary. */ icon:\n string | undefined;\n /** Owned directory for generated Gradle sources and intermediates. */ projectDirectory: string;\n /** Destination for APKs and result metadata. */ outputDirectory: string;\n /** SDK override. */ sdkPath: string | undefined;\n /** Debug package or unsigned release package. */ variant:\n \"debug\" | \"release\";\n /** Process environment. */ environment: NodeJS.ProcessEnv;\n /** Progress sink, or undefined for a quiet build. */ output:\n ((text: string) => void) | undefined;\n}\n\n/** Android APK result, without desktop launcher or CEF fields. */\nexport interface MuonAndroidApplicationResult {\n /** Target discriminator. */ readonly target: \"android\";\n /** Absolute APK path. */ readonly packagePath: string;\n /** Generated Gradle project for diagnostics. */ readonly projectDirectory: string;\n /** Android variant. */ readonly variant: \"debug\" | \"release\";\n /** Included native ABIs. */ readonly abis: readonly MuonAndroidAbi[];\n /** Application identifier. */ readonly applicationId: string;\n /** Update version. */ readonly versionCode: number;\n /** Display version. */ readonly versionName: string;\n /** Actual signing state. */ readonly signing:\n \"debug\" | \"unsigned\" | \"release\";\n}\n\nconst xml = (value: string): string =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&apos;\");\n\nconst render = async (\n template: string,\n variables: ReadonlyMap<string, unknown>,\n): Promise<string> => {\n const logs: FunCityLogEntry[] = [];\n const value = await runScriptOnceToText(await readFile(template, \"utf8\"), {\n sourceId: template,\n variables,\n logs,\n });\n if (value === undefined || logs.some((log) => log.type === \"error\")) {\n throw new Error(\n `Cannot render Android template ${template}: ${JSON.stringify(logs)}`,\n );\n }\n return value;\n};\n\n/**\n * Builds a self-contained APK from the shipped AAR and prebuilt web assets.\n * @param input - Explicit application, artifact and toolchain inputs.\n * @returns The APK path and its actual variant/signing state.\n * @remarks Does not run Vite, compile native code or infer a repository root.\n */\nexport const buildAndroidApplication = async (\n input: MuonAndroidApplicationInput,\n): Promise<MuonAndroidApplicationResult> => {\n const tools = await prepareAndroid({\n componentsDirectory: input.componentsDirectory,\n sdkPath: input.sdkPath,\n environment: input.environment,\n prepareGradle: false,\n });\n const project = resolve(input.projectDirectory);\n const assetRelative = relative(resolve(input.assetsDirectory), project);\n if (\n assetRelative === \"\" ||\n (!assetRelative.startsWith(\"..\") && !isAbsolute(assetRelative))\n ) {\n throw new Error(\n \"The generated Android project must be outside the web assets directory.\",\n );\n }\n if (\n isAbsolute(input.assetPath) ||\n input.assetPath\n .split(/[\\\\/]/u)\n .some((part) => part === \"..\" || part === \"muon\")\n ) {\n throw new Error(\n \"Android assetPath must be relative and must not use the reserved muon directory.\",\n );\n }\n await rm(project, { recursive: true, force: true });\n await cp(join(tools.componentsDirectory, \"templates\"), project, {\n recursive: true,\n });\n await chmod(join(project, \"gradlew\"), 0o755);\n const assets = join(project, \"app/src/main/assets\");\n await mkdir(assets, { recursive: true });\n await cp(input.assetsDirectory, join(assets, input.assetPath), {\n recursive: true,\n dereference: true,\n });\n const frameworkAssets = join(assets, \"muon\");\n try {\n await stat(frameworkAssets);\n throw new Error(\"Web assets must not contain the reserved muon directory.\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n await mkdir(frameworkAssets, { recursive: true });\n await cp(\n join(tools.componentsDirectory, \"licenses\"),\n join(frameworkAssets, \"licenses\"),\n { recursive: true },\n );\n await copyFile(\n join(tools.componentsDirectory, \"renderer/renderer.js\"),\n join(frameworkAssets, \"renderer.js\"),\n );\n await writeFile(\n join(frameworkAssets, \"config.json\"),\n JSON.stringify({\n startPage: input.startPage,\n values: input.values,\n plugin: input.pluginAccess,\n }),\n );\n await writeFile(\n join(frameworkAssets, \"plugins.json\"),\n JSON.stringify({\n schemaVersion: 1,\n plugins: input.plugins.map(\n ({ name, soname, allow, config, expectedFunctions }) => ({\n name,\n soname,\n allow,\n config,\n ...(expectedFunctions === undefined ? {} : { expectedFunctions }),\n }),\n ),\n }),\n );\n for (const plugin of input.plugins) {\n for (const abi of input.abis) {\n const library = plugin.libraries[abi];\n if (!library)\n throw new Error(`${plugin.name} is missing its ${abi} library.`);\n const destination = join(\n project,\n \"app/src/main/jniLibs\",\n abi,\n plugin.soname,\n );\n await mkdir(dirname(destination), { recursive: true });\n await copyFile(library, destination);\n for (const dependency of plugin.dependencies?.[abi] ?? [])\n await copyFile(\n dependency,\n join(dirname(destination), basename(dependency)),\n );\n }\n }\n await writeFile(\n join(project, \"muon-build.json\"),\n JSON.stringify(\n {\n ...tools.toolchain,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n abis: input.abis,\n maven: pathToFileURL(join(tools.componentsDirectory, \"maven\")).href,\n },\n null,\n 2,\n ),\n );\n await writeFile(\n join(project, \"app/src/main/AndroidManifest.xml\"),\n await render(\n join(project, \"AndroidManifest.xml.fc\"),\n new Map([[\"permissions\", input.permissions.map(xml)]]),\n ),\n );\n const resources = join(project, \"app/src/main/res\");\n await mkdir(join(resources, \"values\"), { recursive: true });\n await writeFile(\n join(resources, \"values/strings.xml\"),\n await render(\n join(project, \"strings.xml.fc\"),\n new Map([\n [\n \"label\",\n xml(input.label.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll('\"', '\\\\\"')),\n ],\n ]),\n ),\n );\n if (input.icon !== undefined) {\n await rm(join(resources, \"mipmap/ic_launcher.xml\"));\n await copyFile(input.icon, join(resources, \"mipmap/ic_launcher.png\"));\n }\n await runAndroidCommand(\n join(project, \"gradlew\"),\n [\n \"--no-daemon\",\n \"--console=plain\",\n input.variant === \"debug\" ? \":app:assembleDebug\" : \":app:assembleRelease\",\n ],\n project,\n {\n ...input.environment,\n ANDROID_HOME: tools.sdkPath,\n ANDROID_SDK_ROOT: tools.sdkPath,\n },\n input.output,\n );\n const name =\n input.variant === \"debug\" ? \"app-debug.apk\" : \"app-release-unsigned.apk\";\n const packagePath = join(\n resolve(input.outputDirectory),\n `${input.applicationId}-${input.versionCode}-${input.variant}.apk`,\n );\n await mkdir(dirname(packagePath), { recursive: true });\n await copyFile(\n join(project, \"app/build/outputs/apk\", input.variant, name),\n packagePath,\n );\n const result: MuonAndroidApplicationResult = {\n target: \"android\",\n packagePath,\n projectDirectory: project,\n variant: input.variant,\n abis: input.abis,\n applicationId: input.applicationId,\n versionCode: input.versionCode,\n versionName: input.versionName,\n signing: input.variant === \"debug\" ? \"debug\" : \"unsigned\",\n };\n await writeFile(\n `${packagePath}.json`,\n JSON.stringify(result, null, 2) + \"\\n\",\n );\n return result;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- aee96550696d84ca26ae9b95e3e00536
1
+ ec2aada440f7f82924173e3e9a8d4898
@@ -1 +1 @@
1
- 9a8824dd7e81babc908c3b4d9d886465f6f2a4d8
1
+ 83e540bc7727f775531f4fcdb1110808226ae9bf
@@ -1 +1 @@
1
- 9f62fb631a7511f4bc79a98cf7065670476d48a10d3768f86c8d67b6a158705e
1
+ 90bd0cbd4cd0155dbcb227221488527a75222f73d2ca6f17a13f07876947fa3f
@@ -1 +1 @@
1
- 31c812c1873fdd746baf28cb0ed44551379dc7ca917e234aa78904601013b642c6f7989603a3a2542328e1a9b5e3f23c828c523793baaf0b7f60b3ce039c42d7
1
+ bbb84b6bbe52de655c11f765aafa4c32ee2f41a8c5854574925cd94a7beed9575b209d93eb015be81d4c1316416ac2bf66c2ebfd304f51ea72222a570bdf1a59
@@ -35,11 +35,11 @@
35
35
  {
36
36
  "name": "runtime-0.1.0.aar",
37
37
  "url": "runtime-0.1.0.aar",
38
- "size": 1508548,
39
- "sha512": "31c812c1873fdd746baf28cb0ed44551379dc7ca917e234aa78904601013b642c6f7989603a3a2542328e1a9b5e3f23c828c523793baaf0b7f60b3ce039c42d7",
40
- "sha256": "9f62fb631a7511f4bc79a98cf7065670476d48a10d3768f86c8d67b6a158705e",
41
- "sha1": "9a8824dd7e81babc908c3b4d9d886465f6f2a4d8",
42
- "md5": "aee96550696d84ca26ae9b95e3e00536"
38
+ "size": 1514484,
39
+ "sha512": "bbb84b6bbe52de655c11f765aafa4c32ee2f41a8c5854574925cd94a7beed9575b209d93eb015be81d4c1316416ac2bf66c2ebfd304f51ea72222a570bdf1a59",
40
+ "sha256": "90bd0cbd4cd0155dbcb227221488527a75222f73d2ca6f17a13f07876947fa3f",
41
+ "sha1": "83e540bc7727f775531f4fcdb1110808226ae9bf",
42
+ "md5": "ec2aada440f7f82924173e3e9a8d4898"
43
43
  }
44
44
  ]
45
45
  },
@@ -78,11 +78,11 @@
78
78
  {
79
79
  "name": "runtime-0.1.0.aar",
80
80
  "url": "runtime-0.1.0.aar",
81
- "size": 1508548,
82
- "sha512": "31c812c1873fdd746baf28cb0ed44551379dc7ca917e234aa78904601013b642c6f7989603a3a2542328e1a9b5e3f23c828c523793baaf0b7f60b3ce039c42d7",
83
- "sha256": "9f62fb631a7511f4bc79a98cf7065670476d48a10d3768f86c8d67b6a158705e",
84
- "sha1": "9a8824dd7e81babc908c3b4d9d886465f6f2a4d8",
85
- "md5": "aee96550696d84ca26ae9b95e3e00536"
81
+ "size": 1514484,
82
+ "sha512": "bbb84b6bbe52de655c11f765aafa4c32ee2f41a8c5854574925cd94a7beed9575b209d93eb015be81d4c1316416ac2bf66c2ebfd304f51ea72222a570bdf1a59",
83
+ "sha256": "90bd0cbd4cd0155dbcb227221488527a75222f73d2ca6f17a13f07876947fa3f",
84
+ "sha1": "83e540bc7727f775531f4fcdb1110808226ae9bf",
85
+ "md5": "ec2aada440f7f82924173e3e9a8d4898"
86
86
  }
87
87
  ]
88
88
  }
@@ -1 +1 @@
1
- 2743fab95a05cd28473cf04375b43b88
1
+ 2caeaa47aa8dcf6e50624b478248e365
@@ -1 +1 @@
1
- 5af3c10ecdab3905dd9836c7c0cad63dc4c1c4c6
1
+ bdde7fec7bfbe6e525a4ef2862fa0ac42adae9e0
@@ -1 +1 @@
1
- f1de07260c2ac565f587aff946dbc4b6388201d5de67ca6edb5ea9ccf76a2ae7
1
+ 6d545342f96722f52829002ff6c087764f57e96e8ecb1d91e13b4b77a21753d5
@@ -1 +1 @@
1
- 51f184e3fad49e16dec0231b2775d8aeb42a080503e45981f948c23985dbf9aea5467d39574d5bfa685819e3763a94fa4d571a3ac8d84b920282dc782b525bd5
1
+ d99dc7b310fe3b03fdc239edbab862b68e6298a526251e6cc2bc2fc8fc277a3ecc88c4bea5f0e59471f94513159d835d83df3a9438b2cb49baa13d9ec879ccd6
@@ -8,6 +8,6 @@
8
8
  <versions>
9
9
  <version>0.1.0</version>
10
10
  </versions>
11
- <lastUpdated>20261007202904</lastUpdated>
11
+ <lastUpdated>20261012020911</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- cdaf4e82ecf5b65ee1a834ae4e374756
1
+ 1a0231530bbaa768a6ef67192d06eb60
@@ -1 +1 @@
1
- af0ad570657d0abb49d2b57ab6ee92c558a0c481
1
+ f9c1fbf3690b2ed6c67b7c7d1cc6da71541913f9
@@ -1 +1 @@
1
- 5acce75771fb0fc38ea59ff0998690d3bd94d4b48290ea8b801af3ebb1b8a6c4
1
+ edfde4230e7c0d84c574eae6c7e5df4f6587935b6305213bac4b648059bc02ab
@@ -1 +1 @@
1
- 69e4dc4c18da7aa9e4ce225a2e585ff467d0489ff84a77a2719625567ed26bcf3561eec0f84c6cbb0e0e5667f75e4b688c05ee6a0f5dad5faeb090f87e1665a1
1
+ 5415dc9cdbd48bc56f7a8474642eed83fd8d20933550c5a8089e202e026a67d0b56f3c96c2a875c22922c36fc90107e51435b8010338848c10d32b579807e30b