archstone 1.4.0 → 1.4.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 CHANGED
@@ -8,6 +8,8 @@
8
8
 
9
9
  Build on Domain-Driven Design and Clean Architecture — without writing the same boilerplate on every project.
10
10
 
11
+ [![failcraft](https://img.shields.io/badge/powered%20by-failcraft-F97316?style=for-the-badge)](https://github.com/joao-coimbra/failcraft)
12
+
11
13
  <br />
12
14
 
13
15
  [![npm version](https://img.shields.io/npm/v/archstone?style=for-the-badge&logo=npm&color=CB3837&logoColor=white)](https://www.npmjs.com/package/archstone)
@@ -27,7 +29,7 @@ Build on Domain-Driven Design and Clean Architecture — without writing the sam
27
29
 
28
30
  ## Why Archstone?
29
31
 
30
- Every backend project in DDD needs the same structural pieces — and most teams rewrite them from scratch each time. Archstone gives you a **battle-tested, zero-dependency set of base classes and contracts** so you can skip the boilerplate and go straight to modeling your domain.
32
+ Every backend project in DDD needs the same structural pieces — and most teams rewrite them from scratch each time. Archstone gives you a **battle-tested, minimal set of base classes and contracts** so you can skip the boilerplate and go straight to modeling your domain.
31
33
 
32
34
  ```ts
33
35
  // ❌ Before — scattered, inconsistent, no error contract
@@ -46,6 +48,7 @@ async function createUser(): Promise<Either<NotFoundError, User>> { ... }
46
48
  | | |
47
49
  |---|---|
48
50
  | **`Either`** | Functional error handling — use cases never throw |
51
+ | **`Maybe`** | Nullable value handling without null checks — `just`, `nothing`, `maybe` |
49
52
  | **`Entity` / `AggregateRoot`** | Identity-based domain objects with built-in event support |
50
53
  | **`ValueObject`** | Equality by value, not reference |
51
54
  | **`UniqueEntityId`** | UUID v7 identity, consistent across your entire domain |
@@ -64,7 +67,7 @@ bun add archstone
64
67
  npm install archstone
65
68
  ```
66
69
 
67
- > Zero runtime dependencies. Pure TypeScript.
70
+ > Minimal dependencies — only [failcraft](https://github.com/joao-coimbra/failcraft) for `Either` and `Maybe`. Pure TypeScript.
68
71
 
69
72
  ---
70
73
 
@@ -96,6 +99,29 @@ if (result.isLeft()) {
96
99
 
97
100
  ---
98
101
 
102
+ ### `Maybe` — nullable values without null checks
103
+
104
+ ```ts
105
+ import { Maybe, just, nothing, maybe } from 'archstone/core'
106
+
107
+ type FindUserResult = Maybe<User>
108
+
109
+ async function findUser(id: string): Promise<FindUserResult> {
110
+ const user = await repo.findById(id)
111
+ return maybe(user) // wraps null/undefined as nothing(), anything else as just()
112
+ }
113
+
114
+ const result = await findUser('123')
115
+
116
+ if (result.isNothing()) {
117
+ console.log('not found')
118
+ } else {
119
+ console.log(result.value) // User ✓
120
+ }
121
+ ```
122
+
123
+ ---
124
+
99
125
  ### `Entity` & `AggregateRoot` — model your domain
100
126
 
101
127
  ```ts
@@ -224,7 +250,7 @@ export interface AuditRepository extends Creatable<AuditLog> {}
224
250
  | Import | Contents |
225
251
  |---|---|
226
252
  | `archstone` | Everything |
227
- | `archstone/core` | `Either`, `ValueObject`, `UniqueEntityId`, `WatchedList`, `Optional`, `DomainEvent`, `DomainEvents`, `EventHandler` |
253
+ | `archstone/core` | `Either`, `Maybe`, `left`, `right`, `just`, `nothing`, `maybe`, `ValueObject`, `UniqueEntityId`, `WatchedList`, `Optional`, `DomainEvent`, `DomainEvents`, `EventHandler` |
228
254
  | `archstone/domain` | All domain exports |
229
255
  | `archstone/domain/enterprise` | `Entity`, `AggregateRoot` |
230
256
  | `archstone/domain/application` | `UseCase`, `UseCaseError`, repository contracts |
@@ -238,7 +264,6 @@ All sub-paths share type declarations via a common chunk — mixing imports from
238
264
  ```
239
265
  src/
240
266
  ├── core/ # Zero domain knowledge — pure language utilities
241
- │ ├── either.ts # Left / Right functional result type
242
267
  │ ├── value-object.ts # Value equality base class
243
268
  │ ├── unique-entity-id.ts # UUID v7 identity wrapper
244
269
  │ ├── watched-list.ts # Change-tracked collection
@@ -278,7 +303,7 @@ src/
278
303
  | **Test Framework** | `bun:test` (built-in) |
279
304
  | **Build Tool** | [bunup](https://github.com/nicepkg/bunup) |
280
305
  | **Linter / Formatter** | [Biome](https://biomejs.dev) via [Ultracite](https://ultracite.dev) |
281
- | **Dependencies** | None (zero runtime dependencies) |
306
+ | **Dependencies** | [failcraft](https://github.com/joao-coimbra/failcraft) `Either` and `Maybe` types |
282
307
 
283
308
  ---
284
309
 
@@ -1,2 +1,2 @@
1
- import { DomainEvent, DomainEvents, Either, EventHandler1 as EventHandler, Maybe, Optional, UniqueEntityId, ValueObject, WatchedList, just, left, maybe, nothing, right } from "../shared/chunk-w9w4akh1.js";
2
- export { right, nothing, maybe, left, just, WatchedList, ValueObject, UniqueEntityId, Optional, Maybe, EventHandler, Either, DomainEvents, DomainEvent };
1
+ import { AsyncEither, DomainEvent, DomainEvents, Either, EventHandler1 as EventHandler, Left, Maybe, Optional, Right, UniqueEntityId, ValueObject, WatchedList, attempt, from, just, left, maybe, nothing, right } from "../shared/chunk-rd3d1767.js";
2
+ export { right, nothing, maybe, left, just, from, attempt, WatchedList, ValueObject, UniqueEntityId, Right, Optional, Maybe, Left, EventHandler, Either, DomainEvents, DomainEvent, AsyncEither };
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{c as a,d as b,e as c,f as d,g as e,h as f,i as g,j as h,k as i}from"../shared/chunk-q4ayz844.js";export{i as right,h as nothing,g as maybe,f as left,e as just,d as WatchedList,c as ValueObject,b as UniqueEntityId,a as DomainEvents};
2
+ import{c as a,d as b,e as c,f as d,g as e,h as f,i as g,j as h,k as i,l as j,m as k}from"../shared/chunk-2zkxpq9t.js";export{k as right,j as nothing,i as maybe,h as left,g as just,f as from,e as attempt,d as WatchedList,c as ValueObject,b as UniqueEntityId,a as DomainEvents};
@@ -1,2 +1,2 @@
1
- import { Creatable, Deletable, Findable, Repository, Saveable, UseCase, UseCaseError } from "../../shared/chunk-w9w4akh1.js";
1
+ import { Creatable, Deletable, Findable, Repository, Saveable, UseCase, UseCaseError } from "../../shared/chunk-rd3d1767.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-w9w4akh1.js";
1
+ import { AggregateRoot, DomainEvent, DomainEvents, Entity, EventHandler } from "../../shared/chunk-rd3d1767.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-whqnrgyf.js";import{c as a}from"../../shared/chunk-q4ayz844.js";export{b as Entity,a as DomainEvents,c as AggregateRoot};
2
+ import{a as b,b as c}from"../../shared/chunk-0s74as1n.js";import{c as a}from"../../shared/chunk-2zkxpq9t.js";export{b as Entity,a as DomainEvents,c as AggregateRoot};
@@ -1,2 +1,2 @@
1
- import { AggregateRoot, Creatable, Deletable, DomainEvent, DomainEvents, Entity, EventHandler, Findable, Repository, Saveable, UseCase, UseCaseError } from "../shared/chunk-w9w4akh1.js";
1
+ import { AggregateRoot, Creatable, Deletable, DomainEvent, DomainEvents, Entity, EventHandler, Findable, Repository, Saveable, UseCase, UseCaseError } from "../shared/chunk-rd3d1767.js";
2
2
  export { UseCaseError, UseCase, Saveable, Repository, Findable, EventHandler, Entity, DomainEvents, DomainEvent, Deletable, Creatable, AggregateRoot };
@@ -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-whqnrgyf.js";import{c as a}from"../shared/chunk-q4ayz844.js";export{b as Entity,a as DomainEvents,c as AggregateRoot};
2
+ import"../shared/chunk-x296z7h1.js";import"../shared/chunk-wsjyhnpq.js";import{a as b,b as c}from"../shared/chunk-0s74as1n.js";import{c as a}from"../shared/chunk-2zkxpq9t.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, Findable, Maybe, Optional, Repository, Saveable, UniqueEntityId, UseCase, UseCaseError, ValueObject, WatchedList, just, left, maybe, nothing, right } from "./shared/chunk-w9w4akh1.js";
2
- export { right, nothing, maybe, left, just, WatchedList, ValueObject, UseCaseError, UseCase, UniqueEntityId, Saveable, Repository, Optional, Maybe, Findable, Entity, Either, DomainEvents, DomainEvent, Deletable, Creatable, AggregateRoot };
1
+ import { AggregateRoot, AsyncEither, Creatable, Deletable, DomainEvent, DomainEvents, Either, Entity, Findable, Left, Maybe, Optional, Repository, Right, Saveable, UniqueEntityId, UseCase, UseCaseError, ValueObject, WatchedList, attempt, from, just, left, maybe, nothing, right } from "./shared/chunk-rd3d1767.js";
2
+ export { right, nothing, maybe, left, just, from, attempt, WatchedList, ValueObject, UseCaseError, UseCase, UniqueEntityId, Saveable, Right, Repository, Optional, Maybe, Left, Findable, Entity, Either, DomainEvents, DomainEvent, Deletable, Creatable, AsyncEither, 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 g,b as h}from"./shared/chunk-whqnrgyf.js";import{c as f,d as m,e as p,f as t,g as x,h as a,i as b,j as c,k as d}from"./shared/chunk-q4ayz844.js";export{d as right,c as nothing,b as maybe,a as left,x as just,t as WatchedList,p as ValueObject,m as UniqueEntityId,g as Entity,f as DomainEvents,h as AggregateRoot};
2
+ import"./shared/chunk-x296z7h1.js";import"./shared/chunk-wsjyhnpq.js";import{a as i,b as j}from"./shared/chunk-0s74as1n.js";import{c as f,d as m,e as p,f as t,g as x,h as a,i as b,j as c,k as d,l as g,m as h}from"./shared/chunk-2zkxpq9t.js";export{h as right,g as nothing,d as maybe,c as left,b as just,a as from,x as attempt,t as WatchedList,p as ValueObject,m as UniqueEntityId,i as Entity,f as DomainEvents,j as AggregateRoot};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{c as j,d as k}from"./chunk-q4ayz844.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};
2
+ import{c as j,d as k}from"./chunk-2zkxpq9t.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};
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{attempt as Q,from as R,just as X,left as Y,maybe as Z,nothing as _,right as $}from"failcraft";class E{handlersMap=new Map;markedAggregates=new Set;shouldRun=!0;markAggregateForDispatch(x){if(!this.findMarkedAggregateByID(x.id))this.markedAggregates.add(x)}dispatchEventsForAggregate(x){let y=this.findMarkedAggregateByID(x);if(y)this.dispatchAggregateEvents(y),y.clearEvents(),this.removeAggregateFromMarkedDispatchList(y)}register(x,y){if(!this.handlersMap.has(y))this.handlersMap.set(y,[]);this.handlersMap.get(y)?.push(x)}clearHandlers(){this.handlersMap.clear()}clearMarkedAggregates(){this.markedAggregates.clear()}dispatchAggregateEvents(x){for(let y of x.domainEvents)this.dispatch(y)}removeAggregateFromMarkedDispatchList(x){this.markedAggregates.delete(x)}findMarkedAggregateByID(x){return[...this.markedAggregates].find((y)=>y.id.equals(x))}dispatch(x){if(!this.shouldRun)return;let y=this.handlersMap.get(x.constructor.name)??[];for(let f of y)f(x)}}var H=new E;var{randomUUIDv7:M}=globalThis.Bun;class L{value;constructor(x){this.value=x??M()}toValue(){return this.value}toString(){return this.value}equals(x){return x.toValue()===this.value}}class O{props;constructor(x){this.props=x}equals(x){return JSON.stringify(this.props)===JSON.stringify(x.props)}}class A{currentItems;initial;new;removed;constructor(x){this.currentItems=x??[],this.initial=x??[],this.new=[],this.removed=[]}getItems(){return this.currentItems}getNewItems(){return this.new}getRemovedItems(){return this.removed}exists(x){return this.isCurrentItem(x)}add(x){if(this.isRemovedItem(x))this.removeFromRemoved(x);if(!(this.isNewItem(x)||this.wasAddedInitially(x)))this.new.push(x);if(!this.isCurrentItem(x))this.currentItems.push(x)}remove(x){if(this.removeFromCurrent(x),this.isNewItem(x)){this.removeFromNew(x);return}if(!this.isRemovedItem(x))this.removed.push(x)}update(x){this.new=x.filter((y)=>!this.getItems().some((f)=>this.compareItems(y,f))),this.removed=this.getItems().filter((y)=>!x.some((f)=>this.compareItems(y,f))),this.currentItems=x}isCurrentItem(x){return this.currentItems.some((y)=>this.compareItems(x,y))}isNewItem(x){return this.new.some((y)=>this.compareItems(x,y))}isRemovedItem(x){return this.removed.some((y)=>this.compareItems(x,y))}removeFromNew(x){this.new=this.new.filter((y)=>!this.compareItems(y,x))}removeFromCurrent(x){this.currentItems=this.currentItems.filter((y)=>!this.compareItems(x,y))}removeFromRemoved(x){this.removed=this.removed.filter((y)=>!this.compareItems(x,y))}wasAddedInitially(x){return this.initial.some((y)=>this.compareItems(x,y))}}export{H as c,L as d,O as e,A as f,Q as g,R as h,X as i,Y as j,Z as k,_ as l,$ as m};
@@ -76,7 +76,7 @@ interface Saveable<T> {
76
76
  * ```
77
77
  */
78
78
  interface Repository<T> extends Findable<T>, Saveable<T>, Creatable<T>, Deletable<T> {}
79
- import { Either, just, left, Maybe, maybe, nothing, right } from "failcraft";
79
+ import { AsyncEither, attempt, Either, from, just, Left, left, Maybe, maybe, nothing, Right, right } from "failcraft";
80
80
  /**
81
81
  * Base contract for all domain events.
82
82
  *
@@ -587,4 +587,4 @@ interface UseCase<
587
587
  > {
588
588
  execute(input: Input): Promise<Output>;
589
589
  }
590
- export { DomainEvent, Creatable, Deletable, Findable, Saveable, Repository, UseCaseError, UseCase, Entity, AggregateRoot, EventHandler, DomainEvents, EventHandler2 as EventHandler1, Optional, UniqueEntityId, ValueObject, WatchedList, Either, just, left, Maybe, maybe, nothing, right };
590
+ export { DomainEvent, Creatable, Deletable, Findable, Saveable, Repository, UseCaseError, UseCase, Entity, AggregateRoot, EventHandler, DomainEvents, EventHandler2 as EventHandler1, Optional, UniqueEntityId, ValueObject, WatchedList, AsyncEither, attempt, Either, from, just, Left, left, Maybe, maybe, nothing, Right, right };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archstone",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "author": {
5
5
  "name": "João Henrique Benatti Coimbra",
6
6
  "url": "https://github.com/joao-coimbra"
@@ -1,2 +0,0 @@
1
- // @bun
2
- import{just as Q,left as X,maybe as Y,nothing as Z,right as _}from"failcraft";class O{handlersMap=new Map;markedAggregates=new Set;shouldRun=!0;markAggregateForDispatch(x){if(!this.findMarkedAggregateByID(x.id))this.markedAggregates.add(x)}dispatchEventsForAggregate(x){let E=this.findMarkedAggregateByID(x);if(E)this.dispatchAggregateEvents(E),E.clearEvents(),this.removeAggregateFromMarkedDispatchList(E)}register(x,E){if(!this.handlersMap.has(E))this.handlersMap.set(E,[]);this.handlersMap.get(E)?.push(x)}clearHandlers(){this.handlersMap.clear()}clearMarkedAggregates(){this.markedAggregates.clear()}dispatchAggregateEvents(x){for(let E of x.domainEvents)this.dispatch(E)}removeAggregateFromMarkedDispatchList(x){this.markedAggregates.delete(x)}findMarkedAggregateByID(x){return[...this.markedAggregates].find((E)=>E.id.equals(x))}dispatch(x){if(!this.shouldRun)return;let E=this.handlersMap.get(x.constructor.name)??[];for(let f of E)f(x)}}var M=new O;var{randomUUIDv7:V}=globalThis.Bun;class y{value;constructor(x){this.value=x??V()}toValue(){return this.value}toString(){return this.value}equals(x){return x.toValue()===this.value}}class H{props;constructor(x){this.props=x}equals(x){return JSON.stringify(this.props)===JSON.stringify(x.props)}}class L{currentItems;initial;new;removed;constructor(x){this.currentItems=x??[],this.initial=x??[],this.new=[],this.removed=[]}getItems(){return this.currentItems}getNewItems(){return this.new}getRemovedItems(){return this.removed}exists(x){return this.isCurrentItem(x)}add(x){if(this.isRemovedItem(x))this.removeFromRemoved(x);if(!(this.isNewItem(x)||this.wasAddedInitially(x)))this.new.push(x);if(!this.isCurrentItem(x))this.currentItems.push(x)}remove(x){if(this.removeFromCurrent(x),this.isNewItem(x)){this.removeFromNew(x);return}if(!this.isRemovedItem(x))this.removed.push(x)}update(x){this.new=x.filter((E)=>!this.getItems().some((f)=>this.compareItems(E,f))),this.removed=this.getItems().filter((E)=>!x.some((f)=>this.compareItems(E,f))),this.currentItems=x}isCurrentItem(x){return this.currentItems.some((E)=>this.compareItems(x,E))}isNewItem(x){return this.new.some((E)=>this.compareItems(x,E))}isRemovedItem(x){return this.removed.some((E)=>this.compareItems(x,E))}removeFromNew(x){this.new=this.new.filter((E)=>!this.compareItems(E,x))}removeFromCurrent(x){this.currentItems=this.currentItems.filter((E)=>!this.compareItems(x,E))}removeFromRemoved(x){this.removed=this.removed.filter((E)=>!this.compareItems(x,E))}wasAddedInitially(x){return this.initial.some((E)=>this.compareItems(x,E))}}export{M as c,y as d,H as e,L as f,Q as g,X as h,Y as i,Z as j,_ as k};