@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
package/index.js CHANGED
@@ -22,9 +22,12 @@ import { mkdir } from "fs/promises";
22
22
  var basePath = `${Bun.env.HOME ?? Bun.env.USERPROFILE}/.akan`;
23
23
  var configPath = `${basePath}/config.json`;
24
24
  var akanCloudHost = process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? "http://localhost" : "https://cloud.akanjs.com";
25
- var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? ":8282" : ""}/\uBA54\u3151`;
25
+ var akanCloudUrl = `${akanCloudHost}${process.env.AKAN_PUBLIC_OPERATION_MODE === "local" ? ":8282" : ""}/api`;
26
26
  var defaultHostConfig = {};
27
- var defaultAkanGlobalConfig = { cloudHost: {}, llm: null };
27
+ var defaultAkanGlobalConfig = {
28
+ cloudHost: {},
29
+ llm: null
30
+ };
28
31
 
29
32
  // pkgs/@akanjs/devkit/fileSys.ts
30
33
  import { stat } from "fs/promises";
@@ -484,7 +487,18 @@ var DEFAULT_OPTIMIZE_IMPORTS = [
484
487
  var WORKSPACE_BARREL_FACETS = ["ui", "webkit", "common", "client", "server"];
485
488
  var SSR_RUNTIME_PACKAGES = ["react", "react-dom", "react-server-dom-webpack"];
486
489
  var NATIVE_RUNTIME_PACKAGES = ["sharp"];
487
- var AKAN_RUNTIME_PACKAGES = new Set([...SSR_RUNTIME_PACKAGES, ...NATIVE_RUNTIME_PACKAGES]);
490
+ var DEFAULT_BACKEND_RUNTIME_PACKAGES = ["croner"];
491
+ var DATABASE_MODE_RUNTIME_PACKAGES = {
492
+ single: [],
493
+ multiple: ["@libsql/client", "bullmq", "ioredis", "protobufjs"],
494
+ cluster: ["bullmq", "ioredis", "postgres", "protobufjs"]
495
+ };
496
+ var AKAN_RUNTIME_PACKAGES = new Set([
497
+ ...SSR_RUNTIME_PACKAGES,
498
+ ...NATIVE_RUNTIME_PACKAGES,
499
+ ...DEFAULT_BACKEND_RUNTIME_PACKAGES,
500
+ ...Object.values(DATABASE_MODE_RUNTIME_PACKAGES).flat()
501
+ ]);
488
502
  var DEFAULT_AKAN_IMAGE_CONFIG = {
489
503
  deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
490
504
  imageSizes: [32, 48, 64, 96, 128, 256, 384],
@@ -693,13 +707,22 @@ CMD [${command.map((c) => `"${c}"`).join(",")}]`;
693
707
  if (AKAN_RUNTIME_PACKAGES.has(lib))
694
708
  return akanPackageJson.dependencies?.[lib] ?? akanPackageJson.peerDependencies?.[lib];
695
709
  }
