@akanjs/cli 2.1.2-rc.1 → 2.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,8 +20,8 @@ import chalk from "chalk";
20
20
  // pkgs/@akanjs/devkit/cloud/constants.ts
21
21
  var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
22
22
  var configPath = `${basePath}/config.json`;
23
- var akanCloudHost = process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? "http://localhost" : "https://cloud.akanjs.com";
24
- var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? ":8282" : ""}/api`;
23
+ var akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? "http://localhost" : "https://cloud.akanjs.com";
24
+ var akanCloudUrl = `${akanCloudHost}${process.env.USE_AKANJS_PKGS === "true" ? ":8282" : ""}/api`;
25
25
  var defaultHostConfig = {};
26
26
  var defaultAkanGlobalConfig = {
27
27
  cloudHost: {},
@@ -4608,6 +4608,11 @@ import { loadFonts } from "akanjs/client";
4608
4608
  import { System } from "akanjs/ui";
4609
4609
  import { env } from "@apps/${opts.appName}/env/env.client";
4610
4610
  ${clientImport}${inheritedImport}${userImport}
4611
+ // SSR builds (target=bun) load the full dictionary server-side and pass only the active locale to the client.
4612
+ // CSR builds (target=browser) fold this branch to undefined, so the macro-seeded dictionary is used and the
4613
+ // server-only dict module (which pulls @libs/*/server) is dead-code-eliminated out of the browser bundle.
4614
+ const getActiveLocaleDictionary =
4615
+ process.env.AKAN_PUBLIC_RENDER_ENV === "ssr" ? (await import("@apps/${opts.appName}/lib/dict")).getDictionary : undefined;
4611
4616
  const userFonts = userLayout.fonts ?? inheritedLayout.fonts ?? [];
4612
4617
  const defaultFonts = userFonts.filter((font) => font.default);
4613
4618
  if (defaultFonts.length > 1) throw new Error("[route-convention] only one default font is allowed per root layout");
@@ -4639,6 +4644,7 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
4639
4644
  gaTrackingId={userLayout.gaTrackingId ?? inheritedLayout.gaTrackingId}
4640
4645
  layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
4641
4646
  reconnect={userLayout.reconnect ?? inheritedLayout.reconnect ?? false}
4647
+ dictionary={getActiveLocaleDictionary ? getActiveLocaleDictionary(params.lang) : undefined}
4642
4648
  >
4643
4649
  <UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>
4644
4650
  </System.Provider>
@@ -6228,7 +6234,9 @@ import { mkdir as mkdir5, rm, unlink } from "fs/promises";
6228
6234
  import path21 from "path";
6229
6235
 
6230
6236
  // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
6237
+ import fs3 from "fs";
6231
6238
  import path20 from "path";
6239
+ import ts5 from "typescript";
6232
6240
 
6233
6241
  class PagesEntrySourceGenerator {
6234
6242
  #pageEntries;
@@ -6257,8 +6265,9 @@ ${lines.join(`
6257
6265
  const absPath = path20.resolve(moduleAbsPath);
6258
6266
  return `import * as page${index} from ${JSON.stringify(absPath)};`;
6259
6267
  });
6260
- const entries = this.#pageEntries.map(({ key }, index) => {
6261
- return ` ${JSON.stringify(key)}: async () => page${index},`;
6268
+ const entries = this.#pageEntries.map(({ key, moduleAbsPath }, index) => {
6269
+ const isAsyncDefault = PagesEntrySourceGenerator.#hasAsyncDefaultExport(moduleAbsPath);
6270
+ return ` ${JSON.stringify(key)}: { loader: async () => page${index}, isAsyncDefault: ${isAsyncDefault} },`;
6262
6271
  });
6263
6272
  return `${imports.join(`
6264
6273
  `)}
@@ -6268,6 +6277,63 @@ ${entries.join(`
6268
6277
  };
6269
6278
  `;
6270
6279
  }
6280
+ static #hasAsyncDefaultExport(moduleAbsPath) {
6281
+ try {
6282
+ const source = fs3.readFileSync(path20.resolve(moduleAbsPath), "utf8");
6283
+ const sourceFile = ts5.createSourceFile(moduleAbsPath, source, ts5.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
6284
+ return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile);
6285
+ } catch {
6286
+ return false;
6287
+ }
6288
+ }
6289
+ static #sourceFileHasAsyncDefaultExport(sourceFile) {
6290
+ const asyncBindings = new Map;
6291
+ let defaultIdentifier = null;
6292
+ for (const statement of sourceFile.statements) {
6293
+ if (ts5.isFunctionDeclaration(statement)) {
6294
+ if (PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.DefaultKeyword)) {
6295
+ return PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword);
6296
+ }
6297
+ if (statement.name) {
6298
+ asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword));
6299
+ }
6300
+ continue;
6301
+ }
6302
+ if (ts5.isVariableStatement(statement)) {
6303
+ for (const declaration of statement.declarationList.declarations) {
6304
+ if (!ts5.isIdentifier(declaration.name))
6305
+ continue;
6306
+ asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
6307
+ }
6308
+ continue;
6309
+ }
6310
+ if (ts5.isExportAssignment(statement)) {
6311
+ if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
6312
+ return true;
6313
+ if (ts5.isIdentifier(statement.expression))
6314
+ defaultIdentifier = statement.expression.text;
6315
+ continue;
6316
+ }
6317
+ if (ts5.isExportDeclaration(statement) && statement.exportClause && ts5.isNamedExports(statement.exportClause)) {
6318
+ const exportClause = statement.exportClause;
6319
+ for (const specifier of exportClause.elements) {
6320
+ if (specifier.name.text !== "default")
6321
+ continue;
6322
+ defaultIdentifier = specifier.propertyName?.text ?? specifier.name.text;
6323
+ }
6324
+ }
6325
+ }
6326
+ return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
6327
+ }
6328
+ static #hasModifier(node, kind) {
6329
+ return ts5.canHaveModifiers(node) && (ts5.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
6330
+ }
6331
+ static #isAsyncFunctionExpression(node) {
6332
+ return Boolean(node && (ts5.isArrowFunction(node) || ts5.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts5.SyntaxKind.AsyncKeyword));
6333
+ }
6334
+ static #scriptKind(moduleAbsPath) {
6335
+ return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts5.ScriptKind.TSX : ts5.ScriptKind.TS;
6336
+ }
6271
6337
  }
6272
6338
 
6273
6339
  // pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
@@ -6403,6 +6469,13 @@ ${remainingAssets.join(`
6403
6469
  jsFiles.push(jsPath);
