@akanjs/cli 3.0.0-beta.8 → 3.0.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.
- package/.build-stamp +1 -1
- package/CodeAgent-2vmp9qe0.js +9 -0
- package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
- package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
- package/CodeTui-5ed6bg2a.js +1457 -0
- package/README.ko.md +83 -28
- package/README.md +70 -27
- package/TunnelShare-cwh9ezsm.js +9 -0
- package/{agent.command-0q17pnrs.js → agent.command-gn73rhe7.js} +8 -9
- package/akanCode.js +102 -0
- package/application.command-e968t0hw.js +246 -0
- package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-64taxseg.js} +121 -77
- package/buildBatch.proc.js +120 -32
- package/cloud.command-0jm301rr.js +95 -0
- package/cloud.script-nemnzjpv.js +20 -0
- package/code.command-18kcm7hq.js +154 -0
- package/commandManifest.json +1 -1
- package/consoleToStderr-h5bryj94.js +7 -0
- package/context.command-trd9bn18.js +48 -0
- package/context.runner-y5hwh673.js +21 -0
- package/{dependencyScanner-shs82ynp.js → dependencyScanner-06z2dmrr.js} +2 -2
- package/{devTui-m1atgkc9.js → devTui-q7k7bakd.js} +122 -40
- package/fileSys-wzzrntkw.js +9 -0
- package/guideline.command-bdmdn2de.js +42 -0
- package/guidelines/agentRule/agentRule.instruction.md +154 -26
- package/guidelines/conventions/conventions.instruction.md +134 -48
- package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
- package/guidelines/queryRule/queryRule.instruction.md +21 -7
- package/guidelines/runtimeRule/runtimeRule.instruction.md +291 -6
- package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
- package/guidelines/transportRule/transportRule.instruction.md +10 -8
- package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +20 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
- package/incrementalBuilder.proc.js +564 -109
- package/index-0wpybxtr.js +2729 -0
- package/{index-kcxmv48c.js → index-2ahj896a.js} +45 -79
- package/index-2wc41k5w.js +49 -0
- package/index-3hx1z96c.js +87 -0
- package/{index-2tv3fdx4.js → index-3w94e7n3.js} +1228 -1458
- package/{index-hwkygn9s.js → index-48k96p55.js} +325 -36
- package/index-4npz05nm.js +187 -0
- package/{index-q0y2jq9j.js → index-52w0fvh8.js} +21 -4
- package/index-6he6gvfg.js +4300 -0
- package/index-7md2g9vw.js +6 -0
- package/{index-04bk599g.js → index-93j60em0.js} +10 -17
- package/index-94s080qm.js +266 -0
- package/index-9dp031by.js +12 -0
- package/{index-ktb5njgy.js → index-9z771ptz.js} +49 -99
- package/{index-y6n8nmny.js → index-abxpehf8.js} +75 -203
- package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
- package/{index-9077wzd2.js → index-by9pxkr0.js} +43 -26
- package/index-c6eggbee.js +123 -0
- package/index-d2242ksy.js +99 -0
- package/index-drehwpdt.js +1119 -0
- package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
- package/{index-ffvk10zz.js → index-f3c78nd6.js} +107 -241
- package/index-gbggbqcp.js +1058 -0
- package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
- package/index-hsmtysz4.js +53 -0
- package/{index-j9yhg404.js → index-jmrn54tt.js} +4 -7
- package/{index-a64esmtb.js → index-kcdj1z5v.js} +523 -1022
- package/{index-d43r08tf.js → index-kqabytj7.js} +77 -150
- package/{index-vyvre9en.js → index-mbxbhay5.js} +6 -2
- package/{index-vxtad5bd.js → index-mgxpx3f2.js} +5 -8
- package/index-p6pbz9n5.js +25 -0
- package/{index-sj5vxr8f.js → index-p993efkq.js} +981 -897
- package/{index-2xp0kfkt.js → index-pmhqttv3.js} +37 -25
- package/index-tqm7jjcn.js +700 -0
- package/{index-0g7r8xz3.js → index-vpj42xwt.js} +114 -232
- package/index-wa5jbxj1.js +760 -0
- package/{index-k2j1hc4r.js → index-wprnsjms.js} +12 -12
- package/{index-gyd220p2.js → index-y3mphr1m.js} +554 -577
- package/index-yg7jhz8x.js +69 -0
- package/{index-h7yw2z9n.js → index-zzvvc845.js} +8 -14
- package/index.js +23 -22
- package/{library.command-qzzbj6d8.js → library.command-9h749a1x.js} +4 -5
- package/{localRegistry.command-vyrgg4xw.js → localRegistry.command-2bqqhxyz.js} +23 -43
- package/{module.command-rq5hq3ax.js → module.command-nv8nzgft.js} +8 -12
- package/{package.command-d9hd6v9n.js → package.command-mq4bggp6.js} +6 -7
- package/package.json +15 -7
- package/{page.command-126d56te.js → page.command-j639n707.js} +4 -5
- package/{primitive.command-taxd1538.js → primitive.command-kz6849th.js} +9 -23
- package/prompter-76k56b37.js +8 -0
- package/{quality.command-6gsna0a3.js → quality.command-4hyabwkb.js} +205 -377
- package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
- package/{repair.command-tq2dgy72.js → repair.command-a9awpbqr.js} +11 -35
- package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
- package/{scalar.command-3bcmrrkv.js → scalar.command-ma4fpm9m.js} +7 -11
- package/skills/akan-code/SKILL.md +130 -0
- package/skills/akan-debug/SKILL.md +42 -0
- package/skills/akan-deps/SKILL.md +50 -0
- package/skills/akan-err/SKILL.md +39 -0
- package/skills/akan-module/SKILL.md +45 -0
- package/skills/akan-scaffold/SKILL.md +76 -0
- package/skills/akan-scalar/SKILL.md +52 -0
- package/skills/akan-service/SKILL.md +34 -0
- package/skills/akan-store/SKILL.md +67 -0
- package/skills/akan-ui/SKILL.md +63 -0
- package/skills/akan-validate/SKILL.md +44 -0
- package/{subspace.command-eddzqpx3.js → subspace.command-3k2pmrs4.js} +53 -62
- package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
- package/templates/app/page/_index.tsx +257 -258
- package/templates/app/page/_layout.tsx +5 -1
- package/templates/app/page/_overrides.tsx +12 -0
- package/templates/app/page/styles.css.template +316 -14
- package/templates/app/public/apple-touch-icon.png +0 -0
- package/templates/app/public/favicon.ico +0 -0
- package/templates/app/public/jelly/cloud.webp +0 -0
- package/templates/app/public/jelly/comet.webp +0 -0
- package/templates/app/public/jelly/moon.webp +0 -0
- package/templates/app/public/jelly/planet.webp +0 -0
- package/templates/app/public/jelly/rocket.webp +0 -0
- package/templates/app/public/jelly/star.webp +0 -0
- package/templates/app/public/jelly/sugar.webp +0 -0
- package/templates/app/public/logo.png +0 -0
- package/templates/app/ui/Recipe/index.ts +9 -0
- package/templates/app/ui/Recipe/jellyButton.ts +63 -0
- package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
- package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
- package/templates/appSample/lib/task/Task.Unit.tsx +1 -1
- package/templates/appSample/lib/task/Task.Util.tsx +10 -13
- package/templates/appSample/lib/task/Task.View.tsx +2 -2
- package/templates/appSample/lib/task/Task.Zone.tsx +5 -2
- package/templates/appSample/lib/task/task.abstract.ts +12 -32
- package/templates/appSample/lib/task/task.signal.spec.ts +1 -15
- package/templates/appSample/lib/task/task.signal.test.ts +15 -1
- package/templates/appSample/lib/task/task.signal.ts +10 -8
- package/templates/appSample/page/task/[taskId]/_index.tsx +6 -6
- package/templates/appSample/page/task/[taskId]/edit.tsx +5 -4
- package/templates/appSample/page/task/_index.tsx +4 -3
- package/templates/appSample/page/task/_layout.tsx +1 -1
- package/templates/appSample/page/task/new.tsx +5 -4
- package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
- package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
- package/templates/appSample/ui/GlobalLoading.tsx +2 -1
- package/templates/appSample/ui/QuantityControl.tsx +3 -3
- package/templates/client.ts +7 -30
- package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
- package/templates/crudPages/[__model__Id]/page.tsx +2 -1
- package/templates/crudPages/new/page.tsx +2 -1
- package/templates/crudPages/page.tsx +2 -1
- package/templates/crudSinglePage/page.tsx +2 -1
- package/templates/lib/__lib/lib.dictionary.ts +0 -2
- package/templates/lib/__lib/lib.document.ts +0 -2
- package/templates/lib/sig.ts +8 -30
- package/templates/localDev/docker-compose.yaml.template +3 -14
- package/templates/module/__model__.signal.ts +12 -4
- package/templates/pkgRoot/tsconfig.json.template +2 -7
- package/templates/server.ts +1 -3
- package/templates/service/__model__.abstract.md.template +8 -0
- package/templates/workspaceRoot/.gitignore.template +0 -1
- package/templates/workspaceRoot/AGENTS.md.template +6 -0
- package/templates/workspaceRoot/package.json.template +1 -3
- package/tunnel.command-xwr46b66.js +129 -0
- package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
- package/typecheck.proc.js +1 -1
- package/workflow.command-t7wqe4h7.js +79 -0
- package/{workspace.command-06wvstgr.js → workspace.command-4derhzrh.js} +79 -109
- package/abstractCompactor-gmkc0z8j.js +0 -102
- package/application.command-18y0s485.js +0 -204
- package/applicationReleasePackager-4yasxwv9.js +0 -244
- package/capacitorApp-36rbr858.js +0 -12
- package/cloud.command-av97ndh6.js +0 -94
- package/cloud.script-cm11xjdz.js +0 -20
- package/context.command-5v37ef3n.js +0 -81
- package/devTuiView-0hc2emhe.js +0 -9
- package/getDirname-dr3jz1xg.js +0 -7
- package/guideline.command-4pz9g1rt.js +0 -360
- package/guidelines/agentRule/agentRule.generate.json +0 -31
- package/guidelines/componentRule/componentRule.generate.json +0 -31
- package/guidelines/conventions/conventions.generate.json +0 -25
- package/guidelines/cssRule/cssRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.generate.json +0 -31
- package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
- package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
- package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
- package/guidelines/enumConstant/enumConstant.generate.json +0 -31
- package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
- package/guidelines/fieldRule/fieldRule.generate.json +0 -31
- package/guidelines/framework/framework.generate.json +0 -32
- package/guidelines/mcpRule/mcpRule.generate.json +0 -35
- package/guidelines/modelConstant/modelConstant.generate.json +0 -32
- package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
- package/guidelines/modelDocument/modelDocument.generate.json +0 -31
- package/guidelines/modelService/modelService.generate.json +0 -31
- package/guidelines/modelSignal/modelSignal.generate.json +0 -31
- package/guidelines/modelStore/modelStore.generate.json +0 -31
- package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
- package/guidelines/modelUnit/modelUnit.generate.json +0 -31
- package/guidelines/modelUtil/modelUtil.generate.json +0 -31
- package/guidelines/modelView/modelView.generate.json +0 -31
- package/guidelines/modelZone/modelZone.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
- package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
- package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
- package/guidelines/queryRule/queryRule.generate.json +0 -31
- package/guidelines/recipeRule/recipeRule.generate.json +0 -31
- package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
- package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
- package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
- package/guidelines/scalarModule/scalarModule.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
- package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
- package/guidelines/ssrRule/ssrRule.generate.json +0 -31
- package/guidelines/transportRule/transportRule.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
- package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
- package/index-47pj3aee.js +0 -76
- package/index-5ystnsd5.js +0 -841
- package/index-6wwzs1bc.js +0 -7
- package/index-a17x49vg.js +0 -229
- package/index-m0xccmmm.js +0 -228
- package/index-meh558jy.js +0 -65
- package/index-rtxxan88.js +0 -471
- package/index-te54x9zm.js +0 -338
- package/index-w8kmx1b6.js +0 -2176
- package/index-wt7qrtd4.js +0 -1516
- package/templates/__scalar/__model__/__model__.abstract.md +0 -28
- package/templates/module/__model__.abstract.md +0 -28
- package/templates/service/__model__.abstract.md +0 -28
- package/templates/workspaceRoot/patches/react-dom@19.2.7.patch.template +0 -62
- package/workflow.command-gtdnzvbz.js +0 -108
|
@@ -3,38 +3,18 @@ import type { AppInfo, LibInfo } from "akanjs";
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
4
|
return {
|
|
5
5
|
filename: "task.abstract.md",
|
|
6
|
-
content: `#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- task.service.ts — business logic orchestration bound to DB via serve(db.task, ...)
|
|
19
|
-
- task.signal.ts — API surface (query, mutation, pubsub endpoints bound via endpoint(srv.task, ...))
|
|
20
|
-
- task.store.ts — client state management bound to signal via store(sig.task, ...)
|
|
21
|
-
- Task.*.tsx — UI components (Zone -> Load -> Unit / View / Template / Util)
|
|
22
|
-
|
|
23
|
-
## Convention: lib/<module>/ directory naming
|
|
24
|
-
|
|
25
|
-
- Database modules live under lib/<module>/ (no underscore prefix)
|
|
26
|
-
- Files follow <module>.<layer>.ts naming — e.g., task.constant.ts, task.service.ts
|
|
27
|
-
- UI files use PascalCase with explicit suffix: Task.Zone.tsx, Task.Unit.tsx, Task.View.tsx
|
|
28
|
-
|
|
29
|
-
## Convention: scan-registered barrels
|
|
30
|
-
|
|
31
|
-
akan sync auto-discovers each file and registers it in the corresponding barrel:
|
|
32
|
-
cnst.ts, db.ts, dict.ts, srv.ts, sig.ts, st.ts
|
|
33
|
-
|
|
34
|
-
## Related Modules
|
|
35
|
-
|
|
36
|
-
- lib/__scalar/workHistory/ — standard scalar modules with double-underscore prefix (reusable field sets)
|
|
37
|
-
- lib/_noti/ — pure service module (compare structure differences: no constant/document, serve without DB binding)
|
|
6
|
+
content: `# task Abstract
|
|
7
|
+
A task is one unit of work that moves from todo through in progress to completed, and keeps a record of each move.
|
|
8
|
+
|
|
9
|
+
## Rules
|
|
10
|
+
- A task only moves forward: \`start()\` needs \`todo\` and \`complete()\` needs \`inProgress\`; any other state throws.
|
|
11
|
+
- Every move appends one \`workHistory\` entry, and creation writes the first (\`created\`), so the history is never
|
|
12
|
+
empty and its last entry always matches \`status\`.
|
|
13
|
+
- Anyone may read a task; creating, changing, starting and completing one needs a signed-in caller. There is no
|
|
14
|
+
generated admin API (\`root: None\`).
|
|
15
|
+
- Removal is soft: a removed task keeps its row with \`removedAt\` set.
|
|
16
|
+
|
|
17
|
+
todo -> inProgress -> completed
|
|
38
18
|
`,
|
|
39
19
|
};
|
|
40
20
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
2
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
|
-
return `import {
|
|
5
|
-
import type { DocumentModel } from "akanjs/constant";
|
|
4
|
+
return `import type { DocumentModel } from "akanjs/constant";
|
|
6
5
|
import { getOrSetupSignalTestFetch, sampleOf } from "akanjs/test";
|
|
7
6
|
|
|
8
7
|
import * as cnst from "../cnst";
|
|
@@ -27,13 +26,6 @@ export const createTask = async (overrides: Partial<DocumentModel<cnst.TaskInput
|
|
|
27
26
|
|
|
28
27
|
const task = await fetch.createTask(taskInput);
|
|
29
28
|
|
|
30
|
-
expect(task).toMatchObject({
|
|
31
|
-
title: taskInput.title,
|
|
32
|
-
content: taskInput.content,
|
|
33
|
-
status: "todo",
|
|
34
|
-
});
|
|
35
|
-
expect(task.workHistory.map((entry) => entry.action)).toEqual(["created"]);
|
|
36
|
-
|
|
37
29
|
return {
|
|
38
30
|
task,
|
|
39
31
|
fetch,
|
|
@@ -45,9 +37,6 @@ export const getStartedTask = async (overrides: Partial<DocumentModel<cnst.TaskI
|
|
|
45
37
|
const agent = await createTask(overrides);
|
|
46
38
|
const task = await agent.fetch.startTask(agent.task.id);
|
|
47
39
|
|
|
48
|
-
expect(task.status).toBe("inProgress");
|
|
49
|
-
expect(task.workHistory.map((entry) => entry.action)).toEqual(["created", "started"]);
|
|
50
|
-
|
|
51
40
|
return {
|
|
52
41
|
...agent,
|
|
53
42
|
task,
|
|
@@ -58,9 +47,6 @@ export const getCompletedTask = async (overrides: Partial<DocumentModel<cnst.Tas
|
|
|
58
47
|
const agent = await getStartedTask(overrides);
|
|
59
48
|
const task = await agent.fetch.completeTask(agent.task.id);
|
|
60
49
|
|
|
61
|
-
expect(task.status).toBe("completed");
|
|
62
|
-
expect(task.workHistory.map((entry) => entry.action)).toEqual(["created", "started", "completed"]);
|
|
63
|
-
|
|
64
50
|
return {
|
|
65
51
|
...agent,
|
|
66
52
|
task,
|
|
@@ -6,9 +6,23 @@ import { configureSignalTest } from "akanjs/test";
|
|
|
6
6
|
|
|
7
7
|
import * as taskSpec from "./task.signal.spec";
|
|
8
8
|
|
|
9
|
-
configureSignalTest({
|
|
9
|
+
configureSignalTest({ storage: "memory" });
|
|
10
10
|
|
|
11
11
|
describe("Task signal smoke", () => {
|
|
12
|
+
test("creates a task in todo", async () => {
|
|
13
|
+
const { task, taskInput } = await taskSpec.createTask({ title: "Signal smoke task" });
|
|
14
|
+
|
|
15
|
+
expect(task).toMatchObject({ title: taskInput.title, content: taskInput.content, status: "todo" });
|
|
16
|
+
expect(task.workHistory.map((entry) => entry.action)).toEqual(["created"]);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("starts a task", async () => {
|
|
20
|
+
const { task } = await taskSpec.getStartedTask({ title: "Signal smoke task" });
|
|
21
|
+
|
|
22
|
+
expect(task.status).toBe("inProgress");
|
|
23
|
+
expect(task.workHistory.map((entry) => entry.action)).toEqual(["created", "started"]);
|
|
24
|
+
});
|
|
25
|
+
|
|
12
26
|
test("exposes custom task mutations over fetch", async () => {
|
|
13
27
|
const { task } = await taskSpec.getCompletedTask({ title: "Signal smoke task" });
|
|
14
28
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
2
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
|
-
return `import {
|
|
5
|
-
import { endpoint, internal, None, Public, slice } from "akanjs/signal";
|
|
4
|
+
return `import { endpoint, internal, None, Public, slice } from "akanjs/signal";
|
|
6
5
|
|
|
7
6
|
import * as cnst from "../cnst";
|
|
8
7
|
import * as srv from "../srv";
|
|
@@ -23,23 +22,26 @@ import * as srv from "../srv";
|
|
|
23
22
|
export class TaskInternal extends internal(srv.task, ({ interval }) => ({})) {}
|
|
24
23
|
|
|
25
24
|
// Guards, per key: root = the generated admin API (runs any filter with caller-supplied args), get = reads,
|
|
26
|
-
// cru = create/update/remove.
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
// cru = create/update/remove. None here means "nobody until you name a guard".
|
|
26
|
+
// The sample lets guests write so it works before the app has sign-in. Once it does, swap Public for SignedIn
|
|
27
|
+
// (srvkit/guards.ts) on cru and on the mutations below — a real app never leaves writes Public.
|
|
28
|
+
export class TaskSlice extends slice(srv.task, { guards: { root: None, get: Public, cru: Public } }, (init) => ({
|
|
29
|
+
inPublic: init({ guards: [Public] }).exec(function () {
|
|
29
30
|
return this.taskService.queryAny();
|
|
30
31
|
}),
|
|
31
32
|
})) {}
|
|
32
33
|
|
|
33
34
|
// Every custom endpoint names its own guards array — the slice's map above only covers generated CRUD.
|
|
34
|
-
// It is also the MCP decision: an endpoint declaring no guard
|
|
35
|
+
// It is also the MCP decision: an endpoint declaring no guard, or a mutation guarded only by Public, is not
|
|
36
|
+
// published to agents at all.
|
|
35
37
|
export class TaskEndpoint extends endpoint(srv.task, ({ mutation }) => ({
|
|
36
|
-
startTask: mutation(cnst.Task, { guards: [
|
|
38
|
+
startTask: mutation(cnst.Task, { guards: [Public] })
|
|
37
39
|
.param("taskId", String)
|
|
38
40
|
.exec(async function (taskId) {
|
|
39
41
|
return await this.taskService.startTask(taskId);
|
|
40
42
|
}),
|
|
41
43
|
|
|
42
|
-
completeTask: mutation(cnst.Task, { guards: [
|
|
44
|
+
completeTask: mutation(cnst.Task, { guards: [Public] })
|
|
43
45
|
.param("taskId", String)
|
|
44
46
|
.exec(async function (taskId) {
|
|
45
47
|
return await this.taskService.completeTask(taskId);
|
|
@@ -3,11 +3,11 @@ import type { AppInfo, LibInfo } from "akanjs";
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
4
|
return {
|
|
5
5
|
filename: "_index.tsx",
|
|
6
|
-
content: `import { fetch, usePage } from "@apps/${dict.appName}/client";
|
|
7
|
-
import {
|
|
6
|
+
content: `import { fetch, Task, usePage } from "@apps/${dict.appName}/client";
|
|
7
|
+
import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
|
|
8
8
|
import { ID } from "akanjs/base";
|
|
9
9
|
import { page } from "akanjs/client";
|
|
10
|
-
import { Link
|
|
10
|
+
import { Link } from "akanjs/ui";
|
|
11
11
|
|
|
12
12
|
export default page()
|
|
13
13
|
.param("taskId", ID)
|
|
@@ -17,10 +17,10 @@ export default page()
|
|
|
17
17
|
return (
|
|
18
18
|
<main className="mx-auto max-w-4xl px-6 py-8">
|
|
19
19
|
<div className="mb-6 flex items-center justify-between">
|
|
20
|
-
<
|
|
20
|
+
<Link href="/task" className={jellyButtonRecipe({ variant: "ghost", size: "sm" })}>
|
|
21
21
|
{l("task.taskBackToTasks")}
|
|
22
|
-
</
|
|
23
|
-
<Link href={\`/task/\${taskId}/edit\`} className={
|
|
22
|
+
</Link>
|
|
23
|
+
<Link href={\`/task/\${taskId}/edit\`} className={jellyButtonRecipe({ variant: "primary", size: "sm" })}>
|
|
24
24
|
{l("task.taskEdit")}
|
|
25
25
|
</Link>
|
|
26
26
|
</div>
|
|
@@ -4,9 +4,10 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "edit.tsx",
|
|
6
6
|
content: `import { fetch, Task } from "@apps/${dict.appName}/client";
|
|
7
|
+
import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
|
|
7
8
|
import { ID } from "akanjs/base";
|
|
8
9
|
import { page } from "akanjs/client";
|
|
9
|
-
import {
|
|
10
|
+
import { Link, Load } from "akanjs/ui";
|
|
10
11
|
|
|
11
12
|
export default page()
|
|
12
13
|
.param("taskId", ID)
|
|
@@ -16,15 +17,15 @@ export default page()
|
|
|
16
17
|
return (
|
|
17
18
|
<main className="mx-auto max-w-2xl px-6 py-8">
|
|
18
19
|
<div className="mb-6">
|
|
19
|
-
<Link href={\`/task/\${taskId}\`} className={
|
|
20
|
+
<Link href={\`/task/\${taskId}\`} className={jellyButtonRecipe({ variant: "ghost", size: "sm" })}>
|
|
20
21
|
← Back to Task
|
|
21
22
|
</Link>
|
|
22
23
|
</div>
|
|
23
24
|
<div className="mb-6">
|
|
24
|
-
<h1 className="font-
|
|
25
|
+
<h1 className="font-black text-4xl text-foreground">Edit Task</h1>
|
|
25
26
|
<p className="mt-1 text-foreground/60 text-sm">Update the task details</p>
|
|
26
27
|
</div>
|
|
27
|
-
<div className="
|
|
28
|
+
<div className="jelly-glass rounded-box p-6">
|
|
28
29
|
<Load.Edit slice={fetch.slice.taskInPublic} edit={taskEdit} type="form" onSubmit={\`/task/\${taskId}\`}>
|
|
29
30
|
<Task.Template.General />
|
|
30
31
|
</Load.Edit>
|
|
@@ -4,8 +4,9 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "_index.tsx",
|
|
6
6
|
content: `import { fetch, Task, usePage } from "@apps/${dict.appName}/client";
|
|
7
|
+
import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
|
|
7
8
|
import { page } from "akanjs/client";
|
|
8
|
-
import { Link
|
|
9
|
+
import { Link } from "akanjs/ui";
|
|
9
10
|
|
|
10
11
|
export default page().render(async () => {
|
|
11
12
|
const { l } = usePage();
|
|
@@ -14,10 +15,10 @@ export default page().render(async () => {
|
|
|
14
15
|
<main className="mx-auto max-w-4xl px-6 py-8">
|
|
15
16
|
<div className="mb-6 flex items-center justify-between">
|
|
16
17
|
<div>
|
|
17
|
-
<h1 className="font-
|
|
18
|
+
<h1 className="font-black text-4xl text-foreground">{l("task.modelName")}</h1>
|
|
18
19
|
<p className="mt-1 text-foreground/60 text-sm">{l("task.modelDesc")}</p>
|
|
19
20
|
</div>
|
|
20
|
-
<Link href="/task/new" className={
|
|
21
|
+
<Link href="/task/new" className={jellyButtonRecipe({ variant: "primary", size: "sm" })}>
|
|
21
22
|
{l("task.taskNew")}
|
|
22
23
|
</Link>
|
|
23
24
|
</div>
|
|
@@ -6,7 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
6
6
|
content: `import { layout } from "akanjs/client";
|
|
7
7
|
|
|
8
8
|
export default layout().render(({ children }) => {
|
|
9
|
-
return <div className="min-h-screen
|
|
9
|
+
return <div className="min-h-screen">{children}</div>;
|
|
10
10
|
});
|
|
11
11
|
`,
|
|
12
12
|
};
|
|
@@ -4,8 +4,9 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
4
4
|
return {
|
|
5
5
|
filename: "new.tsx",
|
|
6
6
|
content: `import { type cnst, fetch, Task } from "@apps/${dict.appName}/client";
|
|
7
|
+
import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
|
|
7
8
|
import { page } from "akanjs/client";
|
|
8
|
-
import {
|
|
9
|
+
import { Link, Load } from "akanjs/ui";
|
|
9
10
|
|
|
10
11
|
export default page().render(() => {
|
|
11
12
|
const taskForm: Partial<cnst.Task> = { status: "todo" };
|
|
@@ -13,15 +14,15 @@ export default page().render(() => {
|
|
|
13
14
|
return (
|
|
14
15
|
<main className="mx-auto max-w-2xl px-6 py-8">
|
|
15
16
|
<div className="mb-6">
|
|
16
|
-
<Link href="/task" className={
|
|
17
|
+
<Link href="/task" className={jellyButtonRecipe({ variant: "ghost", size: "sm" })}>
|
|
17
18
|
← Tasks
|
|
18
19
|
</Link>
|
|
19
20
|
</div>
|
|
20
21
|
<div className="mb-6">
|
|
21
|
-
<h1 className="font-
|
|
22
|
+
<h1 className="font-black text-4xl text-foreground">New Task</h1>
|
|
22
23
|
<p className="mt-1 text-foreground/60 text-sm">Create a new task with title and description</p>
|
|
23
24
|
</div>
|
|
24
|
-
<div className="
|
|
25
|
+
<div className="jelly-glass rounded-box p-6">
|
|
25
26
|
<Load.Edit slice={fetch.slice.taskInPublic} edit={taskForm} type="form" onCancel="back" onSubmit="/task">
|
|
26
27
|
<Task.Template.General />
|
|
27
28
|
</Load.Edit>
|
|
@@ -2,14 +2,14 @@ import type { AppInfo, LibInfo } from "akanjs";
|
|
|
2
2
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
4
|
return {
|
|
5
|
-
filename: "
|
|
5
|
+
filename: "guards.ts",
|
|
6
6
|
content: `import type { Guard, GuardScope, SignalContext } from "akanjs/signal";
|
|
7
7
|
|
|
8
|
-
// =====
|
|
8
|
+
// ===== guards.ts =====
|
|
9
9
|
// Convention: srvkit/ folder — server-only helpers, cannot import from client code.
|
|
10
10
|
// Implements the Guard interface from akanjs/signal.
|
|
11
11
|
// Guards are applied at endpoint/slice declaration: { guards: { root: SignedIn } }.
|
|
12
|
-
// Naming:
|
|
12
|
+
// Naming: camelCase file, PascalCase classes; each static name matches its guard identifier.
|
|
13
13
|
// Scanned by akan sync into srvkit/index.ts barrel automatically.
|
|
14
14
|
|
|
15
15
|
export class SignedIn implements Guard {
|
|
@@ -21,7 +21,10 @@ export class SignedIn implements Guard {
|
|
|
21
21
|
|
|
22
22
|
canPass(context: SignalContext): boolean {
|
|
23
23
|
// Reads the account the middleware resolved, so the same guard answers over HTTP, a websocket and MCP alike.
|
|
24
|
-
|
|
24
|
+
// A guest still has an account — libs/shared resolves one to \`{ appName, environment }\` — so only an
|
|
25
|
+
// identity on it proves a sign-in: your own middleware's \`id\`, or libs/shared's \`self\` (user) / \`me\` (admin).
|
|
26
|
+
const account = context.get<{ id?: string; self?: { id?: string }; me?: { id?: string } }>("account");
|
|
27
|
+
return !!(account?.id ?? account?.self?.id ?? account?.me?.id);
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
@@ -2,22 +2,24 @@ import type { AppInfo, LibInfo } from "akanjs";
|
|
|
2
2
|
|
|
3
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
|
|
4
4
|
return {
|
|
5
|
-
filename: "
|
|
5
|
+
filename: "internalArgs.ts",
|
|
6
6
|
content: `import type { InternalArg, SignalContext } from "akanjs/signal";
|
|
7
7
|
|
|
8
|
-
// =====
|
|
8
|
+
// ===== internalArgs.ts =====
|
|
9
9
|
// Convention: srvkit/ folder — server-only helpers.
|
|
10
10
|
// Implements the InternalArg interface from akanjs/signal.
|
|
11
11
|
// InternalArg is an auto-injected argument for resolveField/endpoint .with() chains.
|
|
12
12
|
// Appended to a query/mutation via: .with(CurrentUserId, { nullable: true }).exec(...)
|
|
13
|
-
// Naming:
|
|
13
|
+
// Naming: camelCase file, PascalCase classes; each class name is its arg identifier.
|
|
14
14
|
// Scanned by akan sync into srvkit/index.ts barrel automatically.
|
|
15
15
|
|
|
16
16
|
export class CurrentUserId implements InternalArg<string | null> {
|
|
17
17
|
getArg(context: SignalContext): string | null {
|
|
18
18
|
// \`context.get\` reads what the account middleware resolved, on every transport. Branching on
|
|
19
19
|
// \`getHttpContext()\` would return null for the same caller arriving over a websocket or MCP.
|
|
20
|
-
|
|
20
|
+
// An app's own middleware may put the id on the account itself; libs/shared puts it on \`self\` or \`me\`.
|
|
21
|
+
const account = context.get<{ id?: string; self?: { id?: string }; me?: { id?: string } }>("account");
|
|
22
|
+
return account?.id ?? account?.self?.id ?? account?.me?.id ?? null;
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -6,6 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
6
6
|
content: `"use client";
|
|
7
7
|
|
|
8
8
|
import { cn } from "akanjs/client";
|
|
9
|
+
import { Image } from "akanjs/ui";
|
|
9
10
|
|
|
10
11
|
// ===== GlobalLoading.tsx =====
|
|
11
12
|
// Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
|
|
@@ -20,7 +21,7 @@ interface GlobalLoadingProps {
|
|
|
20
21
|
export const GlobalLoading = ({ className, message = "Loading..." }: GlobalLoadingProps) => {
|
|
21
22
|
return (
|
|
22
23
|
<div className={cn("flex flex-col items-center justify-center gap-4 py-32", className)}>
|
|
23
|
-
<
|
|
24
|
+
<Image alt="" className="size-12 animate-bounce" height={96} src="/jelly/star.webp" width={96} />
|
|
24
25
|
<span className="text-foreground/60 text-sm">{message}</span>
|
|
25
26
|
</div>
|
|
26
27
|
);
|
|
@@ -6,7 +6,7 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
|
|
|
6
6
|
content: `"use client";
|
|
7
7
|
|
|
8
8
|
import { cn } from "akanjs/client";
|
|
9
|
-
import {
|
|
9
|
+
import { jellyButtonRecipe } from "./Recipe";
|
|
10
10
|
|
|
11
11
|
// ===== QuantityControl.tsx =====
|
|
12
12
|
// Convention: ui/ folder — reusable visual components. PascalCase .tsx, "use client" directive.
|
|
@@ -31,7 +31,7 @@ export const QuantityControl = ({
|
|
|
31
31
|
return (
|
|
32
32
|
<div className={cn("inline-flex items-center gap-1", className)}>
|
|
33
33
|
<button
|
|
34
|
-
className={
|
|
34
|
+
className={jellyButtonRecipe({ variant: "default", size: "icon" }, "size-7")}
|
|
35
35
|
disabled={value <= min}
|
|
36
36
|
onClick={() => onChange(Math.max(min, value - 1))}
|
|
37
37
|
>
|
|
@@ -39,7 +39,7 @@ export const QuantityControl = ({
|
|
|
39
39
|
</button>
|
|
40
40
|
<span className="w-8 text-center font-medium tabular-nums">{value}</span>
|
|
41
41
|
<button
|
|
42
|
-
className={
|
|
42
|
+
className={jellyButtonRecipe({ variant: "default", size: "icon" }, "size-7")}
|
|
43
43
|
disabled={value >= max}
|
|
44
44
|
onClick={() => onChange(Math.min(max, value + 1))}
|
|
45
45
|
>
|
package/templates/client.ts
CHANGED
|
@@ -4,36 +4,13 @@ const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
|
4
4
|
|
|
5
5
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
|
|
6
6
|
if (!scanInfo) return null;
|
|
7
|
-
const
|
|
8
|
-
.
|
|
9
|
-
([_, fileTypes]) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
fileTypes.has("zone"),
|
|
15
|
-
)
|
|
16
|
-
.map(([key]) => key);
|
|
17
|
-
const scalarModules = [...scanInfo.scalar.entries()]
|
|
18
|
-
.filter(
|
|
19
|
-
([_, fileTypes]) =>
|
|
20
|
-
fileTypes.has("template") ||
|
|
21
|
-
fileTypes.has("unit") ||
|
|
22
|
-
fileTypes.has("util") ||
|
|
23
|
-
fileTypes.has("view") ||
|
|
24
|
-
fileTypes.has("zone"),
|
|
25
|
-
)
|
|
26
|
-
.map(([key]) => key);
|
|
27
|
-
const serviceModules = [...scanInfo.service.entries()]
|
|
28
|
-
.filter(
|
|
29
|
-
([_, fileTypes]) =>
|
|
30
|
-
fileTypes.has("template") ||
|
|
31
|
-
fileTypes.has("unit") ||
|
|
32
|
-
fileTypes.has("util") ||
|
|
33
|
-
fileTypes.has("view") ||
|
|
34
|
-
fileTypes.has("zone"),
|
|
35
|
-
)
|
|
36
|
-
.map(([key]) => key);
|
|
7
|
+
const uiModules = (modules: Map<string, Set<string>>) =>
|
|
8
|
+
[...modules.entries()]
|
|
9
|
+
.filter(([_, fileTypes]) => ["template", "unit", "util", "view", "zone"].some((type) => fileTypes.has(type)))
|
|
10
|
+
.map(([key]) => key);
|
|
11
|
+
const databaseModules = uiModules(scanInfo.database);
|
|
12
|
+
const scalarModules = uiModules(scanInfo.scalar);
|
|
13
|
+
const serviceModules = uiModules(scanInfo.service);
|
|
37
14
|
return `
|
|
38
15
|
export * as cnst from "./lib/cnst";
|
|
39
16
|
export { msg, Err, usePage, fetch, sig } from "./lib/useClient";
|
|
@@ -4,12 +4,13 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
appName: string;
|
|
7
|
+
clientPath: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
10
11
|
filename: "_index.tsx",
|
|
11
12
|
content: `
|
|
12
|
-
import { ${dict.Model}, fetch, usePage } from "
|
|
13
|
+
import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
|
|
13
14
|
import { ID } from "akanjs/base";
|
|
14
15
|
import { page } from "akanjs/client";
|
|
15
16
|
import { Load } from "akanjs/ui";
|
|
@@ -4,12 +4,13 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
appName: string;
|
|
7
|
+
clientPath: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
10
11
|
filename: "_index.tsx",
|
|
11
12
|
content: `
|
|
12
|
-
import { ${dict.Model}, fetch, usePage } from "
|
|
13
|
+
import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
|
|
13
14
|
import { ID } from "akanjs/base";
|
|
14
15
|
import { page } from "akanjs/client";
|
|
15
16
|
import { buttonRecipe, Link } from "akanjs/ui";
|
|
@@ -4,12 +4,13 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
appName: string;
|
|
7
|
+
clientPath: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
10
11
|
filename: "_index.tsx",
|
|
11
12
|
content: `
|
|
12
|
-
import { type cnst, fetch, usePage, ${dict.Model} } from "
|
|
13
|
+
import { type cnst, fetch, usePage, ${dict.Model} } from "${dict.clientPath}";
|
|
13
14
|
import { page } from "akanjs/client";
|
|
14
15
|
import { Load } from "akanjs/ui";
|
|
15
16
|
|
|
@@ -4,12 +4,13 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
appName: string;
|
|
7
|
+
clientPath: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
10
11
|
filename: "_index.tsx",
|
|
11
12
|
content: `
|
|
12
|
-
import { ${dict.Model}, fetch, usePage } from "
|
|
13
|
+
import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
|
|
13
14
|
import { page } from "akanjs/client";
|
|
14
15
|
import { buttonRecipe, Link } from "akanjs/ui";
|
|
15
16
|
|
|
@@ -4,12 +4,13 @@ interface Dict {
|
|
|
4
4
|
Model: string;
|
|
5
5
|
model: string;
|
|
6
6
|
appName: string;
|
|
7
|
+
clientPath: string;
|
|
7
8
|
}
|
|
8
9
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: Dict) {
|
|
9
10
|
return {
|
|
10
11
|
filename: "_index.tsx",
|
|
11
12
|
content: `
|
|
12
|
-
import { ${dict.Model}, fetch, usePage } from "
|
|
13
|
+
import { ${dict.Model}, fetch, usePage } from "${dict.clientPath}";
|
|
13
14
|
import { page } from "akanjs/client";
|
|
14
15
|
import { buttonRecipe, Model } from "akanjs/ui";
|
|
15
16
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
2
|
|
|
3
|
-
const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
4
|
-
|
|
5
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
|
|
6
4
|
if (!scanInfo) return null;
|
|
7
5
|
const libs = scanInfo.getLibs();
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { AppInfo, LibInfo } from "akanjs";
|
|
2
2
|
|
|
3
|
-
const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
4
|
-
|
|
5
3
|
export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [key: string]: string } = {}) {
|
|
6
4
|
if (!scanInfo) return null;
|
|
7
5
|
const libs = scanInfo.getLibs();
|
package/templates/lib/sig.ts
CHANGED
|
@@ -13,6 +13,8 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { [
|
|
|
13
13
|
const libs = scanInfo.getLibs();
|
|
14
14
|
|
|
15
15
|
const signalNames = [...(libs.length === 0 ? ["base"] : libs), ...databaseModules, ...serviceModules];
|
|
16
|
+
const serverSignalClass = (module: string) =>
|
|
17
|
+
`export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`;
|
|
16
18
|
|
|
17
19
|
return `
|
|
18
20
|
import { FetchClient, type FetchClientType } from "akanjs/fetch";
|
|
@@ -20,38 +22,14 @@ import { SignalRegistry, serverSignal${libs.length === 0 ? ", fetch as base" : "
|
|
|
20
22
|
import { Err } from "./dict";
|
|
21
23
|
${libs.map((lib) => `import { fetch as ${lib} } from "@libs/${lib}/lib/sig";`).join("\n")}
|
|
22
24
|
|
|
23
|
-
${
|
|
24
|
-
|
|
25
|
-
.map(([module]) => `import * as ${module}Sig from "./${module}/${module}.signal";`)
|
|
26
|
-
.join("\n")}
|
|
27
|
-
${[...scanInfo.service.entries()]
|
|
28
|
-
.filter(([_, files]) => files.has("signal"))
|
|
29
|
-
.map(([module]) => `import * as ${module}Sig from "./_${module}/${module}.signal";`)
|
|
30
|
-
.join("\n")}
|
|
25
|
+
${databaseModules.map((module) => `import * as ${module}Sig from "./${module}/${module}.signal";`).join("\n")}
|
|
26
|
+
${serviceModules.map((module) => `import * as ${module}Sig from "./_${module}/${module}.signal";`).join("\n")}
|
|
31
27
|
|
|
32
|
-
${
|
|
33
|
-
|
|
34
|
-
.map(([module]) => `export * from "./${module}/${module}.signal";`)
|
|
35
|
-
.join("\n")}
|
|
36
|
-
${[...scanInfo.service.entries()]
|
|
37
|
-
.filter(([_, files]) => files.has("signal"))
|
|
38
|
-
.map(([module]) => `export * from "./_${module}/${module}.signal";`)
|
|
39
|
-
.join("\n")}
|
|
28
|
+
${databaseModules.map((module) => `export * from "./${module}/${module}.signal";`).join("\n")}
|
|
29
|
+
${serviceModules.map((module) => `export * from "./_${module}/${module}.signal";`).join("\n")}
|
|
40
30
|
|
|
41
|
-
${
|
|
42
|
-
|
|
43
|
-
.map(
|
|
44
|
-
([module]) =>
|
|
45
|
-
`export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`,
|
|
46
|
-
)
|
|
47
|
-
.join("\n")}
|
|
48
|
-
${[...scanInfo.service.entries()]
|
|
49
|
-
.filter(([_, files]) => files.has("signal"))
|
|
50
|
-
.map(
|
|
51
|
-
([module]) =>
|
|
52
|
-
`export class ${capitalize(module)} extends serverSignal(${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Internal) {}`,
|
|
53
|
-
)
|
|
54
|
-
.join("\n")}
|
|
31
|
+
${databaseModules.map(serverSignalClass).join("\n")}
|
|
32
|
+
${serviceModules.map(serverSignalClass).join("\n")}
|
|
55
33
|
|
|
56
34
|
${databaseModules.map((module) => `export const ${module} = SignalRegistry.registerDatabase("${module}" as const, ${module}Sig.${capitalize(module)}Internal, ${module}Sig.${capitalize(module)}Endpoint, ${module}Sig.${capitalize(module)}Slice, ${capitalize(module)});`).join("\n")}
|
|
57
35
|
${serviceModules.map((module) => `export const ${module} = SignalRegistry.registerService("${module}" as const, ${module}Sig.${capitalize(module)}Internal, ${module}Sig.${capitalize(module)}Endpoint, ${capitalize(module)});`).join("\n")}
|
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
version: "3.8"
|
|
2
1
|
networks:
|
|
3
2
|
<%= repoName %>-network:
|
|
4
3
|
driver: bridge
|
|
5
4
|
services:
|
|
6
5
|
redis:
|
|
7
6
|
container_name: <%= repoName %>-redis
|
|
8
|
-
image: redis
|
|
7
|
+
image: redis:8
|
|
9
8
|
restart: unless-stopped
|
|
10
9
|
ports:
|
|
11
10
|
- 6379:6379
|
|
12
11
|
networks:
|
|
13
12
|
- <%= repoName %>-network
|
|
14
|
-
libsql:
|
|
15
|
-
container_name: <%= repoName %>-libsql
|
|
16
|
-
image: ghcr.io/tursodatabase/libsql-server:latest
|
|
17
|
-
restart: unless-stopped
|
|
18
|
-
ports:
|
|
19
|
-
- 8080:8080
|
|
20
|
-
volumes:
|
|
21
|
-
- ./libsql:/var/lib/sqld
|
|
22
|
-
networks:
|
|
23
|
-
- <%= repoName %>-network
|
|
24
13
|
postgres:
|
|
25
14
|
container_name: <%= repoName %>-postgres
|
|
26
|
-
image: postgres:
|
|
15
|
+
image: postgres:18
|
|
27
16
|
restart: unless-stopped
|
|
28
17
|
ports:
|
|
29
18
|
- 5432:5432
|
|
@@ -32,6 +21,6 @@ services:
|
|
|
32
21
|
- POSTGRES_USER=akan
|
|
33
22
|
- POSTGRES_PASSWORD=akan
|
|
34
23
|
volumes:
|
|
35
|
-
- ./postgres:/var/lib/postgresql
|
|
24
|
+
- ./postgres:/var/lib/postgresql
|
|
36
25
|
networks:
|
|
37
26
|
- <%= repoName %>-network
|