@solid-stack/mason 1.0.20 → 1.0.21
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 +713 -137
- package/package.json +3 -2
- package/schema.json +29 -0
package/README.md
CHANGED
|
@@ -1,238 +1,814 @@
|
|
|
1
|
-
# @solid-stack/
|
|
1
|
+
# 🧱 Mason (@solid-stack/mason)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **The CLI Generator & Registry Engine for Solid Stack Clean Architecture**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@solid-stack/mason)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
|
|
9
|
+
**Mason** is a type-safe CLI scaffolding tool and code-registry manager purpose-built for the **Solid Stack Clean Architecture** ecosystem (`@solid-stack/agnos`, `@solid-stack/agnos-express`, and `@solid-stack/di`).
|
|
10
|
+
|
|
11
|
+
Mason enables you to:
|
|
12
|
+
1. **Scaffold production-grade vertical slices**: Generate features, use cases, domain models, runtime abstract interfaces, infrastructure adapters/stubs, HTTP endpoints, and DI providers via the CLI.
|
|
13
|
+
2. **Scaffold reusable shared modules**: Generate encapsulated ports, adapters, and domain utilities with test stubs.
|
|
14
|
+
3. **Import from remote code registries**: Download and link verified, pre-built modules from the Solid Stack Registry with topological dependency graph resolution, SHA-256 cryptographic drift detection, intelligent conflict resolution, import aliasing, and test file distribution.
|
|
15
|
+
4. **Enforce clean boundaries**: Strictly decouple domain logic from presentation and database frameworks with zero runtime boilerplate.
|
|
4
16
|
|
|
5
17
|
---
|
|
6
18
|
|
|
7
|
-
##
|
|
19
|
+
## 📑 Table of Contents
|
|
20
|
+
|
|
21
|
+
- [Architectural Blueprint](#-architectural-blueprint)
|
|
22
|
+
- [Installation & Quick Start](#-installation--quick-start)
|
|
23
|
+
- [Configuration (`mason.config.json`)](#-configuration-masonconfigjson)
|
|
24
|
+
- [CLI Architecture & Execution Modes](#-cli-architecture--execution-modes)
|
|
25
|
+
- [Global CLI Flags](#-global-cli-flags)
|
|
26
|
+
- [Command Reference: Scaffolding (`create`)](#-command-reference-scaffolding-create)
|
|
27
|
+
- [`mason create feature`](#1-mason-create-feature-name)
|
|
28
|
+
- [`mason create shared`](#2-mason-create-shared-name)
|
|
29
|
+
- [`mason create usecase`](#3-mason-create-usecase-name)
|
|
30
|
+
- [`mason create domain`](#4-mason-create-domain-name)
|
|
31
|
+
- [`mason create interface`](#5-mason-create-interface-name)
|
|
32
|
+
- [`mason create infrastructure`](#6-mason-create-infrastructure-name)
|
|
33
|
+
- [`mason create httpHandler`](#7-mason-create-httphandler-name)
|
|
34
|
+
- [`mason create injectable`](#8-mason-create-injectable-name)
|
|
35
|
+
- [Command Reference: Registry Import (`import`)](#-command-reference-registry-import-import)
|
|
36
|
+
- [Import Command Syntax](#import-command-syntax)
|
|
37
|
+
- [Import Options & Flags](#import-options--flags)
|
|
38
|
+
- [Cryptographic Drift Detection & Resolution Flags](#cryptographic-drift-detection--resolution-flags)
|
|
39
|
+
- [Test Files Management](#test-files-management)
|
|
40
|
+
- [Programmatic TypeScript API](#-programmatic-typescript-api)
|
|
41
|
+
- [Docker, Testing & Makefiles](#-docker-testing--makefiles)
|
|
42
|
+
- [License](#-license)
|
|
43
|
+
- [🎯 CLI Cookbook: Real-World Examples & Complex Cases](#-cli-cookbook-real-world-examples--complex-cases)
|
|
44
|
+
- [Basic Scaffolding Examples](#basic-scaffolding-examples)
|
|
45
|
+
- [Domain & Infrastructure Scaffolding](#domain--infrastructure-scaffolding)
|
|
46
|
+
- [Use Cases & HTTP Handler Scaffolding](#use-cases--http-handler-scaffolding)
|
|
47
|
+
- [End-to-End Vertical Slice Construction Pipeline](#end-to-end-vertical-slice-construction-pipeline)
|
|
48
|
+
- [Shared Module & Registry Authoring Examples](#shared-module--registry-authoring-examples)
|
|
49
|
+
- [Registry Import: Simple to Highly Complex Scenarios](#registry-import-simple-to-highly-complex-scenarios)
|
|
8
50
|
|
|
9
|
-
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 🏗️ Architectural Blueprint
|
|
54
|
+
|
|
55
|
+
Mason scaffolds code according to strict **Clean Architecture** and **Domain-Driven Design (DDD)** vertical slice boundaries:
|
|
10
56
|
|
|
11
57
|
```text
|
|
12
|
-
|
|
13
|
-
├──
|
|
14
|
-
│
|
|
15
|
-
│
|
|
16
|
-
├──
|
|
17
|
-
│ └──
|
|
18
|
-
├──
|
|
19
|
-
│ ├── <
|
|
20
|
-
│ └── <
|
|
21
|
-
├──
|
|
22
|
-
│ ├──
|
|
23
|
-
│ └──
|
|
24
|
-
│
|
|
25
|
-
|
|
58
|
+
src/
|
|
59
|
+
├── features/
|
|
60
|
+
│ └── <feature>/
|
|
61
|
+
│ ├── domain/ # Pure domain models, entities, and runtime abstract interfaces
|
|
62
|
+
│ │ ├── <Entity>.ts # Pure domain model / value object (Zero DI dependencies!)
|
|
63
|
+
│ │ └── I<Entity>Repo.ts # Runtime abstract class (Serves as both type & DI token)
|
|
64
|
+
│ ├── infrastructure/ # Implementations of domain interfaces
|
|
65
|
+
│ │ ├── Stub<Entity>Repo.ts # In-memory test stub with helpers (clear, setError, getAll)
|
|
66
|
+
│ │ └── <Db><Entity>Repo.ts # Production adapter (@MakeInjectable)
|
|
67
|
+
│ ├── useCases/ # Application business logic
|
|
68
|
+
│ │ ├── <UseCase>.ts # Single-responsibility use case class (@MakeInjectable)
|
|
69
|
+
│ │ └── <UseCase>.test.ts # Vitest unit test exercising use case with test stubs
|
|
70
|
+
│ ├── pxExpress/ # Presentation layer (@solid-stack/agnos-express)
|
|
71
|
+
│ │ ├── index.ts # Route prefix (e.g. export const path = "/<feature>")
|
|
72
|
+
│ │ └── handlers/
|
|
73
|
+
│ │ └── <Handler>Http.ts # Endpoint extending ExpressRoute with Zod validation
|
|
74
|
+
│ └── diProvider.ts # Feature DI module registering interface -> infrastructure bindings
|
|
75
|
+
└── shared/
|
|
76
|
+
└── <module>/ # Reusable cross-cutting utility or port (e.g. hasher, time, uuid, jwt)
|
|
77
|
+
├── ports/ # Abstract classes defining ports (e.g. IHashEngine.ts)
|
|
78
|
+
├── infrastructure/ # Test stubs (StubHashEngine.ts) & concrete engines (ScryptHashEngine.ts)
|
|
79
|
+
├── <Module>.ts # Primary @MakeInjectable service facade
|
|
80
|
+
├── domain/ # Value objects or custom domain error types
|
|
81
|
+
├── <Module>.test.ts # Vitest unit tests
|
|
82
|
+
└── diProvider.ts # Shared DI provider module
|
|
26
83
|
```
|
|
27
84
|
|
|
85
|
+
### Core Architecture Rules Enforced by Mason:
|
|
86
|
+
1. **Zero DI in Domain**: Entities and Value Objects never import `@solid-stack/di` or framework decorators.
|
|
87
|
+
2. **Abstract Classes as DI Tokens**: Abstract classes are used for repositories and ports instead of plain TypeScript interfaces because abstract classes preserve runtime identity in JavaScript, eliminating string-token DI collisions.
|
|
88
|
+
3. **Dedicated In-Memory Stubs**: Every domain interface and shared port receives an in-memory stub implementation with test manipulation methods (`clear()`, `setError()`, `setNextToken()`, `advance()`), making use case tests fast, deterministic, and dependency-free.
|
|
89
|
+
4. **Strict Import Portability**: Modules use TypeScript path aliases (`@/shared/*`, `@/features/*`), enabling automatic import rewriting when dependencies are aliased or relocated.
|
|
90
|
+
|
|
28
91
|
---
|
|
29
92
|
|
|
30
93
|
## 🚀 Installation & Quick Start
|
|
31
94
|
|
|
32
|
-
|
|
95
|
+
Mason can be executed directly on-demand or installed as a project dev dependency:
|
|
33
96
|
|
|
34
97
|
```bash
|
|
35
|
-
#
|
|
36
|
-
|
|
98
|
+
# Execute on-demand via pnpm dlx or npx
|
|
99
|
+
pnpm dlx @solid-stack/mason --help
|
|
100
|
+
# or
|
|
101
|
+
npx @solid-stack/mason --help
|
|
37
102
|
|
|
38
|
-
# Or
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
npx @solid-stack/create interface IUserRepository -f users
|
|
44
|
-
npx @solid-stack/create httpHandler CreateUserHttp -f users
|
|
45
|
-
npx @solid-stack/create injectable PasswordHasher
|
|
103
|
+
# Or install locally as a development dependency
|
|
104
|
+
pnpm add -D @solid-stack/mason
|
|
105
|
+
|
|
106
|
+
# Run directly via pnpm
|
|
107
|
+
pnpm mason --help
|
|
46
108
|
```
|
|
47
109
|
|
|
48
110
|
---
|
|
49
111
|
|
|
50
|
-
##
|
|
112
|
+
## ⚙️ Configuration (`mason.config.json`)
|
|
113
|
+
|
|
114
|
+
Mason works out of the box with sensible defaults (`src/features` and `src/shared`), but custom destination paths can be configured using a `mason.config.json` file in your project root:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"$schema": "https://raw.githubusercontent.com/solid-stack-digital/mason/main/schema.json",
|
|
119
|
+
"paths": {
|
|
120
|
+
"features": "src/features",
|
|
121
|
+
"shared": "src/shared"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
> [!NOTE]
|
|
127
|
+
> The schema definition exists in the Mason repository root as [`schema.json`](schema.json) and is distributed directly inside the `@solid-stack/mason` package (`@solid-stack/mason/schema.json`), providing full IDE auto-completion and validation.
|
|
128
|
+
|
|
129
|
+
### Configuration Options
|
|
51
130
|
|
|
52
|
-
|
|
53
|
-
|
|
131
|
+
| Option | Type | Default | Description |
|
|
132
|
+
| :--- | :--- | :--- | :--- |
|
|
133
|
+
| `$schema` | `string` | — | URI or local path pointing to the Mason JSON validation schema. |
|
|
134
|
+
| `paths.features` | `string` | `"src/features"` | Destination directory for feature slices. |
|
|
135
|
+
| `paths.shared` | `string` | `"src/shared"` | Destination directory for reusable shared modules. |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 🔄 CLI Architecture & Execution Modes
|
|
140
|
+
|
|
141
|
+
Mason provides a dual-interface CLI designed for both developer terminal usage and automated shell scripts / CI pipelines:
|
|
142
|
+
|
|
143
|
+
1. **Direct CLI Mode (Recommended for workflows & automation)**:
|
|
144
|
+
Pass subcommands, arguments, and flags directly. Use `-y` or `--yes` to bypass prompts and accept intelligent defaults.
|
|
145
|
+
```bash
|
|
146
|
+
pnpm mason create feature billing --yes
|
|
147
|
+
pnpm mason create usecase ProcessInvoice -f billing --yes
|
|
148
|
+
```
|
|
149
|
+
2. **Interactive Wizard Mode**:
|
|
150
|
+
Running `mason` or `mason create` without arguments launches an interactive wizard with guided selections and codebase discovery.
|
|
151
|
+
3. **Application Mode vs. Registry Mode**:
|
|
152
|
+
- **Application Mode (Default)**: Generates application code inside your project. Does not emit `registry.json` manifests.
|
|
153
|
+
- **Registry Mode (`--registry`)**: Used by module authors maintaining code registries (e.g. `mason-registry`). Emits stamped `registry.json` manifests containing version, dependency metadata, and file lists.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 🌐 Global CLI Flags
|
|
158
|
+
|
|
159
|
+
The following flags are supported across all Mason commands:
|
|
160
|
+
|
|
161
|
+
| Flag | Shorthand | Type | Description |
|
|
162
|
+
| :--- | :--- | :--- | :--- |
|
|
163
|
+
| `--help` | `-h` | `boolean` | Display help message and options for any command. |
|
|
164
|
+
| `--version` | `-v` | `boolean` | Display the current version of `@solid-stack/mason`. |
|
|
165
|
+
| `--dry-run` | `-d` | `boolean` | Preview file operations and transformations without writing to disk. |
|
|
166
|
+
| `--overwrite` | `-o` | `boolean` | Overwrite existing files if destination collisions are detected. |
|
|
167
|
+
| `--yes` | `-y` | `boolean` | Accept all recommended defaults and bypass interactive prompts for scripting. |
|
|
168
|
+
| `--target <dir>` | `-t` | `string` | Override the destination directory for the generated component. |
|
|
169
|
+
| `--dest <dir>` | | `string` | Alias for `--target <dir>`. |
|
|
170
|
+
| `--registry` | | `boolean` | Run or scaffold in registry mode (creates `registry.json` manifests). |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 🔨 Command Reference: Scaffolding (`create`)
|
|
175
|
+
|
|
176
|
+
All scaffolding subcommands can be invoked via the canonical syntax `mason create <type> [name] [options]` or using flat top-level aliases (`mason <type> [name] [options]`).
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### 1. `mason create feature [name]`
|
|
181
|
+
*(Shorthand: `mason feature [name]`)*
|
|
182
|
+
|
|
183
|
+
Scaffolds a complete, self-contained Clean Architecture vertical slice with domain models, repository interfaces, in-memory stubs, use cases, Express route handlers, and a DI provider module.
|
|
54
184
|
|
|
55
185
|
```bash
|
|
56
|
-
|
|
57
|
-
|
|
186
|
+
mason create feature <name> [options]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Arguments
|
|
190
|
+
- `[name]` *(string, optional)*: Name of the feature (e.g., `users`, `billing`, `orders`). Automatically converted to camelCase for directories and PascalCase for entities. Defaults to `"feature"` if omitted with `--yes`.
|
|
191
|
+
|
|
192
|
+
#### Options & Flags
|
|
193
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
194
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
195
|
+
| `--yes` | `-y` | `boolean` | `false` | Non-interactive mode; accepts all recommended defaults. |
|
|
196
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview generated files and paths without writing to disk. |
|
|
197
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing files if the feature directory already exists. |
|
|
198
|
+
| `--target <dir>` | `-t` | `string` | `src/features/<name>` | Custom destination directory for the feature slice. |
|
|
199
|
+
| `--dest <dir>` | | `string` | `src/features/<name>` | Alias for `--target`. |
|
|
200
|
+
| `--express` | | `boolean` | `true` | Include the Express presentation layer (`pxExpress/index.ts` and handlers). |
|
|
201
|
+
| `--no-express` | | `boolean` | `false` | Exclude Express presentation layer (creates a headless core feature slice). |
|
|
202
|
+
| `--domainNames <names>` | | `string` | Singular feature name | Comma-separated list of domain entity names to bootstrap (e.g. `Product,Category`). |
|
|
203
|
+
| `--registry` | | `boolean` | `false` | Scaffold in registry mode (generates `registry.json` manifest). |
|
|
204
|
+
| `--description <text>` | | `string` | `"<name> feature module"` | Module description for `registry.json` in registry mode. |
|
|
205
|
+
|
|
206
|
+
#### Generated Vertical Slice Structure
|
|
207
|
+
```text
|
|
208
|
+
src/features/billing/
|
|
209
|
+
├── domain/
|
|
210
|
+
│ ├── Invoice.ts # Pure domain entity
|
|
211
|
+
│ └── IInvoiceRepo.ts # Abstract class serving as DI token & contract
|
|
212
|
+
├── infrastructure/
|
|
213
|
+
│ └── StubInvoiceRepo.ts # In-memory test stub with manipulation helpers
|
|
214
|
+
├── useCases/
|
|
215
|
+
│ ├── CreateInvoice.ts # Business logic class with @MakeInjectable
|
|
216
|
+
│ ├── CreateInvoice.test.ts # Vitest unit test pre-wired with StubInvoiceRepo
|
|
217
|
+
│ ├── GetInvoice.ts
|
|
218
|
+
│ ├── ListInvoices.ts
|
|
219
|
+
│ ├── UpdateInvoice.ts
|
|
220
|
+
│ └── DeleteInvoice.ts
|
|
221
|
+
├── pxExpress/
|
|
222
|
+
│ ├── index.ts # Route prefix export (e.g. path = "/billing")
|
|
223
|
+
│ └── handlers/
|
|
224
|
+
│ ├── CreateInvoiceHttp.ts # ExpressRoute endpoint with Zod validation
|
|
225
|
+
│ ├── GetInvoiceHttp.ts
|
|
226
|
+
│ ├── ListInvoicesHttp.ts
|
|
227
|
+
│ ├── UpdateInvoiceHttp.ts
|
|
228
|
+
│ └── DeleteInvoiceHttp.ts
|
|
229
|
+
└── diProvider.ts # DI module binding IInvoiceRepo -> StubInvoiceRepo
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
58
233
|
|
|
59
|
-
|
|
60
|
-
|
|
234
|
+
### 2. `mason create shared [name]`
|
|
235
|
+
*(Shorthand: `mason shared [name]`)*
|
|
61
236
|
|
|
62
|
-
|
|
63
|
-
npx @solid-stack/create feature orders --yes
|
|
237
|
+
Scaffolds a reusable shared utility module with abstract ports, in-memory stubs, facade classes, and DI registration.
|
|
64
238
|
|
|
65
|
-
|
|
66
|
-
|
|
239
|
+
```bash
|
|
240
|
+
mason create shared <name> [options]
|
|
67
241
|
```
|
|
68
242
|
|
|
69
|
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
|
|
243
|
+
#### Arguments
|
|
244
|
+
- `[name]` *(string, optional)*: Shared module name (e.g., `hasher`, `time`, `uuid`, `cache`, `logger`). Converted to kebab-case. Defaults to `"shared"` if omitted with `--yes`.
|
|
245
|
+
|
|
246
|
+
#### Options & Flags
|
|
247
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
248
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
249
|
+
| `--yes` | `-y` | `boolean` | `false` | Non-interactive mode; accepts all recommended defaults. |
|
|
250
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview generated files without writing to disk. |
|
|
251
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing files if module directory exists. |
|
|
252
|
+
| `--target <dir>` | `-t` | `string` | `src/shared/<name>` | Custom destination directory for the shared module. |
|
|
253
|
+
| `--dest <dir>` | | `string` | `src/shared/<name>` | Alias for `--target`. |
|
|
254
|
+
| `--description <text>` | | `string` | `""` | Description of the shared module. |
|
|
255
|
+
| `--registry` | | `boolean` | `false` | Scaffold in registry mode (generates `registry.json` manifest). |
|
|
256
|
+
|
|
257
|
+
#### Generated Structure
|
|
258
|
+
```text
|
|
259
|
+
src/shared/cache/
|
|
260
|
+
├── ports/
|
|
261
|
+
│ └── ICacheEngine.ts # Abstract class defining the port contract
|
|
262
|
+
├── infrastructure/
|
|
263
|
+
│ └── StubCacheEngine.ts # In-memory test stub for deterministic tests
|
|
264
|
+
├── Cache.ts # Primary injectable facade service
|
|
265
|
+
├── Cache.test.ts # Vitest unit tests
|
|
266
|
+
└── diProvider.ts # DI module registering ICacheEngine -> StubCacheEngine
|
|
267
|
+
```
|
|
78
268
|
|
|
79
269
|
---
|
|
80
270
|
|
|
81
|
-
###
|
|
82
|
-
|
|
271
|
+
### 3. `mason create usecase [name]`
|
|
272
|
+
*(Shorthand: `mason usecase [name]`)*
|
|
273
|
+
|
|
274
|
+
Scaffolds a single-responsibility application use case class decorated with `@MakeInjectable`, typed input/output DTOs, and an accompanying Vitest unit test.
|
|
83
275
|
|
|
84
276
|
```bash
|
|
85
|
-
|
|
277
|
+
mason create usecase <name> [options]
|
|
86
278
|
```
|
|
87
279
|
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
280
|
+
#### Arguments
|
|
281
|
+
- `[name]` *(string, optional)*: Name of the use case (e.g., `PlaceOrder`, `ResetPassword`, `VerifyEmail`). Converted to PascalCase.
|
|
282
|
+
|
|
283
|
+
#### Options & Flags
|
|
284
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
285
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
286
|
+
| `-f, --feature <feature>` | `-f` | `string` | None | Target feature slice (required in non-interactive CLI mode). |
|
|
287
|
+
| `--yes` | `-y` | `boolean` | `false` | Accept defaults; skips interactive input/output property prompts. |
|
|
288
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview changes without writing to disk. |
|
|
289
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing use case files. |
|
|
290
|
+
|
|
291
|
+
#### Generated Files
|
|
292
|
+
- `src/features/<feature>/useCases/<UseCase>.ts`: Contains input DTO, output DTO, static dependencies injection mapping, and `execute()` method.
|
|
293
|
+
- `src/features/<feature>/useCases/<UseCase>.test.ts`: Vitest test skeleton pre-wired with feature test stubs.
|
|
96
294
|
|
|
97
295
|
---
|
|
98
296
|
|
|
99
|
-
###
|
|
100
|
-
|
|
297
|
+
### 4. `mason create domain [name]`
|
|
298
|
+
*(Shorthand: `mason domain [name]`)*
|
|
299
|
+
|
|
300
|
+
Scaffolds a pure domain model, entity class, or value object without framework dependencies.
|
|
101
301
|
|
|
102
302
|
```bash
|
|
103
|
-
|
|
303
|
+
mason create domain <name> [options]
|
|
104
304
|
```
|
|
105
305
|
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
306
|
+
#### Arguments
|
|
307
|
+
- `[name]` *(string, optional)*: Domain entity name (e.g., `User`, `Order`, `Money`). Converted to PascalCase.
|
|
308
|
+
|
|
309
|
+
#### Options & Flags
|
|
310
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
311
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
312
|
+
| `-f, --feature <feature>` | `-f` | `string` | None | Target feature slice (required in non-interactive CLI mode). |
|
|
313
|
+
| `--yes` | `-y` | `boolean` | `false` | Accept defaults (generates TypeScript interface with `id`, `createdAt`, `updatedAt`). |
|
|
314
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview generated file without writing to disk. |
|
|
315
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing domain file. |
|
|
316
|
+
|
|
317
|
+
#### Supported Domain Models
|
|
318
|
+
- **TypeScript Interface**: Pure data contract for lightweight domain models.
|
|
319
|
+
- **Entity Class**: Class with constructor, properties, and encapsulation methods.
|
|
320
|
+
- **Value Object**: Immutable model with private constructor, static factory `create()`, and `equals()` equality method.
|
|
114
321
|
|
|
115
322
|
---
|
|
116
323
|
|
|
117
|
-
###
|
|
118
|
-
|
|
324
|
+
### 5. `mason create interface [name]`
|
|
325
|
+
*(Shorthand: `mason interface [name]`)*
|
|
326
|
+
|
|
327
|
+
Scaffolds a domain repository or service interface abstract class, auto-generates an in-memory test stub in `infrastructure/`, and updates `diProvider.ts`.
|
|
119
328
|
|
|
120
329
|
```bash
|
|
121
|
-
|
|
330
|
+
mason create interface <name> [options]
|
|
122
331
|
```
|
|
123
332
|
|
|
124
|
-
|
|
125
|
-
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
333
|
+
#### Arguments
|
|
334
|
+
- `[name]` *(string, optional)*: Interface name (e.g., `IUserRepository`, `IOrderRepo`). Automatically prefixed with `I` if omitted.
|
|
335
|
+
|
|
336
|
+
#### Options & Flags
|
|
337
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
338
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
339
|
+
| `-f, --feature <feature>` | `-f` | `string` | None | Target feature slice (required in non-interactive CLI mode). |
|
|
340
|
+
| `--entity <entity>` | | `string` | Inferred | Associated domain entity name for method signature generation. |
|
|
341
|
+
| `--yes` | `-y` | `boolean` | `false` | Non-interactive mode (creates abstract class, CRUD signatures, stub, and DI provider entry). |
|
|
342
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview generated files without writing to disk. |
|
|
343
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing interface or stub files. |
|
|
132
344
|
|
|
133
345
|
---
|
|
134
346
|
|
|
135
|
-
###
|
|
136
|
-
|
|
347
|
+
### 6. `mason create infrastructure [name]`
|
|
348
|
+
*(Shorthand: `mason infrastructure [name]`)*
|
|
349
|
+
|
|
350
|
+
Scaffolds an infrastructure adapter (e.g. database repository, cloud client) or an in-memory test stub implementing a domain interface.
|
|
137
351
|
|
|
138
352
|
```bash
|
|
139
|
-
|
|
140
|
-
|
|
353
|
+
mason create infrastructure <name> [options]
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### Arguments
|
|
357
|
+
- `[name]` *(string, optional)*: Class name (e.g., `PostgresUserRepository`, `StubOrderRepo`, `S3StorageAdapter`). Converted to PascalCase.
|
|
358
|
+
|
|
359
|
+
#### Options & Flags
|
|
360
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
361
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
362
|
+
| `-f, --feature <feature>` | `-f` | `string` | None | Target feature slice (when scoped to a feature). |
|
|
363
|
+
| `-g, --global` | `-g` | `boolean` | `false` | Place in global `src/infrastructure/` instead of inside a feature slice. |
|
|
364
|
+
| `-i, --interface <iface>` | `-i` | `string` | Inferred | Domain interface or abstract class implemented by this class. |
|
|
365
|
+
| `-k, --kind <kind>` | `-k` | `"stub" \| "concrete"` | Inferred | Implementation kind (`stub` with test helpers or `concrete` with `@MakeInjectable`). Inferred from `Stub` prefix. |
|
|
366
|
+
| `--no-provider` | | `boolean` | `false` | Skip automatic registration in feature `diProvider.ts` when using `-y`. |
|
|
367
|
+
| `--yes` | `-y` | `boolean` | `false` | Non-interactive mode; accepts defaults. |
|
|
368
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview generated files without writing to disk. |
|
|
369
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing implementation files. |
|
|
370
|
+
|
|
371
|
+
---
|
|
141
372
|
|
|
142
|
-
|
|
143
|
-
|
|
373
|
+
### 7. `mason create httpHandler [name]`
|
|
374
|
+
*(Shorthand: `mason httpHandler [name]`)*
|
|
144
375
|
|
|
145
|
-
|
|
146
|
-
|
|
376
|
+
Scaffolds an Express endpoint handler extending `ExpressRoute` for `@solid-stack/agnos-express`, configured with dependency injection, use case execution, and Zod input validation.
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
mason create httpHandler <name> [options]
|
|
147
380
|
```
|
|
148
381
|
|
|
149
|
-
|
|
150
|
-
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
382
|
+
#### Arguments
|
|
383
|
+
- `[name]` *(string, optional)*: HTTP Route Handler class name (e.g., `CreateUserHttp`, `GetUserHttp`). Automatically appends `Http` suffix if omitted.
|
|
384
|
+
|
|
385
|
+
#### Options & Flags
|
|
386
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
387
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
388
|
+
| `-f, --feature <feature>` | `-f` | `string` | None | Target feature slice (required in non-interactive CLI mode). |
|
|
389
|
+
| `-m, --method <method>` | `-m` | `"get" \| "post" \| "put" \| "patch" \| "delete"` | `"get"` | HTTP method for the route. |
|
|
390
|
+
| `-p, --path <path>` | `-p` | `string` | `"/"` | Route subpath relative to feature route prefix (e.g. `/`, `/:id`, `/search`). |
|
|
391
|
+
| `-u, --usecase <usecase>` | `-u` | `string` | None | Name of the domain use case class to inject and execute. |
|
|
392
|
+
| `--message <message>` | | `string` | None | Custom success message returned in the standard HTTP response JSON. |
|
|
393
|
+
| `--yes` | `-y` | `boolean` | `false` | Non-interactive mode; accepts defaults. |
|
|
394
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview generated files without writing to disk. |
|
|
395
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing handler files. |
|
|
156
396
|
|
|
157
397
|
---
|
|
158
398
|
|
|
159
|
-
###
|
|
160
|
-
|
|
399
|
+
### 8. `mason create injectable [name]`
|
|
400
|
+
*(Shorthand: `mason injectable [name]`)*
|
|
401
|
+
|
|
402
|
+
Scaffolds a general-purpose class decorated with `@MakeInjectable` for services, transformers, or utilities.
|
|
161
403
|
|
|
162
404
|
```bash
|
|
163
|
-
|
|
405
|
+
mason create injectable <name> [options]
|
|
164
406
|
```
|
|
165
407
|
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
408
|
+
#### Arguments
|
|
409
|
+
- `[name]` *(string, optional)*: Injectable class name (e.g., `PasswordHasher`, `TokenService`, `UserTransformer`). Converted to PascalCase.
|
|
410
|
+
|
|
411
|
+
#### Options & Flags
|
|
412
|
+
| Flag | Shorthand | Type | Default | Description |
|
|
413
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
414
|
+
| `-f, --feature <feature>` | `-f` | `string` | None | Target feature to scope the service into (`features/<feature>/services/`). |
|
|
415
|
+
| `-t, --target <dir>` | `-t` | `string` | None | Custom destination directory path. |
|
|
416
|
+
| `--dest <dir>` | | `string` | None | Alias for `--target`. |
|
|
417
|
+
| `--yes` | `-y` | `boolean` | `false` | Non-interactive mode; accepts defaults. |
|
|
418
|
+
| `--dry-run` | `-d` | `boolean` | `false` | Preview generated file without writing to disk. |
|
|
419
|
+
| `--overwrite` | `-o` | `boolean` | `false` | Overwrite existing injectable files. |
|
|
174
420
|
|
|
175
421
|
---
|
|
176
422
|
|
|
177
|
-
|
|
178
|
-
|
|
423
|
+
## 📦 Command Reference: Registry Import (`import`)
|
|
424
|
+
|
|
425
|
+
Mason includes a package and module registry client that downloads verified pre-built modules from the **Solid Stack Registry** into your project, automatically resolving recursive dependency graphs, handling cryptographic drift, rewriting import paths, and installing required npm packages.
|
|
426
|
+
|
|
427
|
+
### Import Command Syntax
|
|
179
428
|
|
|
180
429
|
```bash
|
|
181
|
-
|
|
182
|
-
npx @solid-stack/create injectable UserTransformer -f users
|
|
430
|
+
mason import [type] [name] [options]
|
|
183
431
|
```
|
|
184
432
|
|
|
185
|
-
|
|
186
|
-
-
|
|
187
|
-
- Architectural location:
|
|
188
|
-
- Feature Service (`features/<feature>/services/`)
|
|
189
|
-
- Feature Transformer (`features/<feature>/pxExpress/transformers/`)
|
|
190
|
-
- Shared Service (`shared/<name>/`)
|
|
191
|
-
- Core Module (`modules/<name>/`)
|
|
192
|
-
- Custom path
|
|
193
|
-
- Injected dependencies
|
|
194
|
-
- Generate runtime abstract class interface / DI token
|
|
433
|
+
- `[type]`: Module type to import: `shared` or `feature` (or `features`).
|
|
434
|
+
- `[name]`: Name of the module from the registry (e.g., `hasher`, `authn`, `jwt`, `time`, `uuid`).
|
|
195
435
|
|
|
196
436
|
---
|
|
197
437
|
|
|
198
|
-
|
|
438
|
+
### Import Options & Flags
|
|
439
|
+
|
|
440
|
+
| Flag | Shorthand | Type | Description |
|
|
441
|
+
| :--- | :--- | :--- | :--- |
|
|
442
|
+
| `--registry <url \| path>` | | `string` | Override the registry URL or specify a local directory path (e.g. `../mason-registry`). |
|
|
443
|
+
| `--tests` | | `boolean` | Include unit test files from the registry (default: `true`). |
|
|
444
|
+
| `--no-tests` | | `boolean` | Exclude unit test files during import, leaving only production code. |
|
|
445
|
+
| `--alias <mapping>` | | `string` | Programmatically import a conflicting dependency under a new alias name (e.g. `--alias time:time-mason`). |
|
|
446
|
+
| `--point-to <mapping>` | | `string` | Point a dependency to an existing local module without downloading duplicates (e.g. `--point-to time:mytime`). |
|
|
447
|
+
| `--use-existing <mapping>` | | `string` | Alias for `--point-to <mapping>`. |
|
|
448
|
+
| `-o, --overwrite` | `-o` | `boolean` | Overwrite existing local files with registry copies without prompting. |
|
|
449
|
+
| `--skip-install` | | `boolean` | Skip automatic detection and installation of missing npm packages via package manager. |
|
|
450
|
+
| `-y, --yes` | `-y` | `boolean` | Accept all defaults non-interactively; keeps existing local versions on conflict and skips prompts. |
|
|
451
|
+
| `-d, --dry-run` | `-d` | `boolean` | Preview files to be downloaded and import rewrites without writing to disk. |
|
|
199
452
|
|
|
200
|
-
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
### Cryptographic Drift Detection & Resolution Flags
|
|
456
|
+
|
|
457
|
+
Mason calculates composite SHA-256 hashes of local source code (normalizing line endings) and compares them against remote registry integrity hashes.
|
|
458
|
+
|
|
459
|
+
When local modules have drifted or differ from registry versions, CLI flags provide deterministic, non-interactive control:
|
|
460
|
+
|
|
461
|
+
1. **Keep Existing Local Version (Default in `-y` mode)**:
|
|
462
|
+
Keeps your customized local files intact. Incoming dependent modules are linked to your local module.
|
|
463
|
+
2. **Import Fresh Copy Under an Alias (`--alias <dep>:<new-name>`)**:
|
|
464
|
+
Downloads the registry dependency into `src/shared/<new-name>`. Mason **automatically rewrites all TypeScript import paths** across all dependent files to point to the new alias.
|
|
465
|
+
```bash
|
|
466
|
+
pnpm mason import feature authn --alias time:time-mason -y
|
|
467
|
+
```
|
|
468
|
+
3. **Point to Another Existing Module (`--point-to <dep>:<existing-name>`)**:
|
|
469
|
+
Re-links the dependency to a different local module. Zero duplicate files are downloaded, and Mason rewrites all import paths to point to `@/shared/<existing-name>`.
|
|
470
|
+
```bash
|
|
471
|
+
pnpm mason import feature authn --point-to time:mytime -y
|
|
472
|
+
```
|
|
473
|
+
4. **Overwrite Local Version (`--overwrite` / `-o`)**:
|
|
474
|
+
Replaces the local diverged files with clean registry copies.
|
|
475
|
+
```bash
|
|
476
|
+
pnpm mason import feature authn --overwrite -y
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
### Test Files Management
|
|
482
|
+
|
|
483
|
+
Every registry module includes full unit test suites (e.g. `Hasher.test.ts`, `Login.test.ts`).
|
|
484
|
+
|
|
485
|
+
- **Include Tests (Default / `--tests`)**: Downloads test files and rewrites all path aliases so tests pass immediately in Vitest.
|
|
486
|
+
- **Exclude Tests (`--no-tests`)**: Omits test files for a minimal production footprint.
|
|
487
|
+
- **Integrity Invariance**: Registry integrity hashes are calculated exclusively on non-test source files. Module hashes remain 100% valid whether tests are included or excluded.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## 💻 Programmatic TypeScript API
|
|
492
|
+
|
|
493
|
+
Mason can be used programmatically in custom generators, node scripts, or CI automation:
|
|
201
494
|
|
|
202
495
|
```typescript
|
|
203
496
|
import {
|
|
204
497
|
generateFeature,
|
|
498
|
+
generateShared,
|
|
205
499
|
generateUseCase,
|
|
206
500
|
generateDomain,
|
|
207
501
|
generateInterface,
|
|
208
502
|
generateInfrastructure,
|
|
209
503
|
generateHttpHandler,
|
|
210
504
|
generateInjectable,
|
|
211
|
-
|
|
212
|
-
|
|
505
|
+
rewriteImports,
|
|
506
|
+
computeDirectoryHash,
|
|
507
|
+
isTestFile,
|
|
508
|
+
} from "@solid-stack/mason";
|
|
213
509
|
|
|
214
|
-
//
|
|
510
|
+
// 1. Programmatically scaffold a feature
|
|
215
511
|
const files = generateFeature({
|
|
216
|
-
name: "
|
|
512
|
+
name: "notifications",
|
|
513
|
+
projectRoot: process.cwd(),
|
|
217
514
|
includeExpress: true,
|
|
218
515
|
includeTests: true,
|
|
219
516
|
});
|
|
517
|
+
|
|
518
|
+
// 2. Programmatically rewrite import strings
|
|
519
|
+
const rewritten = rewriteImports(
|
|
520
|
+
`import { Clock } from "@/shared/time/Clock.js";`,
|
|
521
|
+
new Map([["@/shared/time", "@/shared/custom-time"]])
|
|
522
|
+
);
|
|
523
|
+
// Output: 'import { Clock } from "@/shared/custom-time/Clock.js";'
|
|
524
|
+
|
|
525
|
+
// 3. Compute deterministic directory hash (invariant to line endings & test files)
|
|
526
|
+
const hash = computeDirectoryHash("./src/shared/hasher");
|
|
527
|
+
console.log(hash); // 'sha256-09ebf144dd06...'
|
|
220
528
|
```
|
|
221
529
|
|
|
222
530
|
---
|
|
223
531
|
|
|
224
|
-
##
|
|
532
|
+
## 🐳 Docker, Testing & Makefiles
|
|
533
|
+
|
|
534
|
+
Mason is verified with Docker, Docker Compose, and Makefiles for hermetic reliability.
|
|
535
|
+
|
|
536
|
+
### Available Makefile Targets
|
|
225
537
|
|
|
226
|
-
| Command | Description |
|
|
227
|
-
|
|
|
228
|
-
| `
|
|
229
|
-
| `
|
|
230
|
-
| `
|
|
231
|
-
| `
|
|
232
|
-
| `
|
|
538
|
+
| Target | Command | Description |
|
|
539
|
+
| :--- | :--- | :--- |
|
|
540
|
+
| `make test` | `docker compose up --build test` | Runs the full test suite in an isolated Linux container with a fresh build. |
|
|
541
|
+
| `make test/cache` | `docker compose up test` | Runs the test suite in Docker using cached image layers for maximum speed. |
|
|
542
|
+
| `make dev` | `docker compose up dev` | Runs the watcher in a container with mounted source volumes. |
|
|
543
|
+
| `make build` | `docker compose up --build build` | Builds the production distribution packages inside Docker. |
|
|
544
|
+
| `make clean` | `docker compose down -v --remove-orphans` | Tears down all containers, volumes, and temporary networks. |
|
|
545
|
+
|
|
546
|
+
### Local Development Commands
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
pnpm dev # Start tsup watcher
|
|
550
|
+
pnpm build # Compile ESM/CJS bundles to dist/
|
|
551
|
+
pnpm test # Run Vitest unit tests
|
|
552
|
+
pnpm typecheck # Typecheck TypeScript without emitting (tsc --noEmit)
|
|
553
|
+
pnpm check # Run typecheck, tests, and build in sequence
|
|
554
|
+
```
|
|
233
555
|
|
|
234
556
|
---
|
|
235
557
|
|
|
236
558
|
## 📄 License
|
|
237
559
|
|
|
238
|
-
UNLICENSED © [Solid Stack Digital](https://github.com/solid-stack-digital)
|
|
560
|
+
UNLICENSED © [Solid Stack Digital](https://github.com/solid-stack-digital). All rights reserved.
|
|
561
|
+
|
|
562
|
+
Strictly confidential and proprietary. No part of this software may be used, copied, modified, distributed, sublicensed, or sold in any form or by any means without the prior written permission of the copyright owner. See [LICENSE](LICENSE) for full details.
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## 🎯 CLI Cookbook: Real-World Examples & Complex Cases
|
|
567
|
+
|
|
568
|
+
Below is an exhaustive collection of real-world use cases mapping specific developer objectives directly to Mason CLI commands.
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
### Basic Scaffolding Examples
|
|
573
|
+
|
|
574
|
+
#### 1. Scaffold a standard feature slice with default CRUD and Express routes
|
|
575
|
+
```bash
|
|
576
|
+
# Goal: Create a full 'users' feature slice non-interactively
|
|
577
|
+
pnpm mason create feature users --yes
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
#### 2. Scaffold a headless / backend-only feature slice (no Express presentation layer)
|
|
581
|
+
```bash
|
|
582
|
+
# Goal: Create an 'analytics' slice with domain and usecases only, omitting pxExpress/
|
|
583
|
+
pnpm mason create feature analytics --no-express --yes
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
#### 3. Scaffold a feature slice with multiple domain entities
|
|
587
|
+
```bash
|
|
588
|
+
# Goal: Create an 'inventory' feature with multiple domain entities (Product, Warehouse, StockLevel)
|
|
589
|
+
pnpm mason create feature inventory --domainNames Product,Warehouse,StockLevel --yes
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
#### 4. Scaffold a feature slice into a custom directory path
|
|
593
|
+
```bash
|
|
594
|
+
# Goal: Place the feature in a custom path or monorepo package
|
|
595
|
+
pnpm mason create feature billing --target packages/billing-service/src/features/billing --yes
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
#### 5. Preview feature generation without writing anything to disk (dry-run)
|
|
599
|
+
```bash
|
|
600
|
+
# Goal: Inspect generated files and directory paths without creating files
|
|
601
|
+
pnpm mason create feature orders --dry-run
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
#### 6. Force overwrite an existing feature slice with clean defaults
|
|
605
|
+
```bash
|
|
606
|
+
# Goal: Re-scaffold the 'auth' feature, replacing any colliding files
|
|
607
|
+
pnpm mason create feature auth --overwrite --yes
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
### Domain & Infrastructure Scaffolding
|
|
613
|
+
|
|
614
|
+
#### 7. Scaffold a domain entity model into a feature
|
|
615
|
+
```bash
|
|
616
|
+
# Goal: Add a 'Customer' domain entity to the 'customers' feature
|
|
617
|
+
pnpm mason create domain Customer -f customers --yes
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
#### 8. Scaffold a domain repository interface with automatic stub and DI binding
|
|
621
|
+
```bash
|
|
622
|
+
# Goal: Create ICustomerRepo, generate StubCustomerRepo, and wire them in diProvider.ts
|
|
623
|
+
pnpm mason create interface ICustomerRepo -f customers --entity Customer --yes
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
#### 9. Scaffold a concrete production database adapter implementing a domain interface
|
|
627
|
+
```bash
|
|
628
|
+
# Goal: Create PostgresCustomerRepo implementing ICustomerRepo with @MakeInjectable
|
|
629
|
+
pnpm mason create infrastructure PostgresCustomerRepo -f customers -i ICustomerRepo -k concrete --yes
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
#### 10. Scaffold an in-memory test stub for an existing domain interface
|
|
633
|
+
```bash
|
|
634
|
+
# Goal: Explicitly generate a test stub with in-memory map and test helper methods
|
|
635
|
+
pnpm mason create infrastructure StubCustomerRepo -f customers -i ICustomerRepo -k stub --yes
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
#### 11. Scaffold a global infrastructure service outside of feature slices
|
|
639
|
+
```bash
|
|
640
|
+
# Goal: Create a cross-cutting S3ObjectStorage adapter placed in src/infrastructure/
|
|
641
|
+
pnpm mason create infrastructure S3ObjectStorage --global -k concrete --yes
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
---
|
|
645
|
+
|
|
646
|
+
### Use Cases & HTTP Handler Scaffolding
|
|
647
|
+
|
|
648
|
+
#### 12. Add a new business logic use case to an existing feature
|
|
649
|
+
```bash
|
|
650
|
+
# Goal: Add a 'ChangePassword' use case class and test skeleton to 'auth'
|
|
651
|
+
pnpm mason create usecase ChangePassword -f auth --yes
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
#### 13. Scaffold a POST HTTP endpoint handler bound to a use case with a custom path and response message
|
|
655
|
+
```bash
|
|
656
|
+
# Goal: Create endpoint POST /billing/checkout executing ProcessCheckout usecase
|
|
657
|
+
pnpm mason create httpHandler ProcessCheckoutHttp -f billing -m post -p /checkout -u ProcessCheckout --message "Checkout processed successfully" --yes
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
#### 14. Scaffold a GET HTTP endpoint handler with route parameter
|
|
661
|
+
```bash
|
|
662
|
+
# Goal: Create endpoint GET /users/:id executing GetUser usecase
|
|
663
|
+
pnpm mason create httpHandler GetUserHttp -f users -m get -p /:id -u GetUser --yes
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
#### 15. Scaffold a general-purpose injectable service in a feature
|
|
667
|
+
```bash
|
|
668
|
+
# Goal: Create TokenGenerator service inside features/auth/services/
|
|
669
|
+
pnpm mason create injectable TokenGenerator -f auth --yes
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
### End-to-End Vertical Slice Construction Pipeline
|
|
675
|
+
|
|
676
|
+
The following scripted CLI pipeline demonstrates building a production-ready vertical slice from scratch with zero manual prompts:
|
|
677
|
+
|
|
678
|
+
```bash
|
|
679
|
+
#!/usr/bin/env bash
|
|
680
|
+
set -e
|
|
681
|
+
|
|
682
|
+
# Step 1: Scaffold feature slice without express routes initially
|
|
683
|
+
pnpm mason create feature subscriptions --no-express --yes
|
|
684
|
+
|
|
685
|
+
# Step 2: Add additional domain entity
|
|
686
|
+
pnpm mason create domain Plan -f subscriptions --yes
|
|
687
|
+
|
|
688
|
+
# Step 3: Create domain repository interface (auto-creates StubSubscriptionRepo & binds in diProvider.ts)
|
|
689
|
+
pnpm mason create interface ISubscriptionRepo -f subscriptions --entity Subscription --yes
|
|
690
|
+
|
|
691
|
+
# Step 4: Create concrete production adapter (e.g. Postgres repository)
|
|
692
|
+
pnpm mason create infrastructure PostgresSubscriptionRepo -f subscriptions -i ISubscriptionRepo -k concrete --yes
|
|
693
|
+
|
|
694
|
+
# Step 5: Create application use cases
|
|
695
|
+
pnpm mason create usecase ActivateSubscription -f subscriptions --yes
|
|
696
|
+
pnpm mason create usecase CancelSubscription -f subscriptions --yes
|
|
697
|
+
|
|
698
|
+
# Step 6: Create presentation HTTP endpoints extending ExpressRoute
|
|
699
|
+
pnpm mason create httpHandler ActivateSubscriptionHttp -f subscriptions -m post -p /activate -u ActivateSubscription --message "Subscription activated" --yes
|
|
700
|
+
pnpm mason create httpHandler CancelSubscriptionHttp -f subscriptions -m post -p /cancel -u CancelSubscription --message "Subscription cancelled" --yes
|
|
701
|
+
|
|
702
|
+
# Step 7: Run tests to verify generated code passes immediately
|
|
703
|
+
pnpm test
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
### Shared Module & Registry Authoring Examples
|
|
709
|
+
|
|
710
|
+
#### 16. Scaffold a reusable shared module with description
|
|
711
|
+
```bash
|
|
712
|
+
# Goal: Create a shared cache module with ports, stubs, and facade
|
|
713
|
+
pnpm mason create shared cache --description "Multi-tier memory and Redis caching abstraction" --yes
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
#### 17. Scaffold a shared module in Registry Mode (`registry.json`)
|
|
717
|
+
```bash
|
|
718
|
+
# Goal: Scaffold shared module with an author manifest for publishing to mason-registry
|
|
719
|
+
pnpm mason create shared logger --description "Structured Pino logger port and stub" --registry --yes
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
#### 18. Scaffold a feature slice in Registry Mode
|
|
723
|
+
```bash
|
|
724
|
+
# Goal: Scaffold a complete reusable feature with registry.json manifest
|
|
725
|
+
pnpm mason create feature payments --description "Stripe and PayPal payment processing slice" --registry --yes
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
730
|
+
### Registry Import: Simple to Highly Complex Scenarios
|
|
731
|
+
|
|
732
|
+
#### 19. Import a shared utility module from the official registry
|
|
733
|
+
```bash
|
|
734
|
+
# Goal: Download pre-built 'hasher' module (Argon2/Scrypt port and stubs) into src/shared/hasher
|
|
735
|
+
pnpm mason import shared hasher --yes
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
#### 20. Import a complete feature slice with all transitive dependencies
|
|
739
|
+
```bash
|
|
740
|
+
# Goal: Import 'authn' feature; automatically imports dependencies (hasher, jwt, time, uuid, otp)
|
|
741
|
+
pnpm mason import feature authn --yes
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
#### 21. Import a module excluding unit tests for lean production deployments
|
|
745
|
+
```bash
|
|
746
|
+
# Goal: Download only runtime code, omitting *.test.ts and test fixtures
|
|
747
|
+
pnpm mason import feature authn --no-tests --yes
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
#### 22. Import without running the package manager (skip npm/pnpm install)
|
|
751
|
+
```bash
|
|
752
|
+
# Goal: Defer package installation in CI or scripted environments
|
|
753
|
+
pnpm mason import feature authn --skip-install --yes
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
#### 23. Import from a local directory registry (Monorepo or local development)
|
|
757
|
+
```bash
|
|
758
|
+
# Goal: Import directly from a local repository clone rather than remote GitHub
|
|
759
|
+
pnpm mason import shared hasher --registry ../mason-registry --yes
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
#### 24. Complex Case: Resolving drift by aliasing a dependency to a clean copy (`--alias`)
|
|
763
|
+
```bash
|
|
764
|
+
# Scenario:
|
|
765
|
+
# Your project already contains a customized 'src/shared/time' module.
|
|
766
|
+
# The incoming 'authn' feature requires the official registry version of 'time'.
|
|
767
|
+
#
|
|
768
|
+
# Goal: Download registry 'time' under 'time-mason' and automatically rewrite all imports
|
|
769
|
+
# in 'authn' and 'jwt' from '@/shared/time/*' to '@/shared/time-mason/*' without touching local 'time'.
|
|
770
|
+
pnpm mason import feature authn --alias time:time-mason --yes
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
#### 25. Complex Case: Resolving drift by pointing a dependency to an existing module (`--point-to`)
|
|
774
|
+
```bash
|
|
775
|
+
# Scenario:
|
|
776
|
+
# Your project has an existing custom module at 'src/shared/myhasher'.
|
|
777
|
+
# The incoming 'authn' feature depends on 'shared/hasher'.
|
|
778
|
+
#
|
|
779
|
+
# Goal: Reuse 'myhasher' with zero duplicate downloads and rewrite all imports
|
|
780
|
+
# in 'authn' from '@/shared/hasher/*' to '@/shared/myhasher/*'.
|
|
781
|
+
pnpm mason import feature authn --point-to hasher:myhasher --yes
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
#### 26. Complex Case: Multi-dependency resolution in a single automated command
|
|
785
|
+
```bash
|
|
786
|
+
# Scenario:
|
|
787
|
+
# Importing 'authn' which depends on 'time', 'hasher', and 'uuid'.
|
|
788
|
+
# - 'time' has local drift -> alias to fresh copy 'time-upstream'
|
|
789
|
+
# - 'hasher' exists locally as 'custom-hasher' -> point to 'custom-hasher'
|
|
790
|
+
# - Exclude test files to keep project lean
|
|
791
|
+
# - Skip package manager installation
|
|
792
|
+
# - Fully non-interactive execution
|
|
793
|
+
pnpm mason import feature authn \
|
|
794
|
+
--alias time:time-upstream \
|
|
795
|
+
--point-to hasher:custom-hasher \
|
|
796
|
+
--no-tests \
|
|
797
|
+
--skip-install \
|
|
798
|
+
--yes
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
#### 27. Complex Case: Force complete upstream overwrite in CI/CD pipelines
|
|
802
|
+
```bash
|
|
803
|
+
# Scenario:
|
|
804
|
+
# Automated nightly update job synchronizing core features against upstream registry.
|
|
805
|
+
# Overwrite any local modifications with canonical registry versions.
|
|
806
|
+
pnpm mason import feature authn --overwrite --yes
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
#### 28. Complex Case: Dry-run previewing topological resolution and import rewrites
|
|
810
|
+
```bash
|
|
811
|
+
# Scenario:
|
|
812
|
+
# Inspecting what modules, files, and import rewrites will occur without modifying the workspace.
|
|
813
|
+
pnpm mason import feature authn --alias time:time-v2 --dry-run
|
|
814
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solid-stack/mason",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "An interactive, type-safe CLI generator for scaffolding Solid Stack Clean Architecture features, usecases, domain entities, infrastructure, interfaces, httpHandlers, and injectables.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"dist",
|
|
24
|
-
"templates"
|
|
24
|
+
"templates",
|
|
25
|
+
"schema.json"
|
|
25
26
|
],
|
|
26
27
|
"keywords": [
|
|
27
28
|
"solid-stack",
|
package/schema.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/solid-stack-digital/mason/main/schema.json",
|
|
4
|
+
"title": "MasonConfig",
|
|
5
|
+
"description": "Configuration schema for Solid Stack Mason CLI (mason.config.json)",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "URL or path to the JSON Schema"
|
|
11
|
+
},
|
|
12
|
+
"paths": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"description": "Custom destination directory paths for features and shared modules",
|
|
15
|
+
"properties": {
|
|
16
|
+
"features": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Destination directory for feature slices (default: 'src/features')"
|
|
19
|
+
},
|
|
20
|
+
"shared": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "Destination directory for reusable shared modules (default: 'src/shared')"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"additionalProperties": false
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"additionalProperties": false
|
|
29
|
+
}
|