@oniroproject/core 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -180,6 +180,7 @@ var ALL_SDKS = [
180
180
  { version: "7.0", api: "26", tarballStrip: { linuxWindows: 1, darwin: 3 }, archiveSuffix: "_20260829" }
181
181
  ];
182
182
  var OHOS_URL_BASE = "https://repo.huaweicloud.com/openharmony/os";
183
+ var OHOS_DAILY_BUILDS_URL = "https://dcp.openharmony.cn/workbench/cicd/dailybuild/dailylist";
183
184
 
184
185
  // src/sdk/platform.ts
185
186
  import * as os2 from "os";
@@ -762,8 +763,17 @@ async function extractZipWithProgress(opts) {
762
763
  if (inc > 0) progress.report({ message: "Extracting: 100%", increment: inc });
763
764
  }
764
765
  }
765
- async function extractTarball(tarPath, dest, strip = 0) {
766
- await tar.x({ file: tarPath, cwd: dest, strip });
766
+ async function extractTarball(tarPath, dest, strip = 0, filter) {
767
+ await tar.x({ file: tarPath, cwd: dest, strip, ...filter ? { filter: (p) => filter(p) } : {} });
768
+ }
769
+ async function readZipEntry(zipPath, match) {
770
+ const zip = new StreamZip.async({ file: zipPath });
771
+ try {
772
+ const entry = Object.values(await zip.entries()).find((e) => !e.isDirectory && match(e.name));
773
+ return entry ? await zip.entryData(entry) : void 0;
774
+ } finally {
775
+ await zip.close();
776
+ }
767
777
  }
768
778
 
769
779
  // src/sdk/list.ts
@@ -869,34 +879,7 @@ async function downloadAndInstallSdk(opts) {
869
879
  `Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`
870
880
  );
871
881
  }
872
- const zipFiles = fs10.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
873
- const componentsStart = 60;
874
- const componentsBudget = 35;
875
- const n = zipFiles.length;
876
- if (n === 0) {
877
- progress?.report({ message: "No SDK component ZIPs found.", increment: componentsBudget });
878
- } else {
879
- progress?.report({ message: "Extracting SDK components...", increment: 0 });
880
- }
881
- const base = n > 0 ? Math.floor(componentsBudget / n) : 0;
882
- let rem = n > 0 ? componentsBudget % n : 0;
883
- let cursor = componentsStart;
884
- for (const zipFile of zipFiles) {
885
- checkCancelled();
886
- logger.info(`Extracting component ${zipFile}`);
887
- const zipPath = path10.join(osContentPath, zipFile);
888
- const thisBudget = base + (rem > 0 ? 1 : 0);
889
- if (rem > 0) rem--;
890
- await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
891
- cursor += thisBudget;
892
- fs10.unlinkSync(zipPath);
893
- }
894
- progress?.report({ message: "Finalizing installation...", increment: 0 });
895
- if (fs10.existsSync(sdkInstallDir)) {
896
- fs10.rmSync(sdkInstallDir, { recursive: true, force: true });
897
- }
898
- movePath(osContentPath, sdkInstallDir);
899
- progress?.report({ message: "Finalizing installation...", increment: 3 });
882
+ await installComponents({ osContentPath, sdkInstallDir, progress, logger, start: 60, range: 35, checkCancelled });
900
883
  progress?.report({ message: "Cleaning up...", increment: 0 });
901
884
  removeTempWorkDir(tmpDir, tmpRoot);
902
885
  progress?.report({ message: "Cleaning up...", increment: 2 });
@@ -907,6 +890,115 @@ async function downloadAndInstallSdk(opts) {
907
890
  throw wrapped;
908
891
  }
909
892
  }
893
+ async function installComponents(opts) {
894
+ const { osContentPath, sdkInstallDir, progress, logger, checkCancelled } = opts;
895
+ const zipFiles = fs10.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
896
+ const n = zipFiles.length;
897
+ if (n === 0) {
898
+ progress?.report({ message: "No SDK component ZIPs found.", increment: opts.range });
899
+ } else {
900
+ progress?.report({ message: "Extracting SDK components...", increment: 0 });
901
+ }
902
+ const base = n > 0 ? Math.floor(opts.range / n) : 0;
903
+ let rem = n > 0 ? opts.range % n : 0;
904
+ let cursor = opts.start;
905
+ for (const zipFile of zipFiles) {
906
+ checkCancelled();
907
+ logger.info(`Extracting component ${zipFile}`);
908
+ const zipPath = path10.join(osContentPath, zipFile);
909
+ const thisBudget = base + (rem > 0 ? 1 : 0);
910
+ if (rem > 0) rem--;
911
+ await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
912
+ cursor += thisBudget;
913
+ fs10.unlinkSync(zipPath);
914
+ }
915
+ progress?.report({ message: "Finalizing installation...", increment: 0 });
916
+ if (fs10.existsSync(sdkInstallDir)) {
917
+ fs10.rmSync(sdkInstallDir, { recursive: true, force: true });
918
+ }
919
+ movePath(osContentPath, sdkInstallDir);
920
+ progress?.report({ message: "Finalizing installation...", increment: 3 });
921
+ }
922
+ async function installSdkFromArchive(opts) {
923
+ const { config, archivePath, progress, abortSignal } = opts;
924
+ const logger = opts.logger ?? noopLogger;
925
+ if (!fs10.statSync(archivePath, { throwIfNoEntry: false })?.isFile()) {
926
+ throw new OniroError(`SDK archive not found: ${archivePath}`);
927
+ }
928
+ const osFolder = getOsFolder();
929
+ const what = `the SDK install from '${path10.basename(archivePath)}'`;
930
+ const sdkRoot = getSdkRootDir(config);
931
+ const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
932
+ config,
933
+ override: opts.tmpDir,
934
+ installRoot: sdkRoot,
935
+ prefix: "oniro-sdk-",
936
+ logger
937
+ });
938
+ const extractDir = path10.join(tmpDir, "extract");
939
+ fs10.mkdirSync(extractDir);
940
+ const checkCancelled = () => {
941
+ if (abortSignal?.aborted) throw new CancelledError();
942
+ };
943
+ try {
944
+ progress?.report({ message: "Extracting SDK archive (this may take a while)...", increment: 0 });
945
+ await extractTarball(archivePath, extractDir, 0, (p) => p.split("/").includes(osFolder));
946
+ progress?.report({ message: "Extracting SDK archive (this may take a while)...", increment: 40 });
947
+ checkCancelled();
948
+ const osContentPath = findSdkOsDir(extractDir, osFolder);
949
+ if (!osContentPath) {
950
+ throw new OniroError(
951
+ `No '${osFolder}' SDK components (a '${osFolder}' folder of ZIPs) found in ${archivePath}. Is it an OpenHarmony SDK archive for this OS?`
952
+ );
953
+ }
954
+ const { api, version } = await readSdkComponentsMeta(osContentPath);
955
+ const sdkInstallDir = path10.join(sdkRoot, osFolder, api);
956
+ if (fs10.existsSync(sdkInstallDir) && !opts.force) {
957
+ throw new OniroError(
958
+ `An SDK for api ${api} is already installed at ${sdkInstallDir}; pass --force to replace it with this archive, or set ONIRO_SDK_ROOT_DIR to install it in a separate SDK root.`
959
+ );
960
+ }
961
+ fs10.mkdirSync(path10.dirname(sdkInstallDir), { recursive: true });
962
+ await installComponents({ osContentPath, sdkInstallDir, progress, logger, start: 40, range: 55, checkCancelled });
963
+ progress?.report({ message: "Cleaning up...", increment: 0 });
964
+ removeTempWorkDir(tmpDir, tmpRoot);
965
+ progress?.report({ message: "Cleaning up...", increment: 2 });
966
+ return { api, version, dir: sdkInstallDir };
967
+ } catch (err) {
968
+ removeTempWorkDir(tmpDir, tmpRoot);
969
+ throw toSpaceError(err, tmpRoot, what);
970
+ }
971
+ }
972
+ function findSdkOsDir(root, osFolder, maxDepth = 4) {
973
+ let level = [root];
974
+ for (let depth = 0; depth < maxDepth && level.length > 0; depth++) {
975
+ const next = [];
976
+ for (const dir of level) {
977
+ for (const entry of fs10.readdirSync(dir, { withFileTypes: true })) {
978
+ if (!entry.isDirectory()) continue;
979
+ const p = path10.join(dir, entry.name);
980
+ if (entry.name === osFolder && fs10.readdirSync(p).some((n) => n.endsWith(".zip"))) return p;
981
+ next.push(p);
982
+ }
983
+ }
984
+ level = next;
985
+ }
986
+ return void 0;
987
+ }
988
+ async function readSdkComponentsMeta(dir) {
989
+ const zips = fs10.readdirSync(dir).filter((n) => n.endsWith(".zip")).sort((a, b) => Number(b.startsWith("ets-")) - Number(a.startsWith("ets-")));
990
+ for (const name of zips) {
991
+ const data = await readZipEntry(path10.join(dir, name), (e) => /^[^/]+\/oh-uni-package\.json$/.test(e));
992
+ if (!data) continue;
993
+ try {
994
+ const pkg = JSON.parse(data.toString("utf8"));
995
+ const api = String(pkg.apiVersion ?? "");
996
+ if (/^\d+$/.test(api)) return { api, version: String(pkg.version ?? "") };
997
+ } catch {
998
+ }
999
+ }
1000
+ throw new OniroError("No SDK component in the archive declares a numeric apiVersion (oh-uni-package.json).");
1001
+ }
910
1002
 
