@velony/domain 1.1.0 → 1.1.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 ADDED
@@ -0,0 +1,237 @@
1
+ # @velony/domain
2
+
3
+ A TypeScript library providing core building blocks for Domain-Driven Design (DDD) applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @velony/domain
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Type-safe** - Full TypeScript support with comprehensive type definitions
14
+ - **DDD Patterns** - Implementations of core DDD tactical patterns
15
+ - **Immutable** - Value objects and events are immutable by design
16
+ - **Minimal dependencies** - Only depends on `uuid` for event ID generation
17
+
18
+ ## Core Concepts
19
+
20
+ ### Entity
21
+
22
+ An object with a distinct identity that runs through time and different states.
23
+
24
+ ```typescript
25
+ import { Entity, Id } from '@velony/domain';
26
+
27
+ class UserId extends Id<string> {
28
+ static create(value: string): UserId {
29
+ return new UserId(value);
30
+ }
31
+ }
32
+
33
+ class User extends Entity<UserId> {
34
+ constructor(
35
+ id: UserId,
36
+ private name: string,
37
+ private email: string
38
+ ) {
39
+ super(id);
40
+ }
41
+
42
+ getName(): string {
43
+ return this.name;
44
+ }
45
+
46
+ getEmail(): string {
47
+ return this.email;
48
+ }
49
+ }
50
+
51
+ const userId = UserId.create('user-123');
52
+ const user = new User(userId, 'John Doe', 'john@example.com');
53
+ ```
54
+
55
+ ### Value Object
56
+
57
+ An immutable object defined by its attributes rather than a unique identifier.
58
+
59
+ ```typescript
60
+ import { ValueObject } from '@velony/domain';
61
+
62
+ class Email extends ValueObject<string> {
63
+ private constructor(value: string) {
64
+ super(value);
65
+ }
66
+
67
+ static create(value: string): Email {
68
+ if (!value.includes('@')) {
69
+ throw new Error('Invalid email format');
70
+ }
71
+ return new Email(value);
72
+ }
73
+
74
+ equals(other: Email): boolean {
75
+ return this.value === other.value;
76
+ }
77
+
78
+ toString(): string {
79
+ return this.value;
80
+ }
81
+ }
82
+
83
+ const email = Email.create('user@example.com');
84
+ ```
85
+
86
+ ### Primitive Value Object
87
+
88
+ A convenient base class for value objects wrapping primitive types.
89
+
90
+ ```typescript
91
+ import { PrimitiveValueObject } from '@velony/domain';
92
+
93
+ class Age extends PrimitiveValueObject<number> {
94
+ private constructor(value: number) {
95
+ super(value);
96
+ }
97
+
98
+ static create(value: number): Age {
99
+ if (value < 0 || value > 150) {
100
+ throw new Error('Invalid age');
101
+ }
102
+ return new Age(value);
103
+ }
104
+ }
105
+
106
+ const age = Age.create(25);
107
+ console.log(age.toString()); // "25"
108
+ ```
109
+
110
+ ### Aggregate Root
111
+
112
+ The entry point to an aggregate that maintains consistency boundaries and manages domain events.
113
+
114
+ ```typescript
115
+ import { AggregateRoot, Id, DomainEvent } from '@velony/domain';
116
+
117
+ class OrderId extends Id<string> {
118
+ static create(value: string): OrderId {
119
+ return new OrderId(value);
120
+ }
121
+ }
122
+
123
+ class OrderPlacedEvent extends DomainEvent<{ total: number }> {
124
+ static readonly type = 'order.placed';
125
+
126
+ constructor(aggregateId: string, total: number) {
127
+ super(aggregateId, { total });
128
+ }
129
+ }
130
+
131
+ class Order extends AggregateRoot<OrderId> {
132
+ constructor(
133
+ id: OrderId,
134
+ private total: number
135
+ ) {
136
+ super(id);
137
+ }
138
+
139
+ place(): void {
140
+ this.pushDomainEvent(
141
+ new OrderPlacedEvent(this.id.toString(), this.total)
142
+ );
143
+ }
144
+ }
145
+
146
+ const order = new Order(OrderId.create('order-123'), 100);
147
+ order.place();
148
+ const events = order.pullDomainEvents();
149
+ ```
150
+
151
+ ### Domain Event
152
+
153
+ Represents something significant that happened in the domain.
154
+
155
+ ```typescript
156
+ import { DomainEvent } from '@velony/domain';
157
+
158
+ interface UserRegisteredPayload {
159
+ email: string;
160
+ name: string;
161
+ }
162
+
163
+ class UserRegisteredEvent extends DomainEvent<UserRegisteredPayload> {
164
+ static readonly type = 'user.registered';
165
+
166
+ constructor(aggregateId: string, email: string, name: string) {
167
+ super(aggregateId, { email, name });
168
+ }
169
+ }
170
+
171
+ const event = new UserRegisteredEvent('user-123', 'john@example.com', 'John Doe');
172
+ console.log(event.id); // UUIDv7
173
+ console.log(event.type); // "user.registered"
174
+ console.log(event.occurredAt); // Date
175
+ console.log(event.payload); // { email: "john@example.com", name: "John Doe" }
176
+ ```
177
+
178
+ ### StoragePath
179
+
180
+ A built-in value object for safe storage paths.
181
+
182
+ ```typescript
183
+ import { StoragePath } from '@velony/domain';
184
+
185
+ const path = StoragePath.create('uploads/images/photo.jpg');
186
+ console.log(path.extension); // "jpg"
187
+ console.log(path.toUrl('https://storage.example.com'));
188
+ // "https://storage.example.com/uploads/images/photo.jpg"
189
+
190
+ // Validation prevents unsafe paths
191
+ StoragePath.create('/etc/passwd'); // Error: Storage path should not start with /
192
+ StoragePath.create('../secrets'); // Error: Storage path cannot contain ..
193
+ StoragePath.create('files//data'); // Error: Storage path contains invalid double slashes
194
+ ```
195
+
196
+ ## API Reference
197
+
198
+ ### `Entity<TIdentifier>`
199
+ - `id: TIdentifier` - The unique identifier
200
+ - `equals(other: this): boolean` - Compare entities by identity
201
+
202
+ ### `ValueObject<TValue>`
203
+ - `value: TValue` - The wrapped value
204
+ - `equals(other: this): boolean` - Compare by value (abstract)
205
+ - `toString(): string` - String representation (abstract)
206
+
207
+ ### `PrimitiveValueObject<T>`
208
+ - Extends `ValueObject<T>` with default implementations for primitives
209
+ - `equals(other: this): boolean` - Compares using strict equality
210
+ - `toString(): string` - Converts value to string
211
+
212
+ ### `Id<T>`
213
+ - Extends `PrimitiveValueObject<T>` for entity identifiers
214
+
215
+ ### `AggregateRoot<TIdentifier>`
216
+ - Extends `Entity<TIdentifier>`
217
+ - `pullDomainEvents(): DomainEvent<any>[]` - Retrieve and clear events
218
+ - `pushDomainEvent(event: DomainEvent<any>): void` - Add event (protected)
219
+
220
+ ### `DomainEvent<TPayload>`
221
+ - `id: string` - Unique event ID (UUIDv7)
222
+ - `aggregateId: string` - ID of the aggregate that produced the event
223
+ - `payload: TPayload` - Event-specific data
224
+ - `occurredAt: Date` - Timestamp of occurrence
225
+ - `type: string` - Event type identifier
226
+
227
+ ## License
228
+
229
+ MIT
230
+
231
+ ## Repository
232
+
233
+ [https://github.com/velony-ai/domain](https://github.com/velony-ai/domain)
234
+
235
+ ## Issues
236
+
237
+ [https://github.com/velony-ai/domain/issues](https://github.com/velony-ai/domain/issues)
@@ -2,10 +2,37 @@ import { DomainEvent } from './domain-event';
2
2
  import { Entity } from './entity';
3
3
  import { Id } from './id';
4
4
  declare const AGGREGATE_ROOT_BRAND: unique symbol;
5
+ /**
6
+ * Abstract base class for aggregate roots in Domain-Driven Design.
7
+ * An aggregate root is the entry point to an aggregate and is responsible for
8
+ * maintaining the consistency of the aggregate boundary.
9
+ * It manages domain events that occur within the aggregate.
10
+ *
11
+ * @template TIdentifier - The type of identifier for the aggregate root, must extend Id
12
+ * @extends Entity
13
+ */
5
14
  export declare abstract class AggregateRoot<TIdentifier extends Id<string | number>> extends Entity<TIdentifier> {
6
15
  private readonly [AGGREGATE_ROOT_BRAND];
16
+ /**
17
+ * Collection of domain events that have occurred within this aggregate.
18
+ * @private
19
+ */
7
20
  private _domainEvents;
21
+ /**
22
+ * Retrieves and clears all pending domain events from the aggregate.
23
+ * This method is typically called by infrastructure code after persisting
24
+ * the aggregate to publish the events.
25
+ *
26
+ * @returns An array of domain events that occurred within the aggregate
27
+ */
8
28
  pullDomainEvents(): DomainEvent<any>[];
9
- protected addDomainEvent(event: DomainEvent<any>): void;
29
+ /**
30
+ * Adds a domain event to the aggregate's event collection.
31
+ * Protected to allow only the aggregate itself to record events.
32
+ *
33
+ * @param event - The domain event to add
34
+ * @protected
35
+ */
36
+ protected pushDomainEvent(event: DomainEvent<any>): void;
10
37
  }
11
38
  export {};
@@ -2,15 +2,42 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AggregateRoot = void 0;
4
4
  const entity_1 = require("./entity");
5
+ /**
6
+ * Abstract base class for aggregate roots in Domain-Driven Design.
7
+ * An aggregate root is the entry point to an aggregate and is responsible for
8
+ * maintaining the consistency of the aggregate boundary.
9
+ * It manages domain events that occur within the aggregate.
10
+ *
11
+ * @template TIdentifier - The type of identifier for the aggregate root, must extend Id
12
+ * @extends Entity
13
+ */
5
14
  class AggregateRoot extends entity_1.Entity {
6
15
  [AGGREGATE_ROOT_BRAND];
16
+ /**
17
+ * Collection of domain events that have occurred within this aggregate.
18
+ * @private
19
+ */
7
20
  _domainEvents = [];
21
+ /**
22
+ * Retrieves and clears all pending domain events from the aggregate.
23
+ * This method is typically called by infrastructure code after persisting
24
+ * the aggregate to publish the events.
25
+ *
26
+ * @returns An array of domain events that occurred within the aggregate
27
+ */
8
28
  pullDomainEvents() {
9
29
  const events = [...this._domainEvents];
10
30
  this._domainEvents = [];
11
31
  return events;
12
32
  }
13
- addDomainEvent(event) {
33
+ /**
34
+ * Adds a domain event to the aggregate's event collection.
35
+ * Protected to allow only the aggregate itself to record events.
36
+ *
37
+ * @param event - The domain event to add
38
+ * @protected
39
+ */
40
+ pushDomainEvent(event) {
14
41
  this._domainEvents.push(event);
15
42
  }
16
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate-root.js","sourceRoot":"","sources":["../src/aggregate-root.ts"],"names":[],"mappings":";;;AACA,qCAAkC;AAKlC,MAAsB,aAEpB,SAAQ,eAAmB;IACV,CAAC,oBAAoB,CAAC,CAAO;IAEtC,aAAa,GAAuB,EAAE,CAAC;IAExC,gBAAgB;QACrB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;QACvC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IAES,cAAc,CAAC,KAAuB;QAC9C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;CACF;AAhBD,sCAgBC"}
1
+ {"version":3,"file":"aggregate-root.js","sourceRoot":"","sources":["../src/aggregate-root.ts"],"names":[],"mappings":";;;AACA,qCAAkC;AAKlC;;;;;;;;GAQG;AACH,MAAsB,aAEpB,SAAQ,eAAmB;IACV,CAAC,oBAAoB,CAAC,CAAO;IAE9C;;;OAGG;IACK,aAAa,GAAuB,EAAE,CAAC;IAE/C;;;;;;OAMG;IACI,gBAAgB;QACrB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;QACvC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;OAMG;IACO,eAAe,CAAC,KAAuB;QAC/C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;CACF;AAlCD,sCAkCC"}
@@ -1,11 +1,50 @@
1
1
  export declare const DOMAIN_EVENT_BRAND: unique symbol;
2
+ /**
3
+ * Abstract base class for domain events in Domain-Driven Design.
4
+ * A domain event represents something that happened in the domain that
5
+ * domain experts care about. Events are immutable and represent facts.
6
+ *
7
+ * @template TPayload - The type of the event payload containing event-specific data
8
+ */
2
9
  export declare abstract class DomainEvent<TPayload> {
3
10
  private readonly [DOMAIN_EVENT_BRAND];
11
+ /**
12
+ * Static type identifier for the event class.
13
+ * Should be overridden in concrete event classes.
14
+ */
4
15
  static readonly type: string;
16
+ /**
17
+ * Unique identifier for this event instance (UUIDv7).
18
+ * @readonly
19
+ */
5
20
  readonly id: string;
21
+ /**
22
+ * The identifier of the aggregate that produced this event.
23
+ * @readonly
24
+ */
6
25
  readonly aggregateId: string;
26
+ /**
27
+ * The data payload specific to this event.
28
+ * @readonly
29
+ */
7
30
  readonly payload: TPayload;
31
+ /**
32
+ * The timestamp when this event occurred.
33
+ * @readonly
34
+ */
8
35
  readonly occurredAt: Date;
36
+ /**
37
+ * Creates a new domain event.
38
+ *
39
+ * @param aggregateId - The ID of the aggregate that produced this event
40
+ * @param payload - The event-specific data
41
+ * @protected
42
+ */
9
43
  protected constructor(aggregateId: string, payload: TPayload);
44
+ /**
45
+ * Gets the type identifier for this event.
46
+ *
47
+ * @returns The event type string from the static type property
48
+ */
10
49
  get type(): string;
11
50
  }
@@ -2,19 +2,58 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DomainEvent = void 0;
4
4
  const uuid_1 = require("uuid");
5
+ /**
6
+ * Abstract base class for domain events in Domain-Driven Design.
7
+ * A domain event represents something that happened in the domain that
8
+ * domain experts care about. Events are immutable and represent facts.
9
+ *
10
+ * @template TPayload - The type of the event payload containing event-specific data
11
+ */
5
12
  class DomainEvent {
6
13
  [exports.DOMAIN_EVENT_BRAND];
14
+ /**
15
+ * Static type identifier for the event class.
16
+ * Should be overridden in concrete event classes.
17
+ */
7
18
  static type;
19
+ /**
20
+ * Unique identifier for this event instance (UUIDv7).
21
+ * @readonly
22
+ */
8
23
  id;
24
+ /**
25
+ * The identifier of the aggregate that produced this event.
26
+ * @readonly
27
+ */
9
28
  aggregateId;
29
+ /**
30
+ * The data payload specific to this event.
31
+ * @readonly
32
+ */
10
33
  payload;
34
+ /**
35
+ * The timestamp when this event occurred.
36
+ * @readonly
37
+ */
11
38
  occurredAt;
39
+ /**
40
+ * Creates a new domain event.
41
+ *
42
+ * @param aggregateId - The ID of the aggregate that produced this event
43
+ * @param payload - The event-specific data
44
+ * @protected
45
+ */
12
46
  constructor(aggregateId, payload) {
13
47
  this.id = (0, uuid_1.v7)();
14
48
  this.aggregateId = aggregateId;
15
49
  this.occurredAt = new Date();
16
50
  this.payload = payload;
17
51
  }
52
+ /**
53
+ * Gets the type identifier for this event.
54
+ *
55
+ * @returns The event type string from the static type property
56
+ */
18
57
  get type() {
19
58
  return this.constructor.type;
20
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"domain-event.js","sourceRoot":"","sources":["../src/domain-event.ts"],"names":[],"mappings":";;;AAAA,+BAAoC;AAIpC,MAAsB,WAAW;IACd,CAAC,0BAAkB,CAAC,CAAO;IAErC,MAAM,CAAU,IAAI,CAAS;IAEpB,EAAE,CAAS;IACX,WAAW,CAAS;IACpB,OAAO,CAAW;IAClB,UAAU,CAAO;IAEjC,YAAsB,WAAmB,EAAE,OAAiB;QAC1D,IAAI,CAAC,EAAE,GAAG,IAAA,SAAM,GAAE,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,IAAW,IAAI;QACb,OAAQ,IAAI,CAAC,WAA4C,CAAC,IAAI,CAAC;IACjE,CAAC;CACF;AApBD,kCAoBC"}
1
+ {"version":3,"file":"domain-event.js","sourceRoot":"","sources":["../src/domain-event.ts"],"names":[],"mappings":";;;AAAA,+BAAoC;AAIpC;;;;;;GAMG;AACH,MAAsB,WAAW;IACd,CAAC,0BAAkB,CAAC,CAAO;IAE5C;;;OAGG;IACI,MAAM,CAAU,IAAI,CAAS;IAEpC;;;OAGG;IACa,EAAE,CAAS;IAE3B;;;OAGG;IACa,WAAW,CAAS;IAEpC;;;OAGG;IACa,OAAO,CAAW;IAElC;;;OAGG;IACa,UAAU,CAAO;IAEjC;;;;;;OAMG;IACH,YAAsB,WAAmB,EAAE,OAAiB;QAC1D,IAAI,CAAC,EAAE,GAAG,IAAA,SAAM,GAAE,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,IAAW,IAAI;QACb,OAAQ,IAAI,CAAC,WAA4C,CAAC,IAAI,CAAC;IACjE,CAAC;CACF;AAvDD,kCAuDC"}
package/dist/entity.d.ts CHANGED
@@ -1,10 +1,40 @@
1
1
  import { Id } from './id';
2
2
  declare const ENTITY_BRAND: unique symbol;
3
+ /**
4
+ * Abstract base class for entities in Domain-Driven Design.
5
+ * An entity is an object that has a distinct identity that runs through time
6
+ * and different states. Two entities with different identifiers are considered
7
+ * different even if all other attributes are the same.
8
+ *
9
+ * @template TIdentifier - The type of identifier for the entity, must extend Id
10
+ */
3
11
  export declare abstract class Entity<TIdentifier extends Id<string | number>> {
4
12
  private readonly [ENTITY_BRAND];
13
+ /**
14
+ * The unique identifier for this entity.
15
+ * @protected
16
+ */
5
17
  protected readonly _id: TIdentifier;
18
+ /**
19
+ * Creates a new entity with the given identifier.
20
+ *
21
+ * @param id - The unique identifier for this entity
22
+ * @protected
23
+ */
6
24
  protected constructor(id: TIdentifier);
25
+ /**
26
+ * Gets the unique identifier of this entity.
27
+ *
28
+ * @returns The entity's identifier
29
+ */
7
30
  get id(): TIdentifier;
31
+ /**
32
+ * Checks if this entity is equal to another entity.
33
+ * Two entities are equal if they have the same identifier.
34
+ *
35
+ * @param other - The entity to compare with
36
+ * @returns True if the entities have the same identifier, false otherwise
37
+ */
8
38
  equals(other: this): boolean;
9
39
  }
10
40
  export {};
package/dist/entity.js CHANGED
@@ -1,15 +1,45 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Entity = void 0;
4
+ /**
5
+ * Abstract base class for entities in Domain-Driven Design.
6
+ * An entity is an object that has a distinct identity that runs through time
7
+ * and different states. Two entities with different identifiers are considered
8
+ * different even if all other attributes are the same.
9
+ *
10
+ * @template TIdentifier - The type of identifier for the entity, must extend Id
11
+ */
4
12
  class Entity {
5
13
  [ENTITY_BRAND];
14
+ /**
15
+ * The unique identifier for this entity.
16
+ * @protected
17
+ */
6
18
  _id;
19
+ /**
20
+ * Creates a new entity with the given identifier.
21
+ *
22
+ * @param id - The unique identifier for this entity
23
+ * @protected
24
+ */
7
25
  constructor(id) {
8
26
  this._id = id;
9
27
  }
28
+ /**
29
+ * Gets the unique identifier of this entity.
30
+ *
31
+ * @returns The entity's identifier
32
+ */
10
33
  get id() {
11
34
  return this._id;
12
35
  }
36
+ /**
37
+ * Checks if this entity is equal to another entity.
38
+ * Two entities are equal if they have the same identifier.
39
+ *
40
+ * @param other - The entity to compare with
41
+ * @returns True if the entities have the same identifier, false otherwise
42
+ */
13
43
  equals(other) {
14
44
  return this._id.equals(other._id);
15
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entity.js","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":";;;AAIA,MAAsB,MAAM;IACT,CAAC,YAAY,CAAC,CAAO;IAEnB,GAAG,CAAc;IAEpC,YAAsB,EAAe;QACnC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,IAAW,EAAE;QACX,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;IAEM,MAAM,CAAC,KAAW;QACvB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;CACF;AAhBD,wBAgBC"}
1
+ {"version":3,"file":"entity.js","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":";;;AAIA;;;;;;;GAOG;AACH,MAAsB,MAAM;IACT,CAAC,YAAY,CAAC,CAAO;IAEtC;;;OAGG;IACgB,GAAG,CAAc;IAEpC;;;;;OAKG;IACH,YAAsB,EAAe;QACnC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,IAAW,EAAE;QACX,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,KAAW;QACvB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;CACF;AAtCD,wBAsCC"}
package/dist/id.d.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  import { PrimitiveValueObject } from './primitive-value-object.js';
2
2
  declare const ID_BRAND: unique symbol;
3
+ /**
4
+ * Abstract base class for entity identifiers.
5
+ * Represents a unique identifier for domain entities, ensuring type safety
6
+ * and proper value object semantics for IDs.
7
+ *
8
+ * @template T - The primitive type of the identifier (string or number)
9
+ * @extends PrimitiveValueObject
10
+ */
3
11
  export declare abstract class Id<T extends string | number> extends PrimitiveValueObject<T> {
4
12
  private readonly [ID_BRAND];
5
13
  }
package/dist/id.js CHANGED
@@ -2,6 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Id = void 0;
4
4
  const primitive_value_object_js_1 = require("./primitive-value-object.js");
5
+ /**
6
+ * Abstract base class for entity identifiers.
7
+ * Represents a unique identifier for domain entities, ensuring type safety
8
+ * and proper value object semantics for IDs.
9
+ *
10
+ * @template T - The primitive type of the identifier (string or number)
11
+ * @extends PrimitiveValueObject
12
+ */
5
13
  class Id extends primitive_value_object_js_1.PrimitiveValueObject {
6
14
  [ID_BRAND];
7
15
  }
package/dist/id.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"id.js","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":";;;AAAA,2EAAmE;AAInE,MAAsB,EAEpB,SAAQ,gDAAuB;IACd,CAAC,QAAQ,CAAC,CAAO;CACnC;AAJD,gBAIC"}
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":";;;AAAA,2EAAmE;AAInE;;;;;;;GAOG;AACH,MAAsB,EAEpB,SAAQ,gDAAuB;IACd,CAAC,QAAQ,CAAC,CAAO;CACnC;AAJD,gBAIC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @velony/domain - Domain-Driven Design building blocks
3
+ *
4
+ * This package provides core abstractions for implementing Domain-Driven Design (DDD)
5
+ * patterns in TypeScript applications. It includes base classes for:
6
+ * - Entities: Objects with unique identities
7
+ * - Value Objects: Immutable objects defined by their attributes
8
+ * - Aggregate Roots: Entry points to aggregates that maintain consistency
9
+ * - Domain Events: Represent significant occurrences in the domain
10
+ *
11
+ * @packageDocumentation
12
+ */
1
13
  export { Entity } from './entity';
2
14
  export { Id } from './id';
3
15
  export { ValueObject } from './value-object';
package/dist/index.js CHANGED
@@ -1,4 +1,16 @@
1
1
  "use strict";
2
+ /**
3
+ * @velony/domain - Domain-Driven Design building blocks
4
+ *
5
+ * This package provides core abstractions for implementing Domain-Driven Design (DDD)
6
+ * patterns in TypeScript applications. It includes base classes for:
7
+ * - Entities: Objects with unique identities
8
+ * - Value Objects: Immutable objects defined by their attributes
9
+ * - Aggregate Roots: Entry points to aggregates that maintain consistency
10
+ * - Domain Events: Represent significant occurrences in the domain
11
+ *
12
+ * @packageDocumentation
13
+ */
2
14
  Object.defineProperty(exports, "__esModule", { value: true });
3
15
  exports.StoragePath = exports.DomainEvent = exports.AggregateRoot = exports.PrimitiveValueObject = exports.ValueObject = exports.Id = exports.Entity = void 0;
4
16
  var entity_1 = require("./entity");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AACf,2BAA0B;AAAjB,wFAAA,EAAE,OAAA;AACX,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mEAAgE;AAAvD,8HAAA,oBAAoB,OAAA;AAC7B,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mEAA8D;AAArD,8GAAA,WAAW,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAEH,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AACf,2BAA0B;AAAjB,wFAAA,EAAE,OAAA;AACX,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mEAAgE;AAAvD,8HAAA,oBAAoB,OAAA;AAC7B,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mEAA8D;AAArD,8GAAA,WAAW,OAAA"}
@@ -1,8 +1,29 @@
1
1
  import { ValueObject } from './value-object';
2
2
  declare const PRIMITIVE_VO_BRAND: unique symbol;
3
+ /**
4
+ * Abstract base class for value objects wrapping primitive values.
5
+ * This class provides a convenient base for value objects that wrap
6
+ * primitive types (string, number, or boolean) with default implementations
7
+ * for equality and string conversion.
8
+ *
9
+ * @template T - The primitive type of the wrapped value (string, number, or boolean)
10
+ * @extends ValueObject
11
+ */
3
12
  export declare abstract class PrimitiveValueObject<T extends string | number | boolean> extends ValueObject<T> {
4
13
  private readonly [PRIMITIVE_VO_BRAND];
14
+ /**
15
+ * Checks if this value object is equal to another by comparing primitive values.
16
+ * Uses strict equality (===) for comparison.
17
+ *
18
+ * @param other - The value object to compare with
19
+ * @returns True if the primitive values are strictly equal, false otherwise
20
+ */
5
21
  equals(other: this): boolean;
22
+ /**
23
+ * Returns a string representation of the primitive value.
24
+ *
25
+ * @returns The string representation of the wrapped primitive value
26
+ */
6
27
  toString(): string;
7
28
  }
8
29
  export {};
@@ -2,11 +2,32 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PrimitiveValueObject = void 0;
4
4
  const value_object_1 = require("./value-object");
5
+ /**
6
+ * Abstract base class for value objects wrapping primitive values.
7
+ * This class provides a convenient base for value objects that wrap
8
+ * primitive types (string, number, or boolean) with default implementations
9
+ * for equality and string conversion.
10
+ *
11
+ * @template T - The primitive type of the wrapped value (string, number, or boolean)
12
+ * @extends ValueObject
13
+ */
5
14
  class PrimitiveValueObject extends value_object_1.ValueObject {
6
15
  [PRIMITIVE_VO_BRAND];
16
+ /**
17
+ * Checks if this value object is equal to another by comparing primitive values.
18
+ * Uses strict equality (===) for comparison.
19
+ *
20
+ * @param other - The value object to compare with
21
+ * @returns True if the primitive values are strictly equal, false otherwise
22
+ */
7
23
  equals(other) {
8
- return this._value === other.value;
24
+ return this._value === other._value;
9
25
  }
26
+ /**
27
+ * Returns a string representation of the primitive value.
28
+ *
29
+ * @returns The string representation of the wrapped primitive value
30
+ */
10
31
  toString() {
11
32
  return String(this._value);
12
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"primitive-value-object.js","sourceRoot":"","sources":["../src/primitive-value-object.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAI7C,MAAsB,oBAEpB,SAAQ,0BAAc;IACL,CAAC,kBAAkB,CAAC,CAAO;IAErC,MAAM,CAAC,KAAW;QACvB,OAAO,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,KAAK,CAAC;IACrC,CAAC;IAEM,QAAQ;QACb,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;CACF;AAZD,oDAYC"}
1
+ {"version":3,"file":"primitive-value-object.js","sourceRoot":"","sources":["../src/primitive-value-object.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAI7C;;;;;;;;GAQG;AACH,MAAsB,oBAEpB,SAAQ,0BAAc;IACL,CAAC,kBAAkB,CAAC,CAAO;IAE5C;;;;;;OAMG;IACI,MAAM,CAAC,KAAW;QACvB,OAAO,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACI,QAAQ;QACb,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;CACF;AAxBD,oDAwBC"}
@@ -1,10 +1,45 @@
1
1
  declare const VO_BRAND: unique symbol;
2
+ /**
3
+ * Abstract base class for value objects in Domain-Driven Design.
4
+ * A value object is an immutable object that represents a descriptive aspect
5
+ * of the domain with no conceptual identity. Value objects are defined by
6
+ * their attributes rather than a unique identifier.
7
+ *
8
+ * @template TValue - The type of the wrapped value
9
+ */
2
10
  export declare abstract class ValueObject<TValue> {
3
11
  private readonly [VO_BRAND];
12
+ /**
13
+ * The encapsulated value.
14
+ * @protected
15
+ */
4
16
  protected readonly _value: TValue;
17
+ /**
18
+ * Creates a new value object wrapping the given value.
19
+ *
20
+ * @param value - The value to wrap
21
+ * @protected
22
+ */
5
23
  protected constructor(value: TValue);
24
+ /**
25
+ * Gets the wrapped value.
26
+ *
27
+ * @returns The encapsulated value
28
+ */
6
29
  get value(): TValue;
30
+ /**
31
+ * Checks if this value object is equal to another value object.
32
+ * Concrete implementations should define equality based on the values.
33
+ *
34
+ * @param other - The value object to compare with
35
+ * @returns True if the value objects are equal, false otherwise
36
+ */
7
37
  abstract equals(other: this): boolean;
38
+ /**
39
+ * Returns a string representation of the value object.
40
+ *
41
+ * @returns A string representation of this value object
42
+ */
8
43
  abstract toString(): string;
9
44
  }
10
45
  export {};
@@ -1,12 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ValueObject = void 0;
4
+ /**
5
+ * Abstract base class for value objects in Domain-Driven Design.
6
+ * A value object is an immutable object that represents a descriptive aspect
7
+ * of the domain with no conceptual identity. Value objects are defined by
8
+ * their attributes rather than a unique identifier.
9
+ *
10
+ * @template TValue - The type of the wrapped value
11
+ */
4
12
  class ValueObject {
5
13
  [VO_BRAND];
14
+ /**
15
+ * The encapsulated value.
16
+ * @protected
17
+ */
6
18
  _value;
19
+ /**
20
+ * Creates a new value object wrapping the given value.
21
+ *
22
+ * @param value - The value to wrap
23
+ * @protected
24
+ */
7
25
  constructor(value) {
8
26
  this._value = value;
9
27
  }
28
+ /**
29
+ * Gets the wrapped value.
30
+ *
31
+ * @returns The encapsulated value
32
+ */
10
33
  get value() {
11
34
  return this._value;
12
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"value-object.js","sourceRoot":"","sources":["../src/value-object.ts"],"names":[],"mappings":";;;AAEA,MAAsB,WAAW;IACd,CAAC,QAAQ,CAAC,CAAO;IAEf,MAAM,CAAS;IAElC,YAAsB,KAAa;QACjC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,IAAW,KAAK;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CAKF;AAhBD,kCAgBC"}
1
+ {"version":3,"file":"value-object.js","sourceRoot":"","sources":["../src/value-object.ts"],"names":[],"mappings":";;;AAEA;;;;;;;GAOG;AACH,MAAsB,WAAW;IACd,CAAC,QAAQ,CAAC,CAAO;IAElC;;;OAGG;IACgB,MAAM,CAAS;IAElC;;;;;OAKG;IACH,YAAsB,KAAa;QACjC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACH,IAAW,KAAK;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CAiBF;AA3CD,kCA2CC"}
@@ -1,10 +1,50 @@
1
1
  import { PrimitiveValueObject } from '../primitive-value-object';
2
2
  declare const STORAGE_PATH_VO_BRAND: unique symbol;
3
+ /**
4
+ * Value object representing a storage path with validation.
5
+ * Ensures paths are safe and properly formatted for storage operations.
6
+ * Paths must not start with '/', contain double slashes, or include '..' for security.
7
+ *
8
+ * @extends PrimitiveValueObject
9
+ */
3
10
  export declare class StoragePath extends PrimitiveValueObject<string> {
4
11
  private readonly [STORAGE_PATH_VO_BRAND];
12
+ /**
13
+ * Private constructor to enforce factory method usage.
14
+ *
15
+ * @param value - The validated storage path string
16
+ * @private
17
+ */
5
18
  private constructor();
19
+ /**
20
+ * Factory method to create a new StoragePath with validation.
21
+ *
22
+ * @param value - The storage path string to validate and wrap
23
+ * @returns A new StoragePath instance
24
+ * @throws {Error} If path starts with '/'
25
+ * @throws {Error} If path contains double slashes '//'
26
+ * @throws {Error} If path contains '..' (parent directory reference)
27
+ */
6
28
  static create(value: string): StoragePath;
29
+ /**
30
+ * Converts the storage path to a full URL by combining with a base URL.
31
+ * Ensures proper URL formatting by removing trailing slashes from base URL.
32
+ *
33
+ * @param baseUrl - The base URL to prepend to the storage path
34
+ * @returns The complete URL with the storage path appended
35
+ * @example
36
+ * const path = StoragePath.create('files/document.pdf');
37
+ * path.toUrl('https://storage.example.com'); // 'https://storage.example.com/files/document.pdf'
38
+ */
7
39
  toUrl(baseUrl: string): string;
40
+ /**
41
+ * Gets the file extension from the storage path.
42
+ *
43
+ * @returns The lowercase file extension without the dot, or empty string if no extension
44
+ * @example
45
+ * StoragePath.create('files/document.PDF').extension // 'pdf'
46
+ * StoragePath.create('files/readme').extension // ''
47
+ */
8
48
  get extension(): string;
9
49
  }
10
50
  export {};
@@ -2,11 +2,33 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StoragePath = void 0;
4
4
  const primitive_value_object_1 = require("../primitive-value-object");
5
+ /**
6
+ * Value object representing a storage path with validation.
7
+ * Ensures paths are safe and properly formatted for storage operations.
8
+ * Paths must not start with '/', contain double slashes, or include '..' for security.
9
+ *
10
+ * @extends PrimitiveValueObject
11
+ */
5
12
  class StoragePath extends primitive_value_object_1.PrimitiveValueObject {
6
13
  [STORAGE_PATH_VO_BRAND];
14
+ /**
15
+ * Private constructor to enforce factory method usage.
16
+ *
17
+ * @param value - The validated storage path string
18
+ * @private
19
+ */
7
20
  constructor(value) {
8
21
  super(value);
9
22
  }
23
+ /**
24
+ * Factory method to create a new StoragePath with validation.
25
+ *
26
+ * @param value - The storage path string to validate and wrap
27
+ * @returns A new StoragePath instance
28
+ * @throws {Error} If path starts with '/'
29
+ * @throws {Error} If path contains double slashes '//'
30
+ * @throws {Error} If path contains '..' (parent directory reference)
31
+ */
10
32
  static create(value) {
11
33
  if (value.startsWith('/')) {
12
34
  throw new Error('Storage path should not start with /');
@@ -19,9 +41,27 @@ class StoragePath extends primitive_value_object_1.PrimitiveValueObject {
19
41
  }
20
42
  return new StoragePath(value);
21
43
  }
44
+ /**
45
+ * Converts the storage path to a full URL by combining with a base URL.
46
+ * Ensures proper URL formatting by removing trailing slashes from base URL.
47
+ *
48
+ * @param baseUrl - The base URL to prepend to the storage path
49
+ * @returns The complete URL with the storage path appended
50
+ * @example
51
+ * const path = StoragePath.create('files/document.pdf');
52
+ * path.toUrl('https://storage.example.com'); // 'https://storage.example.com/files/document.pdf'
53
+ */
22
54
  toUrl(baseUrl) {
23
55
  return `${baseUrl.replace(/\/$/, '')}/${this._value}`;
24
56
  }
57
+ /**
58
+ * Gets the file extension from the storage path.
59
+ *
60
+ * @returns The lowercase file extension without the dot, or empty string if no extension
61
+ * @example
62
+ * StoragePath.create('files/document.PDF').extension // 'pdf'
63
+ * StoragePath.create('files/readme').extension // ''
64
+ */
25
65
  get extension() {
26
66
  const parts = this._value.split('.');
27
67
  return parts.at(-1)?.toLowerCase() ?? '';
@@ -1 +1 @@
1
- {"version":3,"file":"storage-path.vo.js","sourceRoot":"","sources":["../../src/value-objects/storage-path.vo.ts"],"names":[],"mappings":";;;AAAA,sEAAiE;AAIjE,MAAa,WAAY,SAAQ,6CAA4B;IAC1C,CAAC,qBAAqB,CAAC,CAAO;IAE/C,YAAoB,KAAa;QAC/B,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,KAAa;QAChC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAEM,KAAK,CAAC,OAAe;QAC1B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IACxD,CAAC;IAED,IAAW,SAAS;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;CACF;AA7BD,kCA6BC"}
1
+ {"version":3,"file":"storage-path.vo.js","sourceRoot":"","sources":["../../src/value-objects/storage-path.vo.ts"],"names":[],"mappings":";;;AAAA,sEAAiE;AAIjE;;;;;;GAMG;AACH,MAAa,WAAY,SAAQ,6CAA4B;IAC1C,CAAC,qBAAqB,CAAC,CAAO;IAE/C;;;;;OAKG;IACH,YAAoB,KAAa;QAC/B,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,MAAM,CAAC,KAAa;QAChC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,OAAe;QAC1B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IACxD,CAAC;IAED;;;;;;;OAOG;IACH,IAAW,SAAS;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;CACF;AA9DD,kCA8DC"}
package/package.json CHANGED
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "name": "@velony/domain",
3
- "version": "1.1.0",
4
- "description": "",
3
+ "version": "1.1.2",
4
+ "description": "TypeScript library providing core building blocks for Domain-Driven Design (DDD) applications",
5
+ "keywords": [
6
+ "ddd",
7
+ "domain-driven-design",
8
+ "domain",
9
+ "entity",
10
+ "value-object",
11
+ "aggregate",
12
+ "domain-event",
13
+ "typescript",
14
+ "ddd-patterns",
15
+ "tactical-patterns"
16
+ ],
5
17
  "main": "./dist/index.js",
6
18
  "types": "./dist/index.d.ts",
7
19
  "exports": {
@@ -11,8 +23,16 @@
11
23
  }
12
24
  },
13
25
  "files": [
14
- "dist"
26
+ "dist",
27
+ "README.md",
28
+ "LICENSE"
15
29
  ],
30
+ "engines": {
31
+ "node": ">=18.0.0"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
16
36
  "scripts": {
17
37
  "build": "tsc",
18
38
  "lint": "eslint src"