@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.
- package/incrementalBuilder.proc.js +152 -48
- package/index.js +152 -52
- package/package.json +2 -2
|
@@ -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.
|
|
24
|
-
var akanCloudUrl = `${akanCloudHost}${process.env.
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 (!
|
|
7025
|
+
if (!ts6.isVariableStatement(statement))
|
|
6953
7026
|
continue;
|
|
6954
|
-
const modifiers =
|
|
6955
|
-
const isExported = modifiers?.some((modifier) => modifier.kind ===
|
|
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 (!
|
|
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 (
|
|
7043
|
+
if (ts6.isStringLiteralLike(node))
|
|
6971
7044
|
return node.text;
|
|
6972
|
-
if (
|
|
7045
|
+
if (ts6.isNumericLiteral(node))
|
|
6973
7046
|
return Number(node.text);
|
|
6974
|
-
if (node.kind ===
|
|
7047
|
+
if (node.kind === ts6.SyntaxKind.TrueKeyword)
|
|
6975
7048
|
return true;
|
|
6976
|
-
if (node.kind ===
|
|
7049
|
+
if (node.kind === ts6.SyntaxKind.FalseKeyword)
|
|
6977
7050
|
return false;
|
|
6978
|
-
if (
|
|
7051
|
+
if (ts6.isArrayLiteralExpression(node))
|
|
6979
7052
|
return node.elements.map((element) => this.#literalToValue(element));
|
|
6980
|
-
if (
|
|
7053
|
+
if (ts6.isObjectLiteralExpression(node)) {
|
|
6981
7054
|
const obj = {};
|
|
6982
7055
|
for (const prop of node.properties) {
|
|
6983
|
-
if (!
|
|
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 (
|
|
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 (
|
|
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
|
|
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 =
|
|
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
|
|
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 (!
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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:
|
|
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
|
|
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 =
|
|
9810
|
-
return
|
|
9913
|
+
const configFile = ts7.readConfigFile(tsConfigPath, (path37) => {
|
|
9914
|
+
return ts7.sys.readFile(path37);
|
|
9811
9915
|
});
|
|
9812
|
-
return
|
|
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 =
|
|
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 =
|
|
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 (
|
|
9988
|
+
if (ts7.isPropertyAccessExpression(node)) {
|
|
9885
9989
|
const left = node.expression;
|
|
9886
9990
|
const right = node.name;
|
|
9887
|
-
const { line } =
|
|
9888
|
-
if (
|
|
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(`${
|
|
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 (
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
22
|
-
var akanCloudUrl = `${akanCloudHost}${process.env.
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 (!
|
|
7023
|
+
if (!ts6.isVariableStatement(statement))
|
|
6951
7024
|
continue;
|
|
6952
|
-
const modifiers =
|
|
6953
|
-
const isExported = modifiers?.some((modifier) => modifier.kind ===
|
|
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 (!
|
|
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 (
|
|
7041
|
+
if (ts6.isStringLiteralLike(node))
|
|
6969
7042
|
return node.text;
|
|
6970
|
-
if (
|
|
7043
|
+
if (ts6.isNumericLiteral(node))
|
|
6971
7044
|
return Number(node.text);
|
|
6972
|
-
if (node.kind ===
|
|
7045
|
+
if (node.kind === ts6.SyntaxKind.TrueKeyword)
|
|
6973
7046
|
return true;
|
|
6974
|
-
if (node.kind ===
|
|
7047
|
+
if (node.kind === ts6.SyntaxKind.FalseKeyword)
|
|
6975
7048
|
return false;
|
|
6976
|
-
if (
|
|
7049
|
+
if (ts6.isArrayLiteralExpression(node))
|
|
6977
7050
|
return node.elements.map((element) => this.#literalToValue(element));
|
|
6978
|
-
if (
|
|
7051
|
+
if (ts6.isObjectLiteralExpression(node)) {
|
|
6979
7052
|
const obj = {};
|
|
6980
7053
|
for (const prop of node.properties) {
|
|
6981
|
-
if (!
|
|
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 (
|
|
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 (
|
|
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
|
|
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 =
|
|
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
|
|
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 (!
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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:
|
|
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
|
|
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 =
|
|
9808
|
-
return
|
|
9911
|
+
const configFile = ts7.readConfigFile(tsConfigPath, (path37) => {
|
|
9912
|
+
return ts7.sys.readFile(path37);
|
|
9809
9913
|
});
|
|
9810
|
-
return
|
|
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 =
|
|
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 =
|
|
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 (
|
|
9986
|
+
if (ts7.isPropertyAccessExpression(node)) {
|
|
9883
9987
|
const left = node.expression;
|
|
9884
9988
|
const right = node.name;
|
|
9885
|
-
const { line } =
|
|
9886
|
-
if (
|
|
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(`${
|
|
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 (
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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",
|