create-nwire 0.8.17 → 0.9.2
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/README.md +17 -14
- package/dist/__tests__/scaffold.test.d.ts +1 -8
- package/dist/__tests__/scaffold.test.d.ts.map +1 -1
- package/dist/__tests__/scaffold.test.js +28 -25
- package/dist/__tests__/scaffold.test.js.map +1 -1
- package/dist/index.d.ts +11 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -39
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/{L4 → enterprise}/package.json +6 -6
- package/templates/{L1 → minimal}/README.md +6 -5
- package/templates/{L1 → minimal}/app/api.ts +3 -2
- package/templates/{L1 → minimal}/package.json +2 -2
- package/templates/{L2 → service}/README.md +4 -3
- package/templates/{L2 → service}/__tests__/todo-api.test.ts +2 -2
- package/templates/{L2 → service}/app/main.ts +2 -2
- package/templates/{L2 → service}/package.json +5 -5
- /package/templates/{L4 → enterprise}/README.md +0 -0
- /package/templates/{L4 → enterprise}/__tests__/auto-moderate.test.ts +0 -0
- /package/templates/{L4 → enterprise}/__tests__/submit-flow.test.ts +0 -0
- /package/templates/{L1 → enterprise}/_gitignore +0 -0
- /package/templates/{L4 → enterprise}/app/api.ts +0 -0
- /package/templates/{L4 → enterprise}/app/app.ts +0 -0
- /package/templates/{L4 → enterprise}/app/main.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/actions/approve-post.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/actions/reject-post.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/actions/submit-post.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/events/post-was-approved.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/events/post-was-rejected.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/events/post-was-submitted.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/posts.module.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/projections/queue-dashboard.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/queries/posts-by-author.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/routes/approve-post.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/routes/get-post.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/routes/list-queue.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/routes/reject-post.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/routes/submit-post.ts +0 -0
- /package/templates/{L4 → enterprise}/modules/posts/workflows/auto-moderate.ts +0 -0
- /package/templates/{L4 → enterprise}/tsconfig.json +0 -0
- /package/templates/{L1 → minimal}/__tests__/hello.test.ts +0 -0
- /package/templates/{L2 → minimal}/_gitignore +0 -0
- /package/templates/{L1 → minimal}/app/main.ts +0 -0
- /package/templates/{L1 → minimal}/app/routes/hello.ts +0 -0
- /package/templates/{L1 → minimal}/tsconfig.json +0 -0
- /package/templates/{L4 → service}/_gitignore +0 -0
- /package/templates/{L2 → service}/app/api.ts +0 -0
- /package/templates/{L2 → service}/app/errors/todo-errors.ts +0 -0
- /package/templates/{L2 → service}/app/middleware/require-user.ts +0 -0
- /package/templates/{L2 → service}/app/resources/todo.ts +0 -0
- /package/templates/{L2 → service}/app/routes/complete-todo.ts +0 -0
- /package/templates/{L2 → service}/app/routes/create-todo.ts +0 -0
- /package/templates/{L2 → service}/app/routes/delete-todo.ts +0 -0
- /package/templates/{L2 → service}/app/routes/list-todos.ts +0 -0
- /package/templates/{L2 → service}/app/store/todo-store.ts +0 -0
- /package/templates/{L2 → service}/tsconfig.json +0 -0
package/README.md
CHANGED
|
@@ -4,27 +4,30 @@ Scaffold a new Nwire project.
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
# pnpm
|
|
7
|
-
pnpm create nwire my-app --template
|
|
7
|
+
pnpm create nwire my-app --template service
|
|
8
8
|
|
|
9
9
|
# npm
|
|
10
|
-
npm create nwire my-app -- --template
|
|
10
|
+
npm create nwire my-app -- --template service
|
|
11
11
|
|
|
12
12
|
# yarn
|
|
13
|
-
yarn create nwire my-app --template
|
|
13
|
+
yarn create nwire my-app --template service
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Templates
|
|
17
17
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
18
|
+
| Name | What you get |
|
|
19
|
+
| ------------ | -------------------------------------------------------------------------------------------------------- |
|
|
20
|
+
| `minimal` | One POST route. `httpInterface` + `endpoint`. No app, no DI. ~30 LOC. |
|
|
21
|
+
| `service` | Todo CRUD. Container, plugin lifecycle, structured errors, middleware, in-memory store. |
|
|
22
|
+
| `enterprise` | Moderation queue. `createApp`, modules, actors, events, stateful workflow (saga), projection, resolvers. |
|
|
23
23
|
|
|
24
|
-
Pick the smallest
|
|
24
|
+
Pick the smallest template that fits — graduating up is just re-scaffolding
|
|
25
25
|
into a new folder and porting your code one file at a time.
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
The short aliases `L1`, `L2`, `L4` are accepted for one release as
|
|
28
|
+
deprecated synonyms for `minimal`, `service`, and `enterprise`.
|
|
29
|
+
|
|
30
|
+
## What ships with every template
|
|
28
31
|
|
|
29
32
|
- **Zod-validated** route handlers, automatic OpenAPI at `/openapi.json`
|
|
30
33
|
- **Graceful shutdown** via `@nwire/endpoint` (SIGTERM drain + lightship probes)
|
|
@@ -44,7 +47,7 @@ manual dispatch.
|
|
|
44
47
|
|
|
45
48
|
## Flags
|
|
46
49
|
|
|
47
|
-
| Flag | Effect
|
|
48
|
-
| ------------ |
|
|
49
|
-
| `--template` | `
|
|
50
|
-
| `--name` | Override project name (defaults to dir basename)
|
|
50
|
+
| Flag | Effect |
|
|
51
|
+
| ------------ | -------------------------------------------------------------- |
|
|
52
|
+
| `--template` | `minimal` \| `service` \| `enterprise` (defaults to `service`) |
|
|
53
|
+
| `--name` | Override project name (defaults to dir basename) |
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scaffold tests — verify each template materializes a coherent project
|
|
3
3
|
* directory with the project name substituted and the canonical files
|
|
4
|
-
* present.
|
|
5
|
-
*
|
|
6
|
-
* Every template is folder-organized: a flat-file shape would be smaller
|
|
7
|
-
* but graduating L1→L2→L4 with new conventions per level is hostile to
|
|
8
|
-
* users. One shape, one set of mental models.
|
|
9
|
-
*
|
|
10
|
-
* Does NOT install or boot the project (npm install in CI burns minutes
|
|
11
|
-
* and adds nothing — the boot path is exercised by the e2e examples).
|
|
4
|
+
* present. Does not install or boot the project.
|
|
12
5
|
*/
|
|
13
6
|
export {};
|
|
14
7
|
//# sourceMappingURL=scaffold.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/scaffold.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scaffold.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/scaffold.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scaffold tests — verify each template materializes a coherent project
|
|
3
3
|
* directory with the project name substituted and the canonical files
|
|
4
|
-
* present.
|
|
5
|
-
*
|
|
6
|
-
* Every template is folder-organized: a flat-file shape would be smaller
|
|
7
|
-
* but graduating L1→L2→L4 with new conventions per level is hostile to
|
|
8
|
-
* users. One shape, one set of mental models.
|
|
9
|
-
*
|
|
10
|
-
* Does NOT install or boot the project (npm install in CI burns minutes
|
|
11
|
-
* and adds nothing — the boot path is exercised by the e2e examples).
|
|
4
|
+
* present. Does not install or boot the project.
|
|
12
5
|
*/
|
|
13
6
|
import { mkdtempSync, readFileSync, existsSync, rmSync } from "node:fs";
|
|
14
7
|
import { tmpdir } from "node:os";
|
|
15
8
|
import { join } from "node:path";
|
|
16
9
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
17
|
-
import { scaffold } from "../index.js";
|
|
10
|
+
import { scaffold, resolveTemplateName } from "../index.js";
|
|
18
11
|
describe("create-nwire scaffold", () => {
|
|
19
12
|
let target;
|
|
20
13
|
beforeEach(() => {
|
|
@@ -25,14 +18,13 @@ describe("create-nwire scaffold", () => {
|
|
|
25
18
|
if (existsSync(target))
|
|
26
19
|
rmSync(target, { recursive: true, force: true });
|
|
27
20
|
});
|
|
28
|
-
it("
|
|
29
|
-
const { written } = scaffold({ target, template: "
|
|
21
|
+
it("minimal — http+endpoint with folder-organized routes", () => {
|
|
22
|
+
const { written } = scaffold({ target, template: "minimal", name: "alpha" });
|
|
30
23
|
expect(written.length).toBeGreaterThan(0);
|
|
31
24
|
const pkg = JSON.parse(readFileSync(join(target, "package.json"), "utf8"));
|
|
32
25
|
expect(pkg.name).toBe("alpha");
|
|
33
26
|
expect(pkg.dependencies["@nwire/endpoint"]).toBeDefined();
|
|
34
27
|
expect(pkg.dependencies["@nwire/http"]).toBeDefined();
|
|
35
|
-
// Folder shape: app/main.ts + app/api.ts + app/routes/<route>.ts + __tests__/
|
|
36
28
|
expect(existsSync(join(target, "app/main.ts"))).toBe(true);
|
|
37
29
|
expect(existsSync(join(target, "app/api.ts"))).toBe(true);
|
|
38
30
|
expect(existsSync(join(target, "app/routes/hello.ts"))).toBe(true);
|
|
@@ -41,39 +33,34 @@ describe("create-nwire scaffold", () => {
|
|
|
41
33
|
expect(existsSync(join(target, ".gitignore"))).toBe(true);
|
|
42
34
|
expect(readFileSync(join(target, "app/main.ts"), "utf8")).toContain('"alpha"');
|
|
43
35
|
});
|
|
44
|
-
it("
|
|
45
|
-
const { written } = scaffold({ target, template: "
|
|
36
|
+
it("service — resources/errors/middleware/store/routes folders", () => {
|
|
37
|
+
const { written } = scaffold({ target, template: "service", name: "beta-svc" });
|
|
46
38
|
expect(written.length).toBeGreaterThan(0);
|
|
47
39
|
const pkg = JSON.parse(readFileSync(join(target, "package.json"), "utf8"));
|
|
48
40
|
expect(pkg.name).toBe("beta-svc");
|
|
49
41
|
expect(pkg.dependencies["@nwire/forge"]).toBeDefined();
|
|
50
|
-
// Boot files
|
|
51
42
|
for (const f of ["app/main.ts", "app/api.ts"]) {
|
|
52
43
|
expect(existsSync(join(target, f))).toBe(true);
|
|
53
44
|
}
|
|
54
|
-
// Folder-organized pieces
|
|
55
45
|
expect(existsSync(join(target, "app/resources/todo.ts"))).toBe(true);
|
|
56
46
|
expect(existsSync(join(target, "app/errors/todo-errors.ts"))).toBe(true);
|
|
57
47
|
expect(existsSync(join(target, "app/middleware/require-user.ts"))).toBe(true);
|
|
58
48
|
expect(existsSync(join(target, "app/store/todo-store.ts"))).toBe(true);
|
|
59
|
-
// One route per file
|
|
60
49
|
for (const r of ["list-todos", "create-todo", "complete-todo", "delete-todo"]) {
|
|
61
50
|
expect(existsSync(join(target, `app/routes/${r}.ts`))).toBe(true);
|
|
62
51
|
}
|
|
63
52
|
expect(existsSync(join(target, "__tests__/todo-api.test.ts"))).toBe(true);
|
|
64
53
|
});
|
|
65
|
-
it("
|
|
66
|
-
const { written } = scaffold({ target, template: "
|
|
54
|
+
it("enterprise — modules/<bc>/{events,actions,workflows,projections,routes}", () => {
|
|
55
|
+
const { written } = scaffold({ target, template: "enterprise", name: "gamma-app" });
|
|
67
56
|
expect(written.length).toBeGreaterThan(0);
|
|
68
57
|
const pkg = JSON.parse(readFileSync(join(target, "package.json"), "utf8"));
|
|
69
58
|
expect(pkg.name).toBe("gamma-app");
|
|
70
59
|
expect(pkg.dependencies["@nwire/app"]).toBeDefined();
|
|
71
60
|
expect(pkg.dependencies["@nwire/forge"]).toBeDefined();
|
|
72
|
-
// Boot trio in app/
|
|
73
61
|
for (const f of ["app/main.ts", "app/api.ts", "app/app.ts"]) {
|
|
74
62
|
expect(existsSync(join(target, f))).toBe(true);
|
|
75
63
|
}
|
|
76
|
-
// The posts bounded context
|
|
77
64
|
expect(existsSync(join(target, "modules/posts/posts.module.ts"))).toBe(true);
|
|
78
65
|
for (const e of ["post-was-submitted", "post-was-approved", "post-was-rejected"]) {
|
|
79
66
|
expect(existsSync(join(target, `modules/posts/events/${e}.ts`))).toBe(true);
|
|
@@ -86,19 +73,18 @@ describe("create-nwire scaffold", () => {
|
|
|
86
73
|
for (const r of ["submit-post", "approve-post", "reject-post", "list-queue", "get-post"]) {
|
|
87
74
|
expect(existsSync(join(target, `modules/posts/routes/${r}.ts`))).toBe(true);
|
|
88
75
|
}
|
|
89
|
-
// Tests
|
|
90
76
|
expect(existsSync(join(target, "__tests__/submit-flow.test.ts"))).toBe(true);
|
|
91
77
|
expect(existsSync(join(target, "__tests__/auto-moderate.test.ts"))).toBe(true);
|
|
92
78
|
});
|
|
93
79
|
it("refuses to scaffold into a non-empty target", () => {
|
|
94
|
-
const { written } = scaffold({ target, template: "
|
|
80
|
+
const { written } = scaffold({ target, template: "minimal", name: "first" });
|
|
95
81
|
expect(written.length).toBeGreaterThan(0);
|
|
96
|
-
expect(() => scaffold({ target, template: "
|
|
82
|
+
expect(() => scaffold({ target, template: "minimal", name: "second" })).toThrowError(/not empty/);
|
|
97
83
|
});
|
|
98
84
|
it("derives project name from target dir basename when --name omitted", () => {
|
|
99
85
|
const t = join(tmpdir(), "create-nwire-derived-" + Date.now());
|
|
100
86
|
try {
|
|
101
|
-
scaffold({ target: t, template: "
|
|
87
|
+
scaffold({ target: t, template: "minimal" });
|
|
102
88
|
const pkg = JSON.parse(readFileSync(join(t, "package.json"), "utf8"));
|
|
103
89
|
expect(pkg.name).toMatch(/^create-nwire-derived-/);
|
|
104
90
|
}
|
|
@@ -107,4 +93,21 @@ describe("create-nwire scaffold", () => {
|
|
|
107
93
|
}
|
|
108
94
|
});
|
|
109
95
|
});
|
|
96
|
+
describe("resolveTemplateName", () => {
|
|
97
|
+
it("accepts canonical names", () => {
|
|
98
|
+
expect(resolveTemplateName("minimal")).toBe("minimal");
|
|
99
|
+
expect(resolveTemplateName("service")).toBe("service");
|
|
100
|
+
expect(resolveTemplateName("enterprise")).toBe("enterprise");
|
|
101
|
+
});
|
|
102
|
+
it("accepts deprecated short aliases", () => {
|
|
103
|
+
expect(resolveTemplateName("L1")).toBe("minimal");
|
|
104
|
+
expect(resolveTemplateName("L2")).toBe("service");
|
|
105
|
+
expect(resolveTemplateName("L4")).toBe("enterprise");
|
|
106
|
+
expect(resolveTemplateName("l1")).toBe("minimal");
|
|
107
|
+
});
|
|
108
|
+
it("rejects unknown names", () => {
|
|
109
|
+
expect(resolveTemplateName("foo")).toBe(null);
|
|
110
|
+
expect(resolveTemplateName("L3")).toBe(null);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
110
113
|
//# sourceMappingURL=scaffold.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.test.js","sourceRoot":"","sources":["../../src/__tests__/scaffold.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scaffold.test.js","sourceRoot":"","sources":["../../src/__tests__/scaffold.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* create-nwire — scaffold a new Nwire project from one of three templates.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* minimal → httpInterface + endpoint only, no domain
|
|
5
|
+
* service → in-memory app with one bounded context + middleware + structured errors
|
|
6
|
+
* enterprise → full enterprise shape (modules + actors + workflows + projections + resolvers)
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* pnpm create nwire <target-dir> [--template
|
|
10
|
-
*
|
|
11
|
-
* The CLI is deliberately tiny — no interactive wizard, no plugin registry,
|
|
12
|
-
* no template fetching from GitHub. Picking a level is the only decision;
|
|
13
|
-
* everything else is whatever the user does once their starter is live.
|
|
9
|
+
* pnpm create nwire <target-dir> [--template minimal|service|enterprise]
|
|
14
10
|
*/
|
|
15
|
-
export type
|
|
11
|
+
export type TemplateName = "minimal" | "service" | "enterprise";
|
|
16
12
|
interface ScaffoldOptions {
|
|
17
13
|
target: string;
|
|
18
|
-
template:
|
|
14
|
+
template: TemplateName;
|
|
19
15
|
name?: string;
|
|
20
16
|
}
|
|
21
|
-
/**
|
|
22
|
-
* Copy the template tree into target, swapping `{{PROJECT_NAME}}` in
|
|
23
|
-
* package.json and README.md so the scaffolded project reads coherent.
|
|
24
|
-
*/
|
|
25
17
|
export declare function scaffold(opts: ScaffoldOptions): {
|
|
26
18
|
written: string[];
|
|
27
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Normalize whatever the user passed against the canonical name set.
|
|
22
|
+
* Accepts either the new name directly or a deprecated short alias.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveTemplateName(raw: string): TemplateName | null;
|
|
28
25
|
export declare function runCli(): Promise<void>;
|
|
29
26
|
export {};
|
|
30
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkBH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;AA4BhE,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAQD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAiBrE;AAsDD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAYpE;AA8DD,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C"}
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* create-nwire — scaffold a new Nwire project from one of three templates.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* minimal → httpInterface + endpoint only, no domain
|
|
5
|
+
* service → in-memory app with one bounded context + middleware + structured errors
|
|
6
|
+
* enterprise → full enterprise shape (modules + actors + workflows + projections + resolvers)
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* pnpm create nwire <target-dir> [--template
|
|
10
|
-
*
|
|
11
|
-
* The CLI is deliberately tiny — no interactive wizard, no plugin registry,
|
|
12
|
-
* no template fetching from GitHub. Picking a level is the only decision;
|
|
13
|
-
* everything else is whatever the user does once their starter is live.
|
|
9
|
+
* pnpm create nwire <target-dir> [--template minimal|service|enterprise]
|
|
14
10
|
*/
|
|
15
11
|
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, } from "node:fs";
|
|
16
12
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -18,37 +14,36 @@ import { fileURLToPath } from "node:url";
|
|
|
18
14
|
import { defineCommand, runMain } from "citty";
|
|
19
15
|
import pc from "picocolors";
|
|
20
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
/**
|
|
18
|
+
* Deprecated short aliases retained for one release to avoid breaking
|
|
19
|
+
* existing scripts. Emit a one-line warning and rewrite to the canonical
|
|
20
|
+
* name.
|
|
21
|
+
*/
|
|
22
|
+
const TEMPLATE_ALIASES = {
|
|
23
|
+
L1: "minimal",
|
|
24
|
+
L2: "service",
|
|
25
|
+
L4: "enterprise",
|
|
26
|
+
};
|
|
21
27
|
const TEMPLATES = {
|
|
22
|
-
|
|
23
|
-
title: "Minimal
|
|
28
|
+
minimal: {
|
|
29
|
+
title: "Minimal",
|
|
24
30
|
blurb: "httpInterface + endpoint. Folder-organized routes/. No app, no DI.",
|
|
25
31
|
},
|
|
26
|
-
|
|
27
|
-
title: "Service
|
|
32
|
+
service: {
|
|
33
|
+
title: "Service",
|
|
28
34
|
blurb: "Per-file routes/resources/errors/middleware/store. In-memory CRUD.",
|
|
29
35
|
},
|
|
30
|
-
|
|
31
|
-
title: "Enterprise
|
|
36
|
+
enterprise: {
|
|
37
|
+
title: "Enterprise",
|
|
32
38
|
blurb: "modules/<bc>/{events,actions,workflows,projections,routes}. Full forge shape.",
|
|
33
39
|
},
|
|
34
40
|
};
|
|
35
|
-
/**
|
|
36
|
-
* Locate the templates/ folder. In dev it's a sibling of dist/; in a
|
|
37
|
-
* published package it's a sibling of the bin entry. Resolve relative to
|
|
38
|
-
* this module file so both shapes work.
|
|
39
|
-
*/
|
|
40
41
|
function templatesRoot() {
|
|
41
|
-
// dist/index.js → ../templates ; src/index.ts (dev) → ../templates
|
|
42
42
|
const candidate = resolve(__dirname, "..", "templates");
|
|
43
43
|
if (existsSync(candidate))
|
|
44
44
|
return candidate;
|
|
45
|
-
// Fallback: src layout — go up one more
|
|
46
45
|
return resolve(__dirname, "..", "..", "templates");
|
|
47
46
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Copy the template tree into target, swapping `{{PROJECT_NAME}}` in
|
|
50
|
-
* package.json and README.md so the scaffolded project reads coherent.
|
|
51
|
-
*/
|
|
52
47
|
export function scaffold(opts) {
|
|
53
48
|
const src = join(templatesRoot(), opts.template);
|
|
54
49
|
if (!existsSync(src)) {
|
|
@@ -68,10 +63,6 @@ export function scaffold(opts) {
|
|
|
68
63
|
* Files that get a leading underscore in the template tree because
|
|
69
64
|
* npm strips dotfiles when packing tarballs. We rename them back to
|
|
70
65
|
* their canonical dotfile names during scaffold.
|
|
71
|
-
*
|
|
72
|
-
* The earlier blanket rule "any entry starting with `_` becomes `.`"
|
|
73
|
-
* was wrong — it mangled directories like `__tests__` into `._tests__`.
|
|
74
|
-
* Keep the rename explicit so new template files don't surprise us.
|
|
75
66
|
*/
|
|
76
67
|
const UNDERSCORE_TO_DOT = {
|
|
77
68
|
_gitignore: ".gitignore",
|
|
@@ -97,7 +88,6 @@ function copyTree(src, dest, log) {
|
|
|
97
88
|
}
|
|
98
89
|
}
|
|
99
90
|
function applyVariables(root, vars) {
|
|
100
|
-
// Walk dest tree; for *.json, *.md, *.ts, *.mjs apply token substitution.
|
|
101
91
|
for (const entry of readdirSync(root)) {
|
|
102
92
|
const p = join(root, entry);
|
|
103
93
|
const st = statSync(p);
|
|
@@ -120,6 +110,22 @@ function basename(p) {
|
|
|
120
110
|
const parts = p.split(/[\\/]/).filter(Boolean);
|
|
121
111
|
return parts[parts.length - 1] ?? "nwire-app";
|
|
122
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Normalize whatever the user passed against the canonical name set.
|
|
115
|
+
* Accepts either the new name directly or a deprecated short alias.
|
|
116
|
+
*/
|
|
117
|
+
export function resolveTemplateName(raw) {
|
|
118
|
+
const lower = raw.toLowerCase();
|
|
119
|
+
if (lower in TEMPLATES)
|
|
120
|
+
return lower;
|
|
121
|
+
const upper = raw.toUpperCase();
|
|
122
|
+
if (upper in TEMPLATE_ALIASES) {
|
|
123
|
+
const canonical = TEMPLATE_ALIASES[upper];
|
|
124
|
+
console.warn(pc.yellow(`note: template "${upper}" is deprecated. Use --template ${canonical}.`));
|
|
125
|
+
return canonical;
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
123
129
|
const main = defineCommand({
|
|
124
130
|
meta: {
|
|
125
131
|
name: "create-nwire",
|
|
@@ -133,8 +139,8 @@ const main = defineCommand({
|
|
|
133
139
|
},
|
|
134
140
|
template: {
|
|
135
141
|
type: "string",
|
|
136
|
-
description: "Template
|
|
137
|
-
default: "
|
|
142
|
+
description: "Template: minimal | service | enterprise",
|
|
143
|
+
default: "service",
|
|
138
144
|
},
|
|
139
145
|
name: {
|
|
140
146
|
type: "string",
|
|
@@ -145,7 +151,7 @@ const main = defineCommand({
|
|
|
145
151
|
const targetArg = ctx.args.target;
|
|
146
152
|
if (!targetArg) {
|
|
147
153
|
console.error(pc.red("missing target directory."));
|
|
148
|
-
console.error(` ${pc.dim("e.g.")} ${pc.cyan("pnpm create nwire my-app --template
|
|
154
|
+
console.error(` ${pc.dim("e.g.")} ${pc.cyan("pnpm create nwire my-app --template service")}`);
|
|
149
155
|
console.error("");
|
|
150
156
|
console.error("templates:");
|
|
151
157
|
for (const [k, v] of Object.entries(TEMPLATES)) {
|
|
@@ -153,17 +159,16 @@ const main = defineCommand({
|
|
|
153
159
|
}
|
|
154
160
|
process.exit(1);
|
|
155
161
|
}
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
158
|
-
console.error(pc.red(`unknown template "${ctx.args.template}". Use
|
|
162
|
+
const template = resolveTemplateName(String(ctx.args.template));
|
|
163
|
+
if (!template) {
|
|
164
|
+
console.error(pc.red(`unknown template "${ctx.args.template}". Use minimal, service, or enterprise.`));
|
|
159
165
|
process.exit(1);
|
|
160
166
|
}
|
|
161
|
-
const template = tplRaw;
|
|
162
167
|
const target = resolve(process.cwd(), targetArg);
|
|
163
168
|
console.log(pc.cyan(`\n scaffolding ${pc.bold(template)} into ${pc.bold(target)}`));
|
|
164
169
|
try {
|
|
165
170
|
const { written } = scaffold({ target, template, name: ctx.args.name });
|
|
166
|
-
console.log(pc.green(`
|
|
171
|
+
console.log(pc.green(` wrote ${written.length} files\n`));
|
|
167
172
|
console.log(` next:`);
|
|
168
173
|
console.log(` ${pc.dim("$")} ${pc.cyan(`cd ${targetArg}`)}`);
|
|
169
174
|
console.log(` ${pc.dim("$")} ${pc.cyan("pnpm install")}`);
|
|
@@ -171,7 +176,7 @@ const main = defineCommand({
|
|
|
171
176
|
console.log("");
|
|
172
177
|
}
|
|
173
178
|
catch (err) {
|
|
174
|
-
console.error(pc.red(`
|
|
179
|
+
console.error(pc.red(` ${err.message}`));
|
|
175
180
|
process.exit(1);
|
|
176
181
|
}
|
|
177
182
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"test": "vitest run"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@nwire/app": "^0.
|
|
12
|
-
"@nwire/endpoint": "^0.
|
|
13
|
-
"@nwire/forge": "^0.
|
|
14
|
-
"@nwire/http": "^0.
|
|
15
|
-
"@nwire/messages": "^0.
|
|
11
|
+
"@nwire/app": "^0.9.2",
|
|
12
|
+
"@nwire/endpoint": "^0.9.2",
|
|
13
|
+
"@nwire/forge": "^0.9.2",
|
|
14
|
+
"@nwire/http": "^0.9.2",
|
|
15
|
+
"@nwire/messages": "^0.9.2",
|
|
16
16
|
"zod": "^4.0.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@nwire/test-kit": "^0.
|
|
19
|
+
"@nwire/test-kit": "^0.9.2",
|
|
20
20
|
"@types/node": "^22.19.9",
|
|
21
21
|
"typescript": "^5.9.0",
|
|
22
22
|
"vite-node": "^3.2.4",
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
The smallest possible Nwire shape — one POST route, one inline handler,
|
|
4
4
|
no app, no DI, no domain primitives.
|
|
5
5
|
|
|
6
|
-
Despite being tiny, the project is **folder-organized** so it matches
|
|
7
|
-
and
|
|
6
|
+
Despite being tiny, the project is **folder-organized** so it matches the
|
|
7
|
+
`service` and `enterprise` templates. Adding route #2 is a single new
|
|
8
|
+
file, not a rewrite.
|
|
8
9
|
|
|
9
10
|
## Run
|
|
10
11
|
|
|
@@ -46,7 +47,7 @@ pnpm test
|
|
|
46
47
|
| ----------------- | ------------------------------------------------------------------------------------------------- |
|
|
47
48
|
| A new route | `app/routes/<verb-noun>.ts` exports `{name}Route + {name}Handler`; `.wire()` it from `app/api.ts` |
|
|
48
49
|
| Middleware | Inline in `app/api.ts` via `.use(middlewareFn)` |
|
|
49
|
-
| Container deps | Graduate to
|
|
50
|
+
| Container deps | Graduate to `service` — `app/store/` + `.provide(container)` in api.ts |
|
|
50
51
|
|
|
51
52
|
## What you get free
|
|
52
53
|
|
|
@@ -61,5 +62,5 @@ pnpm test
|
|
|
61
62
|
## Grow up
|
|
62
63
|
|
|
63
64
|
When you outgrow inline handlers (multiple routes, persistence, container
|
|
64
|
-
bindings, errors) re-scaffold with `pnpm create nwire <name> --template
|
|
65
|
-
for the service shape or `--template
|
|
65
|
+
bindings, errors) re-scaffold with `pnpm create nwire <name> --template service`
|
|
66
|
+
for the service shape or `--template enterprise` for the full enterprise shape.
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
*
|
|
11
11
|
* - Adding route #2 is a single new file, not a rewrite of api.ts.
|
|
12
12
|
* - Each route's verb + path + schema + handler live together.
|
|
13
|
-
* - The pattern matches
|
|
13
|
+
* - The pattern matches the service and enterprise templates, so
|
|
14
|
+
* graduating up is mechanical.
|
|
14
15
|
*
|
|
15
16
|
* When you outgrow inline handlers (multiple bounded contexts, domain
|
|
16
|
-
* events, persistence) graduate via `pnpm create nwire <name> --template
|
|
17
|
+
* events, persistence) graduate via `pnpm create nwire <name> --template service`.
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
import { httpInterface } from "@nwire/http";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# {{PROJECT_NAME}}
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A `service` Nwire shape — todo CRUD with structured errors, middleware
|
|
4
4
|
chain, public-shape projection, and an in-memory store wired via a
|
|
5
5
|
container binding.
|
|
6
6
|
|
|
7
|
-
No actors, no events, no workflows yet — see
|
|
7
|
+
No actors, no events, no workflows yet — see the `enterprise` template
|
|
8
|
+
for those.
|
|
8
9
|
|
|
9
10
|
## Run
|
|
10
11
|
|
|
@@ -67,4 +68,4 @@ curl -X POST http://localhost:3000/api/todos/<id>/complete \
|
|
|
67
68
|
## Grow up
|
|
68
69
|
|
|
69
70
|
When you need bounded contexts, actors, events, workflows, projections,
|
|
70
|
-
re-scaffold with `pnpm create nwire <name> --template
|
|
71
|
+
re-scaffold with `pnpm create nwire <name> --template enterprise`.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
|
10
10
|
import http from "node:http";
|
|
11
11
|
import type { Server } from "node:http";
|
|
12
|
-
import {
|
|
12
|
+
import { createContainer } from "@nwire/container";
|
|
13
13
|
import { TodoStore } from "../app/store/todo-store";
|
|
14
14
|
import { api } from "../app/api";
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ let server: Server;
|
|
|
17
17
|
let url: string;
|
|
18
18
|
|
|
19
19
|
beforeAll(async () => {
|
|
20
|
-
const container =
|
|
20
|
+
const container = createContainer();
|
|
21
21
|
container.register("todos", new TodoStore());
|
|
22
22
|
api.provide(container);
|
|
23
23
|
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { endpoint } from "@nwire/endpoint";
|
|
26
|
-
import {
|
|
26
|
+
import { createContainer } from "@nwire/container";
|
|
27
27
|
import { TodoStore } from "./store/todo-store";
|
|
28
28
|
import { api } from "./api";
|
|
29
29
|
|
|
30
|
-
const container =
|
|
30
|
+
const container = createContainer();
|
|
31
31
|
container.register("todos", new TodoStore());
|
|
32
32
|
|
|
33
33
|
api.provide(container);
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
"test": "vitest run"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@nwire/app": "^0.
|
|
12
|
-
"@nwire/container": "^0.
|
|
13
|
-
"@nwire/endpoint": "^0.
|
|
14
|
-
"@nwire/forge": "^0.
|
|
15
|
-
"@nwire/http": "^0.
|
|
11
|
+
"@nwire/app": "^0.9.2",
|
|
12
|
+
"@nwire/container": "^0.9.2",
|
|
13
|
+
"@nwire/endpoint": "^0.9.2",
|
|
14
|
+
"@nwire/forge": "^0.9.2",
|
|
15
|
+
"@nwire/http": "^0.9.2",
|
|
16
16
|
"zod": "^4.0.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|