@alveolus/arch 0.3.0 → 0.4.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/dist/index.d.mts CHANGED
@@ -231,16 +231,12 @@ type Upstreams = Readonly<Record<string, readonly string[]>>;
231
231
  declare class ContextMap {
232
232
  private readonly upstreams;
233
233
  constructor(upstreams: Upstreams);
234
- static ofEdges(edges: readonly {
235
- readonly from: string;
236
- readonly to: string;
237
- }[]): ContextMap;
238
234
  get contexts(): string[];
235
+ get consumed(): string[];
236
+ selfConsumers(): string[];
239
237
  allows(from: string, to: string): boolean;
240
238
  cycle(): string[] | undefined;
241
- cycleThrough(from: string, to: string): boolean;
242
239
  private cycleFrom;
243
- private reaches;
244
240
  }
245
241
  //#endregion
246
242
  //#region src/architecture/settings.d.ts
@@ -258,7 +254,7 @@ interface Settings {
258
254
  readonly contextFolders: readonly ContextFolder[];
259
255
  readonly compositionRoot: string;
260
256
  readonly extraFolders: ExtraFolders;
261
- readonly contextMap: ContextMap | undefined;
257
+ readonly contextMap: ContextMap;
262
258
  readonly domainDependencies: AllowedPackages;
263
259
  readonly applicationDependencies: AllowedPackages;
264
260
  }
