akanjs 2.0.5 → 2.0.7

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 (81) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/cli/application/application.command.ts +4 -1
  4. package/cli/application/application.runner.ts +6 -8
  5. package/cli/build.ts +3 -1
  6. package/cli/cloud/cloud.runner.ts +7 -8
  7. package/cli/index.js +288 -115
  8. package/cli/library/library.runner.ts +2 -2
  9. package/cli/module/module.runner.ts +2 -2
  10. package/cli/npmRegistry.ts +13 -0
  11. package/cli/openBrowser.ts +15 -0
  12. package/cli/pluralizeName.ts +5 -0
  13. package/cli/scalar/scalar.prompt.ts +2 -2
  14. package/cli/scalar/scalar.runner.ts +2 -2
  15. package/cli/semver.ts +18 -0
  16. package/cli/templates/lib/sig.ts +2 -2
  17. package/cli/workspace/workspace.runner.ts +3 -3
  18. package/client/cookie.ts +10 -15
  19. package/common/index.ts +1 -0
  20. package/common/jwtDecode.ts +17 -0
  21. package/constant/serialize.ts +1 -1
  22. package/devkit/akanApp/akanApp.host.ts +46 -9
  23. package/devkit/akanConfig/akanConfig.ts +2 -1
  24. package/devkit/capacitor.base.config.ts +18 -4
  25. package/devkit/capacitorApp.ts +118 -64
  26. package/devkit/incrementalBuilder/incrementalBuilder.host.ts +83 -9
  27. package/devkit/mobile/mobileTarget.ts +2 -1
  28. package/devkit/scanInfo.ts +1 -0
  29. package/document/dataLoader.ts +140 -6
  30. package/document/database.ts +1 -1
  31. package/package.json +7 -13
  32. package/server/akanApp.ts +250 -44
  33. package/server/di/diLifecycle.ts +1 -1
  34. package/server/processMetricsCollector.ts +79 -1
  35. package/server/proxy/localeWebProxy.ts +29 -12
  36. package/server/resolver/database.resolver.ts +82 -31
  37. package/server/resolver/signal.resolver.ts +67 -28
  38. package/service/ipcTypes.ts +5 -0
  39. package/service/predefinedAdaptor/database.adaptor.ts +95 -27
  40. package/service/predefinedAdaptor/solidSqlite.ts +7 -7
  41. package/service/predefinedAdaptor/storage.adaptor.ts +35 -9
  42. package/service/serviceModule.ts +1 -6
  43. package/signal/base.signal.ts +1 -1
  44. package/signal/index.ts +1 -0
  45. package/signal/middleware.ts +5 -1
  46. package/signal/signalContext.ts +85 -31
  47. package/signal/signalRegistry.ts +35 -10
  48. package/signal/trace.ts +279 -0
  49. package/types/cli/npmRegistry.d.ts +1 -0
  50. package/types/cli/openBrowser.d.ts +1 -0
  51. package/types/cli/pluralizeName.d.ts +1 -0
  52. package/types/cli/semver.d.ts +1 -0
  53. package/types/client/cookie.d.ts +6 -1
  54. package/types/common/index.d.ts +1 -0
  55. package/types/common/jwtDecode.d.ts +2 -0
  56. package/types/devkit/capacitorApp.d.ts +14 -5
  57. package/types/devkit/incrementalBuilder/incrementalBuilder.host.d.ts +9 -5
  58. package/types/document/dataLoader.d.ts +21 -2
  59. package/types/document/database.d.ts +1 -1
  60. package/types/server/processMetricsCollector.d.ts +2 -0
  61. package/types/service/ipcTypes.d.ts +5 -0
  62. package/types/service/predefinedAdaptor/database.adaptor.d.ts +26 -32
  63. package/types/service/predefinedAdaptor/solidSqlite.d.ts +3 -3
  64. package/types/service/predefinedAdaptor/storage.adaptor.d.ts +8 -2
  65. package/types/service/serviceModule.d.ts +1 -1
  66. package/types/signal/index.d.ts +1 -0
  67. package/types/signal/signalContext.d.ts +4 -1
  68. package/types/signal/signalRegistry.d.ts +25 -4
  69. package/types/signal/trace.d.ts +97 -0
  70. package/types/ui/Signal/style.d.ts +15 -0
  71. package/ui/Signal/Arg.tsx +22 -15
  72. package/ui/Signal/Doc.tsx +30 -24
  73. package/ui/Signal/Listener.tsx +15 -39
  74. package/ui/Signal/Message.tsx +32 -50
  75. package/ui/Signal/Object.tsx +16 -13
  76. package/ui/Signal/PubSub.tsx +29 -47
  77. package/ui/Signal/Response.tsx +7 -17
  78. package/ui/Signal/RestApi.tsx +41 -57
  79. package/ui/Signal/WebSocket.tsx +1 -1
  80. package/ui/Signal/style.ts +36 -0
  81. package/webkit/useCsrValues.ts +147 -37