710
+ #getProductionRuntimePackages() {
711
+ return [
712
+ ...this.externalLibs,
713
+ ...SSR_RUNTIME_PACKAGES,
714
+ ...NATIVE_RUNTIME_PACKAGES,
715
+ ...DEFAULT_BACKEND_RUNTIME_PACKAGES,
716
+ ...DATABASE_MODE_RUNTIME_PACKAGES[this.defaultDatabaseMode]
717
+ ];
718
+ }
696
719
  getProductionPackageJson(data = {}) {
697
720
  return {
698
721
  name: this.app.name,
699
722
  description: this.app.name,
700
723
  version: "1.0.0",
701
724
  main: "./main.js",
702
- dependencies: Object.fromEntries([...new Set([...this.externalLibs, ...SSR_RUNTIME_PACKAGES, ...NATIVE_RUNTIME_PACKAGES])].map((lib) => {
725
+ dependencies: Object.fromEntries([...new Set(this.#getProductionRuntimePackages())].map((lib) => {
703
726
  const version = this.#resolveProductionDependencyVersion(lib);
704
727
  if (!version)
705
728
  throw new Error(`Dependency ${lib} not found in package.json`);
@@ -2118,7 +2141,6 @@ class Executor {
2118
2141
  this.logger = new Logger4(name);
2119
2142
  this.logs = [];
2120
2143
  this.cwdPath = cwdPath;
2121
- //! TODO: 테스트 확인 필요
2122
2144
  }
2123
2145
  #stdout(data) {
2124
2146
  if (Executor.verbose)
@@ -3960,6 +3982,16 @@ function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
3960
3982
  }
3961
3983
  return [...boundaries.values()].sort((a, b) => a.segments.join("/").localeCompare(b.segments.join("/")));
3962
3984
  }
3985
+ function hasAncestorRootBoundary(boundary, boundaries) {
3986
+ return boundaries.some((candidate) => candidate !== boundary && candidate.segments.length < boundary.segments.length && candidate.segments.every((segment, index) => boundary.segments[index] === segment));
3987
+ }
3988
+ function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
3989
+ const rootLayoutKey = pageKeys.find((key) => {
3990
+ const segments = getRootBoundarySegments(key);
3991
+ return segments !== null && segments.length === 0;
3992
+ });
3993
+ return rootLayoutKey ? path10.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
3994
+ }
3963
3995
  function routePrefixForSegments(segments) {
3964
3996
  const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
3965
3997
  return visible[0] ?? null;
@@ -3976,21 +4008,27 @@ async function writeGeneratedRootLayoutFile(opts) {
3976
4008
  await mkdir3(path10.dirname(absPath), { recursive: true });
3977
4009
  const sourceRel = opts.boundary.sourceAbsPath ? path10.relative(path10.dirname(absPath), opts.boundary.sourceAbsPath).split(path10.sep).join("/") : null;
3978
4010
  const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
4011
+ const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
4012
+ const inheritedSourceRel = inheritedSourceAbsPath ? path10.relative(path10.dirname(absPath), inheritedSourceAbsPath).split(path10.sep).join("/") : null;
4013
+ const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
3979
4014
  const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
3980
4015
  void st;
3981
4016
  ` : `import "@apps/${opts.appName}/client";
4017
+ `;
4018
+ const inheritedImport = inheritedSourceSpecifier ? `import * as inheritedLayout from ${JSON.stringify(inheritedSourceSpecifier)};
4019
+ ` : `const inheritedLayout = {};
3982
4020
  `;
3983
4021
  const prefix = routePrefixForSegments(opts.boundary.segments);
3984
4022
  const userImport = sourceSpecifier ? `import UserLayout, * as userLayout from ${JSON.stringify(sourceSpecifier)};
3985
4023
  ` : `const UserLayout = ({ children }) => children;
3986
4024
  const userLayout = {};
3987
4025
  `;
3988
- const source = `import type { LayoutProps, PageProps } from "akanjs/client";
4026
+ const source = opts.includeSystemProvider ? `import type { LayoutProps, PageProps } from "akanjs/client";
3989
4027
  import { loadFonts } from "akanjs/client";
3990
4028
  import { System } from "akanjs/ui";
3991
4029
  import { env } from "@apps/${opts.appName}/env/env.client";
3992
- ${clientImport}${userImport}
3993
- const userFonts = userLayout.fonts ?? [];
4030
+ ${clientImport}${inheritedImport}${userImport}
4031
+ const userFonts = userLayout.fonts ?? inheritedLayout.fonts ?? [];
3994
4032
  const defaultFonts = userFonts.filter((font) => font.default);
3995
4033
  if (defaultFonts.length > 1) throw new Error("[route-convention] only one default font is allowed per root layout");
3996
4034
  const defaultFont = defaultFonts[0];
@@ -3998,7 +4036,9 @@ const defaultFontClassName = defaultFont ? (defaultFont.className ?? \`font-\${d
3998
4036
 
3999
4037
  export async function generateHead(props: PageProps) {
4000
4038
  if (userLayout.generateHead) return userLayout.generateHead(props);
4001
- return userLayout.head;
4039
+ if (userLayout.head !== undefined) return userLayout.head;
4040
+ if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
4041
+ return inheritedLayout.head;
4002
4042
  }
4003
4043
 
4004
4044
  export default function GeneratedLayout({ children, params, searchParams }: LayoutProps) {
@@ -4008,19 +4048,31 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
4008
4048
  appName=${JSON.stringify(opts.appName)}
4009
4049
  ${prefix ? `prefix=${JSON.stringify(prefix)}
4010
4050
  ` : ""}params={params}
4011
- manifest={userLayout.manifest}
4051
+ manifest={userLayout.manifest ?? inheritedLayout.manifest}
4012
4052
  env={env}
4013
- theme={userLayout.theme}
4053
+ theme={userLayout.theme ?? inheritedLayout.theme}
4014
4054
  fonts={loadFonts(userFonts)}
4015
4055
  className={defaultFontClassName}
4016
- gaTrackingId={userLayout.gaTrackingId}
4017
- layoutStyle={userLayout.layoutStyle}
4018
- reconnect={userLayout.reconnect ?? false}
4056
+ gaTrackingId={userLayout.gaTrackingId ?? inheritedLayout.gaTrackingId}
4057
+ layoutStyle={userLayout.layoutStyle ?? inheritedLayout.layoutStyle}
4058
+ reconnect={userLayout.reconnect ?? inheritedLayout.reconnect ?? false}
4019
4059
  >
4020
4060
  <UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>
4021
4061
  </System.Provider>
4022
4062
  );
4023
4063
  }
4064
+ ` : `import type { LayoutProps, PageProps } from "akanjs/client";
4065
+ ${inheritedImport}${userImport}
4066
+ export async function generateHead(props: PageProps) {
4067
+ if (userLayout.generateHead) return userLayout.generateHead(props);
4068
+ if (userLayout.head !== undefined) return userLayout.head;
4069
+ if (inheritedLayout.generateHead) return inheritedLayout.generateHead(props);
4070
+ return inheritedLayout.head;
4071
+ }
4072
+
4073
+ export default function GeneratedLayout({ children, params, searchParams }: LayoutProps) {
4074
+ return <UserLayout params={params} searchParams={searchParams}>{children}</UserLayout>;
4075
+ }
4024
4076
  `;
4025
4077
  await Bun.write(absPath, source);
4026
4078
  return absPath;
@@ -4029,6 +4081,8 @@ async function resolveSsrPageEntries(opts) {
4029
4081
  const absPageDir = path10.resolve(opts.appCwdPath, "page");
4030
4082
  const hasSt = await appHasStModule(opts.appCwdPath);
4031
4083
  const basePaths = opts.basePaths ?? [];
4084
+ const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
4085
+ const rootBoundaries = findRootBoundaries(opts.pageKeys, opts.appCwdPath, basePaths);
4032
4086
  const rootLayoutKeys = new Set(opts.pageKeys.filter((key) => {
4033
4087
  const segments = getRootBoundarySegments(key);
4034
4088
  return segments !== null && isRootBoundarySegments(segments, basePaths);
@@ -4037,15 +4091,17 @@ async function resolveSsrPageEntries(opts) {
4037
4091
  key,
4038
4092
  moduleAbsPath: path10.resolve(absPageDir, key)
4039
4093
  }));
4040
- const generated = await Promise.all(findRootBoundaries(opts.pageKeys, opts.appCwdPath, basePaths).map(async (boundary) => ({
4094
+ const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
4041
4095
  key: implicitRootLayoutKey(boundary.segments),
4042
4096
  moduleAbsPath: await writeGeneratedRootLayoutFile({
4043
4097
  appCwdPath: opts.appCwdPath,
4044
4098
  appName: opts.appName,
4045
4099
  boundary,
4046
- includeStInit: hasSt && boundary.segments.length === 0
4100
+ rootSourceAbsPath,
4101
+ includeStInit: hasSt && boundary.segments.length === 0,
4102
+ includeSystemProvider: !hasAncestorRootBoundary(boundary, rootBoundaries)
4047
4103
  }),
4048
- seedAbsPaths: boundary.sourceAbsPath ? [boundary.sourceAbsPath] : []
4104
+ seedAbsPaths: [...new Set([boundary.sourceAbsPath, rootSourceAbsPath].filter((absPath) => absPath !== null))]
4049
4105
  })));
4050
4106
  const entries = [...base, ...generated];
4051
4107
  entries.sort((a, b) => a.key.localeCompare(b.key));
@@ -7020,6 +7076,13 @@ function formatBytes(bytes) {
7020
7076
  }
7021
7077
  // pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
7022
7078
  import path30 from "path";
7079
+ import { optimize } from "@tailwindcss/node";
7080
+ function prepareCssAsset(command, basePath2, cssText) {
7081
+ if (command !== "build")
7082
+ return cssText;
7083
+ return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: true }).code;
7084
+ }
7085
+
7023
7086
  class SsrBaseArtifactBuilder {
7024
7087
  #app;
7025
7088
  #command;
@@ -7111,14 +7174,15 @@ class SsrBaseArtifactBuilder {
7111
7174
  }
7112
7175
  async#writeCssAsset(basePath2, cssText) {
7113
7176
  const cssAssetName = basePath2 || "root";
7177
+ const preparedCssText = await prepareCssAsset(this.#command, basePath2, cssText);
7114
7178
  const cssHash = Bun.hash(`${basePath2}
7115
- ${cssText}`).toString(36);
7179
+ ${preparedCssText}`).toString(36);
7116
7180
  const [cssRelPath, cssUrl] = [
7117
7181
  `styles/${cssAssetName}-${cssHash}.css`,
7118
7182
  `/_akan/styles/${cssAssetName}-${cssHash}.css`
7119
7183
  ];
7120
- await Bun.write(path30.join(this.#absArtifactDir, cssRelPath), cssText);
7121
- this.#app.verbose(`[base-artifact] wrote ${cssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
7184
+ await Bun.write(path30.join(this.#absArtifactDir, cssRelPath), preparedCssText);
7185
+ this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
7122
7186
  return [basePath2, { cssUrl, cssRelPath }];
7123
7187
  }
7124
7188
  }
@@ -7166,9 +7230,19 @@ var SSR_RENDER_EXTERNALS = [
7166
7230
  "react/jsx-dev-runtime",
7167
7231
  "react-dom",
7168
7232
  "react-dom/server.browser",
7233
+ "react-server-dom-webpack",
7234
+ "react-server-dom-webpack/server.node",
7169
7235
  "react-server-dom-webpack/client.node",
7170
7236
  "react-server-dom-webpack/client.browser"
7171
7237
  ];
7238
+ var AKAN_OPTIONAL_BACKEND_EXTERNALS = [
7239
+ "@libsql/client",
7240
+ "bullmq",
7241
+ "croner",
7242
+ "ioredis",
7243
+ "postgres",
7244
+ "protobufjs"
7245
+ ];
7172
7246
 
7173
7247
  class ApplicationBuildRunner {
7174
7248
  #app;
@@ -7237,7 +7311,9 @@ class ApplicationBuildRunner {
7237
7311
  }
7238
7312
  async#buildBackend() {
7239
7313
  const akanConfig2 = await this.#app.getConfig();
7240
- const backendExternals = [...new Set([...akanConfig2.externalLibs, ...SSR_RENDER_EXTERNALS])];
7314
+ const backendExternals = [
7315
+ ...new Set([...akanConfig2.externalLibs, ...SSR_RENDER_EXTERNALS, ...AKAN_OPTIONAL_BACKEND_EXTERNALS])
7316
+ ];
7241
7317
  const backendEntryPoints = [`${this.#app.cwdPath}/main.ts`, `${this.#app.cwdPath}/server.ts`];
7242
7318
  for (const entrypoint of backendEntryPoints) {
7243
7319
  if (!await Bun.file(entrypoint).exists())
@@ -7259,7 +7335,7 @@ class ApplicationBuildRunner {
7259
7335
  naming: { entry: "[name].[ext]", chunk: "chunk-[hash].[ext]" },
7260
7336
  conditions: ["react-server"],
7261
7337
  define: { "process.env.NODE_ENV": JSON.stringify("production") },
7262
- plugins: akanConfig2.externalLibs.length > 0 ? [this.#createExternalSpecifiersPlugin(akanConfig2.externalLibs)] : []
7338
+ plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
7263
7339
  });
7264
7340
  return {
7265
7341
  entrypoints: backendEntryPoints.length + 1,
@@ -7607,10 +7683,31 @@ class ApplicationReleasePackager {
7607
7683
  `;
7608
7684
  }
7609
7685
  }
7686
+ // pkgs/@akanjs/devkit/applicationTestPreload.ts
7687
+ import path33 from "path";
7688
+ var SIGNAL_TEST_PRELOAD_PATH = "test/signalTest.preload.ts";
7689
+ async function resolveSignalTestPreloadPath(target) {
7690
+ const candidates = [];
7691
+ const addResolvedPackageCandidate = (basePath2) => {
7692
+ try {
7693
+ candidates.push(path33.join(path33.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
7694
+ } catch {}
7695
+ };
7696
+ addResolvedPackageCandidate(target.cwdPath);
7697
+ addResolvedPackageCandidate(process.cwd());
7698
+ addResolvedPackageCandidate(path33.dirname(Bun.main));
7699
+ addResolvedPackageCandidate(import.meta.dir);
7700
+ 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));
7701
+ for (const candidate of [...new Set(candidates)]) {
7702
+ if (await Bun.file(candidate).exists())
7703
+ return candidate;
7704
+ }
7705
+ throw new Error(`Failed to locate ${SIGNAL_TEST_PRELOAD_PATH} from ${target.cwdPath}`);
7706
+ }
7610
7707
  // pkgs/@akanjs/devkit/builder.ts
7611
7708
  import { existsSync as existsSync2 } from "fs";
7612
7709
  import { mkdir as mkdir9 } from "fs/promises";
7613
- import path33 from "path";
7710
+ import path34 from "path";
7614
7711
  var SKIP_ENTRY_DIR_SET = new Set(["node_modules", "dist", "build", ".git", ".next"]);
7615
7712
  var assetExtensions = [".css", ".md", ".js", ".png", ".ico", ".svg", ".json", ".template"];
7616
7713
  var assetLoader = Object.fromEntries(assetExtensions.map((ext) => [ext, "file"]));
@@ -7627,14 +7724,14 @@ class Builder {
7627
7724
  #globEntrypoints(cwd, pattern) {
7628
7725
  const glob = new Bun.Glob(pattern);
7629
7726
  return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
7630
- const segments = relativePath.split(path33.sep);
7727
+ const segments = relativePath.split(path34.sep);
7631
7728
  return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
7632
- }).map((rel) => path33.join(cwd, rel));
7729
+ }).map((rel) => path34.join(cwd, rel));
7633
7730
  }
7634
7731
  #globFiles(cwd, pattern = "**/*.*") {
7635
7732
  const glob = new Bun.Glob(pattern);
7636
7733
  return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
7637
- const segments = relativePath.split(path33.sep);
7734
+ const segments = relativePath.split(path34.sep);
7638
7735
  return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
7639
7736
  });
7640
7737
  }
@@ -7642,17 +7739,17 @@ class Builder {
7642
7739
  const out = [];
7643
7740
  for (const p of additionalEntryPoints) {
7644
7741
  if (p.includes("*")) {
7645
- const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path33.sep}`) ? p.slice(cwd.length + 1) : p;
7742
+ const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path34.sep}`) ? p.slice(cwd.length + 1) : p;
7646
7743
  out.push(...this.#globEntrypoints(cwd, rel));
7647
7744
  } else
7648
- out.push(path33.isAbsolute(p) ? p : path33.join(cwd, p));
7745
+ out.push(path34.isAbsolute(p) ? p : path34.join(cwd, p));
7649
7746
  }
7650
7747
  return out;
7651
7748
  }
7652
7749
  #getBuildOptions({ bundle = false, additionalEntryPoints = [] } = {}) {
7653
7750
  const cwd = this.#executor.cwdPath;
7654
7751
  const entrypoints = [
7655
- ...bundle ? [path33.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
7752
+ ...bundle ? [path34.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
7656
7753
  ...this.#resolveAdditionalEntrypoints(cwd, additionalEntryPoints)
7657
7754
  ];
7658
7755
  return {
@@ -7673,9 +7770,9 @@ class Builder {
7673
7770
  for (const relativePath of this.#globFiles(cwd)) {
7674
7771
  if (relativePath === "package.json")
7675
7772
  continue;
7676
- const sourcePath = path33.join(cwd, relativePath);
7677
- const targetPath = path33.join(this.#distExecutor.cwdPath, relativePath);
7678
- await mkdir9(path33.dirname(targetPath), { recursive: true });
7773
+ const sourcePath = path34.join(cwd, relativePath);
7774
+ const targetPath = path34.join(this.#distExecutor.cwdPath, relativePath);
7775
+ await mkdir9(path34.dirname(targetPath), { recursive: true });
7679
7776
  await Bun.write(targetPath, Bun.file(sourcePath));
7680
7777
  }
7681
7778
  }
@@ -7686,13 +7783,13 @@ class Builder {
7686
7783
  return withoutFormatDir;
7687
7784
  if (!hasDotSlash && withoutFormatDir === publishedPath)
7688
7785
  return publishedPath;
7689
- const parsed = path33.posix.parse(withoutFormatDir);
7786
+ const parsed = path34.posix.parse(withoutFormatDir);
7690
7787
  if (![".js", ".mjs", ".cjs"].includes(parsed.ext))
7691
7788
  return withoutFormatDir;
7692
- const withoutExt = path33.posix.join(parsed.dir, parsed.name);
7789
+ const withoutExt = path34.posix.join(parsed.dir, parsed.name);
7693
7790
  const sourcePath = withoutExt.startsWith("./") ? withoutExt.slice(2) : withoutExt;
7694
7791
  const sourceCandidates = [`${sourcePath}.ts`, `${sourcePath}.tsx`];
7695
- const matchedSource = sourceCandidates.find((candidate) => existsSync2(path33.join(this.#executor.cwdPath, candidate)));
7792
+ const matchedSource = sourceCandidates.find((candidate) => existsSync2(path34.join(this.#executor.cwdPath, candidate)));
7696
7793
  if (!matchedSource)
7697
7794
  return withoutFormatDir;
7698
7795
  return hasDotSlash ? `./${matchedSource}` : matchedSource;
@@ -7742,7 +7839,7 @@ class Builder {
7742
7839
  }
7743
7840
  // pkgs/@akanjs/devkit/capacitorApp.ts
7744
7841
  import { cp as cp2, mkdir as mkdir10, rm as rm4 } from "fs/promises";
7745
- import path34 from "path";
7842
+ import path35 from "path";
7746
7843
  import { MobileProject } from "@trapezedev/project";
7747
7844
  import { capitalize as capitalize2 } from "akanjs/common";
7748
7845
 
@@ -7936,10 +8033,10 @@ class CapacitorApp {
7936
8033
  constructor(app, target) {
7937
8034
  this.app = app;
7938
8035
  this.target = target;
7939
- this.targetRootPath = path34.posix.join("mobile", this.target.name);
7940
- this.targetRoot = path34.join(this.app.cwdPath, this.targetRootPath);
7941
- this.targetWebRoot = path34.join(this.targetRoot, "www");
7942
- this.targetAssetRoot = path34.join(this.targetRoot, "assets");
8036
+ this.targetRootPath = path35.posix.join("mobile", this.target.name);
8037
+ this.targetRoot = path35.join(this.app.cwdPath, this.targetRootPath);
8038
+ this.targetWebRoot = path35.join(this.targetRoot, "www");
8039
+ this.targetAssetRoot = path35.join(this.targetRoot, "assets");
7943
8040
  this.project = new MobileProject(this.app.cwdPath, {
7944
8041
  android: { path: this.androidRootPath },
7945
8042
  ios: { path: this.iosProjectPath }
@@ -7955,9 +8052,9 @@ class CapacitorApp {
7955
8052
  await this.#writeCapacitorConfig();
7956
8053
  if (regenerate) {
7957
8054
  if (!platform || platform === "ios")
7958
- await rm4(path34.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
8055
+ await rm4(path35.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
7959
8056
  if (!platform || platform === "android")
7960
- await rm4(path34.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
8057
+ await rm4(path35.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
7961
8058
  }
7962
8059
  const project = this.project;
7963
8060
  await this.project.load();
@@ -8019,7 +8116,7 @@ class CapacitorApp {
8019
8116
  await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
8020
8117
  }
8021
8118
  async#updateAndroidBuildTypes() {
8022
- const appGradle = await FileEditor.create(path34.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
8119
+ const appGradle = await FileEditor.create(path35.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
8023
8120
  const buildTypesBlock = `
8024
8121
  debug {
8025
8122
  applicationIdSuffix ".debug"
@@ -8062,7 +8159,7 @@ class CapacitorApp {
8062
8159
  const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
8063
8160
  await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
8064
8161
  stdio: "inherit",
8065
- cwd: path34.join(this.app.cwdPath, this.androidRootPath),
8162
+ cwd: path35.join(this.app.cwdPath, this.androidRootPath),
8066
8163
  env: this.#commandEnv("release", env)
8067
8164
  });
8068
8165
  }
@@ -8091,12 +8188,12 @@ class CapacitorApp {
8091
8188
  await this.#prepareAndroid({ operation: "release", env: "main" });
8092
8189
  }
8093
8190
  async prepareWww() {
8094
- const htmlSource = path34.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
8191
+ const htmlSource = path35.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
8095
8192
  if (!await Bun.file(htmlSource).exists())
8096
8193
  throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
8097
8194
  await rm4(this.targetWebRoot, { recursive: true, force: true });
8098
8195
  await mkdir10(this.targetWebRoot, { recursive: true });
8099
- await Bun.write(path34.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
8196
+ await Bun.write(path35.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
8100
8197
  }
8101
8198
  #injectMobileTargetMeta(html) {
8102
8199
  const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
@@ -8108,7 +8205,7 @@ class CapacitorApp {
8108
8205
  }
8109
8206
  async#writeCapacitorConfig() {
8110
8207
  await mkdir10(this.targetRoot, { recursive: true });
8111
- const appInfoPath = path34.relative(this.app.cwdPath, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
8208
+ const appInfoPath = path35.relative(this.app.cwdPath, path35.join(this.app.cwdPath, "akan.app.json")).split(path35.sep).join("/");
8112
8209
  const content = `import type { AppScanResult } from "akanjs";
8113
8210
  import { withBase } from "akanjs/capacitor.base.config";
8114
8211
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
@@ -8129,18 +8226,18 @@ export default withBase(
8129
8226
  appInfo as AppScanResult,
8130
8227
  );
8131
8228
  `;
8132
- await Bun.write(path34.join(this.app.cwdPath, "capacitor.config.ts"), content);
8229
+ await Bun.write(path35.join(this.app.cwdPath, "capacitor.config.ts"), content);
8133
8230
  }
8134
8231
  async#prepareTargetAssets() {
8135
8232
  if (!this.target.assets)
8136
8233
  return;
8137
8234
  await mkdir10(this.targetAssetRoot, { recursive: true });
8138
8235
  if (this.target.assets.icon)
8139
- await cp2(path34.join(this.app.cwdPath, this.target.assets.icon), path34.join(this.targetAssetRoot, "icon.png"), {
8236
+ await cp2(path35.join(this.app.cwdPath, this.target.assets.icon), path35.join(this.targetAssetRoot, "icon.png"), {
8140
8237
  force: true
8141
8238
  });
8142
8239
  if (this.target.assets.splash)
8143
- await cp2(path34.join(this.app.cwdPath, this.target.assets.splash), path34.join(this.targetAssetRoot, "splash.png"), {
8240
+ await cp2(path35.join(this.app.cwdPath, this.target.assets.splash), path35.join(this.targetAssetRoot, "splash.png"), {
8144
8241
  force: true
8145
8242
  });
8146
8243
  }
@@ -8148,11 +8245,11 @@ export default withBase(
8148
8245
  const files = this.target.files?.[platform];
8149
8246
  if (!files)
8150
8247
  return;
8151
- const platformRoot = path34.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
8248
+ const platformRoot = path35.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
8152
8249
  await Promise.all(Object.entries(files).map(async ([to, from]) => {
8153
- const targetPath = path34.join(platformRoot, to);
8154
- await mkdir10(path34.dirname(targetPath), { recursive: true });
8155
- await cp2(path34.join(this.app.cwdPath, from), targetPath, { force: true });
8250
+ const targetPath = path35.join(platformRoot, to);
8251
+ await mkdir10(path35.dirname(targetPath), { recursive: true });
8252
+ await cp2(path35.join(this.app.cwdPath, from), targetPath, { force: true });
8156
8253
  }));
8157
8254
  }
8158
8255
  async#generateAssets({ operation, env }) {
@@ -8162,7 +8259,7 @@ export default withBase(
8162
8259
  "@capacitor/assets",
8163
8260
  "generate",
8164
8261
  "--assetPath",
8165
- path34.posix.join(this.targetRootPath, "assets"),
8262
+ path35.posix.join(this.targetRootPath, "assets"),
8166
8263
  "--iosProject",
8167
8264
  this.iosProjectPath,
8168
8265
  "--androidProject",
@@ -8347,7 +8444,7 @@ var Pkg = createInternalArgToken("Pkg");
8347
8444
  var Module = createInternalArgToken("Module");
8348
8445
  var Workspace = createInternalArgToken("Workspace");
8349
8446
  // pkgs/@akanjs/devkit/commandDecorators/command.ts
8350
- import path35 from "path";
8447
+ import path36 from "path";
8351
8448
  import { confirm, input as input2, select as select2 } from "@inquirer/prompts";
8352
8449
  import { Logger as Logger11 } from "akanjs/common";
8353
8450
  import chalk6 from "chalk";
@@ -8847,7 +8944,7 @@ var runCommands = async (...commands) => {
8847
8944
  process.exit(1);
8848
8945
  });
8849
8946
  const __dirname2 = getDirname(import.meta.url);
8850
- const packageJsonCandidates = [`${path35.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
8947
+ const packageJsonCandidates = [`${path36.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
8851
8948
  let cliPackageJson = null;
8852
8949
  for (const packageJsonPath of packageJsonCandidates) {
8853
8950
  if (!await FileSys.fileExists(packageJsonPath))
@@ -9123,8 +9220,8 @@ var scanModuleSpecifiers = (source, filePath, includeExports) => {
9123
9220
  return importSpecifiers;
9124
9221
  };
9125
9222
  var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
9126
- const configFile = ts6.readConfigFile(tsConfigPath, (path36) => {
9127
- return ts6.sys.readFile(path36);
9223
+ const configFile = ts6.readConfigFile(tsConfigPath, (path37) => {
9224
+ return ts6.sys.readFile(path37);
9128
9225
  });
9129
9226
  return ts6.parseJsonConfigFileContent(configFile.config, ts6.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
9130
9227
  };
@@ -9352,6 +9449,75 @@ import { Box as Box2, Newline, Text as Text2, useInput as useInput2 } from "ink"
9352
9449
  import { useEffect as useEffect3, useState as useState3 } from "react";
9353
9450
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
9354
9451
  "use client";
9452
+ // pkgs/@akanjs/devkit/cloud/cloudApi.ts
9453
+ class HttpClient2 {
9454
+ baseUrl;
9455
+ constructor(baseUrl) {
9456
+ this.baseUrl = baseUrl;
9457
+ }
9458
+ async get(url, { headers } = {}) {
9459
+ const response = await fetch(`${this.baseUrl}${url}`, {
9460
+ headers: { "Content-Type": "application/json", ...headers }
9461
+ });
9462
+ return response.json();
9463
+ }
9464
+ async post(url, data, { headers } = {}) {
9465
+ const isFormData = data instanceof FormData;
9466
+ const response = await fetch(`${this.baseUrl}${url}`, {
9467
+ method: "POST",
9468
+ body: isFormData ? data : JSON.stringify(data),
9469
+ headers: isFormData ? headers : { "Content-Type": "application/json", ...headers }
9470
+ });
9471
+ return response.json();
9472
+ }
9473
+ }
9474
+
9475
+ class CloudApi {
9476
+ api;
9477
+ #accessToken = null;
9478
+ constructor(host, { accessToken } = {}) {
9479
+ this.api = new HttpClient2(`${host}/api`);
9480
+ this.#accessToken = accessToken ?? null;
9481
+ }
9482
+ async uploadEnv(devProjectId, fileStream) {
9483
+ const formData = new FormData;
9484
+ formData.append("devProjectId", devProjectId);
9485
+ formData.append("fileStream", await new Response(fileStream).blob());
9486
+ const response = await this.api.post(`/uploadEnv/${devProjectId}`, formData);
9487
+ return response.success;
9488
+ }
9489
+ async downloadEnv(devProjectId) {
9490
+ const response = await this.api.get(`/downloadEnv/${devProjectId}`);
9491
+ return response.success;
9492
+ }
9493
+ async getRemoteAuthToken(remoteId) {
9494
+ if (this.#needRefreshToken())
9495
+ return await this.refreshAuthToken();
9496
+ else if (this.#accessToken)
9497
+ return this.#accessToken;
9498
+ const accessToken = await this.api.get(`/getRemoteAuthToken/${remoteId}`);
9499
+ this.#accessToken = {
9500
+ jwt: accessToken.jwt,
9501
+ refreshToken: accessToken.refreshToken,
9502
+ expiresAt: new Date(accessToken.expiresAt)
9503
+ };
9504
+ return accessToken;
9505
+ }
9506
+ async refreshAuthToken() {
9507
+ const response = await this.api.post(`/refreshRemoteAuthToken`, {
9508
+ refreshToken: this.#accessToken?.refreshToken
9509
+ });
9510
+ this.#accessToken = {
9511
+ jwt: response.jwt,
9512
+ refreshToken: response.refreshToken,
9513
+ expiresAt: new Date(response.expiresAt)
9514
+ };
9515
+ return response;
9516
+ }
9517
+ #needRefreshToken() {
9518
+ return !!(this.#accessToken?.expiresAt && this.#accessToken.expiresAt.getTime() < Date.now() - 1000 * 60 * 60);
9519
+ }
9520
+ }
9355
9521
  // pkgs/@akanjs/cli/application/application.command.ts
9356
9522
  import { select as select6 } from "@inquirer/prompts";
9357
9523
 
@@ -9469,7 +9635,6 @@ class LibraryScript extends script("library", [LibraryRunner]) {
9469
9635
  }
9470
9636
 
9471
9637
  // pkgs/@akanjs/cli/application/application.runner.ts
9472
- import path36 from "path";
9473
9638
  import { confirm as confirm2, input as input4, select as select5 } from "@inquirer/prompts";
9474
9639
  import { StringOutputParser } from "@langchain/core/output_parsers";
9475
9640
  import { PromptTemplate as PromptTemplate2 } from "@langchain/core/prompts";
@@ -9535,14 +9700,14 @@ class ApplicationRunner extends runner("application") {
9535
9700
  }
9536
9701
  async test(exec2) {
9537
9702
  const isSignalTarget = exec2 instanceof AppExecutor || exec2 instanceof LibExecutor;
9538
- const preloadPath = path36.join(exec2.cwdPath, "../../pkgs/akanjs/test/signalTest.preload.ts");
9703
+ const preloadPath = isSignalTarget ? await resolveSignalTestPreloadPath(exec2) : null;
9539
9704
  const env = isSignalTarget ? {
9540
9705
  AKAN_TEST_SIGNAL: "1",
9541
9706
  AKAN_TEST_TARGET_TYPE: exec2.type,
9542
9707
  AKAN_TEST_TARGET_NAME: exec2.name,
9543
9708
  AKAN_TEST_LIBS: exec2.getScanInfo({ allowEmpty: true })?.getLibs().join(",") ?? ""
9544
9709
  } : {};
9545
- const args = isSignalTarget ? ["test", "--isolate", "--preload", preloadPath] : ["test", "--isolate"];
9710
+ const args = preloadPath ? ["test", "--isolate", "--preload", preloadPath] : ["test", "--isolate"];
9546
9711
  await exec2.spawn("bun", args, {
9547
9712
  ...isSignalTarget ? { env: { ...process.env, ...env } } : {},
9548
9713
  stdio: "inherit"
@@ -9841,12 +10006,17 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
9841
10006
  }
9842
10007
  }
9843
10008
  async test(exec2, { write = true } = {}) {
10009
+ if (exec2 instanceof LibExecutor) {
10010
+ await this.libraryScript.syncLibrary(exec2);
10011
+ const spinner3 = exec2.spinning(`Preparing ${exec2.name}...`);
10012
+ spinner3.succeed(`${exec2.name} prepared`);
10013
+ await this.applicationRunner.test(exec2);
10014
+ return;
10015
+ }
9844
10016
  const spinner2 = exec2.spinning(`Preparing ${exec2.name}...`);
9845
10017
  try {
9846
10018
  if (exec2 instanceof PkgExecutor)
9847
10019
  await exec2.scan({ refresh: true });
9848
- else if (exec2 instanceof LibExecutor)
9849
- await this.libraryScript.syncLibrary(exec2);
9850
10020
  else
9851
10021
  await exec2.scanSync({ write });
9852
10022
  spinner2.succeed(`${exec2.name} prepared`);
@@ -10181,6 +10351,10 @@ class PackageRunner extends runner("package") {
10181
10351
  pkg.generateTsconfigJson()
10182
10352
  ]);
10183
10353
  }
10354
+ await this.#copyPackageReadmes(pkg);
10355
+ }
10356
+ async#copyPackageReadmes(pkg) {
10357
+ await Promise.all(["README.md", "README.ko.md"].map((fileName) => pkg.cp(fileName, `${pkg.dist.cwdPath}/${fileName}`)));
10184
10358
  }
10185
10359
  async updateWorskpaceRootPackageJson(workspace, rootPackageJson) {
10186
10360
  const templatePath = "pkgs/@akanjs/cli/templates/workspaceRoot/package.json.template";
@@ -10229,17 +10403,21 @@ class PackageScript extends script("package", [PackageRunner]) {
10229
10403
  }
10230
10404
 
10231
10405
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
10406
+ import path38 from "path";
10232
10407
  import { confirm as confirm3 } from "@inquirer/prompts";
10233
10408
  import { Logger as Logger15, sleep } from "akanjs/common";
10234
10409
  import chalk7 from "chalk";
10235
10410
  import * as QRcode from "qrcode";
10236
10411
 
10237
10412
  // pkgs/@akanjs/cli/npmRegistry.ts
10238
- async function getLatestPackageVersion(packageName, tag = "latest") {
10239
- const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace(/^%40/, "@")}`;
10413
+ var defaultNpmRegistry = "https://registry.npmjs.org";
10414
+ var getNpmRegistryUrl = (registryUrl = process.env.AKAN_NPM_REGISTRY ?? defaultNpmRegistry) => registryUrl.replace(/\/+$/, "");
10415
+ async function getLatestPackageVersion(packageName, tag = "latest", registryUrl) {
10416
+ const registry = getNpmRegistryUrl(registryUrl);
10417
+ const url = `${registry}/${encodeURIComponent(packageName).replace(/^%40/, "@")}`;
10240
10418
  const res = await fetch(url);
10241
10419
  if (!res.ok)
10242
- throw new Error(`Failed to fetch ${packageName} metadata from npm registry`);
10420
+ throw new Error(`Failed to fetch ${packageName} metadata from ${registry}`);
10243
10421
  const metadata = await res.json();
10244
10422
  const version = metadata["dist-tags"]?.[tag];
10245
10423
  if (!version)
@@ -10249,6 +10427,29 @@ async function getLatestPackageVersion(packageName, tag = "latest") {
10249
10427
 
10250
10428
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
10251
10429
  class CloudRunner extends runner("cloud") {
10430
+ #akanFrameworkPackages = new Set([
10431
+ "akanjs",
10432
+ "@akanjs/devkit",
10433
+ "@akanjs/cli",
10434
+ "create-akan-workspace"
10435
+ ]);
10436
+ #getRegistryArgs(registryUrl) {
10437
+ return registryUrl ? ["--registry", getNpmRegistryUrl(registryUrl)] : [];
10438
+ }
10439
+ #getLocalRegistryAuthArgs(registryUrl) {
10440
+ if (!registryUrl)
10441
+ return [];
10442
+ const { host, pathname } = new URL(getNpmRegistryUrl(registryUrl));
10443
+ const registryPath = pathname === "/" ? "/" : `${pathname.replace(/\/+$/, "")}/`;
10444
+ return [`--//${host}${registryPath}:_authToken=akan-local-registry`];
10445
+ }
10446
+ #getRegistryEnv(registryUrl) {
10447
+ return registryUrl ? {
10448
+ ...process.env,
10449
+ AKAN_NPM_REGISTRY: getNpmRegistryUrl(registryUrl),
10450
+ NPM_CONFIG_REGISTRY: getNpmRegistryUrl(registryUrl)
10451
+ } : process.env;
10452
+ }
10252
10453
  async login() {
10253
10454
  const config = await getHostConfig();
10254
10455
  const self = config.auth ? await getSelf(config.auth.token) : null;
@@ -10327,15 +10528,16 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10327
10528
  const pkgs = await workspace.getPkgs();
10328
10529
  return pkgs.filter((pkg) => pkg === "akanjs" || pkg === "create-akan-workspace" || pkg.startsWith("@akanjs/"));
10329
10530
  }
10330
- async deployAkan(workspace, akanPkgs) {
10531
+ async deployAkan(workspace, akanPkgs, { registryUrl, confirmPublish = true, tag: distTag } = {}) {
10532
+ const registry = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
10331
10533
  const akanPackageJson2 = await workspace.readJson("pkgs/akanjs/package.json");
10332
10534
  const [majorVersion, minorVersion, patchVersion, devPatchVersion] = akanPackageJson2.version.split(".");
10333
10535
  const isOfficialRelease = !devPatchVersion;
10334
10536
  const targetVersionPrefix = isOfficialRelease ? `${majorVersion}.${minorVersion}` : `${majorVersion}.${minorVersion}.${patchVersion}`;
10335
- const tag = isOfficialRelease ? "latest" : patchVersion.split("-").at(1) ?? "dev";
10537
+ const tag = distTag ?? (isOfficialRelease ? "latest" : patchVersion.split("-").at(1) ?? "dev");
10336
10538
  const getNextVersion = async (prefix, tag2) => {
10337
10539
  try {
10338
- const latestPublishedVersion2 = await getLatestPackageVersion("akanjs", tag2);
10540
+ const latestPublishedVersion2 = await getLatestPackageVersion("akanjs", tag2, registry);
10339
10541
  const latestPatch = latestPublishedVersion2.startsWith(prefix) ? parseInt(latestPublishedVersion2.split(".").at(-1) ?? "-1") : -1;
10340
10542
  const nextVersion2 = `${prefix}.${latestPatch + 1}`;
10341
10543
  return { nextVersion: nextVersion2, latestPublishedVersion: latestPublishedVersion2 };
@@ -10348,37 +10550,59 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10348
10550
  Logger15.info(`Next version of akanjs: ${nextVersion}`);
10349
10551
  for (const library of akanPkgs) {
10350
10552
  const packageJson = await workspace.readJson(`pkgs/${library}/package.json`);
10351
- const newPackageJsonStr = JSON.stringify({ ...packageJson, version: nextVersion }, null, 2);
10553
+ const newPackageJsonStr = JSON.stringify(this.#normalizeAkanPackageJson(packageJson, library, nextVersion), null, 2);
10352
10554
  await workspace.writeFile(`pkgs/${library}/package.json`, newPackageJsonStr);
10353
10555
  const distPackageJson = await workspace.readJson(`dist/pkgs/${library}/package.json`);
10354
- const newDistPackageJson = { ...distPackageJson, version: nextVersion };
10556
+ const newDistPackageJson = this.#normalizeAkanPackageJson(distPackageJson, library, nextVersion);
10355
10557
  await workspace.writeJson(`dist/pkgs/${library}/package.json`, newDistPackageJson);
10356
10558
  }
10357
- const isDeployConfirmed = await confirm3({
10358
- message: "Are you sure you want to deploy the libraries?"
10359
- });
10360
- if (!isDeployConfirmed) {
10361
- Logger15.error("Deployment cancelled");
10362
- return;
10559
+ if (confirmPublish) {
10560
+ const isDeployConfirmed = await confirm3({
10561
+ message: "Are you sure you want to deploy the libraries?"
10562
+ });
10563
+ if (!isDeployConfirmed) {
10564
+ Logger15.error("Deployment cancelled");
10565
+ return;
10566
+ }
10363
10567
  }
10364
10568
  await Promise.all(akanPkgs.map(async (library) => {
10365
- Logger15.info(`Publishing ${library}@${nextVersion} to npm...`);
10366
- await workspace.exec(`npm publish --tag ${tag}`, { cwd: `dist/pkgs/${library}` });
10367
- Logger15.info(`${library}@${nextVersion} is published to npm`);
10569
+ Logger15.info(`Publishing ${library}@${nextVersion} to ${registry ?? "npm"}...`);
10570
+ await workspace.spawn("npm", [
10571
+ "publish",
10572
+ "--tag",
10573
+ tag,
10574
+ ...this.#getRegistryArgs(registry),
10575
+ ...this.#getLocalRegistryAuthArgs(registry)
10576
+ ], {
10577
+ cwd: path38.join(workspace.workspaceRoot, "dist/pkgs", library),
10578
+ env: this.#getRegistryEnv(registry),
10579
+ stdio: "inherit"
10580
+ });
10581
+ Logger15.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
10368
10582
  }));
10369
- Logger15.info("All libraries are published to npm");
10583
+ Logger15.info(`All libraries are published to ${registry ?? "npm"}`);
10370
10584
  }
10371
- async update(workspace, tag = "latest") {
10585
+ async update(workspace, tag = "latest", { registryUrl } = {}) {
10586
+ const registry = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
10587
+ const registryArgs = this.#getRegistryArgs(registry);
10588
+ const env = this.#getRegistryEnv(registry);
10372
10589
  if (!await workspace.exists("package.json"))
10373
- await workspace.spawn("bun", ["update", "-g", "akanjs", "--latest", `--tag=${tag}`]);
10590
+ await workspace.spawn("bun", ["update", "-g", "akanjs", "--latest", `--tag=${tag}`, ...registryArgs], { env });
10374
10591
  else
10375
10592
  await Promise.all([
10376
- workspace.spawn("bun", ["update", "-g", "akanjs", "--latest", `--tag=${tag}`]),
10377
- this.#updateAkanPkgs(workspace, tag)
10593
+ workspace.spawn("bun", [
10594
+ "update",
10595
+ "-g",
10596
+ "akanjs",
10597
+ "--latest",
10598
+ `--tag=${tag}`,
10599
+ ...registryArgs
10600
+ ], { env }),
10601
+ this.#updateAkanPkgs(workspace, tag, registry)
10378
10602
  ]);
10379
10603
  }
10380
- async#updateAkanPkgs(workspace, tag = "latest") {
10381
- const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag);
10604
+ async#updateAkanPkgs(workspace, tag = "latest", registryUrl) {
10605
+ const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag, registryUrl);
10382
10606
  const rootPackageJson = await workspace.getPackageJson();
10383
10607
  if (!rootPackageJson.dependencies)
10384
10608
  throw new Error("No dependencies found in package.json");
@@ -10390,13 +10614,51 @@ ${chalk7.green("\u27A4")} Authentication Required`));
10390
10614
  rootPackageJson.dependencies["@akanjs/devkit"] = latestPublishedVersion;
10391
10615
  if (rootPackageJson.devDependencies?.["@akanjs/devkit"])
10392
10616
  rootPackageJson.devDependencies["@akanjs/devkit"] = latestPublishedVersion;
10393
- workspace.setPackageJson(rootPackageJson);
10394
- await workspace.spawn("bun", ["install"]);
10617
+ await workspace.setPackageJson(rootPackageJson);
10618
+ await workspace.spawn("bun", ["install", ...this.#getRegistryArgs(registryUrl)], {
10619
+ env: this.#getRegistryEnv(registryUrl)
10620
+ });
10395
10621
  }
10622
+ #normalizeAkanPackageJson(packageJson, packageName, version) {
10623
+ const normalized = { ...packageJson, version };
10624
+ for (const field of [
10625
+ "dependencies",
10626
+ "devDependencies",
10627
+ "peerDependencies",
10628
+ "optionalDependencies"
10629
+ ]) {
10630
+ const dependencies = normalized[field];
10631
+ if (!dependencies)
10632
+ continue;
10633
+ normalized[field] = Object.fromEntries(Object.entries(dependencies).map(([dep, depVersion]) => [
10634
+ dep,
10635
+ dep !== packageName && this.#akanFrameworkPackages.has(dep) ? version : depVersion
10636
+ ]));
10637
+ }
10638
+ return normalized;
10639
+ }
10640
+ async downloadEnv(workspace) {
10641
+ const repoName = workspace.repoName;
10642
+ const config = await getHostConfig();
10643
+ const self = config.auth ? await getSelf(config.auth.token) : null;
10644
+ if (!self)
10645
+ throw new Error("Not logged in");
10646
+ const res = await fetch(`${akanCloudUrl}/api/akasys/akasys/${repoName}`, {
10647
+ headers: { Authorization: `Bearer ${config.auth?.token}` }
10648
+ });
10649
+ const env = await res.json();
10650
+ Logger15.info(`Downloading environment variables from cloud...`);
10651
+ Logger15.info(`Environment variables: ${JSON.stringify(env.env, null, 2)}`);
10652
+ }
10653
+ async uploadEnv(workspace) {}
10396
10654
  }
10397
10655
 
10398
10656
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
10399
- class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, PackageScript]) {
10657
+ class CloudScript extends script("cloud", [
10658
+ CloudRunner,
10659
+ ApplicationScript,
10660
+ PackageScript
10661
+ ]) {
10400
10662
  async login(workspace) {
10401
10663
  await this.cloudRunner.login();
10402
10664
  }
@@ -10413,7 +10675,13 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
10413
10675
  const session = new AiSession("general", { workspace, isContinued: true });
10414
10676
  await session.ask(question);
10415
10677
  }
10416
- async deployAkan(workspace, { test = true } = {}) {
10678
+ async downloadEnv(workspace) {
10679
+ await this.cloudRunner.downloadEnv(workspace);
10680
+ }
10681
+ async uploadEnv(workspace) {
10682
+ await this.cloudRunner.uploadEnv(workspace);
10683
+ }
10684
+ async deployAkan(workspace, { test = true, registryUrl } = {}) {
10417
10685
  const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
10418
10686
  await this.packageScript.updateWorskpaceRootPackageJson(workspace);
10419
10687
  const pkgs = akanPkgs.map((pkgName) => PkgExecutor.from(workspace, pkgName));
@@ -10422,11 +10690,11 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
10422
10690
  await this.applicationScript.test(pkg);
10423
10691
  for (const pkg of pkgs)
10424
10692
  await this.packageScript.buildPackage(pkg);
10425
- await this.cloudRunner.deployAkan(workspace, akanPkgs);
10693
+ await this.cloudRunner.deployAkan(workspace, akanPkgs, { registryUrl });
10426
10694
  }
10427
- async update(workspace, tag = "latest") {
10695
+ async update(workspace, tag = "latest", { registryUrl } = {}) {
10428
10696
  const spinner2 = workspace.spinning("Updating Akan.js packages and CLI...");
10429
- await this.cloudRunner.update(workspace, tag);
10697
+ await this.cloudRunner.update(workspace, tag, { registryUrl });
10430
10698
  spinner2.succeed("Akan.js packages and CLI updated, global version is below");
10431
10699
  Logger16.raw("> Akan version: ");
10432
10700
  await workspace.spawn("akan", ["--version"], { stdio: "inherit" });
@@ -10434,6 +10702,9 @@ class CloudScript extends script("cloud", [CloudRunner, ApplicationScript, Packa
10434
10702
  }
10435
10703
 
10436
10704
  // pkgs/@akanjs/cli/cloud/cloud.command.ts
10705
+ var localRegistryUrl = () => process.env.AKAN_NPM_REGISTRY ?? "http://127.0.0.1:4873";
10706
+ var resolveRegistryUrl = (registry) => registry === "local" ? localRegistryUrl() : undefined;
10707
+
10437
10708
  class CloudCommand extends command("cloud", [CloudScript], ({ public: target }) => ({
10438
10709
  login: target({ desc: "Login to Akan Cloud services" }).with(Workspace).exec(async function(workspace) {
10439
10710
  await this.cloudScript.login(workspace);
@@ -10450,15 +10721,43 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
10450
10721
  ask: target({ desc: "Ask AI assistant a question about your project" }).option("question", String, { ask: "question to ask" }).with(Workspace).exec(async function(question, workspace) {
10451
10722
  await this.cloudScript.ask(question, workspace);
10452
10723
  }),
10453
- deployAkan: target({ devOnly: true, desc: "Deploy Akan.js framework to cloud (internal use)" }).option("test", Boolean, { desc: "test the deployment", default: true }).with(Workspace).exec(async function(test, workspace) {
10454
- await this.cloudScript.deployAkan(workspace, { test });
10724
+ deployAkan: target({
10725
+ devOnly: true,
10726
+ desc: "Deploy Akan.js framework to cloud (internal use)"
10727
+ }).option("test", Boolean, { desc: "test the deployment", default: true }).option("registry", String, {
10728
+ desc: "registry target for publishing Akan packages",
10729
+ ask: "Select a registry target",
10730
+ enum: [
10731
+ { label: "local", value: "local" },
10732
+ { label: "npm", value: "npm" }
10733
+ ]
10734
+ }).with(Workspace).exec(async function(test, registry, workspace) {
10735
+ await this.cloudScript.deployAkan(workspace, {
10736
+ test,
10737
+ registryUrl: resolveRegistryUrl(registry)
10738
+ });
10455
10739
  }),
10456
10740
  update: target({ desc: "Update Akan.js framework to the latest version" }).with(Workspace).option("tag", String, {
10457
10741
  desc: "tag of the update",
10458
10742
  default: "latest",
10459
10743
  enum: ["latest", "dev", "canary", "beta", "rc", "alpha"]
10460
- }).exec(async function(workspace, tag) {
10461
- await this.cloudScript.update(workspace, tag);
10744
+ }).option("registry", String, {
10745
+ desc: "registry target for resolving Akan packages",
10746
+ ask: "Select a registry target",
10747
+ enum: [
10748
+ { label: "npm", value: "npm" },
10749
+ { label: "local", value: "local" }
10750
+ ]
10751
+ }).exec(async function(workspace, tag, registry) {
10752
+ await this.cloudScript.update(workspace, tag, {
10753
+ registryUrl: resolveRegistryUrl(registry)
10754
+ });
10755
+ }),
10756
+ downloadEnv: target({ desc: "Download environment variables from cloud" }).with(Workspace).exec(async function(workspace) {
10757
+ await this.cloudScript.downloadEnv(workspace);
10758
+ }),
10759
+ uploadEnv: target({ desc: "Upload environment variables to cloud" }).with(Workspace).exec(async function(workspace) {
10760
+ await this.cloudScript.uploadEnv(workspace);
10462
10761
  })
10463
10762
  })) {
10464
10763
  }
@@ -10479,19 +10778,19 @@ class GuidelinePrompt extends Prompter {
10479
10778
  return page;
10480
10779
  if (page.endsWith(".tsx"))
10481
10780
  return page;
10482
- return `apps/angelo/page${page}`;
10781
+ return `apps/akan/page${page}`;
10483
10782
  }
10484
10783
  async#getScanFilePaths(matchPattern, { avoidDirs = ["node_modules", ".next"], filterText } = {}) {
10485
10784
  const glob = new Bun.Glob(matchPattern);
10486
10785
  const paths = [];
10487
- for await (const path38 of glob.scan({ cwd: this.workspace.workspaceRoot, absolute: true })) {
10488
- if (avoidDirs.some((dir) => path38.includes(dir)))
10786
+ for await (const path39 of glob.scan({ cwd: this.workspace.workspaceRoot, absolute: true })) {
10787
+ if (avoidDirs.some((dir) => path39.includes(dir)))
10489
10788
  continue;
10490
- const fileContent = await FileSys.readText(path38);
10789
+ const fileContent = await FileSys.readText(path39);
10491
10790
  const textFilter = filterText ? new RegExp(filterText) : null;
10492
10791
  if (filterText && !textFilter?.test(fileContent))
10493
10792
  continue;
10494
- paths.push(path38);
10793
+ paths.push(path39);
10495
10794
  }
10496
10795
  return paths;
10497
10796
  }
@@ -10786,6 +11085,147 @@ class LibraryCommand extends command("library", [LibraryScript], ({ public: targ
10786
11085
  })) {
10787
11086
  }
10788
11087
 
11088
+ // pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
11089
+ import { mkdir as mkdir11, rm as rm5 } from "fs/promises";
11090
+ import path39 from "path";
11091
+ import { Logger as Logger17 } from "akanjs/common";
11092
+ var defaultLocalRegistryUrl = "http://127.0.0.1:4873";
11093
+ var containerName = "akan-verdaccio";
11094
+ var smokeRepoName = "akan-local-smoke";
11095
+ var smokeAppName = "demo";
11096
+
11097
+ class LocalRegistryRunner extends runner("localRegistry") {
11098
+ getRegistryUrl(registryUrl = process.env.AKAN_NPM_REGISTRY ?? defaultLocalRegistryUrl) {
11099
+ return getNpmRegistryUrl(registryUrl);
11100
+ }
11101
+ async start(workspace, { registryUrl } = {}) {
11102
+ const registry = this.getRegistryUrl(registryUrl);
11103
+ try {
11104
+ await workspace.spawn("docker", ["inspect", containerName]);
11105
+ Logger17.info(`Local registry is already running at ${registry}`);
11106
+ return registry;
11107
+ } catch {}
11108
+ const configPath2 = path39.join(workspace.workspaceRoot, "pkgs/@akanjs/cli/localRegistry/verdaccio.yaml");
11109
+ const storagePath = path39.join(workspace.workspaceRoot, ".akan/verdaccio/storage");
11110
+ await mkdir11(storagePath, { recursive: true });
11111
+ await workspace.spawn("docker", [
11112
+ "run",
11113
+ "--rm",
11114
+ "-d",
11115
+ "--name",
11116
+ containerName,
11117
+ "-p",
11118
+ "4873:4873",
11119
+ "-v",
11120
+ `${configPath2}:/verdaccio/conf/config.yaml:ro`,
11121
+ "-v",
11122
+ `${storagePath}:/verdaccio/storage`,
11123
+ "verdaccio/verdaccio:6"
11124
+ ], { stdio: "inherit" });
11125
+ Logger17.info(`Local registry is running at ${registry}`);
11126
+ return registry;
11127
+ }
11128
+ async reset(workspace) {
11129
+ try {
11130
+ await workspace.spawn("docker", ["rm", "-f", containerName], { stdio: "inherit" });
11131
+ } catch {}
11132
+ await rm5(path39.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
11133
+ Logger17.info("Local registry storage has been reset");
11134
+ }
11135
+ async smoke(workspace, { registryUrl } = {}) {
11136
+ const registry = this.getRegistryUrl(registryUrl);
11137
+ const smokeRoot = path39.join(workspace.workspaceRoot, ".akan/e2e");
11138
+ await rm5(path39.join(smokeRoot, smokeRepoName), { recursive: true, force: true });
11139
+ await workspace.spawn(process.execPath, [
11140
+ "dist/pkgs/create-akan-workspace/index.js",
11141
+ smokeRepoName,
11142
+ "--app",
11143
+ smokeAppName,
11144
+ "--dir",
11145
+ ".akan/e2e",
11146
+ "--init",
11147
+ "true",
11148
+ "--registry",
11149
+ registry
11150
+ ], {
11151
+ env: { ...process.env, AKAN_NPM_REGISTRY: registry, NPM_CONFIG_REGISTRY: registry },
11152
+ stdio: "inherit"
11153
+ });
11154
+ await workspace.spawn("akan", ["build", smokeAppName], {
11155
+ cwd: path39.join(smokeRoot, smokeRepoName),
11156
+ env: { ...process.env, AKAN_NPM_REGISTRY: registry, NPM_CONFIG_REGISTRY: registry },
11157
+ stdio: "inherit"
11158
+ });
11159
+ Logger17.info(`Local registry smoke test completed for ${smokeRepoName}/${smokeAppName}`);
11160
+ }
11161
+ }
11162
+
11163
+ // pkgs/@akanjs/cli/localRegistry/localRegistry.script.ts
11164
+ class LocalRegistryScript extends script("localRegistry", [
11165
+ LocalRegistryRunner,
11166
+ CloudRunner,
11167
+ ApplicationScript,
11168
+ PackageScript
11169
+ ]) {
11170
+ async start(workspace, { registryUrl } = {}) {
11171
+ const spinner2 = workspace.spinning("Starting local npm registry...");
11172
+ const registry = await this.localRegistryRunner.start(workspace, { registryUrl });
11173
+ spinner2.succeed(`Local npm registry is ready at ${registry}`);
11174
+ }
11175
+ async reset(workspace) {
11176
+ const spinner2 = workspace.spinning("Resetting local npm registry...");
11177
+ await this.localRegistryRunner.reset(workspace);
11178
+ spinner2.succeed("Local npm registry reset");
11179
+ }
11180
+ async smoke(workspace, { tag = "rc", test = true, registryUrl } = {}) {
11181
+ const registry = await this.localRegistryRunner.start(workspace, { registryUrl });
11182
+ const akanPkgs = await this.cloudRunner.getAkanPkgs(workspace);
11183
+ await this.#preparePackages(workspace, akanPkgs, { test });
11184
+ await this.cloudRunner.deployAkan(workspace, akanPkgs, {
11185
+ registryUrl: registry,
11186
+ confirmPublish: false,
11187
+ tag
11188
+ });
11189
+ await this.localRegistryRunner.smoke(workspace, { registryUrl: registry });
11190
+ }
11191
+ async#preparePackages(workspace, akanPkgs, { test = true } = {}) {
11192
+ await this.packageScript.updateWorskpaceRootPackageJson(workspace);
11193
+ const pkgs = akanPkgs.map((pkgName) => PkgExecutor.from(workspace, pkgName));
11194
+ if (test)
11195
+ for (const pkg of pkgs)
11196
+ await this.applicationScript.test(pkg);
11197
+ for (const pkg of pkgs)
11198
+ await this.packageScript.buildPackage(pkg, { showSpinner: false });
11199
+ }
11200
+ }
11201
+
11202
+ // pkgs/@akanjs/cli/localRegistry/localRegistry.command.ts
11203
+ class LocalRegistryCommand extends command("local-registry", [LocalRegistryScript], ({ public: target }) => ({
11204
+ startRegistry: target({ devOnly: true, desc: "Start the local Verdaccio npm registry" }).with(Workspace).option("registry", String, {
11205
+ desc: "local npm registry URL",
11206
+ default: process.env.AKAN_NPM_REGISTRY ?? "http://127.0.0.1:4873"
11207
+ }).exec(async function(workspace, registry) {
11208
+ await this.localRegistryScript.start(workspace, { registryUrl: registry });
11209
+ }),
11210
+ resetRegistry: target({ devOnly: true, desc: "Stop and clear the local Verdaccio npm registry" }).with(Workspace).exec(async function(workspace) {
11211
+ await this.localRegistryScript.reset(workspace);
11212
+ }),
11213
+ smokeRegistry: target({ devOnly: true, desc: "Publish to local registry and build a generated workspace" }).with(Workspace).option("tag", String, {
11214
+ flag: "g",
11215
+ desc: "dist-tag for local registry publish",
11216
+ default: "rc"
11217
+ }).option("test", Boolean, {
11218
+ desc: "run package tests before publishing",
11219
+ default: true
11220
+ }).option("registry", String, {
11221
+ desc: "local npm registry URL",
11222
+ default: process.env.AKAN_NPM_REGISTRY
11223
+ }).exec(async function(workspace, tag, test, registry) {
11224
+ await this.localRegistryScript.smoke(workspace, { tag, test, registryUrl: registry });
11225
+ })
11226
+ })) {
11227
+ }
11228
+
10789
11229
  // pkgs/@akanjs/cli/module/module.command.ts
10790
11230
  import { lowerlize } from "akanjs/common";
10791
11231
 
@@ -11581,11 +12021,11 @@ class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target
11581
12021
  }
11582
12022
 
11583
12023
  // pkgs/@akanjs/cli/workspace/workspace.script.ts
11584
- import path39 from "path";
11585
- import { Logger as Logger17 } from "akanjs/common";
12024
+ import path41 from "path";
12025
+ import { Logger as Logger18 } from "akanjs/common";
11586
12026
 
11587
12027
  // pkgs/@akanjs/cli/workspace/workspace.runner.ts
11588
- import path38 from "path";
12028
+ import path40 from "path";
11589
12029
  var defaultWorkspacePeerDependencies = new Set([
11590
12030
  "@radix-ui/react-dialog",
11591
12031
  "@react-spring/web",
@@ -11605,20 +12045,29 @@ var defaultWorkspacePeerDependencies = new Set([
11605
12045
  ]);
11606
12046
 
11607
12047
  class WorkspaceRunner extends runner("workspace") {
11608
- async createWorkspace(repoName, appName, { dirname: dirname3 = ".", init = true, akanVersion }) {
12048
+ async createWorkspace(repoName, appName, {
12049
+ dirname: dirname3 = ".",
12050
+ init = true,
12051
+ akanVersion,
12052
+ registryUrl
12053
+ }) {
11609
12054
  const cwdPath = process.cwd();
11610
- const workspaceRoot = path38.join(cwdPath, dirname3, repoName);
12055
+ const workspaceRoot = path40.join(cwdPath, dirname3, repoName);
12056
+ const normalizedRegistryUrl = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
11611
12057
  const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
11612
12058
  const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname3}/${repoName}...`);
11613
12059
  const [latestBiomeVersion, latestTypesBunVersion] = await Promise.all([
11614
- getLatestPackageVersion("@biomejs/biome"),
11615
- getLatestPackageVersion("@types/bun")
12060
+ getLatestPackageVersion("@biomejs/biome", "latest", normalizedRegistryUrl),
12061
+ getLatestPackageVersion("@types/bun", "latest", normalizedRegistryUrl)
11616
12062
  ]);
11617
12063
  await workspace.applyTemplate({
11618
12064
  basePath: ".",
11619
12065
  template: "workspaceRoot",
11620
12066
  dict: { repoName, appName, serveDomain: "localhost" }
11621
12067
  });
12068
+ if (normalizedRegistryUrl)
12069
+ await workspace.writeFile(".npmrc", `registry=${normalizedRegistryUrl}/
12070
+ `);
11622
12071
  templateSpinner.succeed(`Workspace files created in ${dirname3}/${repoName}`);
11623
12072
  const [rootPackageJson, peerDependencies] = await Promise.all([
11624
12073
  workspace.getPackageJson(),
@@ -11659,9 +12108,9 @@ class WorkspaceRunner extends runner("workspace") {
11659
12108
  }
11660
12109
  async#getCliPackageJson() {
11661
12110
  const packageJsonCandidates = [
11662
- path38.join(import.meta.dir, "../package.json"),
11663
- path38.join(import.meta.dir, "package.json"),
11664
- path38.join(path38.dirname(Bun.main), "package.json")
12111
+ path40.join(import.meta.dir, "../package.json"),
12112
+ path40.join(import.meta.dir, "package.json"),
12113
+ path40.join(path40.dirname(Bun.main), "package.json")
11665
12114
  ];
11666
12115
  try {
11667
12116
  packageJsonCandidates.unshift(Bun.resolveSync("@akanjs/cli/package.json", import.meta.dir));
@@ -11677,9 +12126,9 @@ class WorkspaceRunner extends runner("workspace") {
11677
12126
  }
11678
12127
  async#getAkanPackageJson() {
11679
12128
  const packageJsonCandidates = [
11680
- path38.join(import.meta.dir, "../../../akanjs/package.json"),
11681
- path38.join(process.cwd(), "pkgs/akanjs/package.json"),
11682
- path38.join(path38.dirname(Bun.main), "node_modules/akanjs/package.json")
12129
+ path40.join(import.meta.dir, "../../../akanjs/package.json"),
12130
+ path40.join(process.cwd(), "pkgs/akanjs/package.json"),
12131
+ path40.join(path40.dirname(Bun.main), "node_modules/akanjs/package.json")
11683
12132
  ];
11684
12133
  try {
11685
12134
  packageJsonCandidates.unshift(Bun.resolveSync("akanjs/package.json", import.meta.dir));
@@ -11693,13 +12142,13 @@ class WorkspaceRunner extends runner("workspace") {
11693
12142
  }
11694
12143
  let current = import.meta.dir;
11695
12144
  for (let depth = 0;depth < 6; depth++) {
11696
- const packageJsonPath = path38.join(current, "package.json");
12145
+ const packageJsonPath = path40.join(current, "package.json");
11697
12146
  if (await Bun.file(packageJsonPath).exists()) {
11698
12147
  const packageJson = await FileSys.readJson(packageJsonPath);
11699
12148
  if (packageJson.name === "akanjs")
11700
12149
  return packageJson;
11701
12150
  }
11702
- const parent = path38.dirname(current);
12151
+ const parent = path40.dirname(current);
11703
12152
  if (parent === current)
11704
12153
  break;
11705
12154
  current = parent;
@@ -11723,12 +12172,18 @@ class WorkspaceScript extends script("workspace", [
11723
12172
  LibraryScript,
11724
12173
  PackageScript
11725
12174
  ]) {
11726
- async createWorkspace(repoName, appName, { dirname: dirname3 = ".", installLibs = false, init = true }) {
12175
+ async createWorkspace(repoName, appName, {
12176
+ dirname: dirname3 = ".",
12177
+ installLibs = false,
12178
+ init = true,
12179
+ registryUrl
12180
+ }) {
11727
12181
  const akanVersion = await this.packageScript.version(null, { log: false });
11728
12182
  const workspace = await this.workspaceRunner.createWorkspace(repoName, appName, {
11729
12183
  dirname: dirname3,
11730
12184
  init,
11731
- akanVersion
12185
+ akanVersion,
12186
+ ...registryUrl ? { registryUrl } : {}
11732
12187
  });
11733
12188
  if (installLibs) {
11734
12189
  await this.libraryScript.installLibrary(workspace, "util");
@@ -11742,11 +12197,11 @@ class WorkspaceScript extends script("workspace", [
11742
12197
  } catch (_) {
11743
12198
  gitSpinner.fail("Git repository initialization failed. It's not fatal, you can commit manually");
11744
12199
  }
11745
- const workspacePath = path39.join(dirname3, repoName);
11746
- Logger17.rawLog(`
12200
+ const workspacePath = path41.join(dirname3, repoName);
12201
+ Logger18.rawLog(`
11747
12202
  \uD83C\uDF89 Welcome aboard! Workspace created in ${dirname3}/${repoName}`);
11748
- Logger17.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath} && akan start ${appName}\` to start the development server.`);
11749
- Logger17.rawLog(`
12203
+ Logger18.rawLog(`\uD83D\uDE80 Run \`cd ${workspacePath} && akan start ${appName}\` to start the development server.`);
12204
+ Logger18.rawLog(`
11750
12205
  \uD83D\uDC4B Happy coding!`);
11751
12206
  }
11752
12207
  async lint(exec2, workspace, { fix = true } = {}) {
@@ -11801,9 +12256,12 @@ class WorkspaceCommand extends command("workspace", [WorkspaceScript], ({ public
11801
12256
  }).option("init", Boolean, {
11802
12257
  desc: "Do you want to initialize the workspace? (Recommended)",
11803
12258
  default: true
11804
- }).exec(async function(workspaceName, app, dir, libs, init) {
12259
+ }).option("registry", String, {
12260
+ desc: "npm registry URL for installing Akan packages",
12261
+ default: process.env.AKAN_NPM_REGISTRY
12262
+ }).exec(async function(workspaceName, app, dir, libs, init, registry) {
11805
12263
  const appName = app || "app";
11806
- await this.workspaceScript.createWorkspace(workspaceName.toLowerCase().replace(/ /g, "-"), appName.toLowerCase().replace(/ /g, "-"), { dirname: dir, installLibs: libs, init });
12264
+ await this.workspaceScript.createWorkspace(workspaceName.toLowerCase().replace(/ /g, "-"), appName.toLowerCase().replace(/ /g, "-"), { dirname: dir, installLibs: libs, init, ...registry ? { registryUrl: registry } : {} });
11807
12265
  }),
11808
12266
  lint: target({ desc: "Lint and fix code in a specific app/lib/pkg" }).with(Exec).option("fix", Boolean, { default: true }).with(Workspace).exec(async function(exec2, fix, workspace) {
11809
12267
  await this.workspaceScript.lint(exec2, workspace, { fix });
@@ -11818,4 +12276,4 @@ class WorkspaceCommand extends command("workspace", [WorkspaceScript], ({ public
11818
12276
  }
11819
12277
 
11820
12278
  // pkgs/@akanjs/cli/index.ts
11821
- runCommands(WorkspaceCommand, ApplicationCommand, LibraryCommand, PackageCommand, ModuleCommand, PageCommand, CloudCommand, GuidelineCommand, ScalarCommand);
12279
+ runCommands(WorkspaceCommand, ApplicationCommand, LibraryCommand, LocalRegistryCommand, PackageCommand, ModuleCommand, PageCommand, CloudCommand, GuidelineCommand, ScalarCommand);