911
1003
  // src/cmdTools/install.ts
912
1004
  import * as fs11 from "fs";
@@ -2194,9 +2286,13 @@ function moduleOfHap(hapFileName) {
2194
2286
  const dash = hapFileName.indexOf("-");
2195
2287
  return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
2196
2288
  }
2289
+ function isAppProjectRoot(dir) {
2290
+ return fs17.existsSync(path18.join(dir, "AppScope", "app.json5"));
2291
+ }
2197
2292
  async function discoverHaps(opts) {
2198
2293
  const { projectDir } = opts;
2199
2294
  const maxDepth = opts.maxDepth ?? 8;
2295
+ const skipNestedProjects = isAppProjectRoot(projectDir);
2200
2296
  const result = {};
2201
2297
  const walk = async (dir, depth) => {
2202
2298
  if (depth > maxDepth) return;
@@ -2205,6 +2301,7 @@ async function discoverHaps(opts) {
2205
2301
  const full = path18.join(dir, e.name);
2206
2302
  if (e.isDirectory()) {
2207
2303
  if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
2304
+ if (skipNestedProjects && isAppProjectRoot(full)) continue;
2208
2305
  await walk(full, depth + 1);
2209
2306
  } else if (e.isFile() && e.name.endsWith(".hap")) {
2210
2307
  const moduleName = moduleOfHap(e.name);
@@ -3396,6 +3493,54 @@ async function resolveProcessId(config, bundle, deviceSerial) {
3396
3493
  const proc = await findRunningProcess({ config, bundle, deviceSerial });
3397
3494
  return proc?.pid;
3398
3495
  }
3496
+ async function readDeviceClock(config, deviceSerial) {
3497
+ try {
3498
+ const res = await shell({ config, command: "date +%Y-%m-%dT%H:%M:%S", deviceSerial, timeoutMs: 1e4 });
3499
+ const m = res.code === 0 ? /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/.exec(res.stdout) : null;
3500
+ if (!m) return null;
3501
+ const [year, month, day, hour, minute, second] = m.slice(1).map(Number);
3502
+ return Date.UTC(year, month - 1, day, hour, minute, second);
3503
+ } catch {
3504
+ return null;
3505
+ }
3506
+ }
3507
+ function hilogTimeMs(time, referenceMs) {
3508
+ const m = /^(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.(\d{3})$/.exec(time);
3509
+ if (!m) return null;
3510
+ const [month, day, hour, minute, second, ms] = m.slice(1).map(Number);
3511
+ const year = new Date(referenceMs).getUTCFullYear();
3512
+ let best = null;
3513
+ for (const y of [year - 1, year, year + 1]) {
3514
+ const t = Date.UTC(y, month - 1, day, hour, minute, second, ms);
3515
+ if (best === null || Math.abs(t - referenceMs) < Math.abs(best - referenceMs)) best = t;
3516
+ }
3517
+ return best;
3518
+ }
3519
+ async function recentEntryFilter(opts) {
3520
+ const passAll = { test: () => true, afterReconnect: async () => {
3521
+ } };
3522
+ const lookbackMs = opts.lookbackMs ?? 0;
3523
+ if (lookbackMs === Infinity) return passAll;
3524
+ const startedAt = Date.now();
3525
+ const now = await readDeviceClock(opts.config, opts.deviceSerial);
3526
+ if (now === null) {
3527
+ opts.logger.warn("Could not read the device clock, so lines already in the log buffer can match too.");
3528
+ return passAll;
3529
+ }
3530
+ let since = now - (Date.now() - startedAt) - lookbackMs;
3531
+ return {
3532
+ test: (entry) => {
3533
+ if (since === null) return true;
3534
+ const t = hilogTimeMs(entry.time, now);
3535
+ return t === null || t >= since;
3536
+ },
3537
+ afterReconnect: async () => {
3538
+ if (since === null) return;
3539
+ const later = await readDeviceClock(opts.config, opts.deviceSerial);
3540
+ if (later !== null && later < since) since = null;
3541
+ }
3542
+ };
3543
+ }
3399
3544
  function waitForLog(opts) {
3400
3545
  return new Promise((resolve7, reject) => {
3401
3546
  const deadline = Date.now() + opts.timeoutMs;
@@ -3403,6 +3548,8 @@ function waitForLog(opts) {
3403
3548
  let child = null;
3404
3549
  let reconnectTimer;
3405
3550
  let buf = "";
3551
+ let recent = { test: () => true, afterReconnect: async () => {
3552
+ } };
3406
3553
  const cleanup = () => {
3407
3554
  clearTimeout(timer);
3408
3555
  if (reconnectTimer) clearTimeout(reconnectTimer);
@@ -3443,7 +3590,7 @@ function waitForLog(opts) {
3443
3590
  buf = lines.pop() ?? "";
3444
3591
  for (const line of lines) {
3445
3592
  const entry = parseHilogLine(line);
3446
- if (entry && opts.pattern.test(entryText(entry))) {
3593
+ if (entry && recent.test(entry) && opts.pattern.test(entryText(entry))) {
3447
3594
  finish(entry);
3448
3595
  return;
3449
3596
  }
@@ -3453,13 +3600,21 @@ function waitForLog(opts) {
3453
3600
  if (settled || child !== stream) return;
3454
3601
  child = null;
3455
3602
  if (Date.now() < deadline) {
3456
- reconnectTimer = setTimeout(() => void spawnStream().catch(failWith), 1e3);
3603
+ reconnectTimer = setTimeout(() => void recent.afterReconnect().then(spawnStream).catch(failWith), 1e3);
3457
3604
  }
3458
3605
  };
3459
3606
  stream.once("close", onEnd);
3460
3607
  stream.once("error", onEnd);
3461
3608
  };
3462
- void spawnStream().catch(failWith);
3609
+ void (async () => {
3610
+ recent = await recentEntryFilter({
3611
+ config: opts.config,
3612
+ deviceSerial: opts.deviceSerial,
3613
+ lookbackMs: opts.lookbackMs,
3614
+ logger: opts.logger ?? noopLogger
3615
+ });
3616
+ await spawnStream();
3617
+ })().catch(failWith);
3463
3618
  });
3464
3619
  }
3465
3620
  function watchLog(opts) {
@@ -3468,6 +3623,8 @@ function watchLog(opts) {
3468
3623
  let settled = false;
3469
3624
  let child = null;
3470
3625
  let buf = "";
3626
+ let recent = { test: () => true, afterReconnect: async () => {
3627
+ } };
3471
3628
  const cleanup = () => {
3472
3629
  clearTimeout(timer);
3473
3630
  opts.abortSignal?.removeEventListener("abort", onAbort);
@@ -3491,6 +3648,13 @@ function watchLog(opts) {
3491
3648
  const timer = setTimeout(done, opts.durationMs);
3492
3649
  opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
3493
3650
  void (async () => {
3651
+ recent = await recentEntryFilter({
3652
+ config: opts.config,
3653
+ deviceSerial: opts.deviceSerial,
3654
+ lookbackMs: opts.lookbackMs,
3655
+ logger: opts.logger ?? noopLogger
3656
+ });
3657
+ if (settled) return;
3494
3658
  const processId = await resolveProcessId(opts.config, opts.bundle, opts.deviceSerial);
3495
3659
  if (settled) return;
3496
3660
  const stream = streamHilog({ config: opts.config, processId, domain: opts.domain, deviceSerial: opts.deviceSerial });
@@ -3501,7 +3665,7 @@ function watchLog(opts) {
3501
3665
  buf = lines.pop() ?? "";
3502
3666
  for (const line of lines) {
3503
3667
  const entry = parseHilogLine(line);
3504
- if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);
3668
+ if (entry && recent.test(entry) && opts.pattern.test(entryText(entry))) matches.push(entry);
3505
3669
  }
3506
3670
  });
3507
3671
  })().catch((err) => {
@@ -3786,6 +3950,8 @@ async function ensureOhModules(opts) {
3786
3950
  }
3787
3951
 
3788
3952
  // src/build/codelinter.ts
3953
+ import * as fs26 from "fs";
3954
+ import * as path26 from "path";
3789
3955
  var FINDING_RE = /^(.*?):(\d+):(?:(\d+):)?\s*(error|warning|warn|suggestion|info)\b[:\s-]*(.*)$/i;
3790
3956
  var TRAILING_CODE_RE = /[([]([\w@/.\-]+)[)\]]\s*$/;
3791
3957
  var FILE_HEADER_RE = /^(.+\.\w+)\((\d+)\)$/;
@@ -3872,6 +4038,16 @@ function parseCodelinterReport(output) {
3872
4038
  function parseCodelinterFindings(output) {
3873
4039
  return parseCodelinterReport(output).findings;
3874
4040
  }
4041
+ var PROJECT_ROOT_FILES = [
4042
+ ["build-profile.json5"],
4043
+ ["hvigorfile.ts", "hvigorfile.js"],
4044
+ [path26.join("hvigor", "hvigor-config.json5")]
4045
+ ];
4046
+ function missingProjectRootFiles(projectDir) {
4047
+ return PROJECT_ROOT_FILES.filter((names) => !names.some((f) => fs26.existsSync(path26.join(projectDir, f)))).map(
4048
+ (names) => names[0]
4049
+ );
4050
+ }
3875
4051
  async function runCodelinter(opts) {
3876
4052
  const res = await runProcess({
3877
4053
  command: getCmdToolsBin(opts.config, "codelinter"),
@@ -3889,7 +4065,7 @@ async function runCodelinter(opts) {
3889
4065
  var DIAGNOSIS_OUTPUT_LIMIT = 2e6;
3890
4066
  function diagnoseBuildFailure(output) {
3891
4067
  if (/is not exported from Kit|has no exported member .*@systemapi/i.test(output)) {
3892
- return "The project calls system APIs (`@systemapi`), which the public SDK leaves out. Build against the full OpenHarmony SDK: unpack its components into <root>/<os>/<api> of a separate SDK root and set ONIRO_SDK_ROOT_DIR to that root. Installing such an app also needs privileged signing (`oniro-app sign --apl system_core --acls \u2026 --app-privilege-capabilities \u2026`).";
4068
+ return `The project calls system APIs (\`@systemapi\`), which the public SDK leaves out. Build against the full OpenHarmony SDK: download an \`ohos-sdk-full\` archive from ${OHOS_DAILY_BUILDS_URL} and install it with \`oniro-app sdk install --from-archive <archive> --force\` (this replaces the public SDK of that API level; set ONIRO_SDK_ROOT_DIR to keep the two apart). Installing such an app also needs privileged signing (\`oniro-app sign --apl system_core --acls \u2026 --app-privilege-capabilities \u2026\`).`;
3893
4069
  }
3894
4070
  if (/00308018|SDK path does not exist|SDK license agreement is not accepted/i.test(output)) {
3895
4071
  return "hvigor cannot find the SDK the project compiles against: check `oniro-app sdk list` against compileSdkVersion.";
@@ -3961,21 +4137,21 @@ function isValidBundleName(bundleName) {
3961
4137
  }
3962
4138
 
3963
4139
  // src/project/templates.ts
3964
- import * as fs26 from "fs";
3965
- import * as path26 from "path";
4140
+ import * as fs27 from "fs";
4141
+ import * as path27 from "path";
3966
4142
  function toHumanTemplateName(folderName) {
3967
4143
  return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
3968
4144
  }
3969
4145
  function listTemplates(templateRoot) {
3970
- if (!fs26.existsSync(templateRoot)) return [];
3971
- const entries = fs26.readdirSync(templateRoot, { withFileTypes: true });
4146
+ if (!fs27.existsSync(templateRoot)) return [];
4147
+ const entries = fs27.readdirSync(templateRoot, { withFileTypes: true });
3972
4148
  return entries.filter((e) => e.isDirectory()).map((e) => {
3973
- const dir = path26.join(templateRoot, e.name);
3974
- const metaPath = path26.join(dir, "template.json");
4149
+ const dir = path27.join(templateRoot, e.name);
4150
+ const metaPath = path27.join(dir, "template.json");
3975
4151
  let meta = {};
3976
- if (fs26.existsSync(metaPath)) {
4152
+ if (fs27.existsSync(metaPath)) {
3977
4153
  try {
3978
- meta = JSON.parse(fs26.readFileSync(metaPath, "utf8"));
4154
+ meta = JSON.parse(fs27.readFileSync(metaPath, "utf8"));
3979
4155
  } catch {
3980
4156
  }
3981
4157
  }
@@ -3990,57 +4166,57 @@ function listTemplates(templateRoot) {
3990
4166
  function validateTemplateLayout(templateDir, defaultModuleName) {
3991
4167
  const required = [
3992
4168
  "build-profile.json5",
3993
- path26.join("AppScope", "app.json5"),
3994
- path26.join(defaultModuleName, "src", "main", "module.json5"),
3995
- path26.join(defaultModuleName, "oh-package.json5"),
4169
+ path27.join("AppScope", "app.json5"),
4170
+ path27.join(defaultModuleName, "src", "main", "module.json5"),
4171
+ path27.join(defaultModuleName, "oh-package.json5"),
3996
4172
  "hvigorfile.ts"
3997
4173
  ];
3998
- return required.filter((rel) => !fs26.existsSync(path26.join(templateDir, rel)));
4174
+ return required.filter((rel) => !fs27.existsSync(path27.join(templateDir, rel)));
3999
4175
  }
4000
4176
 
4001
4177
  // src/project/createScaffold.ts
4002
- import * as fs28 from "fs";
4003
- import * as path27 from "path";
4178
+ import * as fs29 from "fs";
4179
+ import * as path28 from "path";
4004
4180
 
4005
4181
  // src/project/jsonHelpers.ts
4006
- import * as fs27 from "fs";
4182
+ import * as fs28 from "fs";
4007
4183
  import JSON55 from "json5";
4008
4184
  function readJson5File(filePath) {
4009
- return JSON55.parse(fs27.readFileSync(filePath, "utf8"));
4185
+ return JSON55.parse(fs28.readFileSync(filePath, "utf8"));
4010
4186
  }
4011
4187
  function writeJson5File(filePath, value) {
4012
- fs27.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
4188
+ fs28.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
4013
4189
  }
4014
4190
  function readJsonFile(filePath) {
4015
- return JSON.parse(fs27.readFileSync(filePath, "utf8"));
4191
+ return JSON.parse(fs28.readFileSync(filePath, "utf8"));
4016
4192
  }
4017
4193
  function writeJsonFile(filePath, value) {
4018
- fs27.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
4194
+ fs28.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
4019
4195
  }
4020
4196
 
4021
4197
  // src/project/createScaffold.ts
4022
4198
  var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
4023
4199
  async function pathExists(p) {
4024
4200
  try {
4025
- await fs28.promises.access(p);
4201
+ await fs29.promises.access(p);
4026
4202
  return true;
4027
4203
  } catch {
4028
4204
  return false;
4029
4205
  }
4030
4206
  }
4031
4207
  async function copyDirRecursive(srcDir, destDir) {
4032
- await fs28.promises.mkdir(destDir, { recursive: true });
4033
- const entries = await fs28.promises.readdir(srcDir, { withFileTypes: true });
4208
+ await fs29.promises.mkdir(destDir, { recursive: true });
4209
+ const entries = await fs29.promises.readdir(srcDir, { withFileTypes: true });
4034
4210
  for (const entry of entries) {
4035
- const src = path27.join(srcDir, entry.name);
4036
- const dest = path27.join(destDir, entry.name);
4211
+ const src = path28.join(srcDir, entry.name);
4212
+ const dest = path28.join(destDir, entry.name);
4037
4213
  if (entry.isDirectory()) {
4038
4214
  await copyDirRecursive(src, dest);
4039
4215
  } else if (entry.isSymbolicLink()) {
4040
4216
  continue;
4041
4217
  } else if (entry.isFile()) {
4042
4218
  if (entry.name === "template.json") continue;
4043
- await fs28.promises.copyFile(src, dest);
4219
+ await fs29.promises.copyFile(src, dest);
4044
4220
  }
4045
4221
  }
4046
4222
  }
@@ -4048,9 +4224,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
4048
4224
  const stack = [projectDir];
4049
4225
  while (stack.length > 0) {
4050
4226
  const currentDir = stack.pop();
4051
- const entries = await fs28.promises.readdir(currentDir, { withFileTypes: true });
4227
+ const entries = await fs29.promises.readdir(currentDir, { withFileTypes: true });
4052
4228
  for (const entry of entries) {
4053
- const fullPath = path27.join(currentDir, entry.name);
4229
+ const fullPath = path28.join(currentDir, entry.name);
4054
4230
  if (entry.isDirectory()) {
4055
4231
  if (IGNORED_DIRS.has(entry.name)) continue;
4056
4232
  stack.push(fullPath);
@@ -4072,23 +4248,23 @@ function toJavaPropertiesPath(p) {
4072
4248
  function createOrUpdateLocalProperties(projectDir, sdkDir) {
4073
4249
  const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
4074
4250
  `;
4075
- fs28.writeFileSync(path27.join(projectDir, "local.properties"), content, "utf8");
4251
+ fs29.writeFileSync(path28.join(projectDir, "local.properties"), content, "utf8");
4076
4252
  }
4077
4253
  function renameIfExists(fromPath, toPath) {
4078
- if (fs28.existsSync(fromPath) && fromPath !== toPath) {
4079
- fs28.renameSync(fromPath, toPath);
4254
+ if (fs29.existsSync(fromPath) && fromPath !== toPath) {
4255
+ fs29.renameSync(fromPath, toPath);
4080
4256
  }
4081
4257
  }
4082
4258
  function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
4083
- const appJsonPath = path27.join(projectDir, "AppScope", "app.json5");
4084
- if (fs28.existsSync(appJsonPath)) {
4259
+ const appJsonPath = path28.join(projectDir, "AppScope", "app.json5");
4260
+ if (fs29.existsSync(appJsonPath)) {
4085
4261
  const appJson = readJson5File(appJsonPath);
4086
4262
  appJson.app = appJson.app ?? {};
4087
4263
  appJson.app.bundleName = args.bundleName;
4088
4264
  writeJson5File(appJsonPath, appJson);
4089
4265
  }
4090
- const stringsPath = path27.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
4091
- if (fs28.existsSync(stringsPath)) {
4266
+ const stringsPath = path28.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
4267
+ if (fs29.existsSync(stringsPath)) {
4092
4268
  const strings = readJsonFile(stringsPath);
4093
4269
  if (Array.isArray(strings.string)) {
4094
4270
  const appName = strings.string.find((s) => s.name === "app_name");
@@ -4096,8 +4272,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
4096
4272
  }
4097
4273
  writeJsonFile(stringsPath, strings);
4098
4274
  }
4099
- const buildProfilePath = path27.join(projectDir, "build-profile.json5");
4100
- if (fs28.existsSync(buildProfilePath)) {
4275
+ const buildProfilePath = path28.join(projectDir, "build-profile.json5");
4276
+ if (fs29.existsSync(buildProfilePath)) {
4101
4277
  const buildProfile = readJson5File(buildProfilePath);
4102
4278
  buildProfile.app = buildProfile.app ?? {};
4103
4279
  if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
@@ -4110,23 +4286,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
4110
4286
  }
4111
4287
  writeJson5File(buildProfilePath, buildProfile);
4112
4288
  }
4113
- const moduleJsonPath = path27.join(projectDir, args.moduleName, "src", "main", "module.json5");
4114
- if (fs28.existsSync(moduleJsonPath)) {
4289
+ const moduleJsonPath = path28.join(projectDir, args.moduleName, "src", "main", "module.json5");
4290
+ if (fs29.existsSync(moduleJsonPath)) {
4115
4291
  const moduleJson = readJson5File(moduleJsonPath);
4116
4292
  moduleJson.module = moduleJson.module ?? {};
4117
4293
  moduleJson.module.name = args.moduleName;
4118
4294
  writeJson5File(moduleJsonPath, moduleJson);
4119
4295
  }
4120
- const moduleOhPackagePath = path27.join(projectDir, args.moduleName, "oh-package.json5");
4121
- if (fs28.existsSync(moduleOhPackagePath)) {
4296
+ const moduleOhPackagePath = path28.join(projectDir, args.moduleName, "oh-package.json5");
4297
+ if (fs29.existsSync(moduleOhPackagePath)) {
4122
4298
  const pkg = readJson5File(moduleOhPackagePath);
4123
4299
  pkg.name = args.moduleName;
4124
4300
  writeJson5File(moduleOhPackagePath, pkg);
4125
4301
  }
4126
- const vscodeDir = path27.join(projectDir, ".vscode");
4127
- fs28.mkdirSync(vscodeDir, { recursive: true });
4302
+ const vscodeDir = path28.join(projectDir, ".vscode");
4303
+ fs29.mkdirSync(vscodeDir, { recursive: true });
4128
4304
  const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
4129
- writeJsonFile(path27.join(vscodeDir, "settings.json"), {
4305
+ writeJsonFile(path28.join(vscodeDir, "settings.json"), {
4130
4306
  "oniro.hapPath": hapPath,
4131
4307
  "files.associations": { "*.json5": "jsonc" }
4132
4308
  });
@@ -4143,7 +4319,7 @@ async function createScaffold(opts) {
4143
4319
  if (!opts.location || !await pathExists(opts.location)) {
4144
4320
  throw new OniroError(`Location does not exist: ${opts.location}`);
4145
4321
  }
4146
- const templateDir = path27.join(opts.templateRoot, opts.templateId);
4322
+ const templateDir = path28.join(opts.templateRoot, opts.templateId);
4147
4323
  if (!await pathExists(templateDir)) {
4148
4324
  throw new OniroError(`Template not found: ${templateDir}`);
4149
4325
  }
@@ -4178,17 +4354,17 @@ async function createScaffold(opts) {
4178
4354
  }
4179
4355
  }
4180
4356
  }
4181
- const projectDir = path27.join(opts.location, opts.projectName);
4357
+ const projectDir = path28.join(opts.location, opts.projectName);
4182
4358
  if (await pathExists(projectDir)) {
4183
4359
  if (!opts.overwrite) {
4184
4360
  throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
4185
4361
  }
4186
- await fs28.promises.rm(projectDir, { recursive: true, force: true });
4362
+ await fs29.promises.rm(projectDir, { recursive: true, force: true });
4187
4363
  }
4188
4364
  logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
4189
4365
  await copyDirRecursive(templateDir, projectDir);
4190
4366
  if (moduleName !== defaultModuleName) {
4191
- renameIfExists(path27.join(projectDir, defaultModuleName), path27.join(projectDir, moduleName));
4367
+ renameIfExists(path28.join(projectDir, defaultModuleName), path28.join(projectDir, moduleName));
4192
4368
  }
4193
4369
  updateTemplateConfigs(
4194
4370
  projectDir,
@@ -4205,11 +4381,11 @@ async function createScaffold(opts) {
4205
4381
  }
4206
4382
 
4207
4383
  // src/project/listModules.ts
4208
- import * as fs29 from "fs";
4209
- import * as path28 from "path";
4384
+ import * as fs30 from "fs";
4385
+ import * as path29 from "path";
4210
4386
  function listModules(opts) {
4211
- const buildProfile = path28.join(opts.projectDir, "build-profile.json5");
4212
- if (!fs29.existsSync(buildProfile)) {
4387
+ const buildProfile = path29.join(opts.projectDir, "build-profile.json5");
4388
+ if (!fs30.existsSync(buildProfile)) {
4213
4389
  throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
4214
4390
  }
4215
4391
  const parsed = readJson5File(buildProfile);
@@ -4221,12 +4397,12 @@ function listModules(opts) {
4221
4397
  }
4222
4398
 
4223
4399
  // src/project/abilities.ts
4224
- import * as fs30 from "fs";
4225
- import * as path29 from "path";
4400
+ import * as fs31 from "fs";
4401
+ import * as path30 from "path";
4226
4402
  function listAbilities(opts) {
4227
4403
  const moduleName = opts.moduleName ?? "entry";
4228
- const moduleJsonPath = path29.join(opts.projectDir, moduleName, "src", "main", "module.json5");
4229
- if (!fs30.existsSync(moduleJsonPath)) {
4404
+ const moduleJsonPath = path30.join(opts.projectDir, moduleName, "src", "main", "module.json5");
4405
+ if (!fs31.existsSync(moduleJsonPath)) {
4230
4406
  throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
4231
4407
  }
4232
4408
  const parsed = readJson5File(moduleJsonPath);
@@ -4234,12 +4410,12 @@ function listAbilities(opts) {
4234
4410
  }
4235
4411
 
4236
4412
  // src/project/prepareSigning.ts
4237
- import * as fs31 from "fs";
4238
- import * as path30 from "path";
4413
+ import * as fs32 from "fs";
4414
+ import * as path31 from "path";
4239
4415
  function hasSigningArtifacts(dir) {
4240
- if (!fs31.existsSync(path30.join(dir, "signatures"))) return false;
4241
- const buildProfile = path30.join(dir, "build-profile.json5");
4242
- if (!fs31.existsSync(buildProfile)) return false;
4416
+ if (!fs32.existsSync(path31.join(dir, "signatures"))) return false;
4417
+ const buildProfile = path31.join(dir, "build-profile.json5");
4418
+ if (!fs32.existsSync(buildProfile)) return false;
4243
4419
  try {
4244
4420
  const parsed = readJson5File(buildProfile);
4245
4421
  return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
@@ -4342,8 +4518,25 @@ async function diffHapAssets(opts) {
4342
4518
  }
4343
4519
 
4344
4520
  // src/install/apply.ts
4345
- import * as fs32 from "fs";
4346
- import * as path31 from "path";
4521
+ import * as fs33 from "fs";
4522
+ import * as path32 from "path";
4523
+
4524
+ // src/install/hapBundleName.ts
4525
+ function bundleNameFromHapConfig(text) {
4526
+ try {
4527
+ const parsed = JSON.parse(text.replace(/^/, ""));
4528
+ const name = parsed.app?.bundleName;
4529
+ return typeof name === "string" && name ? name : null;
4530
+ } catch {
4531
+ return null;
4532
+ }
4533
+ }
4534
+ async function readHapBundleName(hapPath) {
4535
+ const config = await readZipEntry(hapPath, (n) => n === "module.json") ?? await readZipEntry(hapPath, (n) => n === "config.json");
4536
+ return config ? bundleNameFromHapConfig(config.toString("utf8")) : null;
4537
+ }
4538
+
4539
+ // src/install/apply.ts
4347
4540
  function decideInstallMethod(s) {
4348
4541
  if (!s.signInfoInconsistent) return "replace";
4349
4542
  if (s.isSystemBundle && !s.allowUninstall) return "refuse";
@@ -4364,7 +4557,7 @@ async function pidOf(config, bundle, deviceSerial) {
4364
4557
  async function resolveHap(opts, logger) {
4365
4558
  let hap;
4366
4559
  if (opts.hapPath) {
4367
- const hapPath = !path31.isAbsolute(opts.hapPath) && opts.projectDir ? path31.join(opts.projectDir, opts.hapPath) : opts.hapPath;
4560
+ const hapPath = !path32.isAbsolute(opts.hapPath) && opts.projectDir ? path32.join(opts.projectDir, opts.hapPath) : opts.hapPath;
4368
4561
  hap = existingHapOrUnsigned(hapPath);
4369
4562
  if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);
4370
4563
  } else {
@@ -4373,7 +4566,7 @@ async function resolveHap(opts, logger) {
4373
4566
  if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ""}. Build first.`);
4374
4567
  hap = { path: picked.path, fallback: !picked.signed };
4375
4568
  }
4376
- if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path31.basename(hap.path)}.`);
4569
+ if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path32.basename(hap.path)}.`);
4377
4570
  return hap;
4378
4571
  }
4379
4572
  async function applyChanges(opts) {
@@ -4383,9 +4576,18 @@ async function applyChanges(opts) {
4383
4576
  const allowUninstall = opts.allowUninstall ?? false;
4384
4577
  const hap = await resolveHap(opts, logger);
4385
4578
  const hapPath = hap.path;
4579
+ const hapBundle = await readHapBundleName(hapPath).catch((err) => {
4580
+ logger.debug(`bundle name check skipped: ${err.message}`);
4581
+ return null;
4582
+ });
4583
+ if (hapBundle && hapBundle !== bundle) {
4584
+ throw new OniroError(
4585
+ `${path32.basename(hapPath)} (${hapPath}) is bundle ${hapBundle}, not ${bundle}, so installing it would not update ${bundle}. Choose the HAP explicitly, or name ${hapBundle} as the bundle if it is the app to update.`
4586
+ );
4587
+ }
4386
4588
  logger.info(`installing ${hapPath}`);
4387
4589
  let assetsChanged = false;
4388
- if (opts.installedHapPath && fs32.existsSync(opts.installedHapPath)) {
4590
+ if (opts.installedHapPath && fs33.existsSync(opts.installedHapPath)) {
4389
4591
  try {
4390
4592
  const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
4391
4593
  assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
@@ -4418,7 +4620,7 @@ async function applyChanges(opts) {
4418
4620
  }
4419
4621
  if (!await isBundleInstalled({ config, bundle, deviceSerial })) {
4420
4622
  throw new OniroError(
4421
- `hdc reported ${path31.basename(hapPath)} as installed, but bm dump does not list ${bundle}. Check that the HAP was built from this project (its bundleName must match).`
4623
+ `hdc reported ${path32.basename(hapPath)} as installed, but bm dump does not list ${bundle}. Check that the HAP was built from this project (its bundleName must match).`
4422
4624
  );
4423
4625
  }
4424
4626
  let postInstallPid = await pidOf(config, bundle, deviceSerial);
@@ -4495,9 +4697,9 @@ var AUTH_PATHS = {
4495
4697
  };
4496
4698
 
4497
4699
  // src/harmonyos/auth/tokenStore.ts
4498
- import * as fs33 from "fs";
4700
+ import * as fs34 from "fs";
4499
4701
  import * as os11 from "os";
4500
- import * as path32 from "path";
4702
+ import * as path33 from "path";
4501
4703
  import * as crypto3 from "crypto";
4502
4704
  var ALGORITHM = "aes-256-gcm";
4503
4705
  var KEY_LENGTH = 32;
@@ -4533,7 +4735,7 @@ function permissionHint(dir) {
4533
4735
  }
4534
4736
  function ensureDir(dir) {
4535
4737
  try {
4536
- fs33.mkdirSync(dir, { recursive: true, mode: DIR_MODE });
4738
+ fs34.mkdirSync(dir, { recursive: true, mode: DIR_MODE });
4537
4739
  } catch (err) {
4538
4740
  if (err.code === "EACCES") {
4539
4741
  throw new OniroError(permissionHint(dir), err);
@@ -4544,17 +4746,17 @@ function ensureDir(dir) {
4544
4746
  function createTokenStore(opts) {
4545
4747
  const logger = opts.logger ?? noopLogger;
4546
4748
  const authDir = opts.config.get("harmonyosAuthDir", defaultPaths.harmonyosAuthDir());
4547
- const tokenPath = path32.join(authDir, TOKEN_FILE);
4548
- const keyPath = path32.join(os11.homedir(), ".local", "share", "oniro-app", "keys", KEY_FILE);
4749
+ const tokenPath = path33.join(authDir, TOKEN_FILE);
4750
+ const keyPath = path33.join(os11.homedir(), ".local", "share", "oniro-app", "keys", KEY_FILE);
4549
4751
  function loadOrCreateKey() {
4550
- if (fs33.existsSync(keyPath)) {
4551
- const existing = fs33.readFileSync(keyPath);
4752
+ if (fs34.existsSync(keyPath)) {
4753
+ const existing = fs34.readFileSync(keyPath);
4552
4754
  if (existing.length === KEY_LENGTH) return existing;
4553
4755
  logger.warn("[harmonyos] The token key file was malformed; regenerating (you will need to log in again).");
4554
4756
  }
4555
- ensureDir(path32.dirname(keyPath));
4757
+ ensureDir(path33.dirname(keyPath));
4556
4758
  const key = crypto3.randomBytes(KEY_LENGTH);
4557
- fs33.writeFileSync(keyPath, key, { mode: FILE_MODE });
4759
+ fs34.writeFileSync(keyPath, key, { mode: FILE_MODE });
4558
4760
  return key;
4559
4761
  }
4560
4762
  return {
@@ -4564,12 +4766,12 @@ function createTokenStore(opts) {
4564
4766
  const payload = Buffer.from(JSON.stringify(session), "utf8");
4565
4767
  const blob = encrypt2(loadOrCreateKey(), payload);
4566
4768
  ensureDir(authDir);
4567
- fs33.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });
4769
+ fs34.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });
4568
4770
  },
4569
4771
  load() {
4570
- if (!fs33.existsSync(tokenPath)) return null;
4772
+ if (!fs34.existsSync(tokenPath)) return null;
4571
4773
  try {
4572
- const blob = JSON.parse(fs33.readFileSync(tokenPath, "utf8"));
4774
+ const blob = JSON.parse(fs34.readFileSync(tokenPath, "utf8"));
4573
4775
  if (!isEncryptedBlob(blob)) return null;
4574
4776
  const { jwtToken, siteId } = JSON.parse(decrypt2(loadOrCreateKey(), blob).toString("utf8"));
4575
4777
  return typeof jwtToken === "string" && jwtToken && typeof siteId === "string" ? { jwtToken, siteId } : null;
@@ -4581,7 +4783,7 @@ function createTokenStore(opts) {
4581
4783
  }
4582
4784
  logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);
4583
4785
  try {
4584
- fs33.rmSync(tokenPath, { force: true });
4786
+ fs34.rmSync(tokenPath, { force: true });
4585
4787
  } catch {
4586
4788
  }
4587
4789
  return null;
@@ -4589,7 +4791,7 @@ function createTokenStore(opts) {
4589
4791
  },
4590
4792
  clear() {
4591
4793
  try {
4592
- fs33.rmSync(tokenPath, { force: true });
4794
+ fs34.rmSync(tokenPath, { force: true });
4593
4795
  } catch (err) {
4594
4796
  throw new OniroError(`Failed to remove ${tokenPath}.`, err);
4595
4797
  }
@@ -5070,7 +5272,7 @@ function mapAgcError(operation, statusCode, reasonPhrase, body) {
5070
5272
  }
5071
5273
 
5072
5274
  // src/harmonyos/signing/profile.ts
5073
- import * as fs34 from "fs";
5275
+ import * as fs35 from "fs";
5074
5276
  import { X509Certificate } from "crypto";
5075
5277
  import forge from "node-forge";
5076
5278
  function extractProfileJson(buffer) {
@@ -5102,7 +5304,7 @@ function extractProfileJson(buffer) {
5102
5304
  function readProvisionProfile(profilePath) {
5103
5305
  let raw;
5104
5306
  try {
5105
- const json = extractProfileJson(fs34.readFileSync(profilePath));
5307
+ const json = extractProfileJson(fs35.readFileSync(profilePath));
5106
5308
  if (!json) return null;
5107
5309
  raw = JSON.parse(json);
5108
5310
  } catch {
@@ -5131,7 +5333,7 @@ function parseCertificate(pem) {
5131
5333
  }
5132
5334
  function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
5133
5335
  try {
5134
- const der = forge.util.createBuffer(fs34.readFileSync(p12Path).toString("binary"));
5336
+ const der = forge.util.createBuffer(fs35.readFileSync(p12Path).toString("binary"));
5135
5337
  const p12 = forge.pkcs12.pkcs12FromAsn1(forge.asn1.fromDer(der), keyPwd);
5136
5338
  const certBag = forge.pki.oids.certBag ?? "1.2.840.113549.1.12.10.1.3";
5137
5339
  const wanted = certificate.publicKey.export({ type: "spki", format: "der" });
@@ -5147,7 +5349,7 @@ function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
5147
5349
  }
5148
5350
  }
5149
5351
  function verifySigningMaterial(opts) {
5150
- const pems = fs34.readFileSync(opts.cerPath, "utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
5352
+ const pems = fs35.readFileSync(opts.cerPath, "utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
5151
5353
  const chain = (pems ?? []).map(parseCertificate);
5152
5354
  const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);
5153
5355
  if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);
@@ -5166,14 +5368,14 @@ function verifySigningMaterial(opts) {
5166
5368
 
5167
5369
  // src/harmonyos/signing/autoSign.ts
5168
5370
  import * as crypto9 from "crypto";
5169
- import * as fs39 from "fs";
5170
- import * as path38 from "path";
5371
+ import * as fs40 from "fs";
5372
+ import * as path39 from "path";
5171
5373
  import JSON57 from "json5";
5172
5374
 
5173
5375
  // src/harmonyos/signing/agc.ts
5174
5376
  import * as crypto6 from "crypto";
5175
- import * as fs35 from "fs";
5176
- import * as path33 from "path";
5377
+ import * as fs36 from "fs";
5378
+ import * as path34 from "path";
5177
5379
  var ENDPOINTS = {
5178
5380
  CERT_LIST: "/api/cps/harmony-cert-manage/v1/cert/list",
5179
5381
  CERT_ADD: "/api/cps/harmony-cert-manage/v1/cert/add",
@@ -5259,8 +5461,8 @@ function createAgcClient(http3, auth) {
5259
5461
  if (target.sha256 && actual !== target.sha256.toLowerCase()) {
5260
5462
  throw new ChecksumMismatchError(target.sha256, actual);
5261
5463
  }
5262
- fs35.mkdirSync(path33.dirname(dest), { recursive: true, mode: 448 });
5263
- fs35.writeFileSync(dest, buffer, { mode: 384 });
5464
+ fs36.mkdirSync(path34.dirname(dest), { recursive: true, mode: 448 });
5465
+ fs36.writeFileSync(dest, buffer, { mode: 384 });
5264
5466
  }
5265
5467
  };
5266
5468
  }
@@ -5311,22 +5513,22 @@ async function registerDevices(agc, connected, logger) {
5311
5513
 
5312
5514
  // src/harmonyos/signing/keystore.ts
5313
5515
  import * as crypto7 from "crypto";
5314
- import * as fs37 from "fs";
5315
- import * as path35 from "path";
5516
+ import * as fs38 from "fs";
5517
+ import * as path36 from "path";
5316
5518
 
5317
5519
  // src/harmonyos/java.ts
5318
- import * as fs36 from "fs";
5319
- import * as path34 from "path";
5520
+ import * as fs37 from "fs";
5521
+ import * as path35 from "path";
5320
5522
  var JAVA_BIN = process.platform === "win32" ? "java.exe" : "java";
5321
5523
  function findJava(sdk, env = process.env) {
5322
5524
  const candidates = [
5323
- env.JAVA_HOME && path34.join(env.JAVA_HOME, "bin", JAVA_BIN),
5324
- sdk && path34.join(sdk.installRoot, "jbr", "bin", JAVA_BIN),
5525
+ env.JAVA_HOME && path35.join(env.JAVA_HOME, "bin", JAVA_BIN),
5526
+ sdk && path35.join(sdk.installRoot, "jbr", "bin", JAVA_BIN),
5325
5527
  // macOS: the JBR is itself a bundle inside Studio's Contents.
5326
- sdk && path34.join(sdk.installRoot, "jbr", "Contents", "Home", "bin", JAVA_BIN),
5327
- ...(env.PATH ?? "").split(path34.delimiter).map((dir) => dir && path34.join(dir, JAVA_BIN))
5528
+ sdk && path35.join(sdk.installRoot, "jbr", "Contents", "Home", "bin", JAVA_BIN),
5529
+ ...(env.PATH ?? "").split(path35.delimiter).map((dir) => dir && path35.join(dir, JAVA_BIN))
5328
5530
  ];
5329
- const found = candidates.find((c) => !!c && fs36.existsSync(c));
5531
+ const found = candidates.find((c) => !!c && fs37.existsSync(c));
5330
5532
  if (found) return found;
5331
5533
  throw new OniroError(
5332
5534
  "No Java runtime found. HarmonyOS signing runs the SDK's hap-sign-tool.jar, which needs one: install a JDK and set JAVA_HOME, or install DevEco Studio, whose bundled runtime is used automatically."
@@ -5340,13 +5542,13 @@ function redactArgs(args) {
5340
5542
  return args.map((arg, i) => args[i - 1] === "-keyPwd" || args[i - 1] === "-keystorePwd" ? "******" : arg);
5341
5543
  }
5342
5544
  async function generateKeystoreAndCsr(opts) {
5343
- const jar = path35.join(opts.sdk.sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
5344
- if (!fs37.existsSync(jar)) {
5545
+ const jar = path36.join(opts.sdk.sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
5546
+ if (!fs38.existsSync(jar)) {
5345
5547
  throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);
5346
5548
  }
5347
5549
  const java = findJava(opts.sdk);
5348
5550
  const keyPwd = crypto7.randomBytes(12).toString("base64url").replaceAll(/[-_]/g, "");
5349
- fs37.mkdirSync(path35.dirname(opts.p12Path), { recursive: true, mode: 448 });
5551
+ fs38.mkdirSync(path36.dirname(opts.p12Path), { recursive: true, mode: 448 });
5350
5552
  const run = async (what, args) => {
5351
5553
  const argv = ["-jar", jar, ...args, "-keyAlias", KEY_ALIAS, "-keystoreFile", opts.p12Path, "-keystorePwd", keyPwd, "-keyPwd", keyPwd];
5352
5554
  opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(" ")}`);
@@ -5360,28 +5562,28 @@ ${detail}` : ""}`);
5360
5562
  opts.logger.info("[harmonyos] Generating the local keystore and certificate signing request...");
5361
5563
  await run("generate the key pair", ["generate-keypair", "-keyAlg", "ECC", "-keySize", "NIST-P-256"]);
5362
5564
  await run("generate the CSR", ["generate-csr", "-subject", "CN=DebugKey", "-signAlg", SIGN_ALG, "-outFile", opts.csrPath]);
5363
- return { keyPwd, csr: fs37.readFileSync(opts.csrPath, "utf8") };
5565
+ return { keyPwd, csr: fs38.readFileSync(opts.csrPath, "utf8") };
5364
5566
  }
5365
5567
 
5366
5568
  // src/harmonyos/signing/paths.ts
5367
5569
  import * as crypto8 from "crypto";
5368
- import * as path36 from "path";
5570
+ import * as path37 from "path";
5369
5571
  function sanitizeNamePart(raw) {
5370
5572
  const safe = (raw?.trim() ?? "").replace(/[\\/:*?"<>|=.-]+/g, "_");
5371
5573
  return safe.slice(0, 64) || "default";
5372
5574
  }
5373
5575
  function resolveSigningMaterialPaths(config, productName, projectRoot) {
5374
5576
  const hash = crypto8.createHash("sha256").update(projectRoot, "utf8").digest("base64url").replaceAll(/[-_]/g, "");
5375
- const base = path36.join(
5577
+ const base = path37.join(
5376
5578
  config.get("harmonyosSigningDir", defaultPaths.harmonyosSigningDir()),
5377
- `${sanitizeNamePart(productName)}_${path36.basename(projectRoot)}_${hash}=`
5579
+ `${sanitizeNamePart(productName)}_${path37.basename(projectRoot)}_${hash}=`
5378
5580
  );
5379
5581
  return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };
5380
5582
  }
5381
5583
 
5382
5584
  // src/harmonyos/signing/project.ts
5383
- import * as fs38 from "fs";
5384
- import * as path37 from "path";
5585
+ import * as fs39 from "fs";
5586
+ import * as path38 from "path";
5385
5587
  import JSON56 from "json5";
5386
5588
 
5387
5589
  // src/harmonyos/signing/aclPermissionList.ts
@@ -5449,9 +5651,9 @@ var ACL_PERMISSIONS = /* @__PURE__ */ new Set([
5449
5651
 
5450
5652
  // src/harmonyos/signing/project.ts
5451
5653
  function readRequestedPermissions(moduleConfigPath) {
5452
- if (!fs38.existsSync(moduleConfigPath)) return [];
5654
+ if (!fs39.existsSync(moduleConfigPath)) return [];
5453
5655
  try {
5454
- const parsed = JSON56.parse(fs38.readFileSync(moduleConfigPath, "utf-8"));
5656
+ const parsed = JSON56.parse(fs39.readFileSync(moduleConfigPath, "utf-8"));
5455
5657
  return (parsed.module?.requestPermissions ?? []).map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
5456
5658
  } catch {
5457
5659
  return [];
@@ -5460,10 +5662,10 @@ function readRequestedPermissions(moduleConfigPath) {
5460
5662
  function collectAclPermissions(projectDir, logger = noopLogger) {
5461
5663
  const requested = /* @__PURE__ */ new Set();
5462
5664
  for (const module of listModules({ projectDir })) {
5463
- const moduleRoot = path37.resolve(projectDir, module.srcPath);
5665
+ const moduleRoot = path38.resolve(projectDir, module.srcPath);
5464
5666
  for (const sourceSet of ["main", "ohosTest"]) {
5465
5667
  for (const name of readRequestedPermissions(
5466
- path37.join(moduleRoot, "src", sourceSet, "module.json5")
5668
+ path38.join(moduleRoot, "src", sourceSet, "module.json5")
5467
5669
  )) {
5468
5670
  requested.add(name);
5469
5671
  }
@@ -5479,7 +5681,7 @@ function collectAclPermissions(projectDir, logger = noopLogger) {
5479
5681
  // src/harmonyos/signing/autoSign.ts
5480
5682
  function shouldRegenerate(input) {
5481
5683
  if (input.force) return "--force was passed";
5482
- const missing = Object.values(input.paths).find((file) => !fs39.existsSync(file));
5684
+ const missing = Object.values(input.paths).find((file) => !fs40.existsSync(file));
5483
5685
  if (missing) return `${missing} is missing`;
5484
5686
  const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);
5485
5687
  if (config?.type !== "HarmonyOS" || config.material?.profile !== input.paths.profilePath) {
@@ -5518,16 +5720,16 @@ function writeSigningConfig(opts) {
5518
5720
  for (const product of app.products ?? []) {
5519
5721
  if (product.name === opts.productName) product.signingConfig = opts.productName;
5520
5722
  }
5521
- fs39.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));
5723
+ fs40.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));
5522
5724
  }
5523
5725
  async function harmonyOsAutoSign(opts) {
5524
5726
  const logger = opts.logger ?? noopLogger;
5525
5727
  const productName = opts.productName ?? "default";
5526
- const projectDir = path38.resolve(opts.projectDir);
5527
- const buildProfilePath = path38.join(projectDir, "build-profile.json5");
5728
+ const projectDir = path39.resolve(opts.projectDir);
5729
+ const buildProfilePath = path39.join(projectDir, "build-profile.json5");
5528
5730
  let buildProfile;
5529
5731
  try {
5530
- buildProfile = JSON57.parse(fs39.readFileSync(buildProfilePath, "utf-8"));
5732
+ buildProfile = JSON57.parse(fs40.readFileSync(buildProfilePath, "utf-8"));
5531
5733
  } catch (err) {
5532
5734
  throw new OniroError(`Could not read ${buildProfilePath}: ${err.message}`, err);
5533
5735
  }
@@ -5567,7 +5769,7 @@ async function harmonyOsAutoSign(opts) {
5567
5769
  logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);
5568
5770
  const agc = createAgcClient(opts.http ?? createHttpClient({ logger }), auth);
5569
5771
  const deviceIds = await registerDevices(agc, connected, logger);
5570
- for (const file of Object.values(paths)) fs39.rmSync(file, { force: true });
5772
+ for (const file of Object.values(paths)) fs40.rmSync(file, { force: true });
5571
5773
  const certName = `oniro_debug_${auth.teamId.replace(/[\\/.:]/g, "")}.cer`;
5572
5774
  const stale = (await agc.listCertificates()).find((c) => c.certName === certName);
5573
5775
  if (stale) {
@@ -5598,10 +5800,10 @@ async function harmonyOsAutoSign(opts) {
5598
5800
  try {
5599
5801
  verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });
5600
5802
  } catch (err) {
5601
- fs39.rmSync(paths.profilePath, { force: true });
5803
+ fs40.rmSync(paths.profilePath, { force: true });
5602
5804
  throw err;
5603
5805
  }
5604
- const materialDir = path38.join(path38.dirname(paths.p12Path), "material");
5806
+ const materialDir = path39.join(path39.dirname(paths.p12Path), "material");
5605
5807
  try {
5606
5808
  getKey(materialDir);
5607
5809
  } catch {
@@ -5613,7 +5815,7 @@ async function harmonyOsAutoSign(opts) {
5613
5815
  }
5614
5816
 
5615
5817
  // src/index.ts
5616
- var VERSION = "0.14.1";
5818
+ var VERSION = "0.15.0";
5617
5819
  export {
5618
5820
  ALL_SDKS,
5619
5821
  APL_VALUES,
@@ -5627,6 +5829,7 @@ export {
5627
5829
  HUAWEI_SITES,
5628
5830
  INSTALL_TMP_DIRNAME,
5629
5831
  InsufficientSpaceError,
5832
+ OHOS_DAILY_BUILDS_URL,
5630
5833
  OHOS_URL_BASE,
5631
5834
  OniroError,
5632
5835
  SIGNING_ERRORS,
@@ -5647,6 +5850,7 @@ export {
5647
5850
  buildHvigorwArgs,
5648
5851
  buildInputCommand,
5649
5852
  buildRawTouchCommand,
5853
+ bundleNameFromHapConfig,
5650
5854
  captureBurst,
5651
5855
  captureLog,
5652
5856
  cleanCodelinterOutput,
@@ -5700,6 +5904,7 @@ export {
5700
5904
  findLayoutNodes,
5701
5905
  findMissingProjectSdk,
5702
5906
  findRunningProcess,
5907
+ findSdkOsDir,
5703
5908
  flattenLayout,
5704
5909
  forceStop,
5705
5910
  formatBytes,
@@ -5733,10 +5938,12 @@ export {
5733
5938
  hdcTargetArgs,
5734
5939
  hdcTargetArgsFor,
5735
5940
  hideKeyboard,
5941
+ hilogTimeMs,
5736
5942
  installApp,
5737
5943
  installCmdTools,
5738
5944
  installEmulator,
5739
5945
  installFailureReason,
5946
+ installSdkFromArchive,
5740
5947
  isBundleInstalled,
5741
5948
  isCmdToolsInstalled,
5742
5949
  isEmulatorInstalled,
@@ -5753,6 +5960,7 @@ export {
5753
5960
  listRunningProcesses,
5754
5961
  listTemplates,
5755
5962
  locateTarget,
5963
+ missingProjectRootFiles,
5756
5964
  needsCmdWrapper,
5757
5965
  nonInteractivePrompter,
5758
5966
  noopLogger,
@@ -5776,9 +5984,11 @@ export {
5776
5984
  pickTarget,
5777
5985
  prepareSigning,
5778
5986
  pruneLayout,
5987
+ readHapBundleName,
5779
5988
  readJson5File,
5780
5989
  readJsonFile,
5781
5990
  readProvisionProfile,
5991
+ readZipEntry,
5782
5992
  reboot,
5783
5993
  recvFile,
5784
5994
  removeCmdTools,