@velony/domain 1.1.1 → 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 +237 -0
- package/dist/aggregate-root.d.ts +27 -0
- package/dist/aggregate-root.js +27 -0
- package/dist/aggregate-root.js.map +1 -1
- package/dist/domain-event.d.ts +39 -0
- package/dist/domain-event.js +39 -0
- package/dist/domain-event.js.map +1 -1
- package/dist/entity.d.ts +30 -0
- package/dist/entity.js +30 -0
- package/dist/entity.js.map +1 -1
- package/dist/id.d.ts +8 -0
- package/dist/id.js +8 -0
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/primitive-value-object.d.ts +21 -0
- package/dist/primitive-value-object.js +21 -0
- package/dist/primitive-value-object.js.map +1 -1
- package/dist/value-object.d.ts +35 -0
- package/dist/value-object.js +23 -0
- package/dist/value-object.js.map +1 -1
- package/dist/value-objects/storage-path.vo.d.ts +40 -0
- package/dist/value-objects/storage-path.vo.js +40 -0
- package/dist/value-objects/storage-path.vo.js.map +1 -1
- package/package.json +23 -3
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)
|
package/dist/aggregate-root.d.ts
CHANGED
|
@@ -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>[];
|
|
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
|
+
*/
|
|
9
36
|
protected pushDomainEvent(event: DomainEvent<any>): void;
|
|
10
37
|
}
|
|
11
38
|
export {};
|
package/dist/aggregate-root.js
CHANGED
|
@@ -2,14 +2,41 @@
|
|
|
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
|
}
|
|
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
|
+
*/
|
|
13
40
|
pushDomainEvent(event) {
|
|
14
41
|
this._domainEvents.push(event);
|
|
15
42
|
}
|
|
@@ -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;
|
|
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"}
|
package/dist/domain-event.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/domain-event.js
CHANGED
|
@@ -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
|
}
|
package/dist/domain-event.js.map
CHANGED
|
@@ -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;
|
|
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
|
}
|
package/dist/entity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.js","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":";;;AAIA,MAAsB,MAAM;IACT,CAAC,YAAY,CAAC,CAAO;
|
|
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":";;;
|
|
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
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;
|
|
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"}
|
package/dist/value-object.d.ts
CHANGED
|
@@ -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 {};
|
package/dist/value-object.js
CHANGED
|
@@ -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
|
}
|
package/dist/value-object.js.map
CHANGED
|
@@ -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;
|
|
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;
|
|
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.
|
|
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"
|