@akanjs/cli 2.1.0-rc.9 → 2.1.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.ko.md +63 -0
  2. package/README.md +62 -0
  3. package/guidelines/componentRule/componentRule.generate.json +4 -10
  4. package/guidelines/cssRule/cssRule.generate.json +4 -10
  5. package/guidelines/docPageRule/docPageRule.generate.json +4 -10
  6. package/guidelines/docPageRule/docPageRule.instruction.md +1 -1
  7. package/guidelines/docSyncRule/docSyncRule.generate.json +4 -10
  8. package/guidelines/enumConstant/enumConstant.generate.json +4 -10
  9. package/guidelines/fieldRule/fieldRule.generate.json +4 -10
  10. package/guidelines/framework/framework.generate.json +4 -10
  11. package/guidelines/modelConstant/modelConstant.generate.json +4 -10
  12. package/guidelines/modelDictionary/modelDictionary.generate.json +4 -10
  13. package/guidelines/modelDocument/modelDocument.generate.json +4 -10
  14. package/guidelines/modelService/modelService.generate.json +4 -10
  15. package/guidelines/modelSignal/modelSignal.generate.json +4 -10
  16. package/guidelines/modelStore/modelStore.generate.json +4 -10
  17. package/guidelines/modelTemplate/modelTemplate.generate.json +4 -10
  18. package/guidelines/modelUnit/modelUnit.generate.json +4 -10
  19. package/guidelines/modelUtil/modelUtil.generate.json +4 -10
  20. package/guidelines/modelView/modelView.generate.json +4 -10
  21. package/guidelines/modelZone/modelZone.generate.json +4 -10
  22. package/guidelines/moduleCodegen/moduleCodegen.generate.json +4 -10
  23. package/guidelines/moduleOverview/moduleOverview.generate.json +4 -10
  24. package/guidelines/scalarConstant/scalarConstant.generate.json +4 -10
  25. package/guidelines/scalarDictionary/scalarDictionary.generate.json +4 -10
  26. package/guidelines/scalarModule/scalarModule.generate.json +4 -10
  27. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +4 -10
  28. package/guidelines/utilUiUsage/utilUiUsage.generate.json +4 -10
  29. package/incrementalBuilder.proc.js +237 -71
  30. package/index.js +586 -128
  31. package/package.json +3 -2
  32. package/templates/libRoot/lib/___libName__/__libName__.signal.ts +15 -0
@@ -2,7 +2,7 @@
2
2
  var __require = import.meta.require;
3
3
 
4
4
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
5
- import path36 from "path";
5
+ import path37 from "path";
6
6
 
7
7
  // pkgs/@akanjs/devkit/aiEditor.ts
8
8
  import { input, select } from "@inquirer/prompts";
@@ -24,9 +24,12 @@ import { mkdir } from "fs/promises";
24
24
  var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
25
25
  var configPath = `${basePath}/config.json`;
26
26
  var akanCloudHost = process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? "http://localhost" : "https://cloud.akanjs.com";
27
- var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? ":8282" : ""}/\uBA54\u3151`;
27
+ var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? ":8282" : ""}/api`;
28
28
  var defaultHostConfig = {};
29
- var defaultAkanGlobalConfig = { cloudHost: {}, llm: null };
29
+ var defaultAkanGlobalConfig = {
30
+ cloudHost: {},
31
+ llm: null
32
+ };
30
33
 
31
34
  // pkgs/@akanjs/devkit/fileSys.ts
32
35
  import { stat } from "fs/promises";