package/cli/index.js CHANGED
@@ -174321,6 +174321,7 @@ var appRootAllowedDirs = new Set([
174321
174321
  "env",
174322
174322
  "ios",
174323
174323
  "lib",
174324
+ "mobile",
174324
174325
  "page",
174325
174326
  "private",
174326
174327
  "public",
@@ -176299,6 +176300,8 @@ var builderMsgTypeSet = new Set([
176299
176300
  ]);
176300
176301
 
176301
176302
  class IncrementalBuilderHost {
176303
+ static #restartBaseDelayMs = 1000;
176304
+ static #restartMaxDelayMs = 30000;
176302
176305
  logger = new Logger("IncrementalBuilderHost");
176303
176306
  entry;
176304
176307
  env;
@@ -176306,48 +176309,112 @@ class IncrementalBuilderHost {
176306
176309
  ready = false;
176307
176310
  #onMessage;
176308
176311
  #proc = null;
176312
+ #status = "stopped";
176313
+ #restartAttempts = 0;
176314
+ #restartTimer = null;
176315
+ #manualStop = false;
176316
+ #startOptions = {};
176309
176317
  constructor({ app, entry, env, onMessage }) {
176310
176318
  this.app = app;
176311
176319
  this.entry = entry;
176312
176320
  this.env = env;
176313
176321
  this.#onMessage = onMessage;
176314
176322
  }
176315
- start({ onExit, onReady }) {
176323
+ get status() {
176324
+ return this.#status;
176325
+ }
176326
+ start(options = {}) {
176316
176327
  if (this.#proc)
176317
176328
  this.stop();
176318
- this.#proc = Bun.spawn(["bun", this.entry], {
176329
+ this.#manualStop = false;
176330
+ this.#startOptions = options;
176331
+ this.#spawn(false);
176332
+ return this;
176333
+ }
176334
+ #spawn(isRestart) {
176335
+ this.#status = isRestart ? "restarting" : "starting";
176336
+ this.ready = false;
176337
+ let proc;
176338
+ proc = Bun.spawn(["bun", this.entry], {
176319
176339
  cwd: this.app.cwdPath,
176320
176340
  env: { ...this.env, AKAN_WATCH: "1" },
176321
176341
  stdio: ["ignore", "inherit", "inherit"],
176322
176342
  ipc: (msg) => {
176343
+ if (this.#proc !== proc)
176344
+ return;
176323
176345
  if (!msg || typeof msg !== "object")
176324
176346
  return;
176325
176347
  if (builderMsgTypeSet.has(msg.type))
176326
176348
  this.#onMessage(msg);
176327
176349
  if (msg.type === "builder-ready" && !this.ready) {
176328
176350
  this.ready = true;
176329
- onReady?.();
176351
+ this.#status = "ready";
176352
+ this.#restartAttempts = 0;
176353
+ if (isRestart)
176354
+ this.#startOptions.onRestartReady?.();
176355
+ else
176356
+ this.#startOptions.onReady?.();
176330
176357
  }
176331
176358
  },
176332
176359
  serialization: "advanced",
176333
176360
  onExit: () => {
176334
- onExit?.();
176361
+ if (this.#proc !== proc)
176362
+ return;
176363
+ this.#proc = null;
176364
+ const wasReady = this.ready;
176365
+ this.ready = false;
176366
+ if (this.#manualStop || this.#status === "stopped")
176367
+ return;
176368
+ if (!wasReady) {
176369
+ this.#status = "stopped";
176370
+ this.#startOptions.onExit?.();
176371
+ return;
176372
+ }
176373
+ this.#scheduleRestart();
176335
176374
  }
176336
176375
  });
176337
- this.logger.verbose(`builder spawned pid=${this.#proc.pid} entry=${this.entry}`);
176338
- return this;
176376
+ this.#proc = proc;
176377
+ this.logger.verbose(`builder spawned pid=${proc.pid} entry=${this.entry}${isRestart ? " restart=1" : ""}`);
176378
+ }
176379
+ #scheduleRestart() {
176380
+ if (this.#manualStop || this.#restartTimer)
176381
+ return;
176382
+ this.#status = "restarting";
176383
+ const attempt = this.#restartAttempts;
176384
+ const delay = Math.min(IncrementalBuilderHost.#restartBaseDelayMs * 2 ** attempt, IncrementalBuilderHost.#restartMaxDelayMs);
176385
+ this.#restartAttempts = attempt + 1;
176386
+ this.logger.warn(`builder exited after ready; restarting in ${delay}ms (attempt ${this.#restartAttempts})`);
176387
+ this.#restartTimer = setTimeout(() => {
176388
+ this.#restartTimer = null;
176389
+ if (this.#manualStop)
176390
+ return;
176391
+ this.#spawn(true);
176392
+ }, delay);
176339
176393
  }
176340
176394
  send(message) {
176341
- if (this.#proc)
176395
+ if (!this.#proc || this.#status !== "ready") {
176396
+ this.logger.warn(`incrementalBuilderHost is ${this.#status}; cannot send ${message.type}`);
176397
+ return false;
176398
+ }
176399
+ try {
176342
176400
  this.#proc.send(message);
176343
- else
176344
- this.logger.warn("incrementalBuilderHost is not running");
176401
+ return true;
176402
+ } catch (error) {
176403
+ this.logger.warn(`failed to send ${message.type} to builder: ${error instanceof Error ? error.message : String(error)}`);
176404
+ return false;
176405
+ }
176345
176406
  }
176346
176407
  stop() {
176408
+ this.#manualStop = true;
176409
+ if (this.#restartTimer) {
176410
+ clearTimeout(this.#restartTimer);
176411
+ this.#restartTimer = null;
176412
+ }
176347
176413
  if (this.#proc)
176348
176414
  this.#proc.kill();
176349
176415
  this.#proc = null;
176350
176416
  this.ready = false;
176417
+ this.#status = "stopped";
176351
176418
  }
176352
176419
  static async create(app, env, onMessage) {
176353
176420
  const candidates = [
@@ -176365,6 +176432,8 @@ class IncrementalBuilderHost {
176365
176432
  var backendMsgTypeSet = new Set(["build-route"]);
176366
176433
  var BACKEND_RESTART_DEBOUNCE_MS = 120;
176367
176434
  var BACKEND_GRACEFUL_TIMEOUT_MS = 3000;
176435
+ var BACKEND_RECOVERY_BASE_DELAY_MS = 1000;
176436
+ var BACKEND_RECOVERY_MAX_DELAY_MS = 30000;
176368
176437
  var BUILDER_READY_TIMEOUT_MS = 15000;
176369
176438
  var BUILDER_START_MAX_ATTEMPTS = 3;
176370
176439
  var SOURCE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
@@ -176488,6 +176557,8 @@ class AkanAppHost {
176488
176557
  #backendReady = false;
176489
176558
  #plannedBackendStops = new WeakSet;
176490
176559
  #restartTimer = null;
176560
+ #backendRecoveryTimer = null;
176561
+ #backendRecoveryAttempts = 0;
176491
176562
  #restartFiles = new Set;
176492
176563
  #latestPagesUpdated = null;
176493
176564
  #latestCssUpdated = null;
@@ -176518,6 +176589,10 @@ class AkanAppHost {
176518
176589
  clearTimeout(this.#restartTimer);
176519
176590
  this.#restartTimer = null;
176520
176591
  }
176592
+ if (this.#backendRecoveryTimer) {
176593
+ clearTimeout(this.#backendRecoveryTimer);
176594
+ this.#backendRecoveryTimer = null;
176595
+ }
176521
176596
  await this.#stopBackend();
176522
176597
  this.#stopBuilder();
176523
176598
  return this;
@@ -176542,6 +176617,7 @@ class AkanAppHost {
176542
176617
  return;
176543
176618
  if (msg.type === "backend-ready") {
176544
176619
  this.#backendReady = true;
176620
+ this.#backendRecoveryAttempts = 0;
176545
176621
  this.logger.verbose(`backend ready pid=${msg.pid}`);
176546
176622
  this.#replayBuilderState();
176547
176623
  return;
@@ -176558,7 +176634,7 @@ class AkanAppHost {
176558
176634
  this.#plannedBackendStops.delete(backend);
176559
176635
  return;
176560
176636
  }
176561
- this.#stopBuilder();
176637
+ this.#scheduleBackendRecovery("backend-exit");
176562
176638
  }
176563
176639
  });
176564
176640
  this.#backend = backend;
@@ -176606,6 +176682,10 @@ class AkanAppHost {
176606
176682
  #scheduleBackendRestart(files) {
176607
176683
  for (const file of files)
176608
176684
  this.#restartFiles.add(file);
176685
+ if (this.#backendRecoveryTimer) {
176686
+ clearTimeout(this.#backendRecoveryTimer);
176687
+ this.#backendRecoveryTimer = null;
176688
+ }
176609
176689
  if (this.#restartTimer)
176610
176690
  clearTimeout(this.#restartTimer);
176611
176691
  this.#restartTimer = setTimeout(() => {
@@ -176617,9 +176697,27 @@ class AkanAppHost {
176617
176697
  }
176618
176698
  async#restartBackend(files) {
176619
176699
  this.logger.verbose(`[backend-reload] restarting backend for ${files.length} file(s)`);
176700
+ this.#backendRecoveryAttempts = 0;
176620
176701
  await Promise.all([this.#stopBackend(), this.#backendGraph.refresh()]);
176621
176702
  this.#startBackend();
176622
176703
  }
176704
+ #scheduleBackendRecovery(reason) {
176705
+ if (this.#backendRecoveryTimer || this.#backend)
176706
+ return;
176707
+ const attempt = this.#backendRecoveryAttempts;
176708
+ const delay = Math.min(BACKEND_RECOVERY_BASE_DELAY_MS * 2 ** attempt, BACKEND_RECOVERY_MAX_DELAY_MS);
176709
+ this.#backendRecoveryAttempts = attempt + 1;
176710
+ this.logger.warn(`[backend-recovery] backend exited unexpectedly (${reason}); restarting in ${delay}ms (attempt ${this.#backendRecoveryAttempts})`);
176711
+ this.#backendRecoveryTimer = setTimeout(() => {
176712
+ this.#backendRecoveryTimer = null;
176713
+ if (this.#backend)
176714
+ return;
176715
+ this.#backendGraph.refresh().finally(() => {
176716
+ if (!this.#backend)
176717
+ this.#startBackend();
176718
+ });
176719
+ }, delay);
176720
+ }
176623
176721
  #enqueueBuilderMessage(message) {
176624
176722
  this.#builderMessageQueue = this.#builderMessageQueue.then(() => this.#handleBuilderMessage(message)).catch((err) => {
176625
176723
  this.logger.warn(`failed to handle builder message: ${err instanceof Error ? err.message : String(err)}`);
@@ -176688,7 +176786,6 @@ class AkanAppHost {
176688
176786
  if (!this.#builder)
176689
176787
  throw new Error("Builder Not Found");
176690
176788
  let settled = false;
176691
- let ready = false;
176692
176789
  const settle = (fn) => {
176693
176790
  if (settled)
176694
176791
  return;
@@ -176701,24 +176798,31 @@ class AkanAppHost {
176701
176798
  }, BUILDER_READY_TIMEOUT_MS);
176702
176799
  this.#builder.start({
176703
176800
  onExit: () => {
176704
- if (settled && ready) {
176705
- this.#stopBackend();
176706
- return;
176707
- }
176708
176801
  settle(() => reject(new Error(`[cli] builder exited before emitting builder-ready (attempt ${attempt})`)));
176709
176802
  },
176710
176803
  onReady: () => {
176711
- ready = true;
176712
176804
  settle(resolve);
176805
+ },
176806
+ onRestartReady: () => {
176807
+ this.logger.verbose("[builder-recovery] builder ready after restart; replaying latest state");
176808
+ this.#replayBuilderState();
176713
176809
  }
176714
176810
  });
176715
176811
  });
176716
176812
  }
176717
176813
  #sendToBuilder(message) {
176718
- if (this.#builder)
176719
- this.#builder.send(message);
176720
- else
176721
- this.logger.warn("akanAppHost is not running");
176814
+ if (this.#builder?.send(message))
176815
+ return;
176816
+ if (message.type === "build-route") {
176817
+ this.#sendToBackend({
176818
+ type: "build-route-res",
176819
+ id: message.id,
176820
+ ok: false,
176821
+ error: `builder is ${this.#builder?.status ?? "stopped"}; reload after the builder is ready`
176822
+ });
176823
+ return;
176824
+ }
176825
+ this.logger.warn("akanAppHost builder is not running");
176722
176826
  }
176723
176827
  #stopBuilder() {
176724
176828
  if (!this.#builder)
@@ -180678,9 +180782,10 @@ var resolveMobileTargetByBasePath = (targets, basePath2) => {
180678
180782
  if (!template)
180679
180783
  return;
180680
180784
  return {
180681
- name: template.name,
180785
+ name: normalizedBasePath,
180682
180786
  config: {
180683
180787
  ...template.config,
180788
+ name: normalizedBasePath,
180684
180789
  basePath: normalizedBasePath
180685
180790
  }
180686
180791
  };
@@ -180734,32 +180839,46 @@ class CapacitorApp {
180734
180839
  project;
180735
180840
  iosTargetName = "App";
180736
180841
  targetRoot;
180842
+ targetRootPath;
180843
+ targetWebRoot;
180844
+ targetAssetRoot;
180845
+ iosRootPath = "ios";
180846
+ iosProjectPath = "ios/App";
180847
+ androidRootPath = "android";
180737
180848
  constructor(app, target) {
180738
180849
  this.app = app;
180739
180850
  this.target = target;
180740
- this.targetRoot = path34.join(this.app.cwdPath, "mobile", this.target.name);
180741
- this.project = new MobileProject(this.targetRoot, {
180742
- android: { path: "android" },
180743
- ios: { path: "ios/App" }
180851
+ this.targetRootPath = path34.posix.join("mobile", this.target.name);
180852
+ this.targetRoot = path34.join(this.app.cwdPath, this.targetRootPath);
180853
+ this.targetWebRoot = path34.join(this.targetRoot, "www");
180854
+ this.targetAssetRoot = path34.join(this.targetRoot, "assets");
180855
+ this.project = new MobileProject(this.app.cwdPath, {
180856
+ android: { path: this.androidRootPath },
180857
+ ios: { path: this.iosProjectPath }
180744
180858
  });
180745
180859
  }
180746
- async init({ platform, regenerate = false } = {}) {
180860
+ async init({
180861
+ platform,
180862
+ operation = "release",
180863
+ env = "debug",
180864
+ regenerate = false
180865
+ } = {}) {
180747
180866
  await mkdir10(this.targetRoot, { recursive: true });
180748
180867
  await this.#writeCapacitorConfig();
180749
180868
  if (regenerate) {
180750
180869
  if (!platform || platform === "ios")
180751
- await rm4(path34.join(this.targetRoot, "ios"), { recursive: true, force: true });
180870
+ await rm4(path34.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
180752
180871
  if (!platform || platform === "android")
180753
- await rm4(path34.join(this.targetRoot, "android"), { recursive: true, force: true });
180872
+ await rm4(path34.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
180754
180873
  }
180755
180874
  const project = this.project;
180756
180875
  await this.project.load();
180757
180876
  if ((!platform || platform === "android") && !project.android) {
180758
- await this.#spawn("npx", ["cap", "add", "android"]);
180877
+ await this.#spawnMobile("npx", ["cap", "add", "android"], { operation, env });
180759
180878
  await this.project.load();
180760
180879
  }
180761
180880
  if ((!platform || platform === "ios") && !project.ios) {
180762
- await this.#spawn("npx", ["cap", "add", "ios"]);
180881
+ await this.#spawnMobile("npx", ["cap", "add", "ios"], { operation, env });
180763
180882
  await this.project.load();
180764
180883
  }
180765
180884
  return this;
@@ -180767,57 +180886,52 @@ class CapacitorApp {
180767
180886
  async save() {
180768
180887
  await this.project.commit();
180769
180888
  }
180770
- async#prepareIos({ regenerate = false } = {}) {
180771
- await this.init({ platform: "ios", regenerate });
180889
+ async#prepareIos({ operation, env, regenerate = false }) {
180890
+ await this.init({ platform: "ios", operation, env, regenerate });
180772
180891
  await this.#prepareTargetAssets();
180773
180892
  await this.#prepareExternalFiles("ios");
180774
180893
  await this.#applyIosMetadata();
180775
180894
  await this.#applyPermissions();
180776
180895
  await this.#applyLinks();
180777
180896
  await this.project.commit();
180778
- await this.#generateAssets();
180897
+ await this.#generateAssets({ operation, env });
180779
180898
  this.app.verbose(`syncing iOS`);
180780
- await this.#spawn("npx", ["cap", "sync", "ios"]);
180899
+ await this.#spawnMobile("npx", ["cap", "sync", "ios"], { operation, env });
180781
180900
  this.app.verbose(`sync completed.`);
180782
180901
  }
180783
- async buildIos(options = {}) {
180902
+ async buildIos({ env = "debug", regenerate = false } = {}) {
180784
180903
  await this.prepareWww();
180785
- await this.#prepareIos(options);
180786
- await this.#spawn("npx", ["cap", "build", "ios"], { stdio: "inherit" });
180904
+ await this.#prepareIos({ operation: "release", env, regenerate });
180905
+ await this.#spawnMobile("npx", ["cap", "build", "ios"], { operation: "release", env }, { stdio: "inherit" });
180787
180906
  this.app.verbose(`build completed iOS.`);
180788
180907
  return;
180789
180908
  }
180790
180909
  async syncIos() {
180791
- await this.#spawn("npx", ["cap", "sync", "ios"]);
180910
+ await this.#spawnMobile("npx", ["cap", "sync", "ios"], { operation: "local", env: "local" });
180792
180911
  }
180793
180912
  async openIos() {
180794
- await this.#spawn("npx", ["cap", "open", "ios"]);
180913
+ await this.#spawnMobile("npx", ["cap", "open", "ios"], { operation: "local", env: "local" });
180795
180914
  }
180796
180915
  async runIos({ operation, env, regenerate = false }) {
180797
180916
  if (operation === "release")
180798
180917
  await this.prepareWww();
180799
- await this.#prepareIos({ regenerate });
180918
+ await this.#prepareIos({ operation, env, regenerate });
180800
180919
  const args = ["cap", "run", "ios"];
180801
- if (operation !== "release")
180802
- args.push("--live-reload");
180803
- await this.#spawn("npx", args, {
180804
- env: this.#commandEnv(operation, env),
180805
- stdio: "inherit"
180806
- });
180920
+ await this.#spawnMobile("npx", args, { operation, env }, { stdio: "inherit" });
180807
180921
  }
180808
- async#prepareAndroid({ regenerate = false } = {}) {
180809
- await this.init({ platform: "android", regenerate });
180922
+ async#prepareAndroid({ operation, env, regenerate = false }) {
180923
+ await this.init({ platform: "android", operation, env, regenerate });
180810
180924
  await this.#prepareTargetAssets();
180811
180925
  await this.#prepareExternalFiles("android");
180812
180926
  await this.#applyAndroidMetadata();
180813
180927
  await this.#applyPermissions();
180814
180928
  await this.#applyLinks();
180815
180929
  await this.project.commit();
180816
- await this.#generateAssets();
180817
- await this.#spawn("npx", ["cap", "sync", "android"]);
180930
+ await this.#generateAssets({ operation, env });
180931
+ await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
180818
180932
  }
180819
180933
  async#updateAndroidBuildTypes() {
180820
- const appGradle = await FileEditor.create(`${this.targetRoot}/android/app/build.gradle`);
180934
+ const appGradle = await FileEditor.create(path34.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
180821
180935
  const buildTypesBlock = `
180822
180936
  debug {
180823
180937
  applicationIdSuffix ".debug"
@@ -180852,54 +180966,49 @@ class CapacitorApp {
180852
180966
  }
180853
180967
  await appGradle.save();
180854
180968
  }
180855
- async buildAndroid(assembleType, options = {}) {
180969
+ async buildAndroid(assembleType, { env = "debug", regenerate = false } = {}) {
180856
180970
  await this.prepareWww();
180857
- await this.#prepareAndroid(options);
180971
+ await this.#prepareAndroid({ operation: "release", env, regenerate });
180858
180972
  await this.#updateAndroidBuildTypes();
180859
180973
  const isWindows = process.platform === "win32";
180860
180974
  const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
180861
180975
  await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
180862
180976
  stdio: "inherit",
180863
- cwd: `${this.targetRoot}/android`
180977
+ cwd: path34.join(this.app.cwdPath, this.androidRootPath),
180978
+ env: this.#commandEnv("release", env)
180864
180979
  });
180865
180980
  }
180866
180981
  async openAndroid() {
180867
- await this.#spawn("npx", ["cap", "open", "android"]);
180982
+ await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
180868
180983
  }
180869
180984
  async syncAndroid(options = {}) {
180870
180985
  await this.prepareWww();
180871
- await this.#prepareAndroid(options);
180986
+ await this.#prepareAndroid({ operation: "release", env: "debug", ...options });
180872
180987
  this.app.log(`Sync Android Completed.`);
180873
180988
  }
180874
180989
  async runAndroid({ operation, env, regenerate = false }) {
180875
180990
  if (operation === "release")
180876
180991
  await this.prepareWww();
180877
- await this.#prepareAndroid({ regenerate });
180992
+ await this.#prepareAndroid({ operation, env, regenerate });
180878
180993
  this.app.logger.info(`Running Android in ${operation} mode on ${env} env`);
180879
180994
  const args = ["cap", "run", "android"];
180880
- if (operation !== "release")
180881
- args.push("--live-reload");
180882
- await this.#spawn("npx", args, {
180883
- env: this.#commandEnv(operation, env),
180884
- stdio: "inherit"
180885
- });
180995
+ await this.#spawnMobile("npx", args, { operation, env }, { stdio: "inherit" });
180886
180996
  }
180887
180997
  async releaseIos() {
180888
180998
  await this.prepareWww();
180889
- await this.#prepareIos();
180999
+ await this.#prepareIos({ operation: "release", env: "main" });
180890
181000
  }
180891
181001
  async releaseAndroid() {
180892
181002
  await this.prepareWww();
180893
- await this.#prepareAndroid();
181003
+ await this.#prepareAndroid({ operation: "release", env: "main" });
180894
181004
  }
180895
181005
  async prepareWww() {
180896
181006
  const htmlSource = path34.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
180897
181007
  if (!await Bun.file(htmlSource).exists())
180898
181008
  throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
180899
- const wwwDir = path34.join(this.targetRoot, "www");
180900
- await rm4(wwwDir, { recursive: true, force: true });
180901
- await mkdir10(wwwDir, { recursive: true });
180902
- await Bun.write(path34.join(wwwDir, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
181009
+ await rm4(this.targetWebRoot, { recursive: true, force: true });
181010
+ await mkdir10(this.targetWebRoot, { recursive: true });
181011
+ await Bun.write(path34.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
180903
181012
  }
180904
181013
  #injectMobileTargetMeta(html) {
180905
181014
  const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
@@ -180911,24 +181020,40 @@ class CapacitorApp {
180911
181020
  }
180912
181021
  async#writeCapacitorConfig() {
180913
181022
  await mkdir10(this.targetRoot, { recursive: true });
180914
- const appInfoPath = path34.relative(this.targetRoot, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
180915
- const baseConfigPath = path34.relative(this.targetRoot, path34.join(this.app.workspace.cwdPath, "pkgs/akanjs/devkit/capacitor.base.config")).split(path34.sep).join("/");
180916
- const content = `import { withBase } from "${baseConfigPath.startsWith(".") ? baseConfigPath : `./${baseConfigPath}`}";
180917
- import appInfo from "${appInfoPath}";
181023
+ const appInfoPath = path34.relative(this.app.cwdPath, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
181024
+ const baseConfigPath = path34.relative(this.app.cwdPath, path34.join(this.app.workspace.cwdPath, "pkgs/akanjs/devkit/capacitor.base.config")).split(path34.sep).join("/");
181025
+ const content = `import type { AppScanResult } from "akanjs/devkit";
181026
+ import { withBase } from "${baseConfigPath.startsWith(".") ? baseConfigPath : `./${baseConfigPath}`}";
181027
+ import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
180918
181028
 
180919
- export default withBase((config) => config, appInfo, "${this.target.name}");
181029
+ export default withBase(
181030
+ (config, target) => ({
181031
+ ...config,
181032
+ webDir: \`mobile/\${target.name}/www\`,
181033
+ android: {
181034
+ ...config.android,
181035
+ path: "android",
181036
+ },
181037
+ ios: {
181038
+ ...config.ios,
181039
+ path: "ios",
181040
+ },
181041
+ }),
181042
+ appInfo as AppScanResult,
181043
+ );
180920
181044
  `;
180921
- await Bun.write(path34.join(this.targetRoot, "capacitor.config.ts"), content);
181045
+ await Bun.write(path34.join(this.app.cwdPath, "capacitor.config.ts"), content);
180922
181046
  }
180923
181047
  async#prepareTargetAssets() {
180924
181048
  if (!this.target.assets)
180925
181049
  return;
180926
- const assetsDir = path34.join(this.targetRoot, "assets");
180927
- await mkdir10(assetsDir, { recursive: true });
181050
+ await mkdir10(this.targetAssetRoot, { recursive: true });
180928
181051
  if (this.target.assets.icon)
180929
- await cp2(path34.join(this.app.cwdPath, this.target.assets.icon), path34.join(assetsDir, "icon.png"), { force: true });
181052
+ await cp2(path34.join(this.app.cwdPath, this.target.assets.icon), path34.join(this.targetAssetRoot, "icon.png"), {
181053
+ force: true
181054
+ });
180930
181055
  if (this.target.assets.splash)
180931
- await cp2(path34.join(this.app.cwdPath, this.target.assets.splash), path34.join(assetsDir, "splash.png"), {
181056
+ await cp2(path34.join(this.app.cwdPath, this.target.assets.splash), path34.join(this.targetAssetRoot, "splash.png"), {
180932
181057
  force: true
180933
181058
  });
180934
181059
  }
@@ -180936,16 +181061,26 @@ export default withBase((config) => config, appInfo, "${this.target.name}");
180936
181061
  const files = this.target.files?.[platform];
180937
181062
  if (!files)
180938
181063
  return;
181064
+ const platformRoot = path34.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
180939
181065
  await Promise.all(Object.entries(files).map(async ([to, from]) => {
180940
- const targetPath = path34.join(this.targetRoot, platform, to);
181066
+ const targetPath = path34.join(platformRoot, to);
180941
181067
  await mkdir10(path34.dirname(targetPath), { recursive: true });
180942
181068
  await cp2(path34.join(this.app.cwdPath, from), targetPath, { force: true });
180943
181069
  }));
180944
181070
  }
180945
- async#generateAssets() {
181071
+ async#generateAssets({ operation, env }) {
180946
181072
  if (!this.target.assets)
180947
181073
  return;
180948
- await this.#spawn("npx", ["@capacitor/assets", "generate"]);
181074
+ await this.#spawnMobile("npx", [
181075
+ "@capacitor/assets",
181076
+ "generate",
181077
+ "--assetPath",
181078
+ path34.posix.join(this.targetRootPath, "assets"),
181079
+ "--iosProject",
181080
+ this.iosProjectPath,
181081
+ "--androidProject",
181082
+ this.androidRootPath
181083
+ ], { operation, env });
180949
181084
  }
180950
181085
  async#applyIosMetadata() {
180951
181086
  this.project.ios.setBundleId("App", "Debug", this.target.appId);
@@ -180995,16 +181130,21 @@ export default withBase((config) => config, appInfo, "${this.target.name}");
180995
181130
  }
180996
181131
  }
180997
181132
  #commandEnv(operation, env) {
180998
- return {
180999
- ...process.env,
181133
+ return this.app.getCommandEnv({
181000
181134
  APP_OPERATION_MODE: operation,
181001
- AKAN_PUBLIC_OPERATION_MODE: operation,
181135
+ AKAN_PUBLIC_OPERATION_MODE: env === "local" ? "local" : "cloud",
181002
181136
  AKAN_PUBLIC_ENV: env,
181003
181137
  AKAN_MOBILE_TARGET: this.target.name
181004
- };
181138
+ });
181005
181139
  }
181006
181140
  async#spawn(command, args = [], options = {}) {
181007
- return await this.app.spawn(command, args, { cwd: this.targetRoot, ...options });
181141
+ return await this.app.spawn(command, args, { cwd: this.app.cwdPath, ...options });
181142
+ }
181143
+ async#spawnMobile(command, args = [], { operation, env }, options = {}) {
181144
+ return await this.#spawn(command, args, {
181145
+ ...options,
181146
+ env: { ...this.#commandEnv(operation, env), ...options.env }
181147
+ });
181008
181148
  }
181009
181149
  async addCamera() {
181010
181150
  await this.#setPermissionInIos({
@@ -182080,7 +182220,20 @@ var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
182080
182220
 
182081
182221
  import { select as select6 } from "@inquirer/prompts";
182082
182222
 
182083
- import { compareVersions } from "compare-versions";
182223
+ function parseVersion(version) {
182224
+ return version.replace(/^[^\d]*/, "").split(/[.-]/).map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
182225
+ }
182226
+ function compareSemver(a, b) {
182227
+ const left = parseVersion(a);
182228
+ const right = parseVersion(b);
182229
+ const length = Math.max(left.length, right.length);
182230
+ for (let i = 0;i < length; i++) {
182231
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
182232
+ if (diff !== 0)
182233
+ return diff > 0 ? 1 : -1;
182234
+ }
182235
+ return 0;
182236
+ }
182084
182237
 
182085
182238
  class LibraryRunner extends runner("library") {
182086
182239
  async createLibrary(libName, workspace) {
@@ -182124,7 +182277,7 @@ class LibraryRunner extends runner("library") {
182124
182277
  const allDependencies = Object.fromEntries(Object.keys({ ...libDependencies, ...rootDependencies }).map((dep) => {
182125
182278
  const libVersion = libDependencies[dep] ?? "0.0.0";
182126
182279
  const rootVersion = rootDependencies[dep] ?? "0.0.0";
182127
- const newerVersion = compareVersions(rootVersion, libVersion) > 0 ? rootVersion : libVersion;
182280
+ const newerVersion = compareSemver(rootVersion, libVersion) > 0 ? rootVersion : libVersion;
182128
182281
  return [dep, newerVersion];
182129
182282
  }));
182130
182283
  Object.keys(allDependencies).sort().forEach((dep) => {
@@ -182180,9 +182333,17 @@ import { StringOutputParser } from "@langchain/core/output_parsers";
182180
182333
  import { PromptTemplate as PromptTemplate2 } from "@langchain/core/prompts";
182181
182334
  import { RunnableSequence as RunnableSequence2 } from "@langchain/core/runnables";
182182
182335
  import { ChatOpenAI as ChatOpenAI3 } from "@langchain/openai";
182183
- import openBrowser from "open";
182184
182336
  import ora3 from "ora";
182185
182337
 
182338
+ import { spawn as spawn2 } from "child_process";
182339
+ function openBrowser(url) {
182340
+ const command3 = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
182341
+ const child = spawn2(command3[0], command3.slice(1), { detached: true, stdio: "ignore" });
182342
+ child.on("error", () => {});
182343
+ child.unref();
182344
+ return Promise.resolve();
182345
+ }
182346
+
182186
182347
  class ApplicationRunner extends runner("application") {
182187
182348
  async createApplication(appName, workspace, libs = []) {
182188
182349
  await workspace.applyTemplate({
@@ -182261,7 +182422,7 @@ class ApplicationRunner extends runner("application") {
182261
182422
  const targets = await resolveMobileTargets(app, target);
182262
182423
  await this.#buildMobileCsr(app, env);
182263
182424
  await this.#runMobileTargets(targets, async (mobileTarget2) => {
182264
- await new CapacitorApp(app, mobileTarget2.config).buildIos({ regenerate });
182425
+ await new CapacitorApp(app, mobileTarget2.config).buildIos({ env, regenerate });
182265
182426
  });
182266
182427
  }
182267
182428
  async startIos(app, {
@@ -182287,14 +182448,14 @@ class ApplicationRunner extends runner("application") {
182287
182448
  const targets = await resolveMobileTargets(app, target);
182288
182449
  await this.#buildMobileCsr(app, env);
182289
182450
  for (const mobileTarget2 of targets) {
182290
- await new CapacitorApp(app, mobileTarget2.config).buildIos({ regenerate });
182451
+ await new CapacitorApp(app, mobileTarget2.config).buildIos({ env, regenerate });
182291
182452
  }
182292
182453
  }
182293
182454
  async buildAndroid(app, { target, env = "debug", regenerate = false } = {}) {
182294
182455
  const targets = await resolveMobileTargets(app, target);
182295
182456
  await this.#buildMobileCsr(app, env);
182296
182457
  await this.#runMobileTargets(targets, async (mobileTarget2) => {
182297
- await new CapacitorApp(app, mobileTarget2.config).buildAndroid("apk", { regenerate });
182458
+ await new CapacitorApp(app, mobileTarget2.config).buildAndroid("apk", { env, regenerate });
182298
182459
  });
182299
182460
  }
182300
182461
  async startAndroid(app, {
@@ -182320,9 +182481,9 @@ class ApplicationRunner extends runner("application") {
182320
182481
  const targets = await resolveMobileTargets(app, target);
182321
182482
  await this.#buildMobileCsr(app, env);
182322
182483
  for (const mobileTarget2 of targets) {
182323
- await new CapacitorApp(app, mobileTarget2.config).buildAndroid(assembleType, { regenerate });
182484
+ await new CapacitorApp(app, mobileTarget2.config).buildAndroid(assembleType, { env, regenerate });
182324
182485
  app.log(`Release Android ${app.name}/${mobileTarget2.name} ${assembleType} Completed.`);
182325
- app.log(`Path : ${app.cwdPath}/mobile/${mobileTarget2.name}/android/app/build/outputs/${assembleType === "apk" ? "apk" : "bundle"}/release`);
182486
+ app.log(`Path : ${app.cwdPath}/android/app/build/outputs/${assembleType === "apk" ? "apk" : "bundle"}/release`);
182326
182487
  }
182327
182488
  }
182328
182489
  async#buildMobileCsr(app, env) {
@@ -182692,7 +182853,10 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
182692
182853
  start: target({ short: true, desc: "Start development server (frontend SSR + backend)" }).with(App).option("open", Boolean, { desc: "open web browser?", default: false }).option("write", Boolean, { desc: "write code generation", default: true }).exec(async function(app, open, write) {
182693
182854
  await this.applicationScript.start(app, { open, write });
182694
182855
  }),
182695
- startIos: target({ short: true, desc: "Start iOS app in simulator or device" }).with(App).option("target", String, { desc: "mobile target name or all" }).option("env", String, {
182856
+ startIos: target({ short: true, desc: "Start iOS app in simulator or device" }).with(App).option("target", String, {
182857
+ ask: "Select mobile target",
182858
+ enum: async ({ app }) => await getMobileTargetChoices(app)
182859
+ }).option("env", String, {
182696
182860
  enum: ["local", "debug", "develop", "main"],
182697
182861
  desc: "backend environment",
182698
182862
  default: "local"
@@ -182877,10 +183041,19 @@ class PackageScript extends script("package", [PackageRunner]) {
182877
183041
 
182878
183042
  import { confirm as confirm3 } from "@inquirer/prompts";
182879
183043
  import chalk7 from "chalk";
182880
- import latestVersion from "latest-version";
182881
- import open from "open";
182882
183044
  import * as QRcode from "qrcode";
182883
- import { v4 as uuidv4 } from "uuid";
183045
+
183046
+ async function getLatestPackageVersion(packageName, tag = "latest") {
183047
+ const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace(/^%40/, "@")}`;
183048
+ const res = await fetch(url);
183049
+ if (!res.ok)
183050
+ throw new Error(`Failed to fetch ${packageName} metadata from npm registry`);
183051
+ const metadata = await res.json();
183052
+ const version = metadata["dist-tags"]?.[tag];
183053
+ if (!version)
183054
+ throw new Error(`No npm dist-tag "${tag}" found for ${packageName}`);
183055
+ return version;
183056
+ }
182884
183057
 
182885
183058
  class CloudRunner extends runner("cloud") {
182886
183059
  async login() {
@@ -182892,7 +183065,7 @@ class CloudRunner extends runner("cloud") {
182892
183065
  `));
182893
183066
  return true;
182894
183067
  }
182895
- const remoteId = uuidv4();
183068
+ const remoteId = crypto.randomUUID();
182896
183069
  const signinUrl = `${akanCloudUrl}/signin?remoteId=${remoteId}`;
182897
183070
  Logger.rawLog(chalk7.bold(`
182898
183071
  ${chalk7.green("\u27A4")} Authentication Required`));
@@ -182908,7 +183081,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
182908
183081
  });
182909
183082
  });
182910
183083
  Logger.rawLog(qrcode);
182911
- await open(signinUrl);
183084
+ await openBrowser(signinUrl);
182912
183085
  Logger.rawLog(chalk7.dim("Opening browser..."));
182913
183086
  } catch {
182914
183087
  Logger.rawLog(chalk7.yellow("Could not open browser. Please visit the URL manually."));
@@ -182969,11 +183142,11 @@ ${chalk7.green("\u27A4")} Authentication Required`));
182969
183142
  const tag = isOfficialRelease ? "latest" : patchVersion.split("-").at(1) ?? "dev";
182970
183143
  const getNextVersion = async (prefix, tag2) => {
182971
183144
  try {
182972
- const latestPublishedVersion2 = await latestVersion("akanjs", { version: tag2 });
183145
+ const latestPublishedVersion2 = await getLatestPackageVersion("akanjs", tag2);
182973
183146
  const latestPatch = latestPublishedVersion2.startsWith(prefix) ? parseInt(latestPublishedVersion2.split(".").at(-1) ?? "-1") : -1;
182974
183147
  const nextVersion2 = `${prefix}.${latestPatch + 1}`;
182975
183148
  return { nextVersion: nextVersion2, latestPublishedVersion: latestPublishedVersion2 };
182976
- } catch (e) {
183149
+ } catch {
182977
183150
  return { nextVersion: `${prefix}.0`, latestPublishedVersion: null };
182978
183151
  }
182979
183152
  };
@@ -183012,7 +183185,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
183012
183185
  ]);
183013
183186
  }
183014
183187
  async#updateAkanPkgs(workspace, tag = "latest") {
183015
- const latestPublishedVersion = await latestVersion("akanjs", { version: tag });
183188
+ const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag);
183016
183189
  const rootPackageJson = await workspace.getPackageJson();
183017
183190
  if (!rootPackageJson.dependencies)
183018
183191
  throw new Error("No dependencies found in package.json");
@@ -183685,7 +183858,13 @@ var requestUnit = ({
183685
183858
 
183686
183859
  `;
183687
183860
 
183688
- import pluralize from "pluralize";
183861
+ function pluralizeName(name) {
183862
+ if (/[^aeiou]y$/i.test(name))
183863
+ return `${name.slice(0, -1)}ies`;
183864
+ if (/(s|x|z|ch|sh)$/i.test(name))
183865
+ return `${name}es`;
183866
+ return `${name}s`;
183867
+ }
183689
183868
 
183690
183869
  class ModuleRunner extends runner("module") {
183691
183870
  async createModule(workspace, sysType, sysName, moduleName, description) {}
@@ -183706,7 +183885,7 @@ class ModuleRunner extends runner("module") {
183706
183885
  };
183707
183886
  }
183708
183887
  async createModuleTemplate(module) {
183709
- const names = pluralize(module.name);
183888
+ const names = pluralizeName(module.name);
183710
183889
  await module.applyTemplate({
183711
183890
  basePath: `.`,
183712
183891
  template: "module",
@@ -183916,11 +184095,7 @@ class PageCommand extends command("page", [PageScript], ({ public: target }) =>
183916
184095
  })) {
183917
184096
  }
183918
184097
 
183919
- import pluralize3 from "pluralize";
183920
-
183921
184098
  import { input as input5 } from "@inquirer/prompts";
183922
- import pluralize2 from "pluralize";
183923
-
183924
184099
  class ScalarPrompt extends Prompter {
183925
184100
  sys;
183926
184101
  name;
@@ -183940,7 +184115,7 @@ class ScalarPrompt extends Prompter {
183940
184115
  await this.sys.applyTemplate({
183941
184116
  basePath: "./lib/__scalar",
183942
184117
  template: "__scalar",
183943
- dict: { model: this.name, models: pluralize2(this.name), sysName: this.sys.name }
184118
+ dict: { model: this.name, models: pluralizeName(this.name), sysName: this.sys.name }
183944
184119
  });
183945
184120
  const boilerplate = await this.sys.readFile(`lib/__scalar/${this.name}/${this.name}.constant.ts`);
183946
184121
  return await this.#requestConstant({
@@ -184044,7 +184219,7 @@ class ScalarRunner extends runner("scalar") {
184044
184219
  await sys3.applyTemplate({
184045
184220
  basePath: "./lib/__scalar",
184046
184221
  template: "__scalar",
184047
- dict: { model: scalarName, models: pluralize3(scalarName), sysName: sys3.name },
184222
+ dict: { model: scalarName, models: pluralizeName(scalarName), sysName: sys3.name },
184048
184223
  overwrite: false
184049
184224
  });
184050
184225
  }
@@ -184100,15 +184275,13 @@ class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target
184100
184275
  import path38 from "path";
184101
184276
 
184102
184277
  import path37 from "path";
184103
- import latestVersion2 from "latest-version";
184104
-
184105
184278
  class WorkspaceRunner extends runner("workspace") {
184106
184279
  async createWorkspace(repoName, appName, { dirname: dirname3 = ".", init = true, akanVersion }) {
184107
184280
  const cwdPath = process.cwd();
184108
184281
  const workspaceRoot = path37.join(cwdPath, dirname3, repoName);
184109
184282
  const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
184110
184283
  const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname3}/${repoName}...`);
184111
- const latestTypesBunVersion = await latestVersion2("@types/bun");
184284
+ const latestTypesBunVersion = await getLatestPackageVersion("@types/bun");
184112
184285
  await workspace.applyTemplate({
184113
184286
  basePath: ".",
184114
184287
  template: "workspaceRoot",