@@ -357,7 +353,7 @@ export declare class Architecture {
357
353
  get files(): readonly SourceFile[];
358
354
  get domainDependencies(): AllowedPackages;
359
355
  get applicationDependencies(): AllowedPackages;
360
- get contextMap(): ContextMap | undefined;
356
+ get contextMap(): ContextMap;
361
357
  locationOf(file: SourceFile): Location;
362
358
  locationOfTarget(target: FileTarget$1): Location;
363
359
  shapeIssueOf(location: Location): ShapeIssue | undefined;
@@ -587,6 +583,9 @@ export declare class Cli {
587
583
  //#endregion
588
584
  //#region src/config/alveolus-config.d.ts
589
585
  type RuleSetting = "error" | "warn" | "info" | "off";
586
+ type ContextMapConfig = Readonly<Record<string, {
587
+ readonly consumes: readonly string[];
588
+ }>>;
590
589
  interface LayoutConfig {
591
590
  readonly extraFolders?: Readonly<Partial<Record<"domain" | "application", readonly string[]>>>;
592
591
  }
@@ -596,7 +595,7 @@ interface AlveolusConfig {
596
595
  readonly boundedContexts: Readonly<Record<string, string>>;
597
596
  readonly sharedKernel?: string;
598
597
  readonly subdomains?: Subdomains;
599
- readonly contextMap?: Upstreams;
598
+ readonly contextMap: ContextMapConfig;
600
599
  readonly compositionRoot?: string;
601
600
  readonly domainDependencies?: PackageDependencies;
602
601
  readonly applicationDependencies?: PackageDependencies;
@@ -615,7 +614,7 @@ export declare class Config implements CheckSettings {
615
614
  readonly applicationDependencies: AllowedPackages;
616
615
  readonly contextFolders: readonly ContextFolder[];
617
616
  readonly extraFolders: ExtraFolders;
618
- readonly contextMap: ContextMap | undefined;
617
+ readonly contextMap: ContextMap;
619
618
  private readonly ignored;
620
619
  private readonly rules;
621
620
  constructor(config: AlveolusConfig, projectDir: string);
@@ -649,5 +648,5 @@ export declare class Init {
649
648
  private write;
650
649
  }
651
650
  //#endregion
652
- export type { AlveolusConfig, CheckSettings, Finding, FindingData, ImportScope, PackageDependencies, RuleId, RuleMeta, RuleSetting, Settings, Violation, Written };
651
+ export type { AlveolusConfig, CheckSettings, ContextMapConfig, Finding, FindingData, ImportScope, PackageDependencies, RuleId, RuleMeta, RuleSetting, Settings, Violation, Written };
653
652
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":["Project","FileTarget","Project","Project","MorphProject","Project"],"sources":["../src/architecture/allowed-packages.ts","../src/conventions/core-api.ts","../src/conventions/layers.ts","../src/conventions/building-blocks.ts","../src/model/classes/named-type.ts","../src/model/classes/class-type.ts","../src/model/classes/heritage.ts","../src/model/classes/return-shape.ts","../src/model/classes/member.ts","../src/model/classes/class-declaration.ts","../src/model/dependencies/dependency.ts","../src/model/dependencies/global-use.ts","../src/model/statements/disable-comment.ts","../src/model/statements/throw.ts","../src/model/statements/top-level-statement.ts","../src/model/source-file.ts","../src/model/project.ts","../src/architecture/core-api.ts","../src/architecture/context-map.ts","../src/architecture/settings.ts","../src/architecture/paths/location.ts","../src/architecture/paths/place.ts","../src/architecture/building-blocks.ts","../src/architecture/layers.ts","../src/architecture/paths/layer-shape.ts","../src/architecture/architecture.ts","../src/rules/framework/finding.ts","../src/rules/framework/wording.ts","../src/rules/framework/rule.ts","../src/rules/tooling/no-loose-disable.rule.ts","../src/rules/registry.ts","../src/check/violation.ts","../src/check/baseline.ts","../src/importer/importer.ts","../src/importer/ts-morph/ts-morph-importer.ts","../src/check/checker.ts","../src/check/report.ts","../src/docs/page.ts","../src/docs/docs.ts","../src/cli/cli.ts","../src/config/alveolus-config.ts","../src/config/config.ts","../src/config/config-loader.ts","../src/config/define-config.ts","../src/init/init.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":["Project","FileTarget","Project","Project","MorphProject","Project"],"sources":["../src/architecture/allowed-packages.ts","../src/conventions/core-api.ts","../src/conventions/layers.ts","../src/conventions/building-blocks.ts","../src/model/classes/named-type.ts","../src/model/classes/class-type.ts","../src/model/classes/heritage.ts","../src/model/classes/return-shape.ts","../src/model/classes/member.ts","../src/model/classes/class-declaration.ts","../src/model/dependencies/dependency.ts","../src/model/dependencies/global-use.ts","../src/model/statements/disable-comment.ts","../src/model/statements/throw.ts","../src/model/statements/top-level-statement.ts","../src/model/source-file.ts","../src/model/project.ts","../src/architecture/core-api.ts","../src/architecture/context-map.ts","../src/architecture/settings.ts","../src/architecture/paths/location.ts","../src/architecture/paths/place.ts","../src/architecture/building-blocks.ts","../src/architecture/layers.ts","../src/architecture/paths/layer-shape.ts","../src/architecture/architecture.ts","../src/rules/framework/finding.ts","../src/rules/framework/wording.ts","../src/rules/framework/rule.ts","../src/rules/tooling/no-loose-disable.rule.ts","../src/rules/registry.ts","../src/check/violation.ts","../src/check/baseline.ts","../src/importer/importer.ts","../src/importer/ts-morph/ts-morph-importer.ts","../src/check/checker.ts","../src/check/report.ts","../src/docs/page.ts","../src/docs/docs.ts","../src/cli/cli.ts","../src/config/alveolus-config.ts","../src/config/config.ts","../src/config/config-loader.ts","../src/config/define-config.ts","../src/init/init.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as TsMorphImporter, c as Config, d as RuleRegistry, f as Rule, h as Baseline, i as Init, l as Report, m as AllowedPackages, n as Page, o as Importer, p as Architecture, r as Cli, s as ConfigLoader, t as Docs, u as Checker } from "./docs-DsQHpTtV.mjs";
1
+ import { a as TsMorphImporter, c as Config, d as RuleRegistry, f as Rule, h as Baseline, i as Init, l as Report, m as AllowedPackages, n as Page, o as Importer, p as Architecture, r as Cli, s as ConfigLoader, t as Docs, u as Checker } from "./docs-DcFgskuN.mjs";
2
2
  //#region src/config/define-config.ts
3
3
  function defineConfig(config) {
4
4
  return config;
@@ -19,13 +19,16 @@ Nothing here requires a rewrite.
19
19
  Name the bounded contexts as the code has them today, even when they are folders named
20
20
  `modules/orders` or `features/billing`: `boundedContexts` takes any folder under `root`. Say under
21
21
  `subdomains` which ones are the [core domain](./project-layout.md#core-supporting-generic): only
22
- those are checked inside; a supporting or generic context is checked at its boundary only. Leave
23
- the context map for later. Put under `ignore` what has nothing to do with the architecture:
24
- scripts, generated code, migrations.
22
+ those are checked inside; a supporting or generic context is checked at its boundary only. Under
23
+ `contextMap`, start with `consumes: []` for every context: each import between two contexts is
24
+ then a violation, the baseline of the next step keeps them, and the map fills in as each one is
25
+ decided. Put under `ignore` what has nothing to do with the architecture: scripts, generated code,
26
+ migrations.
25
27
 
26
28
  ```ts [alveolus.config.ts]
27
29
  export default defineConfig({
28
30
  boundedContexts: { billing: "features/billing", orders: "modules/orders" },
31
+ contextMap: { billing: { consumes: [] }, orders: { consumes: [] } },
29
32
  ignore: ["src/migrations/**", "src/generated/**"],
30
33
  root: "src",
31
34
  subdomains: { core: ["orders"], supporting: ["billing"] },
@@ -106,8 +106,8 @@ Start from a use case: the [aggregate](../core/domain/aggregates.md) that keeps
106
106
  ## Configure the checks
107
107
 
108
108
  Create `alveolus.config.ts` at the root of the project. It says where the source code is, which
109
- folders are bounded contexts and which subdomain each one implements; everything else has a
110
- default.
109
+ folders are bounded contexts, which subdomain each one implements and which contexts each one
110
+ consumes; everything else has a default.
111
111
 
112
112
  ```sh
113
113
  npx alveolus init
@@ -121,6 +121,11 @@ import { defineConfig } from "@alveolus/arch";
121
121
 
122
122
  export default defineConfig({
123
123
  boundedContexts: { catalog: "catalog", notifications: "notifications", ordering: "ordering" },
124
+ contextMap: {
125
+ catalog: { consumes: [] },
126
+ notifications: { consumes: ["ordering"] },
127
+ ordering: { consumes: ["catalog"] },
128
+ },
124
129
  root: "src",
125
130
  subdomains: { core: ["catalog", "ordering"], generic: ["notifications"] },
126
131
  });
@@ -130,6 +135,12 @@ A [core](./project-layout.md#core-supporting-generic) context is checked by ever
130
135
  supporting or generic one is checked only at its boundary: it may be written any way you like, as
131
136
  long as it reaches the other contexts through their open host services.
132
137
 
138
+ The context map is the strategic design of the system, written down: each line reads as a
139
+ sentence, `ordering` consumes `catalog`, and every context has one, `consumes: []` when it
140
+ consumes nothing. An import that goes against the map is reported by
141
+ [`strategic/no-unmapped-context`](../rules/strategic/no-unmapped-context.md); a cycle in the map
142
+ is refused when the configuration loads.
143
+
133
144
  ### Options
134
145
 
135
146
  | Option | Default | What it does |
@@ -139,7 +150,7 @@ long as it reaches the other contexts through their open host services.
139
150
  | `boundedContexts` | required | Each bounded context and its folder, relative to `root`. `"modules/ordering"` works. |
140
151
  | `sharedKernel` | `"shared-kernel"` | The folder shared by every bounded context, relative to `root`. |
141
152
  | `subdomains` | required | The [subdomain](./project-layout.md#core-supporting-generic) each bounded context implements: `{ core: ["ordering"], supporting: ["billing"], generic: ["notifications"] }`. Every context is listed once. |
142
- | `contextMap` | none | For each bounded context, the ones it consumes: `{ payments: ["ledger"] }`. Checked for cycles; without it, only cycles are reported. |
153
+ | `contextMap` | required | For each bounded context, the ones it consumes: `{ ledger: { consumes: [] }, payments: { consumes: ["ledger"] } }`. Every context is listed, and the map has no cycle. |
143
154
  | `compositionRoot` | `"*.module.ts"` | The file, at the root of a bounded context, that wires it. |
144
155
  | `domainDependencies` | `{}` | npm packages the domain may import, besides `@alveolus/core`. |
145
156
  | `applicationDependencies` | `{}` | npm packages the application may import, besides `@alveolus/core` and `domainDependencies`. |
@@ -152,8 +152,10 @@ name:
152
152
  ```ts [alveolus.config.ts]
153
153
  export default defineConfig({
154
154
  boundedContexts: { ordering: "ordering" },
155
+ contextMap: { ordering: { consumes: [] } },
155
156
  root: "src",
156
157
  rules: { "tactical/no-misplaced-class": "off", "tactical/no-public-field": "warn" },
158
+ subdomains: { core: ["ordering"] },
157
159
  });
158
160
  ```
159
161
 
@@ -153,11 +153,13 @@ to allow everything they export, or with the names you allow:
153
153
  ```ts [alveolus.config.ts]
154
154
  export default defineConfig({
155
155
  boundedContexts: { ordering: "ordering" },
156
+ contextMap: { ordering: { consumes: [] } },
156
157
  domainDependencies: {
157
158
  "date-fns": ["addDays", "isBefore"],
158
159
  "decimal.js": true,
159
160
  },
160
161
  root: "src",
162
+ subdomains: { core: ["ordering"] },
161
163
  });
162
164
  ```
163
165
 
@@ -151,7 +151,9 @@ export default defineConfig({
151
151
  zod: true,
152
152
  },
153
153
  boundedContexts: { ordering: "ordering" },
154
+ contextMap: { ordering: { consumes: [] } },
154
155
  root: "src",
156
+ subdomains: { core: ["ordering"] },
155
157
  });
156
158
  ```
157
159
 
@@ -10,7 +10,7 @@ never depend on each other.
10
10
  <dl class="al-glance">
11
11
  <dt>Rule</dt><dd><code>strategic/no-unmapped-context</code></dd>
12
12
  <dt>Category</dt><dd><a href="/rules/#strategic">Strategic</a>: what crosses a bounded context</dd>
13
- <dt>Reports</dt><dd>An import of another context that <code>contextMap</code> does not allow; without a map, an import that closes a cycle between contexts</dd>
13
+ <dt>Reports</dt><dd>An import of another context that <code>contextMap</code> does not allow</dd>
14
14
  <dt>Applies to</dt><dd>Every file of every bounded context</dd>
15
15
  <dt>Turn off</dt><dd><a href="#turn-it-off"><code>"strategic/no-unmapped-context": "off"</code></a></dd>
16
16
  </dl>
@@ -24,20 +24,22 @@ extracted or rewritten without the other. In a system that lives for years, that
24
24
  turns "change this module" into "rewrite the application".
25
25
 
26
26
  ::: tip The fix
27
- Write the context map, as DDD asks: which context is upstream of which. Declare it in
28
- `alveolus.config.ts`, and the code can no longer stray from it. A dependency that goes against
29
- the map is reversed: `Ledger` publishes an event, `Payments` reacts.
27
+ Write the context map, as DDD asks: which context is upstream of which. `alveolus.config.ts`
28
+ requires it, so the code can no longer stray from it. A dependency that goes against the map is
29
+ reversed: `Ledger` publishes an event, `Payments` reacts. Adding a line to the map is the other
30
+ way out, and it is a strategic decision: take it in a review, not in a fix.
30
31
  :::
31
32
 
32
33
  ## What it checks
33
34
 
34
35
  Every import from a file of one bounded context to a file of another, open host service or
35
- composition root alike:
36
+ composition root alike: the importing context lists the imported one under `consumes` in
37
+ `contextMap`.
36
38
 
37
- <div class="al-cards al-cards-2">
38
- <div class="al-card"><span class="al-card-title">With a context map</span>The importing context lists the imported one in <code>contextMap</code>. The map itself is checked when the configuration loads: an unknown context or a cycle is an error.</div>
39
- <div class="al-card"><span class="al-card-title">Without a context map</span>The imports observed form no cycle. An import that closes one is reported at both ends.</div>
40
- </div>
39
+ The map itself is checked when the configuration loads, before any rule runs: a context left out
40
+ of the map, a context the map names that `boundedContexts` does not declare, a context that
41
+ consumes itself, or a cycle, is an error. Two contexts that depend on each other are therefore
42
+ never allowed, whichever way the code is written.
41
43
 
42
44
  Imports of the shared kernel are not consumptions: every context may import it.
43
45
 
@@ -46,18 +48,17 @@ Imports of the shared kernel are not consumptions: every context may import it.
46
48
  ```
47
49
  src/ledger/driven/payments/adapters/payment-status.adapter.ts
48
50
  2 error strategic/no-unmapped-context: ledger consumes payments, which the
49
- context map does not allow: add payments to contextMap.ledger, or
50
- reverse the dependency.
51
+ context map does not allow: reverse the dependency, or if ledger
52
+ really is downstream of payments, add payments to
53
+ contextMap.ledger.consumes.
51
54
  ```
52
55
 
53
- Without a map:
56
+ A map that would allow it is refused before the check:
54
57
 
55
58
  ```
56
- src/ledger/driven/payments/adapters/payment-status.adapter.ts
57
- 2 error strategic/no-unmapped-context: ledger consumes payments, which
58
- consumes ledger back: two contexts that depend on each other can
59
- no longer change alone; declare a contextMap and reverse one
60
- dependency.
59
+ Invalid configuration in alveolus.config.ts:
60
+ contextMap has a cycle: ledger → payments → ledger. Two contexts that depend
61
+ on each other can no longer change alone: reverse one dependency.
61
62
  ```
62
63
 
63
64
  ## Fix it
@@ -65,21 +66,23 @@ src/ledger/driven/payments/adapters/payment-status.adapter.ts
65
66
  ### Declare the context map
66
67
 
67
68
  So that the direction of every dependency is a decision, not an accident, list for each context
68
- the ones it consumes:
69
+ the ones it consumes. Each line reads as a sentence: `payments` consumes `ledger` and `customers`.
69
70
 
70
71
  ```ts [alveolus.config.ts]
71
72
  export default defineConfig({
72
73
  boundedContexts: { customers: "customers", ledger: "ledger", payments: "payments" },
73
74
  contextMap: {
74
- customers: [],
75
- ledger: ["customers"],
76
- payments: ["ledger", "customers"],
75
+ customers: { consumes: [] },
76
+ ledger: { consumes: ["customers"] },
77
+ payments: { consumes: ["ledger", "customers"] },
77
78
  },
78
79
  root: "src",
80
+ subdomains: { core: ["ledger", "payments"], generic: ["customers"] },
79
81
  });
80
82
  ```
81
83
 
82
- A context absent from the map consumes nothing.
84
+ Every context is in the map. `consumes: []` is a decision too: that context goes its separate
85
+ way, and the day it needs another one, the import is reported and the map is updated on purpose.
83
86
 
84
87
  ### Reverse a dependency with an event
85
88
 
@@ -17,12 +17,20 @@ A query handler receives what reads: nothing that writes or changes state.
17
17
  ## Why
18
18
 
19
19
  `GetOrderSummaryHandler` receives the unit of work: a read can now change state, and the caller who
20
- asked a question gets a side effect too. A command handler or a domain service injected into it
21
- does the same, one step removed.
20
+ asked a question gets a side effect too. A command handler injected into it does the same, one
21
+ step removed.
22
+
23
+ A domain service is different: it is pure, so injecting it changes nothing. What it changes is
24
+ where the business rule runs. `GetSafeguardingReconciliationHandler` receives
25
+ `SafeguardingReconciliation` and computes the reconciliation at each read: two readers at two
26
+ moments see two different results, nothing records which one was reported, and the rule now runs
27
+ on two paths, the command's and the query's, that drift apart. The read side delivers data shaped
28
+ for the reader; the domain's behaviour runs on the write side, once, and leaves a fact.
22
29
 
23
30
  ::: tip The fix
24
31
  A query reads a view through a query repository, and writes nothing. A query that seems to need a
25
- write is a command, or a command followed by a query.
32
+ write is a command, or a command followed by a query. A query that seems to need a domain service
33
+ is reading a fact nobody recorded, or holding a calculation that belongs to a value object.
26
34
  :::
27
35
 
28
36
  ## What it checks
@@ -78,6 +86,91 @@ constructor(private readonly summaries: OrderSummaries) {
78
86
 
79
87
  </div>
80
88
 
89
+ ### Record the fact, then read it
90
+
91
+ So that a result the reader relies on exists once, with its date, a domain service runs in a
92
+ command handler that records its outcome, and the query reads the record. A reconciliation, a
93
+ regulatory figure, a score: when the reader asks "what was it", the answer is a fact to keep, not
94
+ a calculation to redo.
95
+
96
+ <div class="al-compare">
97
+
98
+ ```ts [❌ Avoid: src/safeguarding/application/queries/get-reconciliation.query.ts]
99
+ constructor(
100
+ private readonly balances: SafeguardingBalances,
101
+ private readonly reconciliation: SafeguardingReconciliation,
102
+ ) {
103
+ super();
104
+ }
105
+
106
+ async handle(query: GetReconciliation): Promise<Result<ReconciliationView, NotFound>> {
107
+ const balances = await this.balances.on(query.date);
108
+ return ok(this.reconciliation.reconcile(balances));
109
+ }
110
+ ```
111
+
112
+ ```ts [✅ Prefer: src/safeguarding/application/commands/reconcile-safeguarding.command.ts]
113
+ constructor(
114
+ private readonly accounts: SafeguardingAccounts,
115
+ private readonly reconciliation: SafeguardingReconciliation,
116
+ private readonly unitOfWork: UnitOfWork,
117
+ ) {
118
+ super();
119
+ }
120
+
121
+ async handle(command: ReconcileSafeguarding): Promise<Result<void, NotFound>> {
122
+ const account = await this.accounts.of(command.accountId);
123
+ account.reconcile(this.reconciliation.reconcile(account.balances()), command.at);
124
+ await this.unitOfWork.commit();
125
+ return ok();
126
+ }
127
+ ```
128
+
129
+ </div>
130
+
131
+ The query handler then receives `Reconciliations`, a query repository, and returns the
132
+ reconciliation of the date asked. The aggregate records the outcome, so the domain service keeps
133
+ one caller.
134
+
135
+ ### Move a calculation into a value object
136
+
137
+ So that a figure derived from the values of a view is computed where values are computed, the
138
+ calculation becomes a static factory of a [value object](../../core/domain/value-objects.md),
139
+ which a query may use: a projection, a conversion, a total. Nothing is recorded because nothing
140
+ happened.
141
+
142
+ <div class="al-compare">
143
+
144
+ ```ts [❌ Avoid: src/safeguarding/application/queries/get-own-funds-requirement.query.ts]
145
+ constructor(
146
+ private readonly figures: SafeguardingFigures,
147
+ private readonly calculator: OwnFundsRequirementCalculator,
148
+ ) {
149
+ super();
150
+ }
151
+
152
+ async handle(query: GetOwnFundsRequirement): Promise<Result<OwnFundsRequirementView, NotFound>> {
153
+ const figures = await this.figures.of(query.firmId);
154
+ return ok({ amount: this.calculator.compute(figures) });
155
+ }
156
+ ```
157
+
158
+ ```ts [✅ Prefer: src/safeguarding/application/queries/get-own-funds-requirement.query.ts]
159
+ constructor(private readonly figures: SafeguardingFigures) {
160
+ super();
161
+ }
162
+
163
+ async handle(query: GetOwnFundsRequirement): Promise<Result<OwnFundsRequirementView, NotFound>> {
164
+ const figures = await this.figures.of(query.firmId);
165
+ return ok({ amount: OwnFundsRequirement.of(figures).amount });
166
+ }
167
+ ```
168
+
169
+ </div>
170
+
171
+ Which of the two? If the reader asks for the figure as it was declared or decided, record it. If
172
+ the reader asks what the figure would be from the values on the screen, calculate it.
173
+
81
174
  ## Limits
82
175
 
83
176
  ::: warning What the rule cannot see
@@ -101,6 +194,8 @@ new queries keep to reading while you split the old ones.
101
194
  - [Query handlers](../../core/application/query-handlers.md), what is checked
102
195
  - [Repositories](../../core/domain/repositories.md) and [Views](../../core/domain/views.md), what
103
196
  a query reads
197
+ - [Domain services](../../core/domain/domain-services.md), called by the command handler, and
198
+ [value objects](../../core/domain/value-objects.md), the home of a calculation
104
199
  - [`tactical/no-foreign-command-dependency`](./no-foreign-command-dependency.md), the same list for
105
200
  command handlers
106
201
  - [Rules](../index.md), every rule by category
package/package.json CHANGED
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "sideEffects": false,
50
50
  "type": "module",
51
- "version": "0.3.0",
51
+ "version": "0.4.0",
52
52
  "scripts": {
53
53
  "build": "tsdown && biome check --write package.json",
54
54
  "typecheck": "tsc -p tsconfig.json"