@xeno-js/shared 0.2.0 → 0.2.1

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.
Files changed (3) hide show
  1. package/LICENSE +18 -12
  2. package/README.md +652 -268
  3. package/package.json +2 -2
package/LICENSE CHANGED
@@ -1,15 +1,21 @@
1
- ISC License
1
+ MIT License
2
2
 
3
3
  Copyright (c) 2026 Xeno
4
4
 
5
- Permission to use, copy, modify, and/or distribute this software for any
6
- purpose with or without fee is hereby granted, provided that the above
7
- copyright notice and this permission notice appear in all copies.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
- PERFORMANCE OF THIS SOFTWARE.
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,268 +1,652 @@
1
- <div align="center">
2
- <img src="logo/logo.png" alt="Xeno Shared Logo" width="140" />
3
-
4
- <h1>Xeno Shared</h1>
5
-
6
- <p><em>Enterprise-grade primitive types, constants, and utilities for the Xeno ecosystem</em></p>
7
-
8
- <p>
9
- <a href="https://github.com/xeno-js/xeno-js">
10
- <img src="https://img.shields.io/badge/Powered%20by-Xeno-blueviolet?style=flat-square" alt="Powered by Xeno" />
11
- </a>
12
- <a href="https://github.com/xeno-js/xeno-shared/blob/main/LICENSE">
13
- <img src="https://img.shields.io/npm/l/@xeno-js/shared?style=flat-square" alt="License: ISC" />
14
- </a>
15
- <a href="https://www.npmjs.com/package/@xeno-js/shared">
16
- <img src="https://img.shields.io/npm/v/@xeno-js/shared?style=flat-square" alt="NPM Version" />
17
- </a>
18
- <a href="https://buymeacoffee.com/xenojs">
19
- <img src="https://img.shields.io/badge/Buy%20Me%20A%20Coffee-Support-FFdd00?style=flat-square&logo=buy-me-a-coffee&logoColor=black" alt="Buy Me A Coffee" />
20
- </a>
21
- </p>
22
- </div>
23
-
24
- ---
25
-
26
- ## What is Xeno Shared?
27
-
28
- **Xeno Shared** (`@xeno-js/shared`) is the foundational package for the entire
29
- Xeno framework ecosystem. It acts as the core dependency bridging both the
30
- backend (`@xeno-js/core`) and frontend (`@xeno-js/vue`) implementations.
31
-
32
- This package is meticulously designed to provide zero-dependency (where
33
- possible), highly optimized primitives, enforcing structural consistency, type
34
- safety, and architectural boundaries across all Xeno modules. It guarantees that
35
- constants, interfaces, and utilities behave identically whether executed in a
36
- Node.js server or a browser environment.
37
-
38
- ---
39
-
40
- ## 💡 Key Features & Offerings
41
-
42
- - **Universal Type Definitions**: Centralizes critical `TypeScript` interfaces
43
- and types (`ResponseDto`, `IPaginatedResult`, `ICommand`, `IQuery`,
44
- `InjectionToken`) to ensure a unified contract between the client and server.
45
- - **Agnostic Constants**: Exports canonical constants (`STATUS_CODES`,
46
- `ERROR_CODES`, `LOG_LEVEL`, `REQUEST_TYPE`) preventing magic strings/numbers
47
- and maintaining unified semantics across the infrastructure.
48
- - **Validation & Guards**: Provides the `Guards` utility object for robust,
49
- zero-magic runtime type checking and validation (e.g., `isDefined`,
50
- `isNullOrEmpty`, `isDate`).
51
- - **Resiliency & Async Utilities**: Includes `PromiseHelper` for advanced async
52
- timing logic (delays, jitter for mitigating thundering herds) and constants
53
- for `Cockatiel` resilience policies (`RESILIENCE_DEFAULTS`).
54
- - **Security Primitives**: Features `SanitizeHelper` to enforce OWASP guidelines
55
- against Log Injection (CWE-117) and unsafe URIs.
56
- - **Shared Infrastructural Adapters**: Includes base infrastructural classes and
57
- mappers (e.g., `ReadDao`, `Repository`, `ConsoleLogger`, `AxiosHttpClient`,
58
- `SupabaseClaimsMapper`) allowing downstream packages to extend them.
59
-
60
- ---
61
-
62
- ## 📦 Installation
63
-
64
- This package is typically installed automatically as a dependency of
65
- `@xeno-js/core` or `@xeno-js/vue`. If you need to install it directly for shared
66
- domain logic in a monorepo:
67
-
68
- ```bash
69
- npm install @xeno-js/shared
70
-
71
- ```
72
-
73
- Xeno uses **Optional Peer Dependencies**. You only install the external
74
- libraries you actually need.
75
-
76
- ```bash
77
- # Example: Install tools only if you enable them
78
- npm install axios cockatiel zod @supabase/supabase-js
79
-
80
- ```
81
-
82
- ---
83
-
84
- ## 📖 Core Usage Examples
85
-
86
- ### 1. Unified API Responses
87
-
88
- Use `HttpHelper` to generate standardized success and error payloads.
89
-
90
- ```typescript
91
- import { HttpHelper, STATUS_CODES, ERROR_CODES } from '@xeno-js/shared'
92
-
93
- // Success Response
94
- const response = HttpHelper.success(
95
- { id: 1, name: 'Xeno' },
96
- STATUS_CODES.CREATED,
97
- )
98
-
99
- // Error Response
100
- const errorResponse = HttpHelper.error(
101
- {
102
- success: false,
103
- error: {
104
- code: ERROR_CODES.VALIDATION_FAILED,
105
- message: 'Invalid input provided',
106
- },
107
- correlationId: '...',
108
- requestId: '...',
109
- spanId: '...',
110
- timestamp: new Date().toISOString(),
111
- },
112
- STATUS_CODES.BAD_REQUEST,
113
- )
114
- ```
115
-
116
- ### 2. Runtime Type Guards
117
-
118
- Use the `Guards` namespace to ensure bulletproof runtime checks.
119
-
120
- ```typescript
121
- import { Guards } from '@xeno-js/shared'
122
-
123
- function processData(payload: unknown) {
124
- if (Guards.isNullOrEmpty(payload)) {
125
- throw new Error('Payload cannot be empty')
126
- }
127
-
128
- if (Guards.isString(payload)) {
129
- console.log(payload.toUpperCase())
130
- }
131
- }
132
- ```
133
-
134
- ### 3. Asynchronous Jitter
135
-
136
- Use `PromiseHelper` to stagger requests and avoid network congestion.
137
-
138
- ```typescript
139
- import { PromiseHelper } from '@xeno-js/shared'
140
-
141
- async function fetchWithRetry() {
142
- const BASE_DELAY = 100
143
- const MAX_JITTER = 50
144
-
145
- // Wait for 100ms + a random value up to 50ms
146
- await PromiseHelper.delayWithJitter(BASE_DELAY, MAX_JITTER)
147
- return performNetworkCall()
148
- }
149
- ```
150
-
151
- ---
152
-
153
- ## 🤝 For Contributors
154
-
155
- We welcome contributions to Xeno! To maintain the highest code quality and
156
- stability of the core framework, **direct pushes to the `main` and `develop`
157
- branches are strictly prohibited.** Please follow this Git Flow to contribute:
158
-
159
- 1. **Branch off from `develop**`: Create a new branch for your feature or
160
- bugfix.
161
-
162
- ```bash
163
- git checkout develop
164
- git pull origin develop
165
- git checkout -b feat/your-awesome-feature
166
-
167
- ```
168
-
169
- 2. **Make your changes**: Write your code and ensure it passes all local checks
170
- (linting, types, and tests).
171
-
172
- ```bash
173
- npm run check
174
-
175
- ```
176
-
177
- 3. **Commit your changes**: We enforce
178
- [Conventional Commits](https://www.conventionalcommits.org/?utm_source=gemini).
179
- Husky will verify your commit message format.
180
-
181
- 4. **Commit Format:**
182
-
183
- ```bash
184
- feat(scope): add new feature
185
- fix(scope): resolve bug
186
- chore(scope): update dependencies
187
-
188
- ```
189
-
190
- 5. **Submit a Pull Request (PR)**: Push your branch to GitHub and open a Pull
191
- Request targeting the **`develop`** branch.
192
- 6. **Review**: The repository owner will review your code, run pipeline tests,
193
- and merge it into `develop`.
194
-
195
- _Note: The `main` branch is strictly reserved for production releases. Code
196
- flows from feature branches ➡️ `develop` ➡️ `main`._
197
-
198
- ### Scripts
199
-
200
- | Command | Description |
201
- | ----------------------- | -------------------------------------------------- |
202
- | `npm run build` | Builds the TypeScript source code into `dist/`<br> |
203
- | `npm run typecheck` | Checks types without emitting files |
204
- | `npm run lint` | Runs ESLint |
205
- | `npm run format` | Formats code with Prettier |
206
- | `npm run test` | Runs the Vitest test suite |
207
- | `npm run test:coverage` | Runs tests and generates a coverage report |
208
-
209
- ### Code Quality (Husky & Git Hooks)
210
-
211
- This project strictly enforces code quality rules before pushing to the
212
- repository:
213
-
214
- - **`pre-commit`**: Runs `lint-staged` on staged files (ESLint + Prettier).
215
-
216
- - **`commit-msg`**: Checks commit messages with `commitlint` (we use
217
- Conventional Commits).
218
-
219
- - **`pre-push`**: Runs type checking, linting, and testing before code leaves
220
- your machine.
221
-
222
- ---
223
-
224
- ## 🌱 Support & Appreciation
225
-
226
- Building, benchmarking, and maintaining a progressive, enterprise-ready
227
- open-source framework requires a massive amount of continuous dedication and
228
- architectural engineering.
229
-
230
- If Xeno has brought value to your development workflows, helped decouple your
231
- core business logic, or simplified your system infrastructure layout, consider
232
- supporting its open-source lifecycle. Your backing directly accelerates our
233
- strategic roadmap.
234
-
235
- **[Read our support guidelines and find out how to help](https://www.xeno-js.it/support-us)**
236
-
237
- Thank you for being part of this decoupled open-source journey!
238
-
239
- <amp-bounce>
240
- </amp-bounce>
241
- <a href="https://www.buymeacoffee.com/xenojs" target="_blank">
242
- <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="42" style="height: 42px !important;" />
243
- </a>
244
-
245
- ---
246
-
247
- ## 🛡️ Powered by Xeno
248
-
249
- If you are using Xeno in your project, let the world know! Add this badge to
250
- your README:
251
-
252
- ```html
253
- <a
254
- href="[https://github.com/xeno-js/xeno-js](https://github.com/xeno-js/xeno-js)"
255
- target="_blank"
256
- >
257
- <img
258
- src="[https://img.shields.io/badge/Powered%20by-Xeno-black?style=flat-square](https://img.shields.io/badge/Powered%20by-Xeno-black?style=flat-square)"
259
- alt="Powered by Xeno"
260
- height="20"
261
- />
262
- </a>
263
- ```
264
-
265
- ## 📄 License
266
-
267
- Copyright (c) 2026 Xeno. Licensed under the
268
- [ISC License](https://www.google.com/search?q=LICENSE&utm_source=gemini).
1
+ <div align="center">
2
+ <img src="logo/logo.png" alt="Xeno Shared Logo" width="140" />
3
+
4
+ <h1>@xeno-js/shared</h1>
5
+
6
+ <p><strong>Domain primitives and application contracts for TypeScript.</strong></p>
7
+
8
+ <p>
9
+ Define your domain model, application contracts, and architectural boundaries
10
+ without coupling them to a transport or framework.
11
+ </p>
12
+
13
+ <p>
14
+ <a href="https://github.com/xeno-js/xeno-shared">
15
+ <img src="https://img.shields.io/github/stars/xeno-js/xeno-shared?style=flat-square" alt="GitHub Stars" />
16
+ </a>
17
+ <a href="https://www.npmjs.com/package/@xeno-js/shared">
18
+ <img src="https://img.shields.io/npm/v/@xeno-js/shared?style=flat-square" alt="npm version" />
19
+ </a>
20
+ <a href="https://github.com/xeno-js/xeno-shared/blob/develop/LICENSE">
21
+ <img src="https://img.shields.io/npm/l/@xeno-js/shared?style=flat-square" alt="License: ISC" />
22
+ </a>
23
+ <a href="https://buymeacoffee.com/xenojs">
24
+ <img src="https://img.shields.io/badge/Buy%20Me%20A%20Coffee-Support-FFdd00?style=flat-square&logo=buy-me-a-coffee&logoColor=black" alt="Buy Me A Coffee" />
25
+ </a>
26
+ </p>
27
+ </div>
28
+
29
+ ---
30
+
31
+ ## What is `@xeno-js/shared`?
32
+
33
+ `@xeno-js/shared` provides the **domain primitives and framework-neutral
34
+ contracts** used across the Xeno ecosystem.
35
+
36
+ It gives TypeScript applications explicit building blocks for:
37
+
38
+ - Domain-Driven Design
39
+ - aggregates and value objects
40
+ - domain events
41
+ - entities and domain errors
42
+ - Result-based application flows
43
+ - CQRS contracts
44
+ - repositories and data sources
45
+ - application services and policies
46
+ - request and execution context
47
+ - transactions and infrastructure boundaries
48
+
49
+ The goal is simple:
50
+
51
+ > **Keep the meaning of your application explicit in code.**
52
+
53
+ `@xeno-js/shared` defines the contracts.
54
+
55
+ `@xeno-js/core` provides the runtime architecture that executes them.
56
+
57
+ Your HTTP framework, CLI, worker, or other transport remains outside that
58
+ boundary.
59
+
60
+ ---
61
+
62
+ ## The Xeno architecture
63
+
64
+ Xeno separates **what an application means** from **how the application runs**.
65
+
66
+ ```text
67
+ ┌─────────────────────────────────────────────┐
68
+ │ Transport / Host │
69
+ │ HTTP · CLI · Worker · gRPC · Scheduler │
70
+ └──────────────────────┬──────────────────────┘
71
+ │
72
+ ▼
73
+ ┌─────────────────────────────────────────────┐
74
+ │ @xeno-js/core │
75
+ │ │
76
+ │ DI · scopes · request context · pipelines │
77
+ │ CQRS execution · modules · infrastructure │
78
+ └──────────────────────┬──────────────────────┘
79
+ │
80
+ ▼
81
+ ┌─────────────────────────────────────────────┐
82
+ │ @xeno-js/shared │
83
+ │ │
84
+ │ Domain model · contracts · Result · errors │
85
+ │ aggregates · value objects · domain events │
86
+ │ application interfaces │
87
+ └─────────────────────────────────────────────┘
88
+ ```
89
+
90
+ This separation lets the domain and application contracts remain independent
91
+ from the transport hosting them.
92
+
93
+ ---
94
+
95
+ ## Why Shared?
96
+
97
+ Most application frameworks start from the transport:
98
+
99
+ ```text
100
+ HTTP request
101
+ ↓
102
+ controller
103
+ ↓
104
+ service
105
+ ↓
106
+ database
107
+ ```
108
+
109
+ Xeno starts from the application model instead:
110
+
111
+ ```text
112
+ Domain
113
+ ↓
114
+ Application contracts
115
+ ↓
116
+ Execution model
117
+ ↓
118
+ Transport
119
+ ```
120
+
121
+ That distinction matters when an application grows.
122
+
123
+ The HTTP layer should not define your domain model.
124
+
125
+ Your database should not define your application contracts.
126
+
127
+ And your infrastructure should not become the place where business rules live.
128
+
129
+ `@xeno-js/shared` provides the primitives and contracts that make those
130
+ boundaries explicit.
131
+
132
+ ---
133
+
134
+ # Domain primitives
135
+
136
+ ## Aggregate roots
137
+
138
+ `AggregateRoot` provides a base abstraction for aggregates that need:
139
+
140
+ - an explicit identity
141
+ - aggregate versioning
142
+ - domain event application
143
+ - loading from event history
144
+ - tracking of uncommitted domain events.
145
+
146
+ ```ts
147
+ import { AggregateRoot } from '@xeno-js/shared'
148
+
149
+ class UserId {
150
+ // ...
151
+ }
152
+
153
+ type UserEvent =
154
+ | {
155
+ type: 'UserCreated'
156
+ name: string
157
+ }
158
+ | {
159
+ type: 'UserRenamed'
160
+ name: string
161
+ }
162
+
163
+ class User extends AggregateRoot<UserEvent> {
164
+ private name = ''
165
+
166
+ public rename(name: string): void {
167
+ this.raise({
168
+ eventType: 'UserRenamed',
169
+ payload: {
170
+ type: 'UserRenamed',
171
+ name,
172
+ },
173
+ })
174
+ }
175
+
176
+ protected apply(event: IDomainEvent<UserEvent>, isNew: boolean): void {
177
+ switch (event.eventType) {
178
+ case 'UserRenamed':
179
+ this.name = event.payload.name
180
+ break
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ An aggregate keeps its domain changes explicit:
187
+
188
+ ```text
189
+ Aggregate
190
+ │
191
+ ├── identity
192
+ ├── version
193
+ ├── state
194
+ │
195
+ └── uncommitted events
196
+ │
197
+ ▼
198
+ IDomainEvent
199
+ ```
200
+
201
+ `AggregateRoot` does not provide an event store. It provides the aggregate-side
202
+ primitives required to model and track domain events.
203
+
204
+ ---
205
+
206
+ ## Domain events
207
+
208
+ `IDomainEvent` defines a framework-neutral representation of an event produced
209
+ by an aggregate.
210
+
211
+ ```ts
212
+ export interface IDomainEvent<
213
+ TPayload = unknown,
214
+ TValueObject extends object = object,
215
+ > {
216
+ readonly aggregateId: TValueObject
217
+ readonly eventType: string
218
+ readonly version: number
219
+ readonly occurredAt: Date
220
+ readonly payload: TPayload
221
+ }
222
+ ```
223
+
224
+ A domain event carries:
225
+
226
+ - the aggregate identity
227
+ - an explicit event type
228
+ - the aggregate version
229
+ - the occurrence timestamp
230
+ - the event payload.
231
+
232
+ This makes domain changes representable without coupling the domain model to an
233
+ HTTP server, database driver, or message broker.
234
+
235
+ ---
236
+
237
+ ## Value objects
238
+
239
+ Value objects provide domain concepts whose meaning comes from their value
240
+ rather than object identity.
241
+
242
+ ```ts
243
+ import { ValueObject } from '@xeno-js/shared'
244
+
245
+ interface EmailProps {
246
+ value: string
247
+ }
248
+
249
+ class Email extends ValueObject<EmailProps> {
250
+ public static create(value: string): Email {
251
+ return new Email({ value })
252
+ }
253
+ }
254
+ ```
255
+
256
+ The base implementation provides:
257
+
258
+ - immutable properties
259
+ - value retrieval
260
+ - equality comparison
261
+ - string representation.
262
+
263
+ ```ts
264
+ const first = Email.create('user@example.com')
265
+ const second = Email.create('user@example.com')
266
+
267
+ first.equals(second) // true
268
+ ```
269
+
270
+ ---
271
+
272
+ # Application contracts
273
+
274
+ The package also defines contracts used to keep application code independent
275
+ from concrete infrastructure.
276
+
277
+ These include abstractions for areas such as:
278
+
279
+ - CQRS
280
+ - repositories
281
+ - data sources
282
+ - services
283
+ - factories
284
+ - policies
285
+ - transactions
286
+ - request context
287
+ - middleware
288
+ - logging
289
+ - caching
290
+ - storage
291
+ - HTTP
292
+ - mapping
293
+ - idempotency.
294
+
295
+ The important distinction is between the **contract** and its implementation.
296
+
297
+ For example:
298
+
299
+ ```text
300
+ Application
301
+ │
302
+ │ depends on
303
+ ▼
304
+ Repository contract
305
+ │
306
+ │ implemented by
307
+ ▼
308
+ Infrastructure adapter
309
+ ```
310
+
311
+ The application therefore does not need to know whether data is stored in
312
+ PostgreSQL, Supabase, Redis, or another persistence mechanism.
313
+
314
+ ---
315
+
316
+ # CQRS contracts
317
+
318
+ `@xeno-js/shared` includes the contracts used to model commands and queries.
319
+
320
+ ```text
321
+ Command
322
+ │
323
+ ▼
324
+ Application handler
325
+ │
326
+ ▼
327
+ Domain
328
+ ```
329
+
330
+ and:
331
+
332
+ ```text
333
+ Query
334
+ │
335
+ ▼
336
+ Application handler
337
+ │
338
+ ▼
339
+ Read model / data source
340
+ ```
341
+
342
+ The package defines the contracts.
343
+
344
+ `@xeno-js/core` provides the execution infrastructure around them.
345
+
346
+ This distinction keeps CQRS from becoming tied to a particular transport.
347
+
348
+ ---
349
+
350
+ # Result and errors
351
+
352
+ Application code often needs to represent an expected failure without turning
353
+ every business outcome into an exception.
354
+
355
+ Xeno provides `Result` primitives alongside application/domain errors.
356
+
357
+ Conceptually:
358
+
359
+ ```text
360
+ Operation
361
+ │
362
+ ├── success → Result success
363
+ │
364
+ └── expected failure → Result failure
365
+ ```
366
+
367
+ This allows application boundaries to make outcomes explicit while keeping error
368
+ handling independent from the HTTP layer.
369
+
370
+ ---
371
+
372
+ # Runtime utilities
373
+
374
+ The package also contains shared runtime utilities used across the Xeno
375
+ ecosystem.
376
+
377
+ These include utilities for areas such as:
378
+
379
+ - runtime guards
380
+ - strings
381
+ - dates
382
+ - enumerables
383
+ - GUIDs
384
+ - promises
385
+ - HTTP helpers
386
+ - sanitization
387
+ - abort handling
388
+ - mathematical helpers.
389
+
390
+ These utilities are deliberately secondary to the architectural role of the
391
+ package.
392
+
393
+ The purpose of `@xeno-js/shared` is not to be a generic utility collection.
394
+
395
+ Its primary role is to provide **shared domain and application building
396
+ blocks**.
397
+
398
+ ---
399
+
400
+ # Infrastructure adapters
401
+
402
+ `@xeno-js/shared` also exports a limited set of reusable infrastructure
403
+ components, including integrations and adapters for areas such as:
404
+
405
+ - HTTP clients
406
+ - Supabase authentication
407
+ - caching
408
+ - storage
409
+ - validation
410
+ - mapping
411
+ - factories.
412
+
413
+ These are exported as reusable building blocks; they do not define the
414
+ architecture of the application.
415
+
416
+ For applications using `@xeno-js/core`, infrastructure can be composed through
417
+ the application architecture rather than becoming part of the domain model.
418
+
419
+ ---
420
+
421
+ # Framework independent by design
422
+
423
+ `@xeno-js/shared` does not define an HTTP application lifecycle.
424
+
425
+ You can model your domain and application contracts without choosing a
426
+ particular HTTP framework.
427
+
428
+ For example:
429
+
430
+ ```text
431
+ ┌── Fastify
432
+ │
433
+ ├── Express
434
+ Application ─────┼── Hono
435
+ │
436
+ ├── CLI
437
+ │
438
+ └── Worker
439
+ ```
440
+
441
+ The transport is the host.
442
+
443
+ The domain and application contracts remain the application model.
444
+
445
+ ---
446
+
447
+ # Installation
448
+
449
+ ```bash
450
+ npm install @xeno-js/shared
451
+ ```
452
+
453
+ For the complete Xeno application architecture:
454
+
455
+ ```bash
456
+ npm install @xeno-js/core
457
+ ```
458
+
459
+ You can use `@xeno-js/shared` independently when you only need the domain and
460
+ application building blocks.
461
+
462
+ ---
463
+
464
+ # `@xeno-js/shared` vs `@xeno-js/core`
465
+
466
+ The two packages have different responsibilities.
467
+
468
+ | Package | Responsibility |
469
+ | ------------------- | --------------------------------------------------- |
470
+ | `@xeno-js/shared` | Domain primitives and application contracts |
471
+ | `@xeno-js/core` | Application runtime and architecture |
472
+ | Your transport | HTTP, CLI, worker, gRPC, etc. |
473
+ | Your infrastructure | Database, cache, external services, messaging, etc. |
474
+
475
+ A useful mental model is:
476
+
477
+ ```text
478
+ @xeno-js/shared
479
+ defines the language
480
+
481
+ ↓
482
+
483
+ @xeno-js/core
484
+ executes the architecture
485
+
486
+ ↓
487
+
488
+ your application
489
+ defines the business behavior
490
+
491
+ ↓
492
+
493
+ your transport / infrastructure
494
+ hosts and connects the system
495
+ ```
496
+
497
+ ---
498
+
499
+ # What `@xeno-js/shared` is not
500
+
501
+ `@xeno-js/shared` is not:
502
+
503
+ - an HTTP framework
504
+ - an application server
505
+ - an ORM
506
+ - an event bus
507
+ - an event store
508
+ - a complete event-sourcing framework
509
+ - a replacement for your transport framework.
510
+
511
+ It provides the primitives and contracts that let those concerns remain
512
+ separated from the domain model.
513
+
514
+ ---
515
+
516
+ # Design principles
517
+
518
+ The package follows a few simple principles.
519
+
520
+ ### Explicit contracts
521
+
522
+ Important application boundaries should be represented by explicit TypeScript
523
+ contracts.
524
+
525
+ ### Domain first
526
+
527
+ Business concepts such as aggregates, value objects and domain events should not
528
+ depend on transport details.
529
+
530
+ ### Infrastructure at the boundary
531
+
532
+ Concrete integrations belong outside the domain model.
533
+
534
+ ### Framework independence
535
+
536
+ Domain and application contracts should not require a specific HTTP framework.
537
+
538
+ ### Composition over magic
539
+
540
+ The architecture should be understandable from the code rather than depending on
541
+ runtime discovery or hidden conventions.
542
+
543
+ ---
544
+
545
+ # Relationship with Xeno
546
+
547
+ The Xeno ecosystem can be understood as three layers:
548
+
549
+ ```text
550
+ Your application
551
+ │
552
+ ▼
553
+ ┌───────────────────┐
554
+ │ @xeno-js/core │
555
+ │ │
556
+ │ Runtime │
557
+ │ DI │
558
+ │ Scopes │
559
+ │ CQRS execution │
560
+ │ Pipelines │
561
+ │ Request context │
562
+ └─────────┬─────────┘
563
+ │
564
+ ▼
565
+ ┌───────────────────┐
566
+ │ @xeno-js/shared │
567
+ │ │
568
+ │ Domain │
569
+ │ Contracts │
570
+ │ Result / Errors │
571
+ │ Aggregates │
572
+ │ Value Objects │
573
+ │ Domain Events │
574
+ └───────────────────┘
575
+ ```
576
+
577
+ The transport sits around the application rather than defining it.
578
+
579
+ > **Shared defines the contracts. Core executes the architecture. Your transport
580
+ > hosts the application.**
581
+
582
+ ---
583
+
584
+ # Development
585
+
586
+ Clone the repository:
587
+
588
+ ```bash
589
+ git clone https://github.com/xeno-js/xeno-shared.git
590
+ cd xeno-shared
591
+ npm install
592
+ ```
593
+
594
+ Run the main checks:
595
+
596
+ ```bash
597
+ npm run check
598
+ ```
599
+
600
+ Available scripts:
601
+
602
+ | Command | Description |
603
+ | ----------------------- | ---------------------------- |
604
+ | `npm run build` | Build the package |
605
+ | `npm run typecheck` | Run TypeScript type checking |
606
+ | `npm run lint` | Run ESLint |
607
+ | `npm run format` | Format the repository |
608
+ | `npm run format:check` | Check formatting |
609
+ | `npm run test` | Run tests |
610
+ | `npm run test:watch` | Run tests in watch mode |
611
+ | `npm run test:coverage` | Run tests with coverage |
612
+ | `npm run check` | Typecheck, lint and test |
613
+ | `npm run changelog` | Generate the changelog |
614
+
615
+ ---
616
+
617
+ # Contributing
618
+
619
+ Contributions are welcome.
620
+
621
+ Create a feature or fix branch from `develop`:
622
+
623
+ ```bash
624
+ git checkout develop
625
+ git pull origin develop
626
+ git checkout -b feat/your-feature
627
+ ```
628
+
629
+ Before opening a pull request:
630
+
631
+ ```bash
632
+ npm run check
633
+ ```
634
+
635
+ Use Conventional Commits:
636
+
637
+ ```text
638
+ feat(domain): add aggregate primitive
639
+ fix(result): correct failure handling
640
+ refactor(events): simplify event contract
641
+ docs(readme): improve architecture documentation
642
+ ```
643
+
644
+ Pull requests should target `develop`.
645
+
646
+ ---
647
+
648
+ # License
649
+
650
+ ISC License.
651
+
652
+ Copyright (c) 2026 Xeno.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeno-js/shared",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Domain primitives and framework-neutral application contracts for TypeScript, including DDD, CQRS, Result types, errors, value objects, aggregates and domain events.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -64,7 +64,7 @@
64
64
  "contracts"
65
65
  ],
66
66
  "author": "Xeno",
67
- "license": "ISC",
67
+ "license": "MIT",
68
68
  "engines": {
69
69
  "node": ">=20.0.0"
70
70
  },