akanjs 2.0.5 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/application/application.runner.ts +1 -1
- package/cli/build.ts +2 -1
- package/cli/cloud/cloud.runner.ts +7 -8
- package/cli/index.js +176 -43
- package/cli/library/library.runner.ts +2 -2
- package/cli/module/module.runner.ts +2 -2
- package/cli/npmRegistry.ts +13 -0
- package/cli/openBrowser.ts +15 -0
- package/cli/pluralizeName.ts +5 -0
- package/cli/scalar/scalar.prompt.ts +2 -2
- package/cli/scalar/scalar.runner.ts +2 -2
- package/cli/semver.ts +18 -0
- package/cli/templates/lib/sig.ts +2 -2
- package/cli/workspace/workspace.runner.ts +3 -3
- package/client/cookie.ts +10 -15
- package/common/index.ts +1 -0
- package/common/jwtDecode.ts +17 -0
- package/devkit/akanApp/akanApp.host.ts +46 -9
- package/devkit/akanConfig/akanConfig.ts +2 -1
- package/devkit/incrementalBuilder/incrementalBuilder.host.ts +83 -9
- package/document/dataLoader.ts +140 -6
- package/document/database.ts +1 -1
- package/package.json +7 -13
- package/server/akanApp.ts +197 -32
- package/server/di/diLifecycle.ts +1 -1
- package/server/proxy/localeWebProxy.ts +29 -12
- package/service/serviceModule.ts +1 -6
- package/signal/base.signal.ts +1 -1
- package/signal/signalRegistry.ts +35 -10
- package/types/cli/npmRegistry.d.ts +1 -0
- package/types/cli/openBrowser.d.ts +1 -0
- package/types/cli/pluralizeName.d.ts +1 -0
- package/types/cli/semver.d.ts +1 -0
- package/types/client/cookie.d.ts +6 -1
- package/types/common/index.d.ts +1 -0
- package/types/common/jwtDecode.d.ts +2 -0
- package/types/devkit/incrementalBuilder/incrementalBuilder.host.d.ts +9 -5
- package/types/document/dataLoader.d.ts +21 -2
- package/types/document/database.d.ts +1 -1
- package/types/service/serviceModule.d.ts +1 -1
- package/types/signal/signalRegistry.d.ts +25 -4
- package/ui/Signal/Doc.tsx +2 -3
|
@@ -25,8 +25,8 @@ import {
|
|
|
25
25
|
type TypecheckOptions,
|
|
26
26
|
type Workspace,
|
|
27
27
|
} from "akanjs/devkit";
|
|
28
|
-
import openBrowser from "open";
|
|
29
28
|
import ora from "ora";
|
|
29
|
+
import { openBrowser } from "../openBrowser";
|
|
30
30
|
|
|
31
31
|
export class ApplicationRunner extends runner("application") {
|
|
32
32
|
async createApplication(appName: string, workspace: Workspace, libs: string[] = []) {
|
package/cli/build.ts
CHANGED
|
@@ -7,13 +7,14 @@ const OUT_DIR = process.env.DIST_DIR ?? `${WORKSPACE_ROOT}/dist/pkgs/akanjs`;
|
|
|
7
7
|
|
|
8
8
|
const build = async () => {
|
|
9
9
|
try {
|
|
10
|
+
const packageJson = await Bun.file(`${PACKAGE_DIR}/package.json`).json();
|
|
10
11
|
await $`rm -rf ${OUT_DIR}/cli`;
|
|
11
12
|
await Bun.build({
|
|
12
13
|
entrypoints: [`${CLI_DIR}/index.ts`],
|
|
13
14
|
splitting: false,
|
|
14
15
|
target: "bun",
|
|
15
16
|
outdir: `${OUT_DIR}/cli`,
|
|
16
|
-
external: Object.keys(
|
|
17
|
+
external: Object.keys({ ...packageJson.dependencies, ...packageJson.peerDependencies }),
|
|
17
18
|
});
|
|
18
19
|
await $`cp -R ${CLI_DIR}/templates ${OUT_DIR}/cli/templates`;
|
|
19
20
|
} catch (error) {
|
|
@@ -11,10 +11,9 @@ import {
|
|
|
11
11
|
type Workspace,
|
|
12
12
|
} from "akanjs/devkit";
|
|
13
13
|
import chalk from "chalk";
|
|
14
|
-
import latestVersion from "latest-version";
|
|
15
|
-
import open from "open";
|
|
16
14
|
import * as QRcode from "qrcode";
|
|
17
|
-
import {
|
|
15
|
+
import { getLatestPackageVersion } from "../npmRegistry";
|
|
16
|
+
import { openBrowser } from "../openBrowser";
|
|
18
17
|
|
|
19
18
|
export class CloudRunner extends runner("cloud") {
|
|
20
19
|
async login() {
|
|
@@ -24,7 +23,7 @@ export class CloudRunner extends runner("cloud") {
|
|
|
24
23
|
Logger.rawLog(chalk.green(`\n✓ Already logged in akan cloud as ${self.nickname}\n`));
|
|
25
24
|
return true;
|
|
26
25
|
}
|
|
27
|
-
const remoteId =
|
|
26
|
+
const remoteId = crypto.randomUUID();
|
|
28
27
|
const signinUrl = `${akanCloudUrl}/signin?remoteId=${remoteId}`;
|
|
29
28
|
|
|
30
29
|
Logger.rawLog(chalk.bold(`\n${chalk.green("➤")} Authentication Required`));
|
|
@@ -39,7 +38,7 @@ export class CloudRunner extends runner("cloud") {
|
|
|
39
38
|
});
|
|
40
39
|
});
|
|
41
40
|
Logger.rawLog(qrcode);
|
|
42
|
-
await
|
|
41
|
+
await openBrowser(signinUrl);
|
|
43
42
|
Logger.rawLog(chalk.dim("Opening browser..."));
|
|
44
43
|
} catch {
|
|
45
44
|
Logger.rawLog(chalk.yellow("Could not open browser. Please visit the URL manually."));
|
|
@@ -96,13 +95,13 @@ export class CloudRunner extends runner("cloud") {
|
|
|
96
95
|
const tag = isOfficialRelease ? "latest" : (patchVersion.split("-").at(1) ?? "dev");
|
|
97
96
|
const getNextVersion = async (prefix: string, tag: string) => {
|
|
98
97
|
try {
|
|
99
|
-
const latestPublishedVersion = await
|
|
98
|
+
const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag);
|
|
100
99
|
const latestPatch = latestPublishedVersion.startsWith(prefix)
|
|
101
100
|
? parseInt(latestPublishedVersion.split(".").at(-1) ?? "-1")
|
|
102
101
|
: -1;
|
|
103
102
|
const nextVersion = `${prefix}.${latestPatch + 1}`;
|
|
104
103
|
return { nextVersion, latestPublishedVersion };
|
|
105
|
-
} catch
|
|
104
|
+
} catch {
|
|
106
105
|
return { nextVersion: `${prefix}.0`, latestPublishedVersion: null };
|
|
107
106
|
}
|
|
108
107
|
};
|
|
@@ -147,7 +146,7 @@ export class CloudRunner extends runner("cloud") {
|
|
|
147
146
|
]);
|
|
148
147
|
}
|
|
149
148
|
async #updateAkanPkgs(workspace: Workspace, tag: string = "latest") {
|
|
150
|
-
const latestPublishedVersion = await
|
|
149
|
+
const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag);
|
|
151
150
|
const rootPackageJson = await workspace.getPackageJson();
|
|
152
151
|
if (!rootPackageJson.dependencies) throw new Error("No dependencies found in package.json");
|
|
153
152
|
if (rootPackageJson.dependencies.akanjs) rootPackageJson.dependencies.akanjs = latestPublishedVersion;
|
package/cli/index.js
CHANGED
|
@@ -2203,7 +2203,7 @@ var require_source_map_support = __commonJS((exports, module) => {
|
|
|
2203
2203
|
});
|
|
2204
2204
|
|
|
2205
2205
|
var require_typescript = __commonJS((exports, module) => {
|
|
2206
|
-
var __dirname = "/Users/kangminseon/
|
|
2206
|
+
var __dirname = "/Users/kangminseon/Desktop/Mintaka_Github/bunkan/node_modules/typescript/lib", __filename = "/Users/kangminseon/Desktop/Mintaka_Github/bunkan/node_modules/typescript/lib/typescript.js";
|
|
2207
2207
|
|
|
2208
2208
|
var ts = {};
|
|
2209
2209
|
((module2) => {
|
|
@@ -176299,6 +176299,8 @@ var builderMsgTypeSet = new Set([
|
|
|
176299
176299
|
]);
|
|
176300
176300
|
|
|
176301
176301
|
class IncrementalBuilderHost {
|
|
176302
|
+
static #restartBaseDelayMs = 1000;
|
|
176303
|
+
static #restartMaxDelayMs = 30000;
|
|
176302
176304
|
logger = new Logger("IncrementalBuilderHost");
|
|
176303
176305
|
entry;
|
|
176304
176306
|
env;
|
|
@@ -176306,48 +176308,112 @@ class IncrementalBuilderHost {
|
|
|
176306
176308
|
ready = false;
|
|
176307
176309
|
#onMessage;
|
|
176308
176310
|
#proc = null;
|
|
176311
|
+
#status = "stopped";
|
|
176312
|
+
#restartAttempts = 0;
|
|
176313
|
+
#restartTimer = null;
|
|
176314
|
+
#manualStop = false;
|
|
176315
|
+
#startOptions = {};
|
|
176309
176316
|
constructor({ app, entry, env, onMessage }) {
|
|
176310
176317
|
this.app = app;
|
|
176311
176318
|
this.entry = entry;
|
|
176312
176319
|
this.env = env;
|
|
176313
176320
|
this.#onMessage = onMessage;
|
|
176314
176321
|
}
|
|
176315
|
-
|
|
176322
|
+
get status() {
|
|
176323
|
+
return this.#status;
|
|
176324
|
+
}
|
|
176325
|
+
start(options = {}) {
|
|
176316
176326
|
if (this.#proc)
|
|
176317
176327
|
this.stop();
|
|
176318
|
-
this.#
|
|
176328
|
+
this.#manualStop = false;
|
|
176329
|
+
this.#startOptions = options;
|
|
176330
|
+
this.#spawn(false);
|
|
176331
|
+
return this;
|
|
176332
|
+
}
|
|
176333
|
+
#spawn(isRestart) {
|
|
176334
|
+
this.#status = isRestart ? "restarting" : "starting";
|
|
176335
|
+
this.ready = false;
|
|
176336
|
+
let proc;
|
|
176337
|
+
proc = Bun.spawn(["bun", this.entry], {
|
|
176319
176338
|
cwd: this.app.cwdPath,
|
|
176320
176339
|
env: { ...this.env, AKAN_WATCH: "1" },
|
|
176321
176340
|
stdio: ["ignore", "inherit", "inherit"],
|
|
176322
176341
|
ipc: (msg) => {
|
|
176342
|
+
if (this.#proc !== proc)
|
|
176343
|
+
return;
|
|
176323
176344
|
if (!msg || typeof msg !== "object")
|
|
176324
176345
|
return;
|
|
176325
176346
|
if (builderMsgTypeSet.has(msg.type))
|
|
176326
176347
|
this.#onMessage(msg);
|
|
176327
176348
|
if (msg.type === "builder-ready" && !this.ready) {
|
|
176328
176349
|
this.ready = true;
|
|
176329
|
-
|
|
176350
|
+
this.#status = "ready";
|
|
176351
|
+
this.#restartAttempts = 0;
|
|
176352
|
+
if (isRestart)
|
|
176353
|
+
this.#startOptions.onRestartReady?.();
|
|
176354
|
+
else
|
|
176355
|
+
this.#startOptions.onReady?.();
|
|
176330
176356
|
}
|
|
176331
176357
|
},
|
|
176332
176358
|
serialization: "advanced",
|
|
176333
176359
|
onExit: () => {
|
|
176334
|
-
|
|
176360
|
+
if (this.#proc !== proc)
|
|
176361
|
+
return;
|
|
176362
|
+
this.#proc = null;
|
|
176363
|
+
const wasReady = this.ready;
|
|
176364
|
+
this.ready = false;
|
|
176365
|
+
if (this.#manualStop || this.#status === "stopped")
|
|
176366
|
+
return;
|
|
176367
|
+
if (!wasReady) {
|
|
176368
|
+
this.#status = "stopped";
|
|
176369
|
+
this.#startOptions.onExit?.();
|
|
176370
|
+
return;
|
|
176371
|
+
}
|
|
176372
|
+
this.#scheduleRestart();
|
|
176335
176373
|
}
|
|
176336
176374
|
});
|
|
176337
|
-
this
|
|
176338
|
-
|
|
176375
|
+
this.#proc = proc;
|
|
176376
|
+
this.logger.verbose(`builder spawned pid=${proc.pid} entry=${this.entry}${isRestart ? " restart=1" : ""}`);
|
|
176377
|
+
}
|
|
176378
|
+
#scheduleRestart() {
|
|
176379
|
+
if (this.#manualStop || this.#restartTimer)
|
|
176380
|
+
return;
|
|
176381
|
+
this.#status = "restarting";
|
|
176382
|
+
const attempt = this.#restartAttempts;
|
|
176383
|
+
const delay = Math.min(IncrementalBuilderHost.#restartBaseDelayMs * 2 ** attempt, IncrementalBuilderHost.#restartMaxDelayMs);
|
|
176384
|
+
this.#restartAttempts = attempt + 1;
|
|
176385
|
+
this.logger.warn(`builder exited after ready; restarting in ${delay}ms (attempt ${this.#restartAttempts})`);
|
|
176386
|
+
this.#restartTimer = setTimeout(() => {
|
|
176387
|
+
this.#restartTimer = null;
|
|
176388
|
+
if (this.#manualStop)
|
|
176389
|
+
return;
|
|
176390
|
+
this.#spawn(true);
|
|
176391
|
+
}, delay);
|
|
176339
176392
|
}
|
|
176340
176393
|
send(message) {
|
|
176341
|
-
if (this.#proc)
|
|
176394
|
+
if (!this.#proc || this.#status !== "ready") {
|
|
176395
|
+
this.logger.warn(`incrementalBuilderHost is ${this.#status}; cannot send ${message.type}`);
|
|
176396
|
+
return false;
|
|
176397
|
+
}
|
|
176398
|
+
try {
|
|
176342
176399
|
this.#proc.send(message);
|
|
176343
|
-
|
|
176344
|
-
|
|
176400
|
+
return true;
|
|
176401
|
+
} catch (error) {
|
|
176402
|
+
this.logger.warn(`failed to send ${message.type} to builder: ${error instanceof Error ? error.message : String(error)}`);
|
|
176403
|
+
return false;
|
|
176404
|
+
}
|
|
176345
176405
|
}
|
|
176346
176406
|
stop() {
|
|
176407
|
+
this.#manualStop = true;
|
|
176408
|
+
if (this.#restartTimer) {
|
|
176409
|
+
clearTimeout(this.#restartTimer);
|
|
176410
|
+
this.#restartTimer = null;
|
|
176411
|
+
}
|
|
176347
176412
|
if (this.#proc)
|
|
176348
176413
|
this.#proc.kill();
|
|
176349
176414
|
this.#proc = null;
|
|
176350
176415
|
this.ready = false;
|
|
176416
|
+
this.#status = "stopped";
|
|
176351
176417
|
}
|
|
176352
176418
|
static async create(app, env, onMessage) {
|
|
176353
176419
|
const candidates = [
|
|
@@ -176365,6 +176431,8 @@ class IncrementalBuilderHost {
|
|
|
176365
176431
|
var backendMsgTypeSet = new Set(["build-route"]);
|
|
176366
176432
|
var BACKEND_RESTART_DEBOUNCE_MS = 120;
|
|
176367
176433
|
var BACKEND_GRACEFUL_TIMEOUT_MS = 3000;
|
|
176434
|
+
var BACKEND_RECOVERY_BASE_DELAY_MS = 1000;
|
|
176435
|
+
var BACKEND_RECOVERY_MAX_DELAY_MS = 30000;
|
|
176368
176436
|
var BUILDER_READY_TIMEOUT_MS = 15000;
|
|
176369
176437
|
var BUILDER_START_MAX_ATTEMPTS = 3;
|
|
176370
176438
|
var SOURCE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
@@ -176488,6 +176556,8 @@ class AkanAppHost {
|
|
|
176488
176556
|
#backendReady = false;
|
|
176489
176557
|
#plannedBackendStops = new WeakSet;
|
|
176490
176558
|
#restartTimer = null;
|
|
176559
|
+
#backendRecoveryTimer = null;
|
|
176560
|
+
#backendRecoveryAttempts = 0;
|
|
176491
176561
|
#restartFiles = new Set;
|
|
176492
176562
|
#latestPagesUpdated = null;
|
|
176493
176563
|
#latestCssUpdated = null;
|
|
@@ -176518,6 +176588,10 @@ class AkanAppHost {
|
|
|
176518
176588
|
clearTimeout(this.#restartTimer);
|
|
176519
176589
|
this.#restartTimer = null;
|
|
176520
176590
|
}
|
|
176591
|
+
if (this.#backendRecoveryTimer) {
|
|
176592
|
+
clearTimeout(this.#backendRecoveryTimer);
|
|
176593
|
+
this.#backendRecoveryTimer = null;
|
|
176594
|
+
}
|
|
176521
176595
|
await this.#stopBackend();
|
|
176522
176596
|
this.#stopBuilder();
|
|
176523
176597
|
return this;
|
|
@@ -176542,6 +176616,7 @@ class AkanAppHost {
|
|
|
176542
176616
|
return;
|
|
176543
176617
|
if (msg.type === "backend-ready") {
|
|
176544
176618
|
this.#backendReady = true;
|
|
176619
|
+
this.#backendRecoveryAttempts = 0;
|
|
176545
176620
|
this.logger.verbose(`backend ready pid=${msg.pid}`);
|
|
176546
176621
|
this.#replayBuilderState();
|
|
176547
176622
|
return;
|
|
@@ -176558,7 +176633,7 @@ class AkanAppHost {
|
|
|
176558
176633
|
this.#plannedBackendStops.delete(backend);
|
|
176559
176634
|
return;
|
|
176560
176635
|
}
|
|
176561
|
-
this.#
|
|
176636
|
+
this.#scheduleBackendRecovery("backend-exit");
|
|
176562
176637
|
}
|
|
176563
176638
|
});
|
|
176564
176639
|
this.#backend = backend;
|
|
@@ -176606,6 +176681,10 @@ class AkanAppHost {
|
|
|
176606
176681
|
#scheduleBackendRestart(files) {
|
|
176607
176682
|
for (const file of files)
|
|
176608
176683
|
this.#restartFiles.add(file);
|
|
176684
|
+
if (this.#backendRecoveryTimer) {
|
|
176685
|
+
clearTimeout(this.#backendRecoveryTimer);
|
|
176686
|
+
this.#backendRecoveryTimer = null;
|
|
176687
|
+
}
|
|
176609
176688
|
if (this.#restartTimer)
|
|
176610
176689
|
clearTimeout(this.#restartTimer);
|
|
176611
176690
|
this.#restartTimer = setTimeout(() => {
|
|
@@ -176617,9 +176696,27 @@ class AkanAppHost {
|
|
|
176617
176696
|
}
|
|
176618
176697
|
async#restartBackend(files) {
|
|
176619
176698
|
this.logger.verbose(`[backend-reload] restarting backend for ${files.length} file(s)`);
|
|
176699
|
+
this.#backendRecoveryAttempts = 0;
|
|
176620
176700
|
await Promise.all([this.#stopBackend(), this.#backendGraph.refresh()]);
|
|
176621
176701
|
this.#startBackend();
|
|
176622
176702
|
}
|
|
176703
|
+
#scheduleBackendRecovery(reason) {
|
|
176704
|
+
if (this.#backendRecoveryTimer || this.#backend)
|
|
176705
|
+
return;
|
|
176706
|
+
const attempt = this.#backendRecoveryAttempts;
|
|
176707
|
+
const delay = Math.min(BACKEND_RECOVERY_BASE_DELAY_MS * 2 ** attempt, BACKEND_RECOVERY_MAX_DELAY_MS);
|
|
176708
|
+
this.#backendRecoveryAttempts = attempt + 1;
|
|
176709
|
+
this.logger.warn(`[backend-recovery] backend exited unexpectedly (${reason}); restarting in ${delay}ms (attempt ${this.#backendRecoveryAttempts})`);
|
|
176710
|
+
this.#backendRecoveryTimer = setTimeout(() => {
|
|
176711
|
+
this.#backendRecoveryTimer = null;
|
|
176712
|
+
if (this.#backend)
|
|
176713
|
+
return;
|
|
176714
|
+
this.#backendGraph.refresh().finally(() => {
|
|
176715
|
+
if (!this.#backend)
|
|
176716
|
+
this.#startBackend();
|
|
176717
|
+
});
|
|
176718
|
+
}, delay);
|
|
176719
|
+
}
|
|
176623
176720
|
#enqueueBuilderMessage(message) {
|
|
176624
176721
|
this.#builderMessageQueue = this.#builderMessageQueue.then(() => this.#handleBuilderMessage(message)).catch((err) => {
|
|
176625
176722
|
this.logger.warn(`failed to handle builder message: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -176688,7 +176785,6 @@ class AkanAppHost {
|
|
|
176688
176785
|
if (!this.#builder)
|
|
176689
176786
|
throw new Error("Builder Not Found");
|
|
176690
176787
|
let settled = false;
|
|
176691
|
-
let ready = false;
|
|
176692
176788
|
const settle = (fn) => {
|
|
176693
176789
|
if (settled)
|
|
176694
176790
|
return;
|
|
@@ -176701,24 +176797,31 @@ class AkanAppHost {
|
|
|
176701
176797
|
}, BUILDER_READY_TIMEOUT_MS);
|
|
176702
176798
|
this.#builder.start({
|
|
176703
176799
|
onExit: () => {
|
|
176704
|
-
if (settled && ready) {
|
|
176705
|
-
this.#stopBackend();
|
|
176706
|
-
return;
|
|
176707
|
-
}
|
|
176708
176800
|
settle(() => reject(new Error(`[cli] builder exited before emitting builder-ready (attempt ${attempt})`)));
|
|
176709
176801
|
},
|
|
176710
176802
|
onReady: () => {
|
|
176711
|
-
ready = true;
|
|
176712
176803
|
settle(resolve);
|
|
176804
|
+
},
|
|
176805
|
+
onRestartReady: () => {
|
|
176806
|
+
this.logger.verbose("[builder-recovery] builder ready after restart; replaying latest state");
|
|
176807
|
+
this.#replayBuilderState();
|
|
176713
176808
|
}
|
|
176714
176809
|
});
|
|
176715
176810
|
});
|
|
176716
176811
|
}
|
|
176717
176812
|
#sendToBuilder(message) {
|
|
176718
|
-
if (this.#builder)
|
|
176719
|
-
|
|
176720
|
-
|
|
176721
|
-
this
|
|
176813
|
+
if (this.#builder?.send(message))
|
|
176814
|
+
return;
|
|
176815
|
+
if (message.type === "build-route") {
|
|
176816
|
+
this.#sendToBackend({
|
|
176817
|
+
type: "build-route-res",
|
|
176818
|
+
id: message.id,
|
|
176819
|
+
ok: false,
|
|
176820
|
+
error: `builder is ${this.#builder?.status ?? "stopped"}; reload after the builder is ready`
|
|
176821
|
+
});
|
|
176822
|
+
return;
|
|
176823
|
+
}
|
|
176824
|
+
this.logger.warn("akanAppHost builder is not running");
|
|
176722
176825
|
}
|
|
176723
176826
|
#stopBuilder() {
|
|
176724
176827
|
if (!this.#builder)
|
|
@@ -182080,7 +182183,20 @@ var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
|
182080
182183
|
|
|
182081
182184
|
import { select as select6 } from "@inquirer/prompts";
|
|
182082
182185
|
|
|
182083
|
-
|
|
182186
|
+
function parseVersion(version) {
|
|
182187
|
+
return version.replace(/^[^\d]*/, "").split(/[.-]/).map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
|
|
182188
|
+
}
|
|
182189
|
+
function compareSemver(a, b) {
|
|
182190
|
+
const left = parseVersion(a);
|
|
182191
|
+
const right = parseVersion(b);
|
|
182192
|
+
const length = Math.max(left.length, right.length);
|
|
182193
|
+
for (let i = 0;i < length; i++) {
|
|
182194
|
+
const diff = (left[i] ?? 0) - (right[i] ?? 0);
|
|
182195
|
+
if (diff !== 0)
|
|
182196
|
+
return diff > 0 ? 1 : -1;
|
|
182197
|
+
}
|
|
182198
|
+
return 0;
|
|
182199
|
+
}
|
|
182084
182200
|
|
|
182085
182201
|
class LibraryRunner extends runner("library") {
|
|
182086
182202
|
async createLibrary(libName, workspace) {
|
|
@@ -182124,7 +182240,7 @@ class LibraryRunner extends runner("library") {
|
|
|
182124
182240
|
const allDependencies = Object.fromEntries(Object.keys({ ...libDependencies, ...rootDependencies }).map((dep) => {
|
|
182125
182241
|
const libVersion = libDependencies[dep] ?? "0.0.0";
|
|
182126
182242
|
const rootVersion = rootDependencies[dep] ?? "0.0.0";
|
|
182127
|
-
const newerVersion =
|
|
182243
|
+
const newerVersion = compareSemver(rootVersion, libVersion) > 0 ? rootVersion : libVersion;
|
|
182128
182244
|
return [dep, newerVersion];
|
|
182129
182245
|
}));
|
|
182130
182246
|
Object.keys(allDependencies).sort().forEach((dep) => {
|
|
@@ -182180,9 +182296,17 @@ import { StringOutputParser } from "@langchain/core/output_parsers";
|
|
|
182180
182296
|
import { PromptTemplate as PromptTemplate2 } from "@langchain/core/prompts";
|
|
182181
182297
|
import { RunnableSequence as RunnableSequence2 } from "@langchain/core/runnables";
|
|
182182
182298
|
import { ChatOpenAI as ChatOpenAI3 } from "@langchain/openai";
|
|
182183
|
-
import openBrowser from "open";
|
|
182184
182299
|
import ora3 from "ora";
|
|
182185
182300
|
|
|
182301
|
+
import { spawn as spawn2 } from "child_process";
|
|
182302
|
+
function openBrowser(url) {
|
|
182303
|
+
const command3 = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
|
|
182304
|
+
const child = spawn2(command3[0], command3.slice(1), { detached: true, stdio: "ignore" });
|
|
182305
|
+
child.on("error", () => {});
|
|
182306
|
+
child.unref();
|
|
182307
|
+
return Promise.resolve();
|
|
182308
|
+
}
|
|
182309
|
+
|
|
182186
182310
|
class ApplicationRunner extends runner("application") {
|
|
182187
182311
|
async createApplication(appName, workspace, libs = []) {
|
|
182188
182312
|
await workspace.applyTemplate({
|
|
@@ -182877,10 +183001,19 @@ class PackageScript extends script("package", [PackageRunner]) {
|
|
|
182877
183001
|
|
|
182878
183002
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
182879
183003
|
import chalk7 from "chalk";
|
|
182880
|
-
import latestVersion from "latest-version";
|
|
182881
|
-
import open from "open";
|
|
182882
183004
|
import * as QRcode from "qrcode";
|
|
182883
|
-
|
|
183005
|
+
|
|
183006
|
+
async function getLatestPackageVersion(packageName, tag = "latest") {
|
|
183007
|
+
const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace(/^%40/, "@")}`;
|
|
183008
|
+
const res = await fetch(url);
|
|
183009
|
+
if (!res.ok)
|
|
183010
|
+
throw new Error(`Failed to fetch ${packageName} metadata from npm registry`);
|
|
183011
|
+
const metadata = await res.json();
|
|
183012
|
+
const version = metadata["dist-tags"]?.[tag];
|
|
183013
|
+
if (!version)
|
|
183014
|
+
throw new Error(`No npm dist-tag "${tag}" found for ${packageName}`);
|
|
183015
|
+
return version;
|
|
183016
|
+
}
|
|
182884
183017
|
|
|
182885
183018
|
class CloudRunner extends runner("cloud") {
|
|
182886
183019
|
async login() {
|
|
@@ -182892,7 +183025,7 @@ class CloudRunner extends runner("cloud") {
|
|
|
182892
183025
|
`));
|
|
182893
183026
|
return true;
|
|
182894
183027
|
}
|
|
182895
|
-
const remoteId =
|
|
183028
|
+
const remoteId = crypto.randomUUID();
|
|
182896
183029
|
const signinUrl = `${akanCloudUrl}/signin?remoteId=${remoteId}`;
|
|
182897
183030
|
Logger.rawLog(chalk7.bold(`
|
|
182898
183031
|
${chalk7.green("\u27A4")} Authentication Required`));
|
|
@@ -182908,7 +183041,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
182908
183041
|
});
|
|
182909
183042
|
});
|
|
182910
183043
|
Logger.rawLog(qrcode);
|
|
182911
|
-
await
|
|
183044
|
+
await openBrowser(signinUrl);
|
|
182912
183045
|
Logger.rawLog(chalk7.dim("Opening browser..."));
|
|
182913
183046
|
} catch {
|
|
182914
183047
|
Logger.rawLog(chalk7.yellow("Could not open browser. Please visit the URL manually."));
|
|
@@ -182969,11 +183102,11 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
182969
183102
|
const tag = isOfficialRelease ? "latest" : patchVersion.split("-").at(1) ?? "dev";
|
|
182970
183103
|
const getNextVersion = async (prefix, tag2) => {
|
|
182971
183104
|
try {
|
|
182972
|
-
const latestPublishedVersion2 = await
|
|
183105
|
+
const latestPublishedVersion2 = await getLatestPackageVersion("akanjs", tag2);
|
|
182973
183106
|
const latestPatch = latestPublishedVersion2.startsWith(prefix) ? parseInt(latestPublishedVersion2.split(".").at(-1) ?? "-1") : -1;
|
|
182974
183107
|
const nextVersion2 = `${prefix}.${latestPatch + 1}`;
|
|
182975
183108
|
return { nextVersion: nextVersion2, latestPublishedVersion: latestPublishedVersion2 };
|
|
182976
|
-
} catch
|
|
183109
|
+
} catch {
|
|
182977
183110
|
return { nextVersion: `${prefix}.0`, latestPublishedVersion: null };
|
|
182978
183111
|
}
|
|
182979
183112
|
};
|
|
@@ -183012,7 +183145,7 @@ ${chalk7.green("\u27A4")} Authentication Required`));
|
|
|
183012
183145
|
]);
|
|
183013
183146
|
}
|
|
183014
183147
|
async#updateAkanPkgs(workspace, tag = "latest") {
|
|
183015
|
-
const latestPublishedVersion = await
|
|
183148
|
+
const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag);
|
|
183016
183149
|
const rootPackageJson = await workspace.getPackageJson();
|
|
183017
183150
|
if (!rootPackageJson.dependencies)
|
|
183018
183151
|
throw new Error("No dependencies found in package.json");
|
|
@@ -183685,7 +183818,13 @@ var requestUnit = ({
|
|
|
183685
183818
|
|
|
183686
183819
|
`;
|
|
183687
183820
|
|
|
183688
|
-
|
|
183821
|
+
function pluralizeName(name) {
|
|
183822
|
+
if (/[^aeiou]y$/i.test(name))
|
|
183823
|
+
return `${name.slice(0, -1)}ies`;
|
|
183824
|
+
if (/(s|x|z|ch|sh)$/i.test(name))
|
|
183825
|
+
return `${name}es`;
|
|
183826
|
+
return `${name}s`;
|
|
183827
|
+
}
|
|
183689
183828
|
|
|
183690
183829
|
class ModuleRunner extends runner("module") {
|
|
183691
183830
|
async createModule(workspace, sysType, sysName, moduleName, description) {}
|
|
@@ -183706,7 +183845,7 @@ class ModuleRunner extends runner("module") {
|
|
|
183706
183845
|
};
|
|
183707
183846
|
}
|
|
183708
183847
|
async createModuleTemplate(module) {
|
|
183709
|
-
const names =
|
|
183848
|
+
const names = pluralizeName(module.name);
|
|
183710
183849
|
await module.applyTemplate({
|
|
183711
183850
|
basePath: `.`,
|
|
183712
183851
|
template: "module",
|
|
@@ -183916,11 +184055,7 @@ class PageCommand extends command("page", [PageScript], ({ public: target }) =>
|
|
|
183916
184055
|
})) {
|
|
183917
184056
|
}
|
|
183918
184057
|
|
|
183919
|
-
import pluralize3 from "pluralize";
|
|
183920
|
-
|
|
183921
184058
|
import { input as input5 } from "@inquirer/prompts";
|
|
183922
|
-
import pluralize2 from "pluralize";
|
|
183923
|
-
|
|
183924
184059
|
class ScalarPrompt extends Prompter {
|
|
183925
184060
|
sys;
|
|
183926
184061
|
name;
|
|
@@ -183940,7 +184075,7 @@ class ScalarPrompt extends Prompter {
|
|
|
183940
184075
|
await this.sys.applyTemplate({
|
|
183941
184076
|
basePath: "./lib/__scalar",
|
|
183942
184077
|
template: "__scalar",
|
|
183943
|
-
dict: { model: this.name, models:
|
|
184078
|
+
dict: { model: this.name, models: pluralizeName(this.name), sysName: this.sys.name }
|
|
183944
184079
|
});
|
|
183945
184080
|
const boilerplate = await this.sys.readFile(`lib/__scalar/${this.name}/${this.name}.constant.ts`);
|
|
183946
184081
|
return await this.#requestConstant({
|
|
@@ -184044,7 +184179,7 @@ class ScalarRunner extends runner("scalar") {
|
|
|
184044
184179
|
await sys3.applyTemplate({
|
|
184045
184180
|
basePath: "./lib/__scalar",
|
|
184046
184181
|
template: "__scalar",
|
|
184047
|
-
dict: { model: scalarName, models:
|
|
184182
|
+
dict: { model: scalarName, models: pluralizeName(scalarName), sysName: sys3.name },
|
|
184048
184183
|
overwrite: false
|
|
184049
184184
|
});
|
|
184050
184185
|
}
|
|
@@ -184100,15 +184235,13 @@ class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target
|
|
|
184100
184235
|
import path38 from "path";
|
|
184101
184236
|
|
|
184102
184237
|
import path37 from "path";
|
|
184103
|
-
import latestVersion2 from "latest-version";
|
|
184104
|
-
|
|
184105
184238
|
class WorkspaceRunner extends runner("workspace") {
|
|
184106
184239
|
async createWorkspace(repoName, appName, { dirname: dirname3 = ".", init = true, akanVersion }) {
|
|
184107
184240
|
const cwdPath = process.cwd();
|
|
184108
184241
|
const workspaceRoot = path37.join(cwdPath, dirname3, repoName);
|
|
184109
184242
|
const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
|
|
184110
184243
|
const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname3}/${repoName}...`);
|
|
184111
|
-
const latestTypesBunVersion = await
|
|
184244
|
+
const latestTypesBunVersion = await getLatestPackageVersion("@types/bun");
|
|
184112
184245
|
await workspace.applyTemplate({
|
|
184113
184246
|
basePath: ".",
|
|
184114
184247
|
template: "workspaceRoot",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Lib, LibExecutor, runner, type Workspace } from "akanjs/devkit";
|
|
2
|
-
import {
|
|
2
|
+
import { compareSemver } from "../semver";
|
|
3
3
|
|
|
4
4
|
export class LibraryRunner extends runner("library") {
|
|
5
5
|
async createLibrary(libName: string, workspace: Workspace) {
|
|
@@ -44,7 +44,7 @@ export class LibraryRunner extends runner("library") {
|
|
|
44
44
|
Object.keys({ ...libDependencies, ...rootDependencies }).map((dep) => {
|
|
45
45
|
const libVersion = libDependencies[dep] ?? "0.0.0";
|
|
46
46
|
const rootVersion = rootDependencies[dep] ?? "0.0.0";
|
|
47
|
-
const newerVersion =
|
|
47
|
+
const newerVersion = compareSemver(rootVersion, libVersion) > 0 ? rootVersion : libVersion;
|
|
48
48
|
return [dep, newerVersion];
|
|
49
49
|
}),
|
|
50
50
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { capitalize } from "akanjs/common";
|
|
2
2
|
import { type Module, runner, type Workspace } from "akanjs/devkit";
|
|
3
|
-
import
|
|
3
|
+
import { pluralizeName } from "../pluralizeName";
|
|
4
4
|
|
|
5
5
|
export class ModuleRunner extends runner("module") {
|
|
6
6
|
async createModule(
|
|
@@ -30,7 +30,7 @@ export class ModuleRunner extends runner("module") {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
async createModuleTemplate(module: Module) {
|
|
33
|
-
const names =
|
|
33
|
+
const names = pluralizeName(module.name);
|
|
34
34
|
await module.applyTemplate({
|
|
35
35
|
basePath: `.`,
|
|
36
36
|
template: "module",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface NpmPackageMetadata {
|
|
2
|
+
"dist-tags"?: Record<string, string>;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export async function getLatestPackageVersion(packageName: string, tag = "latest"): Promise<string> {
|
|
6
|
+
const url = `https://registry.npmjs.org/${encodeURIComponent(packageName).replace(/^%40/, "@")}`;
|
|
7
|
+
const res = await fetch(url);
|
|
8
|
+
if (!res.ok) throw new Error(`Failed to fetch ${packageName} metadata from npm registry`);
|
|
9
|
+
const metadata = (await res.json()) as NpmPackageMetadata;
|
|
10
|
+
const version = metadata["dist-tags"]?.[tag];
|
|
11
|
+
if (!version) throw new Error(`No npm dist-tag "${tag}" found for ${packageName}`);
|
|
12
|
+
return version;
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
export function openBrowser(url: string): Promise<void> {
|
|
4
|
+
const command =
|
|
5
|
+
process.platform === "darwin"
|
|
6
|
+
? ["open", url]
|
|
7
|
+
: process.platform === "win32"
|
|
8
|
+
? ["cmd", "/c", "start", "", url]
|
|
9
|
+
: ["xdg-open", url];
|
|
10
|
+
const child = spawn(command[0], command.slice(1), { detached: true, stdio: "ignore" });
|
|
11
|
+
child.on("error", () => {
|
|
12
|
+
});
|
|
13
|
+
child.unref();
|
|
14
|
+
return Promise.resolve();
|
|
15
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { input } from "@inquirer/prompts";
|
|
2
2
|
import { type FileContent, Prompter, type Sys } from "akanjs/devkit";
|
|
3
|
-
import
|
|
3
|
+
import { pluralizeName } from "../pluralizeName";
|
|
4
4
|
|
|
5
5
|
export class ScalarPrompt extends Prompter {
|
|
6
6
|
constructor(
|
|
@@ -20,7 +20,7 @@ export class ScalarPrompt extends Prompter {
|
|
|
20
20
|
await this.sys.applyTemplate({
|
|
21
21
|
basePath: "./lib/__scalar",
|
|
22
22
|
template: "__scalar",
|
|
23
|
-
dict: { model: this.name, models:
|
|
23
|
+
dict: { model: this.name, models: pluralizeName(this.name), sysName: this.sys.name },
|
|
24
24
|
});
|
|
25
25
|
const boilerplate = await this.sys.readFile(`lib/__scalar/${this.name}/${this.name}.constant.ts`);
|
|
26
26
|
return await this.#requestConstant({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AiSession, runner, type Sys } from "akanjs/devkit";
|
|
2
|
-
import
|
|
2
|
+
import { pluralizeName } from "../pluralizeName";
|
|
3
3
|
|
|
4
4
|
import { ScalarPrompt } from "./scalar.prompt";
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ export class ScalarRunner extends runner("scalar") {
|
|
|
8
8
|
await sys.applyTemplate({
|
|
9
9
|
basePath: "./lib/__scalar",
|
|
10
10
|
template: "__scalar",
|
|
11
|
-
dict: { model: scalarName, models:
|
|
11
|
+
dict: { model: scalarName, models: pluralizeName(scalarName), sysName: sys.name },
|
|
12
12
|
overwrite: false,
|
|
13
13
|
});
|
|
14
14
|
}
|
package/cli/semver.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function parseVersion(version: string): number[] {
|
|
2
|
+
return version
|
|
3
|
+
.replace(/^[^\d]*/, "")
|
|
4
|
+
.split(/[.-]/)
|
|
5
|
+
.map((part) => Number.parseInt(part, 10))
|
|
6
|
+
.map((part) => (Number.isFinite(part) ? part : 0));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function compareSemver(a: string, b: string): number {
|
|
10
|
+
const left = parseVersion(a);
|
|
11
|
+
const right = parseVersion(b);
|
|
12
|
+
const length = Math.max(left.length, right.length);
|
|
13
|
+
for (let i = 0; i < length; i++) {
|
|
14
|
+
const diff = (left[i] ?? 0) - (right[i] ?? 0);
|
|
15
|
+
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
16
|
+
}
|
|
17
|
+
return 0;
|
|
18
|
+
}
|