archstone 1.3.0-rc.2 → 1.3.0-rc.3
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 +20 -8
- package/dist/core/index.d.ts +1 -1
- package/dist/domain/application/index.d.ts +1 -1
- package/dist/domain/enterprise/index.d.ts +1 -1
- package/dist/domain/enterprise/index.js +1 -1
- package/dist/domain/index.d.ts +1 -1
- package/dist/domain/index.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/shared/chunk-k39ksk62.js +2 -0
- package/dist/shared/{chunk-rgs8z093.d.ts → chunk-v5h13a5p.d.ts} +34 -12
- package/package.json +1 -1
- package/skills/use-archstone/references/domain-events.md +12 -10
- package/dist/shared/chunk-s2r7zghq.js +0 -2
package/README.md
CHANGED
|
@@ -174,13 +174,25 @@ tags.getRemovedItems() // → [existingTag]
|
|
|
174
174
|
### Domain Events — decouple side effects
|
|
175
175
|
|
|
176
176
|
```ts
|
|
177
|
-
import {
|
|
177
|
+
import type { EventHandler } from 'archstone/core'
|
|
178
|
+
import { DomainEvents } from 'archstone/core'
|
|
178
179
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
class OnUserCreated implements EventHandler<UserCreatedEvent> {
|
|
181
|
+
constructor(private readonly mailer: Mailer) {
|
|
182
|
+
this.setupSubscriptions()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
setupSubscriptions(): void {
|
|
186
|
+
DomainEvents.register(this.handle.bind(this), UserCreatedEvent.name)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async handle(event: UserCreatedEvent): Promise<void> {
|
|
190
|
+
await this.mailer.send(event.user.email.value)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Instantiate in infrastructure — handler self-registers via constructor
|
|
195
|
+
new OnUserCreated(mailer)
|
|
184
196
|
|
|
185
197
|
// Dispatch after persistence — events stay inside the aggregate until then
|
|
186
198
|
await userRepository.create(user)
|
|
@@ -212,9 +224,9 @@ export interface AuditRepository extends Creatable<AuditLog> {}
|
|
|
212
224
|
| Import | Contents |
|
|
213
225
|
|---|---|
|
|
214
226
|
| `archstone` | Everything |
|
|
215
|
-
| `archstone/core` | `Either`, `ValueObject`, `UniqueEntityId`, `WatchedList`, `Optional` |
|
|
227
|
+
| `archstone/core` | `Either`, `ValueObject`, `UniqueEntityId`, `WatchedList`, `Optional`, `EventHandler` |
|
|
216
228
|
| `archstone/domain` | All domain exports |
|
|
217
|
-
| `archstone/domain/enterprise` | `Entity`, `AggregateRoot`, `DomainEvent`, `DomainEvents
|
|
229
|
+
| `archstone/domain/enterprise` | `Entity`, `AggregateRoot`, `DomainEvent`, `DomainEvents` |
|
|
218
230
|
| `archstone/domain/application` | `UseCase`, `UseCaseError`, repository contracts |
|
|
219
231
|
|
|
220
232
|
All sub-paths share type declarations via a common chunk — mixing imports from multiple sub-paths is fully type-safe with no duplicate declaration conflicts.
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { DomainEvent, DomainEvents, Either, EventHandler, Optional, UniqueEntityId, ValueObject, WatchedList, left, right } from "../shared/chunk-
|
|
1
|
+
import { DomainEvent, DomainEvents, Either, EventHandler1 as EventHandler, Optional, UniqueEntityId, ValueObject, WatchedList, left, right } from "../shared/chunk-v5h13a5p.js";
|
|
2
2
|
export { right, left, WatchedList, ValueObject, UniqueEntityId, Optional, EventHandler, Either, DomainEvents, DomainEvent };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Creatable, Deletable, Findable, Repository, Saveable, UseCase, UseCaseError } from "../../shared/chunk-
|
|
1
|
+
import { Creatable, Deletable, Findable, Repository, Saveable, UseCase, UseCaseError } from "../../shared/chunk-v5h13a5p.js";
|
|
2
2
|
export { UseCaseError, UseCase, Saveable, Repository, Findable, Deletable, Creatable };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AggregateRoot, DomainEvent, DomainEvents, Entity, EventHandler } from "../../shared/chunk-
|
|
1
|
+
import { AggregateRoot, DomainEvent, DomainEvents, Entity, EventHandler } from "../../shared/chunk-v5h13a5p.js";
|
|
2
2
|
export { EventHandler, Entity, DomainEvents, DomainEvent, AggregateRoot };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{a as b,b as c}from"../../shared/chunk-
|
|
2
|
+
import{a as b,b as c}from"../../shared/chunk-k39ksk62.js";import{e as a}from"../../shared/chunk-8hx7pxm3.js";export{b as Entity,a as DomainEvents,c as AggregateRoot};
|
package/dist/domain/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AggregateRoot, Creatable, Deletable, DomainEvent, DomainEvents, Entity, EventHandler, Findable, Repository, Saveable, UseCase, UseCaseError } from "../shared/chunk-
|
|
1
|
+
import { AggregateRoot, Creatable, Deletable, DomainEvent, DomainEvents, Entity, EventHandler, Findable, Repository, Saveable, UseCase, UseCaseError } from "../shared/chunk-v5h13a5p.js";
|
|
2
2
|
export { UseCaseError, UseCase, Saveable, Repository, Findable, EventHandler, Entity, DomainEvents, DomainEvent, Deletable, Creatable, AggregateRoot };
|
package/dist/domain/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"../shared/chunk-x296z7h1.js";import"../shared/chunk-wsjyhnpq.js";import{a as b,b as c}from"../shared/chunk-
|
|
2
|
+
import"../shared/chunk-x296z7h1.js";import"../shared/chunk-wsjyhnpq.js";import{a as b,b as c}from"../shared/chunk-k39ksk62.js";import{e as a}from"../shared/chunk-8hx7pxm3.js";export{b as Entity,a as DomainEvents,c as AggregateRoot};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AggregateRoot, Creatable, Deletable, DomainEvent, DomainEvents, Either, Entity,
|
|
2
|
-
export { right, left, WatchedList, ValueObject, UseCaseError, UseCase, UniqueEntityId, Saveable, Repository, Optional, Findable,
|
|
1
|
+
import { AggregateRoot, Creatable, Deletable, DomainEvent, DomainEvents, Either, Entity, Findable, Optional, Repository, Saveable, UniqueEntityId, UseCase, UseCaseError, ValueObject, WatchedList, left, right } from "./shared/chunk-v5h13a5p.js";
|
|
2
|
+
export { right, left, WatchedList, ValueObject, UseCaseError, UseCase, UniqueEntityId, Saveable, Repository, Optional, Findable, Entity, Either, DomainEvents, DomainEvent, Deletable, Creatable, AggregateRoot };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./shared/chunk-x296z7h1.js";import"./shared/chunk-wsjyhnpq.js";import{a as b,b as c}from"./shared/chunk-
|
|
2
|
+
import"./shared/chunk-x296z7h1.js";import"./shared/chunk-wsjyhnpq.js";import{a as b,b as c}from"./shared/chunk-k39ksk62.js";import{c as f,d as m,e as p,f as t,g as x,h as a}from"./shared/chunk-8hx7pxm3.js";export{m as right,f as left,a as WatchedList,x as ValueObject,t as UniqueEntityId,b as Entity,p as DomainEvents,c as AggregateRoot};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{e as j,f as k}from"./chunk-8hx7pxm3.js";class R{_id;props;get id(){return this._id}constructor(A,B){this._id=B??new k,this.props=A}equals(A){if(A===this)return!0;return A.id.equals(this._id)}}class z extends R{_domainEvents=new Set;get domainEvents(){return Array.from(this._domainEvents)}addDomainEvent(A){this._domainEvents.add(A),j.markAggregateForDispatch(this)}clearEvents(){this._domainEvents.clear()}}export{R as a,z as b};
|
|
@@ -305,6 +305,13 @@ declare abstract class AggregateRoot<Props> extends Entity<Props> {
|
|
|
305
305
|
clearEvents(): void;
|
|
306
306
|
}
|
|
307
307
|
/**
|
|
308
|
+
* @deprecated use `EventHandler` from `archstone/core` instead.
|
|
309
|
+
* The new version supports generic typing via `EventHandler<T>`.
|
|
310
|
+
*/
|
|
311
|
+
interface EventHandler {
|
|
312
|
+
setupSubscriptions(): void;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
308
315
|
* Callback function invoked when a domain event is dispatched.
|
|
309
316
|
*/
|
|
310
317
|
type DomainEventCallback = (event: DomainEvent) => void;
|
|
@@ -376,39 +383,54 @@ declare class DomainEventsImplementation {
|
|
|
376
383
|
*/
|
|
377
384
|
declare const DomainEvents: DomainEventsImplementation;
|
|
378
385
|
/**
|
|
379
|
-
* Base contract for all event handlers.
|
|
386
|
+
* Base contract for all domain event handlers.
|
|
380
387
|
*
|
|
381
388
|
* An event handler is responsible for subscribing to domain events
|
|
382
|
-
* and executing side effects in response — such as
|
|
383
|
-
*
|
|
389
|
+
* and executing side effects in response — such as persisting records,
|
|
390
|
+
* broadcasting WebSocket messages, sending emails, or triggering
|
|
391
|
+
* external integrations.
|
|
392
|
+
*
|
|
393
|
+
* Implement {@link setupSubscriptions} to register callbacks in the
|
|
394
|
+
* {@link DomainEvents} registry, and {@link handle} to define the
|
|
395
|
+
* reaction logic for the subscribed event.
|
|
384
396
|
*
|
|
385
|
-
*
|
|
386
|
-
* their callbacks in the {@link DomainEvents} registry.
|
|
397
|
+
* @typeParam T - The specific {@link DomainEvent} this handler reacts to.
|
|
387
398
|
*
|
|
388
399
|
* @example
|
|
389
400
|
* ```ts
|
|
390
|
-
* class OnUserCreated implements EventHandler {
|
|
391
|
-
* constructor(private readonly mailer: Mailer) {
|
|
401
|
+
* class OnUserCreated implements EventHandler<UserCreatedEvent> {
|
|
402
|
+
* constructor(private readonly mailer: Mailer) {
|
|
403
|
+
* this.setupSubscriptions()
|
|
404
|
+
* }
|
|
392
405
|
*
|
|
393
406
|
* setupSubscriptions(): void {
|
|
394
407
|
* DomainEvents.register(
|
|
395
|
-
*
|
|
408
|
+
* this.handle.bind(this),
|
|
396
409
|
* UserCreatedEvent.name,
|
|
397
410
|
* )
|
|
398
411
|
* }
|
|
399
412
|
*
|
|
400
|
-
*
|
|
413
|
+
* async handle(event: UserCreatedEvent): Promise<void> {
|
|
401
414
|
* await this.mailer.send(event.user.email)
|
|
402
415
|
* }
|
|
403
416
|
* }
|
|
404
417
|
* ```
|
|
405
418
|
*/
|
|
406
|
-
interface
|
|
419
|
+
interface EventHandler2<T extends DomainEvent> {
|
|
407
420
|
/**
|
|
408
421
|
* Registers all event subscriptions for this handler.
|
|
409
|
-
*
|
|
422
|
+
*
|
|
423
|
+
* Should be called once during instantiation — typically
|
|
424
|
+
* in the constructor — to ensure the handler is active
|
|
425
|
+
* before any events are dispatched.
|
|
410
426
|
*/
|
|
411
427
|
setupSubscriptions(): void;
|
|
428
|
+
/**
|
|
429
|
+
* Executes the handler logic in response to a dispatched event.
|
|
430
|
+
*
|
|
431
|
+
* @param event - The domain event instance that was dispatched.
|
|
432
|
+
*/
|
|
433
|
+
handle(event: T): Promise<void>;
|
|
412
434
|
}
|
|
413
435
|
/**
|
|
414
436
|
* Make some property optional on type
|
|
@@ -634,4 +656,4 @@ interface UseCase<
|
|
|
634
656
|
> {
|
|
635
657
|
execute(input: Input): Promise<Output>;
|
|
636
658
|
}
|
|
637
|
-
export { Either, left, right, DomainEvent, Creatable, Deletable, Findable, Saveable, Repository, UseCaseError, UseCase, Entity, AggregateRoot, DomainEvents,
|
|
659
|
+
export { Either, left, right, DomainEvent, Creatable, Deletable, Findable, Saveable, Repository, UseCaseError, UseCase, Entity, AggregateRoot, EventHandler, DomainEvents, EventHandler2 as EventHandler1, Optional, UniqueEntityId, ValueObject, WatchedList };
|
package/package.json
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
- Raise events inside the aggregate via `this.addDomainEvent()`
|
|
6
6
|
- Dispatch **after** successful persistence — never before
|
|
7
|
-
- Define handlers as classes implementing `EventHandler` with `setupSubscriptions():
|
|
8
|
-
-
|
|
7
|
+
- Define handlers as classes implementing `EventHandler<T>` from `archstone/core` with `setupSubscriptions()` and `handle(event: T)`
|
|
8
|
+
- Call `setupSubscriptions()` in the constructor — just instantiate the handler in the composition root
|
|
9
9
|
- Dispatch via `DomainEvents.dispatchEventsForAggregate(aggregate.id)` — argument is `UniqueEntityId`
|
|
10
10
|
- `clearEvents()` is called internally by `dispatchEventsForAggregate` — do not call manually
|
|
11
11
|
- Test isolation: call `DomainEvents.clearHandlers()` and `DomainEvents.clearMarkedAggregates()` in `beforeEach`
|
|
@@ -28,20 +28,22 @@ class User extends AggregateRoot<UserProps> {
|
|
|
28
28
|
## Defining a Handler
|
|
29
29
|
|
|
30
30
|
```ts
|
|
31
|
-
import type { EventHandler } from 'archstone/
|
|
32
|
-
import { DomainEvents } from 'archstone/
|
|
31
|
+
import type { EventHandler } from 'archstone/core'
|
|
32
|
+
import { DomainEvents } from 'archstone/core'
|
|
33
33
|
|
|
34
|
-
class OnUserCreated implements EventHandler {
|
|
35
|
-
constructor(private readonly mailer: Mailer) {
|
|
34
|
+
class OnUserCreated implements EventHandler<UserCreatedEvent> {
|
|
35
|
+
constructor(private readonly mailer: Mailer) {
|
|
36
|
+
this.setupSubscriptions()
|
|
37
|
+
}
|
|
36
38
|
|
|
37
39
|
setupSubscriptions(): void {
|
|
38
40
|
DomainEvents.register(
|
|
39
|
-
|
|
41
|
+
this.handle.bind(this),
|
|
40
42
|
UserCreatedEvent.name,
|
|
41
43
|
)
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
async handle(event: UserCreatedEvent): Promise<void> {
|
|
45
47
|
await this.mailer.send(event.user.email.value)
|
|
46
48
|
}
|
|
47
49
|
}
|
|
@@ -59,8 +61,8 @@ async create(user: User): Promise<void> {
|
|
|
59
61
|
## Composition Root Registration
|
|
60
62
|
|
|
61
63
|
```ts
|
|
62
|
-
//
|
|
63
|
-
new OnUserCreated(mailer)
|
|
64
|
+
// setupSubscriptions() is called in the constructor — just instantiate
|
|
65
|
+
new OnUserCreated(mailer)
|
|
64
66
|
```
|
|
65
67
|
|
|
66
68
|
## Common Mistakes
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{e as D,f as H}from"./chunk-8hx7pxm3.js";class A{_id;props;get id(){return this._id}constructor(x,f){this._id=f??new H,this.props=x}equals(x){if(x===this)return!0;return x.id.equals(this._id)}}class R extends A{_domainEvents=new Set;get domainEvents(){return Array.from(this._domainEvents)}addDomainEvent(x){this._domainEvents.add(x),D.markAggregateForDispatch(this)}clearEvents(){this._domainEvents.clear()}}export{A as a,R as b};
|