@@ -486,7 +489,18 @@ var DEFAULT_OPTIMIZE_IMPORTS = [
486
489
  var WORKSPACE_BARREL_FACETS = ["ui", "webkit", "common", "client", "server"];
487
490
  var SSR_RUNTIME_PACKAGES = ["react", "react-dom", "react-server-dom-webpack"];
488
491
  var NATIVE_RUNTIME_PACKAGES = ["sharp"];
489
- var AKAN_RUNTIME_PACKAGES = new Set([...SSR_RUNTIME_PACKAGES, ...NATIVE_RUNTIME_PACKAGES]);
492
+ var DEFAULT_BACKEND_RUNTIME_PACKAGES = ["croner"];
493
+ var DATABASE_MODE_RUNTIME_PACKAGES = {
494
+ single: [],
495
+ multiple: ["@libsql/client", "bullmq", "ioredis", "protobufjs"],
496
+ cluster: ["bullmq", "ioredis", "postgres", "protobufjs"]
497
+ };
498
+ var AKAN_RUNTIME_PACKAGES = new Set([
499
+ ...SSR_RUNTIME_PACKAGES,
500
+ ...NATIVE_RUNTIME_PACKAGES,
501
+ ...DEFAULT_BACKEND_RUNTIME_PACKAGES,
502
+ ...Object.values(DATABASE_MODE_RUNTIME_PACKAGES).flat()
503
+ ]);
490
504
  var DEFAULT_AKAN_IMAGE_CONFIG = {
491
505
  deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
492
506
  imageSizes: [32, 48, 64, 96, 128, 256, 384],
@@ -695,13 +709,22 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
695
709
  if (AKAN_RUNTIME_PACKAGES.has(lib))
696
710
  return akanPackageJson.dependencies?.[lib] ?? akanPackageJson.peerDependencies?.[lib];
697
711
  }
712
+ #getProductionRuntimePackages() {
713
+ return [
714
+ ...this.externalLibs,
715
+ ...SSR_RUNTIME_PACKAGES,
716
+ ...NATIVE_RUNTIME_PACKAGES,
717
+ ...DEFAULT_BACKEND_RUNTIME_PACKAGES,
718
+ ...DATABASE_MODE_RUNTIME_PACKAGES[this.defaultDatabaseMode]
719
+ ];
720
+ }
698
721
  getProductionPackageJson(data = {}) {
699
722
  return {
700
723
  name: this.app.name,
701
724
  description: this.app.name,
702
725
  version: "1.0.0",
703
726
  main: "./main.js",
704
- dependencies: Object.fromEntries([...new Set([...this.externalLibs, ...SSR_RUNTIME_PACKAGES, ...NATIVE_RUNTIME_PACKAGES])].map((lib) => {
727
+ dependencies: Object.fromEntries([...new Set(this.#getProductionRuntimePackages())].map((lib) => {
705
728
  const version = this.#resolveProductionDependencyVersion(lib);
706
729
  if (!version)
707
730
  throw new Error(`Dependency ${lib} not found in package.json`);
@@ -2120,7 +2143,6 @@ class Executor {
2120
2143
  this.logger = new Logger4(name);
2121
2144
  this.logs = [];
2122
2145
  this.cwdPath = cwdPath;
2123
- //! TODO: 테스트 확인 필요
2124
2146
  }
2125
2147
  #stdout(data) {
2126
2148
  if (Executor.verbose)
@@ -3962,6 +3984,16 @@ function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
3962
3984
  }
3963
3985
  return [...boundaries.values()].sort((a, b) => a.segments.join("/").localeCompare(b.segments.join("/")));
3964
3986
  }
3987
+ function hasAncestorRootBoundary(boundary, boundaries) {
3988
+ return boundaries.some((candidate) => candidate !== boundary && candidate.segments.length < boundary.segments.length && candidate.segments.every((segment, index) => boundary.segments[index] === segment));
3989
+ }
3990
+ function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
3991
+ const rootLayoutKey = pageKeys.find((key) => {
3992
+ const segments = getRootBoundarySegments(key);
3993
+ return segments !== null && segments.length === 0;
3994
+ });
3995
+ return rootLayoutKey ? path10.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
3996
+ }
3965
3997
  function routePrefixForSegments(segments) {
3966
3998
  const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
3967
3999
  return visible[0] ?? null;
@@ -3978,21 +4010,27 @@ async function writeGeneratedRootLayoutFile(opts) {
3978
4010
  await mkdir3(path10.dirname(absPath), { recursive: true });
3979
4011
  const sourceRel = opts.boundary.sourceAbsPath ? path10.relative(path10.dirname(absPath), opts.boundary.sourceAbsPath).split(path10.sep).join("/") : null;
3980
4012
  const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
4013
+ const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
4014
+ const inheritedSourceRel = inheritedSourceAbsPath ? path10.relative(path10.dirname(absPath), inheritedSourceAbsPath).split(path10.sep).join("/") : null;
4015
+ const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
3981
4016
  const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
3982
4017
  void st;
3983
4018
  ` : `import "@apps/${opts.appName}/client";
4019
+ `;
4020
+ const inheritedImport = inheritedSourceSpecifier ? `import * as inheritedLayout from ${JSON.stringify(inheritedSourceSpecifier)};
4021
+ ` : `const inheritedLayout = {};
3984
4022
  `;
3985
4023
  const prefix = routePrefixForSegments(opts.boundary.segments);
3986
4024
  const userImport = sourceSpecifier ? `import UserLayout, * as userLayout from ${JSON.stringify(sourceSpecifier)};
3987
4025
  ` : `const UserLayout = ({ children }) => children;
3988
4026
  const userLayout = {};
3989
4027
  `;
3990
- const source = `import type { LayoutProps, PageProps } from "akanjs/client";
4028
+ const source = opts.includeSystemProvider ? `import type { LayoutProps, PageProps } from "akanjs/client";
3991
4029
  import { loadFonts } from "akanjs/client";
3992
4030
  import { System } from "akanjs/ui";
3993
4031
  import { env } from "@apps/${opts.appName}/env/env.client";
3994
- ${clientImport}${userImport}
3995
- const userFonts = userLayout.fonts ?? [];
4032
+ ${clientImport}${inheritedImport}${userImport}
4033
+ const userFonts = userLayout.fonts ?? inheritedLayout.fonts ?? [];
3996
4034
  const defaultFonts = userFonts.filter((font) => font.default);
3997
4035
  if (defaultFonts.length > 1) throw new Error("[route-convention] only one default font is allowed per root layout");
3998
4036
  const defaultFont = defaultFonts[0];
@@ -4000,7 +4038,9 @@ const defaultFontClassName = defaultFont ? (defaultFont.className ?? \`font-\${d
4000
4038
 
4001
4039
  export async function generateHead(props: PageProps) {
4002
4040
  if (userLayout.generateHead) return userLayout.generateHead(props);
4003
- return userLayout.head;
4041
+ if (userLayout.head !== undefined) return userLayout.head;
4042
+ if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
4043
+ return inheritedLayout.head;
4004
4044
  }
4005
4045
 
4006
4046
  export default function GeneratedLayout({ children, params, searchParams }: LayoutProps) {
@@ -4010,19 +4050,31 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
4010
4050
  appName=${JSON.stringify(opts.appName)}
4011
4051
  ${prefix ? `prefix=${JSON.stringify(prefix)}
4012
4052
  ` : ""}params={params}
4013
- manifest={userLayout.manifest}
4053
+ manifest={userLayout.manifest ?? inheritedLayout.manifest}
4014
4054
  env={env}
4015
- theme={userLayout.theme}
4055
+ theme={userLayout.theme ?? inheritedLayout.theme}
4016
4056
  fonts={loadFonts(userFonts)}
4017
4057
  className={defaultFontClassName}
4018
- gaTrackingId={userLayout.gaTrackingId}
4019
- layoutStyle={userLayout.layoutStyle}
4020
- reconnect={userLayout.reconnect ?? false}
4058
+ gaTrackingId={userLayout.gaTrackingId ?? inheritedLayout.gaTrackingId}
4059
+ layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
4060
+ reconnect={userLayout.reconnect ?? inheritedLayout.reconnect ?? false}
4021
4061
  >
4022
4062
  <UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>
4023
4063
  </System.Provider>
4024
4064
  );
4025
4065
  }
4066
+ ` : `import type { LayoutProps, PageProps } from "akanjs/client";
4067
+ ${inheritedImport}${userImport}
4068
+ export async function generateHead(props: PageProps) {
4069
+ if (userLayout.generateHead) return userLayout.generateHead(props);
4070
+ if (userLayout.head !== undefined) return userLayout.head;
4071
+ if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
4072
+ return inheritedLayout.head;
4073
+ }
4074
+
4075
+ export default function GeneratedLayout({ children, params, searchParams }: LayoutProps) {
4076
+ return <UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>;
4077
+ }
4026
4078
  `;
4027
4079
  await Bun.write(absPath, source);
4028
4080
  return absPath;
@@ -4031,6 +4083,8 @@ async function resolveSsrPageEntries(opts) {
4031
4083
  const absPageDir = path10.resolve(opts.appCwdPath, "page");
4032
4084
  const hasSt = await appHasStModule(opts.appCwdPath);
4033
4085
  const basePaths = opts.basePaths ?? [];
4086
+ const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
4087
+ const rootBoundaries = findRootBoundaries(opts.pageKeys, opts.appCwdPath, basePaths);
4034
4088
  const rootLayoutKeys = new Set(opts.pageKeys.filter((key) => {
4035
4089
  const segments = getRootBoundarySegments(key);
4036
4090
  return segments !== null && isRootBoundarySegments(segments, basePaths);
@@ -4039,15 +4093,17 @@ async function resolveSsrPageEntries(opts) {
4039
4093
  key,
4040
4094
  moduleAbsPath: path10.resolve(absPageDir, key)
4041
4095
  }));
4042
- const generated = await Promise.all(findRootBoundaries(opts.pageKeys, opts.appCwdPath, basePaths).map(async (boundary) => ({
4096
+ const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
4043
4097
  key: implicitRootLayoutKey(boundary.segments),
4044
4098
  moduleAbsPath: await writeGeneratedRootLayoutFile({
4045
4099
  appCwdPath: opts.appCwdPath,
4046
4100
  appName: opts.appName,
4047
4101
  boundary,
4048
- includeStInit: hasSt && boundary.segments.length === 0
4102
+ rootSourceAbsPath,
4103
+ includeStInit: hasSt && boundary.segments.length === 0,
4104
+ includeSystemProvider: !hasAncestorRootBoundary(boundary, rootBoundaries)
4049
4105
  }),
4050
- seedAbsPaths: boundary.sourceAbsPath ? [boundary.sourceAbsPath] : []
4106
+ seedAbsPaths: [...new Set([boundary.sourceAbsPath, rootSourceAbsPath].filter((absPath) => absPath !== null))]
4051
4107
  })));
4052
4108
  const entries = [...base, ...generated];
4053
4109
  entries.sort((a, b) => a.key.localeCompare(b.key));
@@ -7022,6 +7078,13 @@ function formatBytes(bytes) {
7022
7078
  }
7023
7079
  // pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
7024
7080
  import path30 from "path";
7081
+ import { optimize } from "@tailwindcss/node";
7082
+ function prepareCssAsset(command, basePath2, cssText) {
7083
+ if (command !== "build")
7084
+ return cssText;
7085
+ return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: true }).code;
7086
+ }
7087
+
7025
7088
  class SsrBaseArtifactBuilder {
7026
7089
  #app;
7027
7090
  #command;
@@ -7113,14 +7176,15 @@ class SsrBaseArtifactBuilder {
7113
7176
  }
7114
7177
  async#writeCssAsset(basePath2, cssText) {
7115
7178
  const cssAssetName = basePath2 || "root";
7179
+ const preparedCssText = await prepareCssAsset(this.#command, basePath2, cssText);
7116
7180
  const cssHash = Bun.hash(`${basePath2}
7117
- ${cssText}`).toString(36);
7181
+ ${preparedCssText}`).toString(36);
7118
7182
  const [cssRelPath, cssUrl] = [
7119
7183
  `styles/${cssAssetName}-${cssHash}.css`,
7120
7184
  `/_akan/styles/${cssAssetName}-${cssHash}.css`
7121
7185
  ];
7122
- await Bun.write(path30.join(this.#absArtifactDir, cssRelPath), cssText);
7123
- this.#app.verbose(`[base-artifact] wrote ${cssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
7186
+ await Bun.write(path30.join(this.#absArtifactDir, cssRelPath), preparedCssText);
7187
+ this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
7124
7188
  return [basePath2, { cssUrl, cssRelPath }];
7125
7189
  }
7126
7190
  }
@@ -7168,9 +7232,19 @@ var SSR_RENDER_EXTERNALS = [
7168
7232
  "react/jsx-dev-runtime",
7169
7233
  "react-dom",
7170
7234
  "react-dom/server.browser",
7235
+ "react-server-dom-webpack",
7236
+ "react-server-dom-webpack/server.node",
7171
7237
  "react-server-dom-webpack/client.node",
7172
7238
  "react-server-dom-webpack/client.browser"
7173
7239
  ];
7240
+ var AKAN_OPTIONAL_BACKEND_EXTERNALS = [
7241
+ "@libsql/client",
7242
+ "bullmq",
7243
+ "croner",
7244
+ "ioredis",
7245
+ "postgres",
7246
+ "protobufjs"
7247
+ ];
7174
7248
 
7175
7249
  class ApplicationBuildRunner {
7176
7250
  #app;
@@ -7239,7 +7313,9 @@ class ApplicationBuildRunner {
7239
7313
  }
7240
7314
  async#buildBackend() {
7241
7315
  const akanConfig2 = await this.#app.getConfig();
7242
- const backendExternals = [...new Set([...akanConfig2.externalLibs, ...SSR_RENDER_EXTERNALS])];
7316
+ const backendExternals = [
7317
+ ...new Set([...akanConfig2.externalLibs, ...SSR_RENDER_EXTERNALS, ...AKAN_OPTIONAL_BACKEND_EXTERNALS])
7318
+ ];
7243
7319
  const backendEntryPoints = [`${this.#app.cwdPath}/main.ts`, `${this.#app.cwdPath}/server.ts`];
7244
7320
  for (const entrypoint of backendEntryPoints) {
7245
7321
  if (!await Bun.file(entrypoint).exists())
@@ -7261,7 +7337,7 @@ class ApplicationBuildRunner {
7261
7337
  naming: { entry: "[name].[ext]", chunk: "chunk-[hash].[ext]" },
7262
7338
  conditions: ["react-server"],
7263
7339
  define: { "process.env.NODE_ENV": JSON.stringify("production") },
7264
- plugins: akanConfig2.externalLibs.length > 0 ? [this.#createExternalSpecifiersPlugin(akanConfig2.externalLibs)] : []
7340
+ plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
7265
7341
  });
7266
7342
  return {
7267
7343
  entrypoints: backendEntryPoints.length + 1,
@@ -7609,10 +7685,31 @@ class ApplicationReleasePackager {
7609
7685
  `;
7610
7686
  }
7611
7687
  }
7688
+ // pkgs/@akanjs/devkit/applicationTestPreload.ts
7689
+ import path33 from "path";
7690
+ var SIGNAL_TEST_PRELOAD_PATH = "test/signalTest.preload.ts";
7691
+ async function resolveSignalTestPreloadPath(target) {
7692
+ const candidates = [];
7693
+ const addResolvedPackageCandidate = (basePath2) => {
7694
+ try {
7695
+ candidates.push(path33.join(path33.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
7696
+ } catch {}
7697
+ };
7698
+ addResolvedPackageCandidate(target.cwdPath);
7699
+ addResolvedPackageCandidate(process.cwd());
7700
+ addResolvedPackageCandidate(path33.dirname(Bun.main));
7701
+ addResolvedPackageCandidate(import.meta.dir);
7702
+ candidates.push(path33.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path33.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path33.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path33.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path33.join(path33.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path33.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
7703
+ for (const candidate of [...new Set(candidates)]) {
7704
+ if (await Bun.file(candidate).exists())
7705
+ return candidate;
7706
+ }
7707
+ throw new Error(`Failed to locate ${SIGNAL_TEST_PRELOAD_PATH} from ${target.cwdPath}`);
7708
+ }
7612
7709
  // pkgs/@akanjs/devkit/builder.ts
7613
7710
  import { existsSync as existsSync2 } from "fs";
7614
7711
  import { mkdir as mkdir9 } from "fs/promises";
7615
- import path33 from "path";
7712
+ import path34 from "path";
7616
7713
  var SKIP_ENTRY_DIR_SET = new Set(["node_modules", "dist", "build", ".git", ".next"]);
7617
7714
  var assetExtensions = [".css", ".md", ".js", ".png", ".ico", ".svg", ".json", ".template"];
7618
7715
  var assetLoader = Object.fromEntries(assetExtensions.map((ext) => [ext, "file"]));
@@ -7629,14 +7726,14 @@ class Builder {
7629
7726
  #globEntrypoints(cwd, pattern) {
7630
7727
  const glob = new Bun.Glob(pattern);
7631
7728
  return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
7632
- const segments = relativePath.split(path33.sep);
7729
+ const segments = relativePath.split(path34.sep);
7633
7730
  return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
7634
- }).map((rel) => path33.join(cwd, rel));
7731
+ }).map((rel) => path34.join(cwd, rel));
7635
7732
  }
7636
7733
  #globFiles(cwd, pattern = "**/*.*") {
7637
7734
  const glob = new Bun.Glob(pattern);
7638
7735
  return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
7639
- const segments = relativePath.split(path33.sep);
7736
+ const segments = relativePath.split(path34.sep);
7640
7737
  return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
7641
7738
  });
7642
7739
  }
@@ -7644,17 +7741,17 @@ class Builder {
7644
7741
  const out = [];
7645
7742
  for (const p of additionalEntryPoints) {
7646
7743
  if (p.includes("*")) {
7647
- const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path33.sep}`) ? p.slice(cwd.length + 1) : p;
7744
+ const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path34.sep}`) ? p.slice(cwd.length + 1) : p;
7648
7745
  out.push(...this.#globEntrypoints(cwd, rel));
7649
7746
  } else
7650
- out.push(path33.isAbsolute(p) ? p : path33.join(cwd, p));
7747
+ out.push(path34.isAbsolute(p) ? p : path34.join(cwd, p));
7651
7748
  }
7652
7749
  return out;
7653
7750
  }
7654
7751
  #getBuildOptions({ bundle = false, additionalEntryPoints = [] } = {}) {
7655
7752
  const cwd = this.#executor.cwdPath;
7656
7753
  const entrypoints = [
7657
- ...bundle ? [path33.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
7754
+ ...bundle ? [path34.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
7658
7755
  ...this.#resolveAdditionalEntrypoints(cwd, additionalEntryPoints)
7659
7756
  ];
7660
7757
  return {
@@ -7675,9 +7772,9 @@ class Builder {
7675
7772
  for (const relativePath of this.#globFiles(cwd)) {
7676
7773
  if (relativePath === "package.json")
7677
7774
  continue;
7678
- const sourcePath = path33.join(cwd, relativePath);
7679
- const targetPath = path33.join(this.#distExecutor.cwdPath, relativePath);
7680
- await mkdir9(path33.dirname(targetPath), { recursive: true });
7775
+ const sourcePath = path34.join(cwd, relativePath);
7776
+ const targetPath = path34.join(this.#distExecutor.cwdPath, relativePath);
7777
+ await mkdir9(path34.dirname(targetPath), { recursive: true });
7681
7778
  await Bun.write(targetPath, Bun.file(sourcePath));
7682
7779
  }
7683
7780
  }
@@ -7688,13 +7785,13 @@ class Builder {
7688
7785
  return withoutFormatDir;
7689
7786
  if (!hasDotSlash && withoutFormatDir === publishedPath)
7690
7787
  return publishedPath;
7691
- const parsed = path33.posix.parse(withoutFormatDir);
7788
+ const parsed = path34.posix.parse(withoutFormatDir);
7692
7789
  if (![".js", ".mjs", ".cjs"].includes(parsed.ext))
7693
7790
  return withoutFormatDir;
7694
- const withoutExt = path33.posix.join(parsed.dir, parsed.name);
7791
+ const withoutExt = path34.posix.join(parsed.dir, parsed.name);
7695
7792
  const sourcePath = withoutExt.startsWith("./") ? withoutExt.slice(2) : withoutExt;
7696
7793
  const sourceCandidates = [`${sourcePath}.ts`, `${sourcePath}.tsx`];
7697
- const matchedSource = sourceCandidates.find((candidate) => existsSync2(path33.join(this.#executor.cwdPath, candidate)));
7794
+ const matchedSource = sourceCandidates.find((candidate) => existsSync2(path34.join(this.#executor.cwdPath, candidate)));
7698
7795
  if (!matchedSource)
7699
7796
  return withoutFormatDir;
7700
7797
  return hasDotSlash ? `./${matchedSource}` : matchedSource;
@@ -7744,7 +7841,7 @@ class Builder {
7744
7841
  }
7745
7842
  // pkgs/@akanjs/devkit/capacitorApp.ts
7746
7843
  import { cp as cp2, mkdir as mkdir10, rm as rm4 } from "fs/promises";
7747
- import path34 from "path";
7844
+ import path35 from "path";
7748
7845
  import { MobileProject } from "@trapezedev/project";
7749
7846
  import { capitalize as capitalize2 } from "akanjs/common";
7750
7847
 
@@ -7938,10 +8035,10 @@ class CapacitorApp {
7938
8035
  constructor(app, target) {
7939
8036
  this.app = app;
7940
8037
  this.target = target;
7941
- this.targetRootPath = path34.posix.join("mobile", this.target.name);
7942
- this.targetRoot = path34.join(this.app.cwdPath, this.targetRootPath);
7943
- this.targetWebRoot = path34.join(this.targetRoot, "www");
7944
- this.targetAssetRoot = path34.join(this.targetRoot, "assets");
8038
+ this.targetRootPath = path35.posix.join("mobile", this.target.name);
8039
+ this.targetRoot = path35.join(this.app.cwdPath, this.targetRootPath);
8040
+ this.targetWebRoot = path35.join(this.targetRoot, "www");
8041
+ this.targetAssetRoot = path35.join(this.targetRoot, "assets");
7945
8042
  this.project = new MobileProject(this.app.cwdPath, {
7946
8043
  android: { path: this.androidRootPath },
7947
8044
  ios: { path: this.iosProjectPath }
@@ -7957,9 +8054,9 @@ class CapacitorApp {
7957
8054
  await this.#writeCapacitorConfig();
7958
8055
  if (regenerate) {
7959
8056
  if (!platform || platform === "ios")
7960
- await rm4(path34.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
8057
+ await rm4(path35.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
7961
8058
  if (!platform || platform === "android")
7962
- await rm4(path34.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
8059
+ await rm4(path35.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
7963
8060
  }
7964
8061
  const project = this.project;
7965
8062
  await this.project.load();
@@ -8021,7 +8118,7 @@ class CapacitorApp {
8021
8118
  await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
8022
8119
  }
8023
8120
  async#updateAndroidBuildTypes() {
8024
- const appGradle = await FileEditor.create(path34.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
8121
+ const appGradle = await FileEditor.create(path35.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
8025
8122
  const buildTypesBlock = `
8026
8123
  debug {
8027
8124
  applicationIdSuffix ".debug"
@@ -8064,7 +8161,7 @@ class CapacitorApp {
8064
8161
  const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
8065
8162
  await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
8066
8163
  stdio: "inherit",
8067
- cwd: path34.join(this.app.cwdPath, this.androidRootPath),
8164
+ cwd: path35.join(this.app.cwdPath, this.androidRootPath),
8068
8165
  env: this.#commandEnv("release", env)
8069
8166
  });
8070
8167
  }
@@ -8093,12 +8190,12 @@ class CapacitorApp {
8093
8190
  await this.#prepareAndroid({ operation: "release", env: "main" });
8094
8191
  }
8095
8192
  async prepareWww() {
8096
- const htmlSource = path34.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
8193
+ const htmlSource = path35.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
8097
8194
  if (!await Bun.file(htmlSource).exists())
8098
8195
  throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
8099
8196
  await rm4(this.targetWebRoot, { recursive: true, force: true });
8100
8197
  await mkdir10(this.targetWebRoot, { recursive: true });
8101
- await Bun.write(path34.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
8198
+ await Bun.write(path35.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
8102
8199
  }
8103
8200
  #injectMobileTargetMeta(html) {
8104
8201
  const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
@@ -8110,7 +8207,7 @@ class CapacitorApp {
8110
8207
  }
8111
8208
  async#writeCapacitorConfig() {
8112
8209
  await mkdir10(this.targetRoot, { recursive: true });
8113
- const appInfoPath = path34.relative(this.app.cwdPath, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
8210
+ const appInfoPath = path35.relative(this.app.cwdPath, path35.join(this.app.cwdPath, "akan.app.json")).split(path35.sep).join("/");
8114
8211
  const content = `import type { AppScanResult } from "akanjs";
8115
8212
  import { withBase } from "akanjs/capacitor.base.config";
8116
8213
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
@@ -8131,18 +8228,18 @@ export default withBase(
8131
8228
  appInfo as AppScanResult,
8132
8229
  );
8133
8230
  `;
8134
- await Bun.write(path34.join(this.app.cwdPath, "capacitor.config.ts"), content);
8231
+ await Bun.write(path35.join(this.app.cwdPath, "capacitor.config.ts"), content);
8135
8232
  }
8136
8233
  async#prepareTargetAssets() {
8137
8234
  if (!this.target.assets)
8138
8235
  return;
8139
8236
  await mkdir10(this.targetAssetRoot, { recursive: true });
8140
8237
  if (this.target.assets.icon)
8141
- await cp2(path34.join(this.app.cwdPath, this.target.assets.icon), path34.join(this.targetAssetRoot, "icon.png"), {
8238
+ await cp2(path35.join(this.app.cwdPath, this.target.assets.icon), path35.join(this.targetAssetRoot, "icon.png"), {
8142
8239
  force: true
8143
8240
  });
8144
8241
  if (this.target.assets.splash)
8145
- await cp2(path34.join(this.app.cwdPath, this.target.assets.splash), path34.join(this.targetAssetRoot, "splash.png"), {
8242
+ await cp2(path35.join(this.app.cwdPath, this.target.assets.splash), path35.join(this.targetAssetRoot, "splash.png"), {
8146
8243
  force: true
8147
8244
  });
8148
8245
  }
@@ -8150,11 +8247,11 @@ export default withBase(
8150
8247
  const files = this.target.files?.[platform];
8151
8248
  if (!files)
8152
8249
  return;
8153
- const platformRoot = path34.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
8250
+ const platformRoot = path35.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
8154
8251
  await Promise.all(Object.entries(files).map(async ([to, from]) => {
8155
- const targetPath = path34.join(platformRoot, to);
8156
- await mkdir10(path34.dirname(targetPath), { recursive: true });
8157
- await cp2(path34.join(this.app.cwdPath, from), targetPath, { force: true });
8252
+ const targetPath = path35.join(platformRoot, to);
8253
+ await mkdir10(path35.dirname(targetPath), { recursive: true });
8254
+ await cp2(path35.join(this.app.cwdPath, from), targetPath, { force: true });
8158
8255
  }));
8159
8256
  }
8160
8257
  async#generateAssets({ operation, env }) {
@@ -8164,7 +8261,7 @@ export default withBase(
8164
8261
  "@capacitor/assets",
8165
8262
  "generate",
8166
8263
  "--assetPath",
8167
- path34.posix.join(this.targetRootPath, "assets"),
8264
+ path35.posix.join(this.targetRootPath, "assets"),
8168
8265
  "--iosProject",
8169
8266
  this.iosProjectPath,
8170
8267
  "--androidProject",
@@ -8349,7 +8446,7 @@ var Pkg = createInternalArgToken("Pkg");
8349
8446
  var Module = createInternalArgToken("Module");
8350
8447
  var Workspace = createInternalArgToken("Workspace");
8351
8448
  // pkgs/@akanjs/devkit/commandDecorators/command.ts
8352
- import path35 from "path";
8449
+ import path36 from "path";
8353
8450
  import { confirm, input as input2, select as select2 } from "@inquirer/prompts";
8354
8451
  import { Logger as Logger11 } from "akanjs/common";
8355
8452
  import chalk6 from "chalk";
@@ -8849,7 +8946,7 @@ var runCommands = async (...commands) => {
8849
8946
  process.exit(1);
8850
8947
  });
8851
8948
  const __dirname2 = getDirname(import.meta.url);
8852
- const packageJsonCandidates = [`${path35.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
8949
+ const packageJsonCandidates = [`${path36.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
8853
8950
  let cliPackageJson = null;
8854
8951
  for (const packageJsonPath of packageJsonCandidates) {
8855
8952
  if (!await FileSys.fileExists(packageJsonPath))
@@ -9125,8 +9222,8 @@ var scanModuleSpecifiers = (source, filePath, includeExports) => {
9125
9222
  return importSpecifiers;
9126
9223
  };
9127
9224
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
9128
- const configFile = ts6.readConfigFile(tsConfigPath, (path36) => {
9129
- return ts6.sys.readFile(path36);
9225
+ const configFile = ts6.readConfigFile(tsConfigPath, (path37) => {
9226
+ return ts6.sys.readFile(path37);
9130
9227
  });
9131
9228
  return ts6.parseJsonConfigFileContent(configFile.config, ts6.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
9132
9229
  };
@@ -9354,6 +9451,75 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
9354
9451
  import { useEffect as useEffect3, useState as useState3 } from "react";
9355
9452
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
9356
9453
  "use client";
9454
+ // pkgs/@akanjs/devkit/cloud/cloudApi.ts
9455
+ class HttpClient2 {
9456
+ baseUrl;
9457
+ constructor(baseUrl) {
9458
+ this.baseUrl = baseUrl;
9459
+ }
9460
+ async get(url, { headers } = {}) {
9461
+ const response = await fetch(`${this.baseUrl}${url}`, {
9462
+ headers: { "Content-Type": "application/json", ...headers }
9463
+ });
9464
+ return response.json();
9465
+ }
9466
+ async post(url, data, { headers } = {}) {
9467
+ const isFormData = data instanceof FormData;
9468
+ const response = await fetch(`${this.baseUrl}${url}`, {
9469
+ method: "POST",
9470
+ body: isFormData ? data : JSON.stringify(data),
9471
+ headers: isFormData ? headers : { "Content-Type": "application/json", ...headers }
9472
+ });
9473
+ return response.json();
9474
+ }
9475
+ }
9476
+
9477
+ class CloudApi {
9478
+ api;
9479
+ #accessToken = null;
9480
+ constructor(host, { accessToken } = {}) {
9481
+ this.api = new HttpClient2(`${host}/api`);
9482
+ this.#accessToken = accessToken ?? null;
9483
+ }
9484
+ async uploadEnv(devProjectId, fileStream) {
9485
+ const formData = new FormData;
9486
+ formData.append("devProjectId", devProjectId);
9487
+ formData.append("fileStream", await new Response(fileStream).blob());
9488
+ const response = await this.api.post(`/uploadEnv/${devProjectId}`, formData);
9489
+ return response.success;
9490
+ }
9491
+ async downloadEnv(devProjectId) {
9492
+ const response = await this.api.get(`/downloadEnv/${devProjectId}`);
9493
+ return response.success;
9494
+ }
9495
+ async getRemoteAuthToken(remoteId) {
9496
+ if (this.#needRefreshToken())
9497
+ return await this.refreshAuthToken();
9498
+ else if (this.#accessToken)
9499
+ return this.#accessToken;
9500
+ const accessToken = await this.api.get(`/getRemoteAuthToken/${remoteId}`);
9501
+ this.#accessToken = {
9502
+ jwt: accessToken.jwt,
9503
+ refreshToken: accessToken.refreshToken,
9504
+ expiresAt: new Date(accessToken.expiresAt)
9505
+ };
9506
+ return accessToken;
9507
+ }
9508
+ async refreshAuthToken() {
9509
+ const response = await this.api.post(`/refreshRemoteAuthToken`, {
9510
+ refreshToken: this.#accessToken?.refreshToken
9511
+ });
9512
+ this.#accessToken = {
9513
+ jwt: response.jwt,
9514
+ refreshToken: response.refreshToken,
9515
+ expiresAt: new Date(response.expiresAt)
9516
+ };
9517
+ return response;
9518
+ }
9519
+ #needRefreshToken() {
9520
+ return !!(this.#accessToken?.expiresAt && this.#accessToken.expiresAt.getTime() < Date.now() - 1000 * 60 * 60);
9521
+ }
9522
+ }
9357
9523
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
9358
9524
  import { Logger as Logger12 } from "akanjs/common";
9359
9525
 
@@ -9428,10 +9594,10 @@ class IncrementalBuilder {
9428
9594
  }
9429
9595
  }
9430
9596
  batchTouchesPagesTree(appDir, batch) {
9431
- const absAppDir = path36.resolve(appDir);
9597
+ const absAppDir = path37.resolve(appDir);
9432
9598
  for (const f of batch.files) {
9433
- const abs = path36.resolve(f);
9434
- if (!abs.startsWith(`${absAppDir}${path36.sep}`) && abs !== absAppDir)
9599
+ const abs = path37.resolve(f);
9600
+ if (!abs.startsWith(`${absAppDir}${path37.sep}`) && abs !== absAppDir)
9435
9601
  continue;
9436
9602
  if (/\.(tsx|ts|jsx|js)$/.test(abs))
9437
9603
  return true;
@@ -9439,15 +9605,15 @@ class IncrementalBuilder {
9439
9605
  return false;
9440
9606
  }
9441
9607
  async batchMayChangePageKeys(appDir, batch) {
9442
- const absAppDir = path36.resolve(appDir);
9443
- const pageKeys = new Set((await this.#app.getPageKeys()).map((key) => path36.normalize(key)));
9608
+ const absAppDir = path37.resolve(appDir);
9609
+ const pageKeys = new Set((await this.#app.getPageKeys()).map((key) => path37.normalize(key)));
9444
9610
  for (const f of batch.files) {
9445
- const abs = path36.resolve(f);
9446
- if (!abs.startsWith(`${absAppDir}${path36.sep}`) && abs !== absAppDir)
9611
+ const abs = path37.resolve(f);
9612
+ if (!abs.startsWith(`${absAppDir}${path37.sep}`) && abs !== absAppDir)
9447
9613
  continue;
9448
9614
  if (!/\.(tsx|ts|jsx|js)$/.test(abs))
9449
9615
  continue;
9450
- const rel = path36.normalize(path36.relative(absAppDir, abs));
9616
+ const rel = path37.normalize(path37.relative(absAppDir, abs));
9451
9617
  if (!await Bun.file(abs).exists() || !pageKeys.has(rel))
9452
9618
  return true;
9453
9619
  }
@@ -9475,7 +9641,7 @@ class IncrementalBuilder {
9475
9641
  ${cssText}`).toString(36);
9476
9642
  const cssRelPath = `styles/${cssAssetName}-${cssHash}.css`;
9477
9643
  const cssUrl = `/_akan/styles/${cssAssetName}-${cssHash}.css`;
9478
- await Bun.write(path36.join(artifactDir, cssRelPath), cssText);
9644
+ await Bun.write(path37.join(artifactDir, cssRelPath), cssText);
9479
9645
  cssAssetEntries.push([basePath2, { cssUrl, cssRelPath }]);
9480
9646
  cssBase64ByUrl[cssUrl] = Buffer.from(new TextEncoder().encode(cssText)).toString("base64");
9481
9647
  })()
@@ -9535,10 +9701,10 @@ ${cssText}`).toString(36);
9535
9701
  if (changedFiles.length === 0)
9536
9702
  return false;
9537
9703
  return changedFiles.some((file) => {
9538
- const normalized = path36.resolve(file);
9704
+ const normalized = path37.resolve(file);
9539
9705
  if (/\.(woff2?|ttf|otf)$/i.test(normalized))
9540
9706
  return true;
9541
- return this.#optimizedFonts.files.some((fontFile) => path36.resolve(fontFile) === normalized);
9707
+ return this.#optimizedFonts.files.some((fontFile) => path37.resolve(fontFile) === normalized);
9542
9708
  });
9543
9709
  }
9544
9710
  async installWatcher() {