6404
6470
  return await Bun.file(jsPath).text();
6405
6471
  });
6472
+ const bundledCss = (await Promise.all(cssFiles.map((cssFile) => Bun.file(cssFile).text().catch(() => "")))).filter(Boolean).join(`
6473
+ `);
6474
+ if (bundledCss) {
6475
+ const style = CsrArtifactBuilder.createInlineStyle(bundledCss);
6476
+ if (!next.includes(style))
6477
+ next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
6478
+ }
6406
6479
  if (cssAsset) {
6407
6480
  const cssPath = path21.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
6408
6481
  const css = await Bun.file(cssPath).text();
@@ -6881,7 +6954,7 @@ import {
6881
6954
  } from "fontaine";
6882
6955
  import { createFont, woff2 } from "fonteditor-core";
6883
6956
  import subsetFont from "subset-font";
6884
- import ts5 from "typescript";
6957
+ import ts6 from "typescript";
6885
6958
  var FONT_URL_PREFIX = "/_akan/fonts";
6886
6959
  var DEFAULT_FONT_SUBSETS = ["latin"];
6887
6960
 
@@ -6946,17 +7019,17 @@ class FontOptimizer {
6946
7019
  this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
6947
7020
  }
6948
7021
  #extractFontsExport(source, filePath) {
6949
- const sourceFile = ts5.createSourceFile(filePath, source, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
7022
+ const sourceFile = ts6.createSourceFile(filePath, source, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TSX);
6950
7023
  const fonts = [];
6951
7024
  for (const statement of sourceFile.statements) {
6952
- if (!ts5.isVariableStatement(statement))
7025
+ if (!ts6.isVariableStatement(statement))
6953
7026
  continue;
6954
- const modifiers = ts5.canHaveModifiers(statement) ? ts5.getModifiers(statement) : undefined;
6955
- const isExported = modifiers?.some((modifier) => modifier.kind === ts5.SyntaxKind.ExportKeyword) ?? false;
7027
+ const modifiers = ts6.canHaveModifiers(statement) ? ts6.getModifiers(statement) : undefined;
7028
+ const isExported = modifiers?.some((modifier) => modifier.kind === ts6.SyntaxKind.ExportKeyword) ?? false;
6956
7029
  if (!isExported)
6957
7030
  continue;
6958
7031
  for (const declaration of statement.declarationList.declarations) {
6959
- if (!ts5.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
7032
+ if (!ts6.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
6960
7033
  continue;
6961
7034
  const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
6962
7035
  if (Array.isArray(value)) {
@@ -6967,20 +7040,20 @@ class FontOptimizer {
6967
7040
  return fonts;
6968
7041
  }
6969
7042
  #literalToValue(node) {
6970
- if (ts5.isStringLiteralLike(node))
7043
+ if (ts6.isStringLiteralLike(node))
6971
7044
  return node.text;
6972
- if (ts5.isNumericLiteral(node))
7045
+ if (ts6.isNumericLiteral(node))
6973
7046
  return Number(node.text);
6974
- if (node.kind === ts5.SyntaxKind.TrueKeyword)
7047
+ if (node.kind === ts6.SyntaxKind.TrueKeyword)
6975
7048
  return true;
6976
- if (node.kind === ts5.SyntaxKind.FalseKeyword)
7049
+ if (node.kind === ts6.SyntaxKind.FalseKeyword)
6977
7050
  return false;
6978
- if (ts5.isArrayLiteralExpression(node))
7051
+ if (ts6.isArrayLiteralExpression(node))
6979
7052
  return node.elements.map((element) => this.#literalToValue(element));
6980
- if (ts5.isObjectLiteralExpression(node)) {
7053
+ if (ts6.isObjectLiteralExpression(node)) {
6981
7054
  const obj = {};
6982
7055
  for (const prop of node.properties) {
6983
- if (!ts5.isPropertyAssignment(prop))
7056
+ if (!ts6.isPropertyAssignment(prop))
6984
7057
  continue;
6985
7058
  const name = this.#getPropertyName(prop.name);
6986
7059
  if (!name)
@@ -6989,13 +7062,13 @@ class FontOptimizer {
6989
7062
  }
6990
7063
  return obj;
6991
7064
  }
6992
- if (ts5.isAsExpression(node) || ts5.isSatisfiesExpression(node) || ts5.isParenthesizedExpression(node)) {
7065
+ if (ts6.isAsExpression(node) || ts6.isSatisfiesExpression(node) || ts6.isParenthesizedExpression(node)) {
6993
7066
  return this.#literalToValue(node.expression);
6994
7067
  }
6995
7068
  return;
6996
7069
  }
6997
7070
  #getPropertyName(name) {
6998
- if (ts5.isIdentifier(name) || ts5.isStringLiteral(name) || ts5.isNumericLiteral(name))
7071
+ if (ts6.isIdentifier(name) || ts6.isStringLiteral(name) || ts6.isNumericLiteral(name))
6999
7072
  return name.text;
7000
7073
  return null;
7001
7074
  }
@@ -7295,7 +7368,7 @@ class HmrChangeClassifier {
7295
7368
  }
7296
7369
  }
7297
7370
  // pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
7298
- import fs3 from "fs";
7371
+ import fs4 from "fs";
7299
7372
  import path26 from "path";
7300
7373
  class HmrWatcher {
7301
7374
  #roots;
@@ -7317,7 +7390,7 @@ class HmrWatcher {
7317
7390
  start() {
7318
7391
  for (const root of this.#roots) {
7319
7392
  try {
7320
- const w = fs3.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
7393
+ const w = fs4.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
7321
7394
  if (!filename)
7322
7395
  return;
7323
7396
  const abs = path26.resolve(root, filename.toString());
@@ -7612,7 +7685,7 @@ class PagesBundleBuilder {
7612
7685
  }
7613
7686
  }
7614
7687
  // pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
7615
- import fs4 from "fs";
7688
+ import fs5 from "fs";
7616
7689
  import path29 from "path";
7617
7690
  var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
7618
7691
  var MIN_COMPRESS_BYTES = 1024;
@@ -7626,7 +7699,7 @@ async function precompressArtifacts(app) {
7626
7699
  return result;
7627
7700
  }
7628
7701
  async function precompressRoot(root, result) {
7629
- if (!fs4.existsSync(root) || !fs4.statSync(root).isDirectory())
7702
+ if (!fs5.existsSync(root) || !fs5.statSync(root).isDirectory())
7630
7703
  return;
7631
7704
  const glob = new Bun.Glob("**/*");
7632
7705
  for await (const filePath of glob.scan({ cwd: root, absolute: true })) {
@@ -7664,9 +7737,7 @@ function formatBytes(bytes) {
7664
7737
  import path30 from "path";
7665
7738
  import { optimize } from "@tailwindcss/node";
7666
7739
  function prepareCssAsset(command, basePath2, cssText) {
7667
- if (command !== "build")
7668
- return cssText;
7669
- return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: true }).code;
7740
+ return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: command === "build" }).code;
7670
7741
  }
7671
7742
 
7672
7743
  class SsrBaseArtifactBuilder {
@@ -7773,7 +7844,7 @@ ${preparedCssText}`).toString(36);
7773
7844
  }
7774
7845
  }
7775
7846
  // pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
7776
- import fs5 from "fs";
7847
+ import fs6 from "fs";
7777
7848
  import path31 from "path";
7778
7849
 
7779
7850
  class WatchRootResolver {
@@ -7793,7 +7864,7 @@ class WatchRootResolver {
7793
7864
  continue;
7794
7865
  const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
7795
7866
  const resolved = path31.resolve(this.#app.workspace.workspaceRoot, cleaned);
7796
- if (fs5.existsSync(resolved))
7867
+ if (fs6.existsSync(resolved))
7797
7868
  set.add(resolved);
7798
7869
  }
7799
7870
  }
@@ -8616,10 +8687,11 @@ class CapacitorApp {
8616
8687
  iosRootPath = "ios";
8617
8688
  iosProjectPath = "ios/App";
8618
8689
  androidRootPath = "android";
8690
+ androidAssetsPath = "android/app/src/main/assets";
8619
8691
  constructor(app, target) {
8620
8692
  this.app = app;
8621
8693
  this.target = target;
8622
- this.targetRootPath = path35.posix.join("mobile", this.target.name);
8694
+ this.targetRootPath = path35.posix.join(".akan", "mobile", this.target.name);
8623
8695
  this.targetRoot = path35.join(this.app.cwdPath, this.targetRootPath);
8624
8696
  this.targetWebRoot = path35.join(this.targetRoot, "www");
8625
8697
  this.targetAssetRoot = path35.join(this.targetRoot, "assets");
@@ -8699,6 +8771,8 @@ class CapacitorApp {
8699
8771
  await this.#applyLinks();
8700
8772
  await this.project.commit();
8701
8773
  await this.#generateAssets({ operation, env });
8774
+ await this.#ensureAndroidAssetsDir();
8775
+ await this.#ensureAndroidDebugKeystore();
8702
8776
  await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
8703
8777
  }
8704
8778
  async#updateAndroidBuildTypes() {
@@ -8746,12 +8820,40 @@ class CapacitorApp {
8746
8820
  await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
8747
8821
  stdio: "inherit",
8748
8822
  cwd: path35.join(this.app.cwdPath, this.androidRootPath),
8749
- env: this.#commandEnv("release", env)
8823
+ env: await this.#commandEnv("release", env)
8750
8824
  });
8751
8825
  }
8752
8826
  async openAndroid() {
8753
8827
  await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
8754
8828
  }
8829
+ async#ensureAndroidAssetsDir() {
8830
+ await mkdir10(path35.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
8831
+ }
8832
+ async#ensureAndroidDebugKeystore() {
8833
+ const keystorePath = path35.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
8834
+ if (await Bun.file(keystorePath).exists())
8835
+ return;
8836
+ await this.#spawn("keytool", [
8837
+ "-genkeypair",
8838
+ "-v",
8839
+ "-keystore",
8840
+ keystorePath,
8841
+ "-storepass",
8842
+ "android",
8843
+ "-alias",
8844
+ "androiddebugkey",
8845
+ "-keypass",
8846
+ "android",
8847
+ "-keyalg",
8848
+ "RSA",
8849
+ "-keysize",
8850
+ "2048",
8851
+ "-validity",
8852
+ "10000",
8853
+ "-dname",
8854
+ "CN=Android Debug,O=Android,C=US"
8855
+ ]);
8856
+ }
8755
8857
  async syncAndroid(options = {}) {
8756
8858
  await this.prepareWww();
8757
8859
  await this.#prepareAndroid({ operation: "release", env: "debug", ...options });
@@ -8793,13 +8895,13 @@ class CapacitorApp {
8793
8895
  await mkdir10(this.targetRoot, { recursive: true });
8794
8896
  const appInfoPath = path35.relative(this.app.cwdPath, path35.join(this.app.cwdPath, "akan.app.json")).split(path35.sep).join("/");
8795
8897
  const content = `import type { AppScanResult } from "akanjs";
8796
- import { withBase } from "akanjs/capacitor.base.config";
8898
+ import { withBase } from "${process.env.USE_AKANJS_PKGS === "true" ? "../../pkgs/" : ""}akanjs/capacitor.base.config";
8797
8899
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
8798
8900
 
8799
8901
  export default withBase(
8800
8902
  (config, target) => ({
8801
8903
  ...config,
8802
- webDir: \`mobile/\${target.name}/www\`,
8904
+ webDir: \`.akan/mobile/\${target.name}/www\`,
8803
8905
  android: {
8804
8906
  ...config.android,
8805
8907
  path: "android",
@@ -8899,12 +9001,14 @@ export default withBase(
8899
9001
  this.project.android.getAndroidManifest().injectFragment("activity", `<intent-filter android:autoVerify="true"><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><data android:scheme="https" android:host="${host}" android:pathPrefix="${pathPrefix}" /></intent-filter>`);
8900
9002
  }
8901
9003
  }
8902
- #commandEnv(operation, env) {
9004
+ async#commandEnv(operation, env) {
9005
+ const devPort = operation === "local" ? (await this.app.getDevPort()).toString() : undefined;
8903
9006
  return this.app.getCommandEnv({
8904
9007
  APP_OPERATION_MODE: operation,
8905
9008
  AKAN_PUBLIC_OPERATION_MODE: env === "local" ? "local" : "cloud",
8906
9009
  AKAN_PUBLIC_ENV: env,
8907
- AKAN_MOBILE_TARGET: this.target.name
9010
+ AKAN_MOBILE_TARGET: this.target.name,
9011
+ ...devPort ? { PORT: devPort, AKAN_PUBLIC_CLIENT_PORT: devPort, AKAN_PUBLIC_SERVER_PORT: devPort } : {}
8908
9012
  });
8909
9013
  }
8910
9014
  async#spawn(command, args = [], options = {}) {
@@ -8913,7 +9017,7 @@ export default withBase(
8913
9017
  async#spawnMobile(command, args = [], { operation, env }, options = {}) {
8914
9018
  return await this.#spawn(command, args, {
8915
9019
  ...options,
8916
- env: { ...this.#commandEnv(operation, env), ...options.env }
9020
+ env: { ...await this.#commandEnv(operation, env), ...options.env }
8917
9021
  });
8918
9022
  }
8919
9023
  async addCamera() {
@@ -9773,7 +9877,7 @@ import yaml from "js-yaml";
9773
9877
  // pkgs/@akanjs/devkit/getRelatedCnsts.ts
9774
9878
  import { readFileSync as readFileSync4, realpathSync } from "fs";
9775
9879
  import ora2 from "ora";
9776
- import * as ts6 from "typescript";
9880
+ import * as ts7 from "typescript";
9777
9881
  var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
9778
9882
  var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
9779
9883
  var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
@@ -9806,10 +9910,10 @@ var scanModuleSpecifiers = (source, filePath, includeExports) => {
9806
9910
  return importSpecifiers;
9807
9911
  };
9808
9912
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
9809
- const configFile = ts6.readConfigFile(tsConfigPath, (path37) => {
9810
- return ts6.sys.readFile(path37);
9913
+ const configFile = ts7.readConfigFile(tsConfigPath, (path37) => {
9914
+ return ts7.sys.readFile(path37);
9811
9915
  });
9812
- return ts6.parseJsonConfigFileContent(configFile.config, ts6.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
9916
+ return ts7.parseJsonConfigFileContent(configFile.config, ts7.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
9813
9917
  };
9814
9918
  var collectImportedFiles = (constantFilePath, parsedConfig) => {
9815
9919
  const allFilesToAnalyze = new Set([constantFilePath]);
@@ -9824,7 +9928,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
9824
9928
  for (const importPath of scanModuleSpecifiers(source, filePath, false)) {
9825
9929
  if (!importPath.startsWith("."))
9826
9930
  continue;
9827
- const resolved = ts6.resolveModuleName(importPath, filePath, parsedConfig.options, ts6.sys).resolvedModule?.resolvedFileName;
9931
+ const resolved = ts7.resolveModuleName(importPath, filePath, parsedConfig.options, ts7.sys).resolvedModule?.resolvedFileName;
9828
9932
  if (resolved && !allFilesToAnalyze.has(resolved)) {
9829
9933
  allFilesToAnalyze.add(resolved);
9830
9934
  collectImported(resolved);
@@ -9841,7 +9945,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
9841
9945
  var createTsProgram = (filePaths, options) => {
9842
9946
  const spinner = ora2("Creating TypeScript program for all files...");
9843
9947
  spinner.start();
9844
- const program2 = ts6.createProgram(Array.from(filePaths), options);
9948
+ const program2 = ts7.createProgram(Array.from(filePaths), options);
9845
9949
  const checker = program2.getTypeChecker();
9846
9950
  spinner.succeed("TypeScript program created.");
9847
9951
  return {
@@ -9881,17 +9985,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
9881
9985
  function visit(node) {
9882
9986
  if (!source)
9883
9987
  return;
9884
- if (ts6.isPropertyAccessExpression(node)) {
9988
+ if (ts7.isPropertyAccessExpression(node)) {
9885
9989
  const left = node.expression;
9886
9990
  const right = node.name;
9887
- const { line } = ts6.getLineAndCharacterOfPosition(source, node.getStart());
9888
- if (ts6.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
9991
+ const { line } = ts7.getLineAndCharacterOfPosition(source, node.getStart());
9992
+ if (ts7.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
9889
9993
  const symbol = getCachedSymbol(right);
9890
9994
  if (symbol?.declarations && symbol.declarations.length > 0) {
9891
9995
  const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
9892
9996
  const property = propertyMap.get(key);
9893
9997
  const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
9894
- const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts6.sys.getCurrentDirectory()}/`, "");
9998
+ const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts7.sys.getCurrentDirectory()}/`, "");
9895
9999
  if (!symbolFilePath)
9896
10000
  throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
9897
10001
  if (property) {
@@ -9915,10 +10019,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
9915
10019
  }
9916
10020
  }
9917
10021
  }
9918
- } else if (ts6.isImportDeclaration(node) && ts6.isStringLiteral(node.moduleSpecifier)) {
10022
+ } else if (ts7.isImportDeclaration(node) && ts7.isStringLiteral(node.moduleSpecifier)) {
9919
10023
  const importPath = node.moduleSpecifier.text;
9920
10024
  if (importPath.startsWith(".")) {
9921
- const resolved = ts6.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts6.sys).resolvedModule?.resolvedFileName;
10025
+ const resolved = ts7.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts7.sys).resolvedModule?.resolvedFileName;
9922
10026
  const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
9923
10027
  const property = propertyMap.get(moduleName);
9924
10028
  const isScalar = importPath.includes("_");
@@ -9933,7 +10037,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
9933
10037
  }
9934
10038
  }
9935
10039
  }
9936
- ts6.forEachChild(node, visit);
10040
+ ts7.forEachChild(node, visit);
9937
10041
  }
9938
10042
  visit(source);
9939
10043
  }
package/index.js CHANGED
@@ -18,8 +18,8 @@ import chalk from "chalk";
18
18
  // pkgs/@akanjs/devkit/cloud/constants.ts
19
19
  var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
20
20
  var configPath = `${basePath}/config.json`;
21
- var akanCloudHost = process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? "http://localhost" : "https://cloud.akanjs.com";
22
- var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? ":8282" : ""}/api`;
21
+ var akanCloudHost = process.env.USE_AKANJS_PKGS === "true" ? "http://localhost" : "https://cloud.akanjs.com";
22
+ var akanCloudUrl = `${akanCloudHost}${process.env.USE_AKANJS_PKGS === "true" ? ":8282" : ""}/api`;
23
23
  var defaultHostConfig = {};
24
24
  var defaultAkanGlobalConfig = {
25
25
  cloudHost: {},
@@ -4606,6 +4606,11 @@ import { loadFonts } from "akanjs/client";
4606
4606
  import { System } from "akanjs/ui";
4607
4607
  import { env } from "@apps/${opts.appName}/env/env.client";
4608
4608
  ${clientImport}${inheritedImport}${userImport}
4609
+ // SSR builds (target=bun) load the full dictionary server-side and pass only the active locale to the client.
4610
+ // CSR builds (target=browser) fold this branch to undefined, so the macro-seeded dictionary is used and the
4611
+ // server-only dict module (which pulls @libs/*/server) is dead-code-eliminated out of the browser bundle.
4612
+ const getActiveLocaleDictionary =
4613
+ process.env.AKAN_PUBLIC_RENDER_ENV === "ssr" ? (await import("@apps/${opts.appName}/lib/dict")).getDictionary : undefined;
4609
4614
  const userFonts = userLayout.fonts ?? inheritedLayout.fonts ?? [];
4610
4615
  const defaultFonts = userFonts.filter((font) => font.default);
4611
4616
  if (defaultFonts.length > 1) throw new Error("[route-convention] only one default font is allowed per root layout");
@@ -4637,6 +4642,7 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
4637
4642
  gaTrackingId={userLayout.gaTrackingId ?? inheritedLayout.gaTrackingId}
4638
4643
  layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
4639
4644
  reconnect={userLayout.reconnect ?? inheritedLayout.reconnect ?? false}
4645
+ dictionary={getActiveLocaleDictionary ? getActiveLocaleDictionary(params.lang) : undefined}
4640
4646
  >
4641
4647
  <UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>
4642
4648
  </System.Provider>
@@ -6226,7 +6232,9 @@ import { mkdir as mkdir5, rm, unlink } from "fs/promises";
6226
6232
  import path21 from "path";
6227
6233
 
6228
6234
  // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
6235
+ import fs3 from "fs";
6229
6236
  import path20 from "path";
6237
+ import ts5 from "typescript";
6230
6238
 
6231
6239
  class PagesEntrySourceGenerator {
6232
6240
  #pageEntries;
@@ -6255,8 +6263,9 @@ ${lines.join(`
6255
6263
  const absPath = path20.resolve(moduleAbsPath);
6256
6264
  return `import * as page${index} from ${JSON.stringify(absPath)};`;
6257
6265
  });
6258
- const entries = this.#pageEntries.map(({ key }, index) => {
6259
- return ` ${JSON.stringify(key)}: async () => page${index},`;
6266
+ const entries = this.#pageEntries.map(({ key, moduleAbsPath }, index) => {
6267
+ const isAsyncDefault = PagesEntrySourceGenerator.#hasAsyncDefaultExport(moduleAbsPath);
6268
+ return ` ${JSON.stringify(key)}: { loader: async () => page${index}, isAsyncDefault: ${isAsyncDefault} },`;
6260
6269
  });
6261
6270
  return `${imports.join(`
6262
6271
  `)}
@@ -6266,6 +6275,63 @@ ${entries.join(`
6266
6275
  };
6267
6276
  `;
6268
6277
  }
6278
+ static #hasAsyncDefaultExport(moduleAbsPath) {
6279
+ try {
6280
+ const source = fs3.readFileSync(path20.resolve(moduleAbsPath), "utf8");
6281
+ const sourceFile = ts5.createSourceFile(moduleAbsPath, source, ts5.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
6282
+ return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile);
6283
+ } catch {
6284
+ return false;
6285
+ }
6286
+ }
6287
+ static #sourceFileHasAsyncDefaultExport(sourceFile) {
6288
+ const asyncBindings = new Map;
6289
+ let defaultIdentifier = null;
6290
+ for (const statement of sourceFile.statements) {
6291
+ if (ts5.isFunctionDeclaration(statement)) {
6292
+ if (PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.DefaultKeyword)) {
6293
+ return PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword);
6294
+ }
6295
+ if (statement.name) {
6296
+ asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts5.SyntaxKind.AsyncKeyword));
6297
+ }
6298
+ continue;
6299
+ }
6300
+ if (ts5.isVariableStatement(statement)) {
6301
+ for (const declaration of statement.declarationList.declarations) {
6302
+ if (!ts5.isIdentifier(declaration.name))
6303
+ continue;
6304
+ asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
6305
+ }
6306
+ continue;
6307
+ }
6308
+ if (ts5.isExportAssignment(statement)) {
6309
+ if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
6310
+ return true;
6311
+ if (ts5.isIdentifier(statement.expression))
6312
+ defaultIdentifier = statement.expression.text;
6313
+ continue;
6314
+ }
6315
+ if (ts5.isExportDeclaration(statement) && statement.exportClause && ts5.isNamedExports(statement.exportClause)) {
6316
+ const exportClause = statement.exportClause;
6317
+ for (const specifier of exportClause.elements) {
6318
+ if (specifier.name.text !== "default")
6319
+ continue;
6320
+ defaultIdentifier = specifier.propertyName?.text ?? specifier.name.text;
6321
+ }
6322
+ }
6323
+ }
6324
+ return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
6325
+ }
6326
+ static #hasModifier(node, kind) {
6327
+ return ts5.canHaveModifiers(node) && (ts5.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
6328
+ }
6329
+ static #isAsyncFunctionExpression(node) {
6330
+ return Boolean(node && (ts5.isArrowFunction(node) || ts5.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts5.SyntaxKind.AsyncKeyword));
6331
+ }
6332
+ static #scriptKind(moduleAbsPath) {
6333
+ return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts5.ScriptKind.TSX : ts5.ScriptKind.TS;
6334
+ }
6269
6335
  }
6270
6336
 
6271
6337
  // pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
@@ -6401,6 +6467,13 @@ ${remainingAssets.join(`
6401
6467
  jsFiles.push(jsPath);
6402
6468
  return await Bun.file(jsPath).text();
6403
6469
  });
6470
+ const bundledCss = (await Promise.all(cssFiles.map((cssFile) => Bun.file(cssFile).text().catch(() => "")))).filter(Boolean).join(`
6471
+ `);
6472
+ if (bundledCss) {
6473
+ const style = CsrArtifactBuilder.createInlineStyle(bundledCss);
6474
+ if (!next.includes(style))
6475
+ next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
6476
+ }
6404
6477
  if (cssAsset) {
6405
6478
  const cssPath = path21.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
6406
6479
  const css = await Bun.file(cssPath).text();
@@ -6879,7 +6952,7 @@ import {
6879
6952
  } from "fontaine";
6880
6953
  import { createFont, woff2 } from "fonteditor-core";
6881
6954
  import subsetFont from "subset-font";
6882
- import ts5 from "typescript";
6955
+ import ts6 from "typescript";
6883
6956
  var FONT_URL_PREFIX = "/_akan/fonts";
6884
6957
  var DEFAULT_FONT_SUBSETS = ["latin"];
6885
6958
 
@@ -6944,17 +7017,17 @@ class FontOptimizer {
6944
7017
  this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
6945
7018
  }
6946
7019
  #extractFontsExport(source, filePath) {
6947
- const sourceFile = ts5.createSourceFile(filePath, source, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
7020
+ const sourceFile = ts6.createSourceFile(filePath, source, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TSX);
6948
7021
  const fonts = [];
6949
7022
  for (const statement of sourceFile.statements) {
6950
- if (!ts5.isVariableStatement(statement))
7023
+ if (!ts6.isVariableStatement(statement))
6951
7024
  continue;
6952
- const modifiers = ts5.canHaveModifiers(statement) ? ts5.getModifiers(statement) : undefined;
6953
- const isExported = modifiers?.some((modifier) => modifier.kind === ts5.SyntaxKind.ExportKeyword) ?? false;
7025
+ const modifiers = ts6.canHaveModifiers(statement) ? ts6.getModifiers(statement) : undefined;
7026
+ const isExported = modifiers?.some((modifier) => modifier.kind === ts6.SyntaxKind.ExportKeyword) ?? false;
6954
7027
  if (!isExported)
6955
7028
  continue;
6956
7029
  for (const declaration of statement.declarationList.declarations) {
6957
- if (!ts5.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
7030
+ if (!ts6.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
6958
7031
  continue;
6959
7032
  const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
6960
7033
  if (Array.isArray(value)) {
@@ -6965,20 +7038,20 @@ class FontOptimizer {
6965
7038
  return fonts;
6966
7039
  }
6967
7040
  #literalToValue(node) {
6968
- if (ts5.isStringLiteralLike(node))
7041
+ if (ts6.isStringLiteralLike(node))
6969
7042
  return node.text;
6970
- if (ts5.isNumericLiteral(node))
7043
+ if (ts6.isNumericLiteral(node))
6971
7044
  return Number(node.text);
6972
- if (node.kind === ts5.SyntaxKind.TrueKeyword)
7045
+ if (node.kind === ts6.SyntaxKind.TrueKeyword)
6973
7046
  return true;
6974
- if (node.kind === ts5.SyntaxKind.FalseKeyword)
7047
+ if (node.kind === ts6.SyntaxKind.FalseKeyword)
6975
7048
  return false;
6976
- if (ts5.isArrayLiteralExpression(node))
7049
+ if (ts6.isArrayLiteralExpression(node))
6977
7050
  return node.elements.map((element) => this.#literalToValue(element));
6978
- if (ts5.isObjectLiteralExpression(node)) {
7051
+ if (ts6.isObjectLiteralExpression(node)) {
6979
7052
  const obj = {};
6980
7053
  for (const prop of node.properties) {
6981
- if (!ts5.isPropertyAssignment(prop))
7054
+ if (!ts6.isPropertyAssignment(prop))
6982
7055
  continue;
6983
7056
  const name = this.#getPropertyName(prop.name);
6984
7057
  if (!name)
@@ -6987,13 +7060,13 @@ class FontOptimizer {
6987
7060
  }
6988
7061
  return obj;
6989
7062
  }
6990
- if (ts5.isAsExpression(node) || ts5.isSatisfiesExpression(node) || ts5.isParenthesizedExpression(node)) {
7063
+ if (ts6.isAsExpression(node) || ts6.isSatisfiesExpression(node) || ts6.isParenthesizedExpression(node)) {
6991
7064
  return this.#literalToValue(node.expression);
6992
7065
  }
6993
7066
  return;
6994
7067
  }
6995
7068
  #getPropertyName(name) {
6996
- if (ts5.isIdentifier(name) || ts5.isStringLiteral(name) || ts5.isNumericLiteral(name))
7069
+ if (ts6.isIdentifier(name) || ts6.isStringLiteral(name) || ts6.isNumericLiteral(name))
6997
7070
  return name.text;
6998
7071
  return null;
6999
7072
  }
@@ -7293,7 +7366,7 @@ class HmrChangeClassifier {
7293
7366
  }
7294
7367
  }
7295
7368
  // pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
7296
- import fs3 from "fs";
7369
+ import fs4 from "fs";
7297
7370
  import path26 from "path";
7298
7371
  class HmrWatcher {
7299
7372
  #roots;
@@ -7315,7 +7388,7 @@ class HmrWatcher {
7315
7388
  start() {
7316
7389
  for (const root of this.#roots) {
7317
7390
  try {
7318
- const w = fs3.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
7391
+ const w = fs4.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
7319
7392
  if (!filename)
7320
7393
  return;
7321
7394
  const abs = path26.resolve(root, filename.toString());
@@ -7610,7 +7683,7 @@ class PagesBundleBuilder {
7610
7683
  }
7611
7684
  }
7612
7685
  // pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
7613
- import fs4 from "fs";
7686
+ import fs5 from "fs";
7614
7687
  import path29 from "path";
7615
7688
  var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
7616
7689
  var MIN_COMPRESS_BYTES = 1024;
@@ -7624,7 +7697,7 @@ async function precompressArtifacts(app) {
7624
7697
  return result;
7625
7698
  }
7626
7699
  async function precompressRoot(root, result) {
7627
- if (!fs4.existsSync(root) || !fs4.statSync(root).isDirectory())
7700
+ if (!fs5.existsSync(root) || !fs5.statSync(root).isDirectory())
7628
7701
  return;
7629
7702
  const glob = new Bun.Glob("**/*");
7630
7703
  for await (const filePath of glob.scan({ cwd: root, absolute: true })) {
@@ -7662,9 +7735,7 @@ function formatBytes(bytes) {
7662
7735
  import path30 from "path";
7663
7736
  import { optimize } from "@tailwindcss/node";
7664
7737
  function prepareCssAsset(command, basePath2, cssText) {
7665
- if (command !== "build")
7666
- return cssText;
7667
- return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: true }).code;
7738
+ return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: command === "build" }).code;
7668
7739
  }
7669
7740
 
7670
7741
  class SsrBaseArtifactBuilder {
@@ -7771,7 +7842,7 @@ ${preparedCssText}`).toString(36);
7771
7842
  }
7772
7843
  }
7773
7844
  // pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
7774
- import fs5 from "fs";
7845
+ import fs6 from "fs";
7775
7846
  import path31 from "path";
7776
7847
 
7777
7848
  class WatchRootResolver {
@@ -7791,7 +7862,7 @@ class WatchRootResolver {
7791
7862
  continue;
7792
7863
  const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
7793
7864
  const resolved = path31.resolve(this.#app.workspace.workspaceRoot, cleaned);
7794
- if (fs5.existsSync(resolved))
7865
+ if (fs6.existsSync(resolved))
7795
7866
  set.add(resolved);
7796
7867
  }
7797
7868
  }
@@ -8614,10 +8685,11 @@ class CapacitorApp {
8614
8685
  iosRootPath = "ios";
8615
8686
  iosProjectPath = "ios/App";
8616
8687
  androidRootPath = "android";
8688
+ androidAssetsPath = "android/app/src/main/assets";
8617
8689
  constructor(app, target) {
8618
8690
  this.app = app;
8619
8691
  this.target = target;
8620
- this.targetRootPath = path35.posix.join("mobile", this.target.name);
8692
+ this.targetRootPath = path35.posix.join(".akan", "mobile", this.target.name);
8621
8693
  this.targetRoot = path35.join(this.app.cwdPath, this.targetRootPath);
8622
8694
  this.targetWebRoot = path35.join(this.targetRoot, "www");
8623
8695
  this.targetAssetRoot = path35.join(this.targetRoot, "assets");
@@ -8697,6 +8769,8 @@ class CapacitorApp {
8697
8769
  await this.#applyLinks();
8698
8770
  await this.project.commit();
8699
8771
  await this.#generateAssets({ operation, env });
8772
+ await this.#ensureAndroidAssetsDir();
8773
+ await this.#ensureAndroidDebugKeystore();
8700
8774
  await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
8701
8775
  }
8702
8776
  async#updateAndroidBuildTypes() {
@@ -8744,12 +8818,40 @@ class CapacitorApp {
8744
8818
  await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
8745
8819
  stdio: "inherit",
8746
8820
  cwd: path35.join(this.app.cwdPath, this.androidRootPath),
8747
- env: this.#commandEnv("release", env)
8821
+ env: await this.#commandEnv("release", env)
8748
8822
  });
8749
8823
  }
8750
8824
  async openAndroid() {
8751
8825
  await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
8752
8826
  }
8827
+ async#ensureAndroidAssetsDir() {
8828
+ await mkdir10(path35.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
8829
+ }
8830
+ async#ensureAndroidDebugKeystore() {
8831
+ const keystorePath = path35.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
8832
+ if (await Bun.file(keystorePath).exists())
8833
+ return;
8834
+ await this.#spawn("keytool", [
8835
+ "-genkeypair",
8836
+ "-v",
8837
+ "-keystore",
8838
+ keystorePath,
8839
+ "-storepass",
8840
+ "android",
8841
+ "-alias",
8842
+ "androiddebugkey",
8843
+ "-keypass",
8844
+ "android",
8845
+ "-keyalg",
8846
+ "RSA",
8847
+ "-keysize",
8848
+ "2048",
8849
+ "-validity",
8850
+ "10000",
8851
+ "-dname",
8852
+ "CN=Android Debug,O=Android,C=US"
8853
+ ]);
8854
+ }
8753
8855
  async syncAndroid(options = {}) {
8754
8856
  await this.prepareWww();
8755
8857
  await this.#prepareAndroid({ operation: "release", env: "debug", ...options });
@@ -8791,13 +8893,13 @@ class CapacitorApp {
8791
8893
  await mkdir10(this.targetRoot, { recursive: true });
8792
8894
  const appInfoPath = path35.relative(this.app.cwdPath, path35.join(this.app.cwdPath, "akan.app.json")).split(path35.sep).join("/");
8793
8895
  const content = `import type { AppScanResult } from "akanjs";
8794
- import { withBase } from "akanjs/capacitor.base.config";
8896
+ import { withBase } from "${process.env.USE_AKANJS_PKGS === "true" ? "../../pkgs/" : ""}akanjs/capacitor.base.config";
8795
8897
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
8796
8898
 
8797
8899
  export default withBase(
8798
8900
  (config, target) => ({
8799
8901
  ...config,
8800
- webDir: \`mobile/\${target.name}/www\`,
8902
+ webDir: \`.akan/mobile/\${target.name}/www\`,
8801
8903
  android: {
8802
8904
  ...config.android,
8803
8905
  path: "android",
@@ -8897,12 +8999,14 @@ export default withBase(
8897
8999
  this.project.android.getAndroidManifest().injectFragment("activity", `<intent-filter android:autoVerify="true"><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><data android:scheme="https" android:host="${host}" android:pathPrefix="${pathPrefix}" /></intent-filter>`);
8898
9000
  }
8899
9001
  }
8900
- #commandEnv(operation, env) {
9002
+ async#commandEnv(operation, env) {
9003
+ const devPort = operation === "local" ? (await this.app.getDevPort()).toString() : undefined;
8901
9004
  return this.app.getCommandEnv({
8902
9005
  APP_OPERATION_MODE: operation,
8903
9006
  AKAN_PUBLIC_OPERATION_MODE: env === "local" ? "local" : "cloud",
8904
9007
  AKAN_PUBLIC_ENV: env,
8905
- AKAN_MOBILE_TARGET: this.target.name
9008
+ AKAN_MOBILE_TARGET: this.target.name,
9009
+ ...devPort ? { PORT: devPort, AKAN_PUBLIC_CLIENT_PORT: devPort, AKAN_PUBLIC_SERVER_PORT: devPort } : {}
8906
9010
  });
8907
9011
  }
8908
9012
  async#spawn(command, args = [], options = {}) {
@@ -8911,7 +9015,7 @@ export default withBase(
8911
9015
  async#spawnMobile(command, args = [], { operation, env }, options = {}) {
8912
9016
  return await this.#spawn(command, args, {
8913
9017
  ...options,
8914
- env: { ...this.#commandEnv(operation, env), ...options.env }
9018
+ env: { ...await this.#commandEnv(operation, env), ...options.env }
8915
9019
  });
8916
9020
  }
8917
9021
  async addCamera() {
@@ -9771,7 +9875,7 @@ import yaml from "js-yaml";
9771
9875
  // pkgs/@akanjs/devkit/getRelatedCnsts.ts
9772
9876
  import { readFileSync as readFileSync4, realpathSync } from "fs";
9773
9877
  import ora2 from "ora";
9774
- import * as ts6 from "typescript";
9878
+ import * as ts7 from "typescript";
9775
9879
  var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
9776
9880
  var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
9777
9881
  var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
@@ -9804,10 +9908,10 @@ var scanModuleSpecifiers = (source, filePath, includeExports) => {
9804
9908
  return importSpecifiers;
9805
9909
  };
9806
9910
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
9807
- const configFile = ts6.readConfigFile(tsConfigPath, (path37) => {
9808
- return ts6.sys.readFile(path37);
9911
+ const configFile = ts7.readConfigFile(tsConfigPath, (path37) => {
9912
+ return ts7.sys.readFile(path37);
9809
9913
  });
9810
- return ts6.parseJsonConfigFileContent(configFile.config, ts6.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
9914
+ return ts7.parseJsonConfigFileContent(configFile.config, ts7.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
9811
9915
  };
9812
9916
  var collectImportedFiles = (constantFilePath, parsedConfig) => {
9813
9917
  const allFilesToAnalyze = new Set([constantFilePath]);
@@ -9822,7 +9926,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
9822
9926
  for (const importPath of scanModuleSpecifiers(source, filePath, false)) {
9823
9927
  if (!importPath.startsWith("."))
9824
9928
  continue;
9825
- const resolved = ts6.resolveModuleName(importPath, filePath, parsedConfig.options, ts6.sys).resolvedModule?.resolvedFileName;
9929
+ const resolved = ts7.resolveModuleName(importPath, filePath, parsedConfig.options, ts7.sys).resolvedModule?.resolvedFileName;
9826
9930
  if (resolved && !allFilesToAnalyze.has(resolved)) {
9827
9931
  allFilesToAnalyze.add(resolved);
9828
9932
  collectImported(resolved);
@@ -9839,7 +9943,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
9839
9943
  var createTsProgram = (filePaths, options) => {
9840
9944
  const spinner = ora2("Creating TypeScript program for all files...");
9841
9945
  spinner.start();
9842
- const program2 = ts6.createProgram(Array.from(filePaths), options);
9946
+ const program2 = ts7.createProgram(Array.from(filePaths), options);
9843
9947
  const checker = program2.getTypeChecker();
9844
9948
  spinner.succeed("TypeScript program created.");
9845
9949
  return {
@@ -9879,17 +9983,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
9879
9983
  function visit(node) {
9880
9984
  if (!source)
9881
9985
  return;
9882
- if (ts6.isPropertyAccessExpression(node)) {
9986
+ if (ts7.isPropertyAccessExpression(node)) {
9883
9987
  const left = node.expression;
9884
9988
  const right = node.name;
9885
- const { line } = ts6.getLineAndCharacterOfPosition(source, node.getStart());
9886
- if (ts6.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
9989
+ const { line } = ts7.getLineAndCharacterOfPosition(source, node.getStart());
9990
+ if (ts7.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
9887
9991
  const symbol = getCachedSymbol(right);
9888
9992
  if (symbol?.declarations && symbol.declarations.length > 0) {
9889
9993
  const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
9890
9994
  const property = propertyMap.get(key);
9891
9995
  const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
9892
- const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts6.sys.getCurrentDirectory()}/`, "");
9996
+ const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts7.sys.getCurrentDirectory()}/`, "");
9893
9997
  if (!symbolFilePath)
9894
9998
  throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
9895
9999
  if (property) {
@@ -9913,10 +10017,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
9913
10017
  }
9914
10018
  }
9915
10019
  }
9916
- } else if (ts6.isImportDeclaration(node) && ts6.isStringLiteral(node.moduleSpecifier)) {
10020
+ } else if (ts7.isImportDeclaration(node) && ts7.isStringLiteral(node.moduleSpecifier)) {
9917
10021
  const importPath = node.moduleSpecifier.text;
9918
10022
  if (importPath.startsWith(".")) {
9919
- const resolved = ts6.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts6.sys).resolvedModule?.resolvedFileName;
10023
+ const resolved = ts7.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts7.sys).resolvedModule?.resolvedFileName;
9920
10024
  const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
9921
10025
  const property = propertyMap.get(moduleName);
9922
10026
  const isScalar = importPath.includes("_");
@@ -9931,7 +10035,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
9931
10035
  }
9932
10036
  }
9933
10037
  }
9934
- ts6.forEachChild(node, visit);
10038
+ ts7.forEachChild(node, visit);
9935
10039
  }
9936
10040
  visit(source);
9937
10041
  }
@@ -10272,8 +10376,6 @@ class ApplicationRunner extends runner("application") {
10272
10376
  const targets = await resolveMobileTargets(app, target);
10273
10377
  if (operation === "release")
10274
10378
  await this.#buildMobileCsr(app, env);
10275
- else
10276
- await this.start(app);
10277
10379
  await this.#runMobileTargets(targets, async (mobileTarget2) => {
10278
10380
  const capacitorApp2 = new CapacitorApp(app, mobileTarget2.config);
10279
10381
  await capacitorApp2.runIos({ operation, env, regenerate });
@@ -10305,8 +10407,6 @@ class ApplicationRunner extends runner("application") {
10305
10407
  const targets = await resolveMobileTargets(app, target);
10306
10408
  if (operation === "release")
10307
10409
  await this.#buildMobileCsr(app, env);
10308
- else
10309
- await this.start(app);
10310
10410
  await this.#runMobileTargets(targets, async (mobileTarget2) => {
10311
10411
  const capacitorApp2 = new CapacitorApp(app, mobileTarget2.config);
10312
10412
  await capacitorApp2.runAndroid({ operation, env, regenerate });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "2.1.2-rc.1",
3
+ "version": "2.2.0-rc.1",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -35,7 +35,7 @@
35
35
  "@langchain/openai": "^1.4.6",
36
36
  "@tailwindcss/node": "^4.3.0",
37
37
  "@trapezedev/project": "^7.1.4",
38
- "akanjs": "2.1.2-rc.1",
38
+ "akanjs": "2.2.0-rc.1",
39
39
  "chalk": "^5.6.2",
40
40
  "commander": "^14.0.3",
41
41
  "daisyui": "^5.5.20",