tshex-cli 1.0.27 → 1.0.29

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 (31) hide show
  1. package/build/main.js +1 -158
  2. package/docs/generated-file-reference.md +13 -10
  3. package/docs/library-structure.md +4 -4
  4. package/docs/shared/application/data.md +13 -1
  5. package/docs/shared/application/http/errors.md +96 -0
  6. package/docs/shared/application/http/handlers.md +102 -0
  7. package/docs/shared/application/http/json-api.md +235 -0
  8. package/docs/shared/application/http/json-web-token.md +209 -0
  9. package/docs/shared/application/http/opengraph.md +161 -0
  10. package/docs/shared/application/loggers.md +5 -4
  11. package/docs/types/json.md +82 -0
  12. package/docs/types/locales.md +77 -0
  13. package/docs/types/objects.md +70 -0
  14. package/docs/types/timezones.md +75 -0
  15. package/package.json +7 -8
  16. package/readme.md +23 -4
  17. package/source/main.ts +34 -11
  18. package/templates/ctx/example-ports.ts +1 -0
  19. package/templates/lib/shared/application/data/capabilities.ts +56 -0
  20. package/templates/lib/shared/application/data/managers.ts +0 -57
  21. package/templates/lib/shared/application/data/repositories.ts +7 -18
  22. package/templates/lib/shared/application/loggers.ts +0 -21
  23. package/templates/lib/shared/domain/entities.ts +1 -1
  24. package/docs/library-types.md +0 -112
  25. package/docs/shared/application/http.md +0 -283
  26. package/templates/lib/shared/application/http/handlers.ts +0 -13
  27. package/templates/lib/shared/application/http/json-api.ts +0 -611
  28. package/templates/lib/shared/application/http/json-web-token.ts +0 -980
  29. package/templates/lib/shared/application/http/opengraph.ts +0 -533
  30. /package/templates/lib/types/{cldr.d.ts → locales.d.ts} +0 -0
  31. /package/templates/lib/types/{iana.d.ts → timezones.d.ts} +0 -0
@@ -0,0 +1,82 @@
1
+ ### JSON
2
+
3
+ The generated root also declares a small family of types that describe plain,
4
+ serializable JSON data.
5
+ They are used when a contract must guarantee that a value survives a round
6
+ trip through `JSON.stringify()` / `JSON.parse()`.
7
+
8
+ #### Declaration
9
+
10
+ These types live in `types/json.d.ts`.
11
+
12
+ ```ts title="types/json.d.ts"
13
+ export type JsonPrimitive = string | number | boolean | null
14
+
15
+ export type JsonValue = JsonPrimitive | JsonObject | JsonArray
16
+
17
+ export type JsonArray = readonly JsonValue[]
18
+
19
+ export type JsonObject = {
20
+ readonly [key: string]: JsonValue
21
+ }
22
+ ```
23
+
24
+ `JsonPrimitive` covers the scalar values allowed in JSON. `JsonValue` extends
25
+ that with nested objects and arrays, so it recursively describes any JSON-safe
26
+ value. `JsonObject` and `JsonArray` name the two composite shapes so other
27
+ declarations can refer to them directly instead of repeating the union.
28
+
29
+ #### Implementation Options
30
+
31
+ A `JsonValue` is always one of four shapes. Each one is a distinct option a
32
+ consumer must be ready to handle.
33
+
34
+ | Shape | Type | Example |
35
+ | --- | --- | --- |
36
+ | Primitive | `JsonPrimitive` | `'active'`, `42`, `true`, `null` |
37
+ | Object | `JsonObject` | `{ id: '1', active: true }` |
38
+ | Array | `JsonArray` | `[1, 2, 3]`, `[{ id: '1' }]` |
39
+ | Nested composite | `JsonValue` | `{ tags: ['a', 'b'], meta: { retries: 2 } }` |
40
+
41
+ ```ts
42
+ import { type JsonValue } from './types/json.js'
43
+
44
+ const primitive: JsonValue = 'ada@example.com'
45
+ const object: JsonValue = { id: '1', active: true }
46
+ const array: JsonValue = [1, 2, 3]
47
+ const nested: JsonValue = { tags: ['a', 'b'], meta: { retries: 2 } }
48
+ ```
49
+
50
+ All four are valid `JsonValue` values because the type is a recursive union;
51
+ there is no separate constructor or runtime check to opt into a shape.
52
+
53
+ #### Basic Usage
54
+
55
+ ```ts
56
+ import { type JsonValue } from './types/json.js'
57
+
58
+ function toLogPayload(value: JsonValue): string {
59
+ return JSON.stringify(value)
60
+ }
61
+ ```
62
+
63
+ Because `JsonValue` excludes functions, `undefined`, symbols, and other
64
+ non-serializable values, `toLogPayload()` can call `JSON.stringify()` without
65
+ guarding against values that would silently disappear or throw.
66
+
67
+ #### JsonObject Versus Generic
68
+
69
+ Use `JsonObject`/`JsonValue` when a contract must guarantee its data is plain
70
+ and serializable, such as request payloads, stored metadata, or wire formats.
71
+ Prefer `types/objects.md`'s `Generic<T>` instead when the value type is not
72
+ required to be JSON-safe.
73
+
74
+ `shared/application/http/json-api.ts` and
75
+ `shared/application/http/json-web-token.ts` build on these types to describe
76
+ JSON:API documents and JOSE/JWT structures; see `shared/application/http/json-api.md`
77
+ and `shared/application/http/json-web-token.md`.
78
+
79
+ > **Hint**
80
+ > These declarations only provide compile-time structure. They do not validate
81
+ > that a runtime value is actually JSON-safe; a value typed as `JsonValue` can
82
+ > still contain a `Date` or a class instance if it was cast into the type.
@@ -0,0 +1,77 @@
1
+ ### Locales
2
+
3
+ `Locale` is a literal string union of every locale identifier available in
4
+ Unicode CLDR.
5
+ It is used when a contract needs to accept only valid locale tags instead of
6
+ an open `string`.
7
+
8
+ #### Declaration
9
+
10
+ `Locale` lives in `types/locales.d.ts` and is generated from Unicode CLDR
11
+ 48.2.1.
12
+
13
+ ```ts title="types/locales.d.ts"
14
+ export type Locale =
15
+ | 'aa'
16
+ | 'af'
17
+ | 'am'
18
+ | 'ar'
19
+ | 'ar-EG'
20
+ | 'de'
21
+ | 'de-AT'
22
+ | 'en'
23
+ | 'en-GB'
24
+ | 'en-US'
25
+ | 'es'
26
+ | 'es-419'
27
+ | 'fr'
28
+ | 'ja'
29
+ | 'zh-Hans'
30
+ // ...every other CLDR locale identifier
31
+ ```
32
+
33
+ The generated file lists every language identifier and every regional variant
34
+ registered by CLDR, from bare language tags such as `'en'` to script- and
35
+ region-qualified tags such as `'zh-Hant-HK'` or `'ca-ES-valencia'`.
36
+
37
+ #### Basic Usage
38
+
39
+ ```ts
40
+ import { type Locale } from './types/locales.js'
41
+
42
+ function formatCount(value: number, locale: Locale): string {
43
+ return new Intl.NumberFormat(locale).format(value)
44
+ }
45
+
46
+ formatCount(1200, 'en-US')
47
+ formatCount(1200, 'es-419')
48
+ ```
49
+
50
+ Because `Locale` only accepts identifiers CLDR actually defines, a typo such
51
+ as `'en-USA'` fails at compile time instead of silently reaching
52
+ `Intl.NumberFormat`.
53
+
54
+ #### Accepting Multiple Locales
55
+
56
+ `Intl` APIs commonly accept a locale or a list of locales in priority order.
57
+ `Locale[]` expresses that same option without widening to `string[]`.
58
+
59
+ ```ts
60
+ import { type Locale } from './types/locales.js'
61
+
62
+ const preferredLocales: Locale[] = ['fr-CA', 'fr', 'en']
63
+ ```
64
+
65
+ The runtime resolves the first supported locale from the list; `Locale[]`
66
+ only guarantees that every candidate is a real CLDR identifier.
67
+
68
+ #### Where It Is Used
69
+
70
+ `shared/application/loggers.ts` uses `Locale[]` for `Logger.datetimeLocales`,
71
+ the locale list passed to `Date.prototype.toLocaleString()` when formatting a
72
+ log timestamp. See `shared/application/loggers.md`.
73
+
74
+ > **Hint**
75
+ > `Locale` is a compile-time contract only. It does not validate that the
76
+ > runtime's ICU data actually supports every listed locale; `Intl` APIs fall
77
+ > back to a default when a requested locale is unsupported at runtime.
@@ -0,0 +1,70 @@
1
+ ### Objects
2
+
3
+ The generated root declares `Generic<T>`, a plain object whose keys are strings
4
+ and whose values share the same type.
5
+ It provides a small common building block for code that works with object-like
6
+ data but does not need a more specific shape yet.
7
+
8
+ #### Declaration
9
+
10
+ `Generic<T>` lives in `types/objects.d.ts`.
11
+
12
+ ```ts title="types/objects.d.ts"
13
+ export type Generic<T = unknown> = Record<string, T>
14
+ ```
15
+
16
+ This alias expands to `Record<string, T>`. When no type argument is provided,
17
+ the values use `unknown`.
18
+
19
+ #### With A Type Argument
20
+
21
+ In the following example we use `Generic<string>` for a set of plain filters.
22
+
23
+ ```ts
24
+ import { type Generic } from './types/objects.js'
25
+
26
+ const filters: Generic<string> = {
27
+ status: 'active',
28
+ sort: 'email',
29
+ }
30
+ ```
31
+
32
+ `filters` can only store string values because the type argument fixes the
33
+ value shape for the whole object.
34
+
35
+ #### Without A Type Argument
36
+
37
+ Now consider the same pattern without providing a type argument.
38
+
39
+ ```ts
40
+ import { type Generic } from './types/objects.js'
41
+
42
+ const metadata: Generic = {
43
+ retries: 2,
44
+ cached: true,
45
+ }
46
+ ```
47
+
48
+ In this case the values use `unknown`. This is useful when the object is plain
49
+ and open-ended, but the caller must narrow each value before using it in a
50
+ specific way.
51
+
52
+ #### When To Use It
53
+
54
+ Use `Generic<T>` when the code needs a simple object contract and the exact set
55
+ of keys is not the main concern.
56
+
57
+ Typical uses include:
58
+
59
+ 1. filter objects;
60
+ 2. metadata objects;
61
+ 3. plain configuration maps;
62
+ 4. transport-neutral dictionaries.
63
+
64
+ When the object has a stable business meaning, prefer a named type instead of a
65
+ generic record.
66
+
67
+ > **Hint**
68
+ > `Generic<T>` is intentionally small. It should support loose object contracts,
69
+ > not replace explicit domain or application types. It is also the base shape
70
+ > used by `types/json.md` when a value only needs to be JSON-safe.
@@ -0,0 +1,75 @@
1
+ ### Time Zones
2
+
3
+ `TimeZone` is a literal string union of every IANA time zone identifier.
4
+ It is used when a contract needs to accept only valid time zone names instead
5
+ of an open `string`.
6
+
7
+ #### Declaration
8
+
9
+ `TimeZone` lives in `types/timezones.d.ts` and is generated from the IANA time
10
+ zone database.
11
+
12
+ ```ts title="types/timezones.d.ts"
13
+ export type TimeZone =
14
+ | 'Africa/Cairo'
15
+ | 'America/Argentina/Buenos_Aires'
16
+ | 'America/Indiana/Indianapolis'
17
+ | 'America/New_York'
18
+ | 'Asia/Tokyo'
19
+ | 'Australia/Sydney'
20
+ | 'Europe/London'
21
+ | 'Europe/Paris'
22
+ | 'Pacific/Auckland'
23
+ | 'UTC'
24
+ // ...every other IANA time zone identifier
25
+ ```
26
+
27
+ The generated file lists every canonical zone, including three-level entries
28
+ such as `'America/Argentina/Buenos_Aires'` and `'America/Indiana/Knox'`, and
29
+ ends with the fixed `'UTC'` identifier.
30
+
31
+ #### Basic Usage
32
+
33
+ ```ts
34
+ import { type TimeZone } from './types/timezones.js'
35
+
36
+ function formatInZone(date: Date, timeZone: TimeZone): string {
37
+ return date.toLocaleString('en-GB', { timeZone })
38
+ }
39
+
40
+ formatInZone(new Date(), 'America/New_York')
41
+ formatInZone(new Date(), 'UTC')
42
+ ```
43
+
44
+ Because `TimeZone` only accepts identifiers the IANA database actually
45
+ defines, a typo such as `'America/New York'` (with a space) fails at compile
46
+ time instead of throwing a `RangeError` at runtime.
47
+
48
+ #### Combining With `Intl.DateTimeFormatOptions`
49
+
50
+ `TimeZone` is meant to replace the loosely typed `timeZone` member of
51
+ `Intl.DateTimeFormatOptions`.
52
+
53
+ ```ts
54
+ import { type TimeZone } from './types/timezones.js'
55
+
56
+ const options: Intl.DateTimeFormatOptions & { timeZone: TimeZone } = {
57
+ timeZone: 'Europe/Madrid',
58
+ hour: '2-digit',
59
+ minute: '2-digit',
60
+ }
61
+ ```
62
+
63
+ The intersection keeps every other formatting option from
64
+ `Intl.DateTimeFormatOptions` while narrowing `timeZone` to a real identifier.
65
+
66
+ #### Where It Is Used
67
+
68
+ `shared/application/loggers.ts` uses this same intersection for
69
+ `Logger.datetimeFormatOptions`, defaulting `timeZone` to `'UTC'`. See
70
+ `shared/application/loggers.md`.
71
+
72
+ > **Hint**
73
+ > `TimeZone` is a compile-time contract only. It does not validate that the
74
+ > runtime's ICU data actually supports every listed zone, and it does not
75
+ > account for future IANA database changes such as renamed or merged zones.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tshex-cli",
3
- "version": "1.0.27",
3
+ "version": "1.0.29",
4
4
  "author": "https://github.com/virtualitems/",
5
5
  "license": "MIT",
6
6
  "description": "Typescript Hexagonal Architecture CLI",
@@ -41,15 +41,14 @@
41
41
  "bin": {
42
42
  "tshex": "./build/main.js"
43
43
  },
44
+ "scripts": {
45
+ "build": "deno run --allow-all npm:esbuild --bundle --minify --platform=node --external:commander --format=esm --outfile=./build/main.js ./source/main.ts",
46
+ "test": "deno test --allow-all tests/"
47
+ },
44
48
  "dependencies": {
45
- "commander": "^12.1.0"
49
+ "commander": "^15.0.0"
46
50
  },
47
51
  "devDependencies": {
48
- "@fission-ai/openspec": "^1.6.0",
49
- "@types/node": "^22.5.4",
50
- "typescript": "^5.4.5"
51
- },
52
- "scripts": {
53
- "build": "tsc"
52
+ "@types/node": "^18"
54
53
  }
55
54
  }
package/readme.md CHANGED
@@ -82,7 +82,6 @@ The command creates this structure:
82
82
 
83
83
  ```text
84
84
  core/
85
- |-- index.d.ts
86
85
  |-- main.ts
87
86
  |-- shared/
88
87
  | |-- application/
@@ -91,7 +90,12 @@ core/
91
90
  | | | |-- managers.ts
92
91
  | | | `-- repositories.ts
93
92
  | | |-- events.ts
94
- | | |-- http.ts
93
+ | | |-- http/
94
+ | | | |-- errors.ts
95
+ | | | |-- handlers.ts
96
+ | | | |-- json-api.ts
97
+ | | | |-- json-web-token.ts
98
+ | | | `-- opengraph.ts
95
99
  | | |-- loggers.ts
96
100
  | | |-- services.ts
97
101
  | | `-- validations.ts
@@ -100,6 +104,11 @@ core/
100
104
  | |-- entities.ts
101
105
  | |-- errors.ts
102
106
  | `-- value-objects.ts
107
+ |-- types/
108
+ | |-- json.d.ts
109
+ | |-- locales.d.ts
110
+ | |-- objects.d.ts
111
+ | `-- timezones.d.ts
103
112
  `-- users/
104
113
  |-- adapters/
105
114
  |-- application/
@@ -224,15 +233,25 @@ From this point on, the guide is split into dedicated documents under `docs/`.
224
233
  ### General
225
234
 
226
235
  - [Project structure](https://github.com/virtualitems/tshex-cli/blob/main/docs/library-structure.md)
227
- - [Project types](https://github.com/virtualitems/tshex-cli/blob/main/docs/library-types.md)
228
236
  - [Context ports](https://github.com/virtualitems/tshex-cli/blob/main/docs/context-ports.md)
229
237
  - [Generated file reference](https://github.com/virtualitems/tshex-cli/blob/main/docs/generated-file-reference.md)
230
238
 
239
+ ### Types
240
+
241
+ - [types/objects.d.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/types/objects.md)
242
+ - [types/json.d.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/types/json.md)
243
+ - [types/locales.d.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/types/locales.md)
244
+ - [types/timezones.d.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/types/timezones.md)
245
+
231
246
  ### Shared application
232
247
 
233
248
  - [shared/application/data](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/data.md)
234
249
  - [shared/application/events.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/events.md)
235
- - [shared/application/http.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/http.md)
250
+ - [shared/application/http/errors.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/http/errors.md)
251
+ - [shared/application/http/handlers.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/http/handlers.md)
252
+ - [shared/application/http/json-api.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/http/json-api.md)
253
+ - [shared/application/http/json-web-token.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/http/json-web-token.md)
254
+ - [shared/application/http/opengraph.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/http/opengraph.md)
236
255
  - [shared/application/loggers.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/loggers.md)
237
256
  - [shared/application/services.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/services.md)
238
257
  - [shared/application/validations.ts](https://github.com/virtualitems/tshex-cli/blob/main/docs/shared/application/validations.md)
package/source/main.ts CHANGED
@@ -9,12 +9,12 @@ import { program } from 'commander'
9
9
  import fs from 'node:fs'
10
10
  import path from 'node:path'
11
11
  import readline from 'node:readline/promises'
12
- import { stdin as input, stdout as output } from 'node:process'
12
+ import { stdin, stdout } from 'node:process'
13
13
 
14
14
  // FUNCTIONS
15
15
 
16
16
  function readPackageJson() {
17
- const filePath = path.join(import.meta.dirname, '..', 'package.json')
17
+ const filePath = path.join(import.meta.dirname!, '..', 'package.json')
18
18
  const fileContents = fs.readFileSync(filePath, 'utf-8')
19
19
  return JSON.parse(fileContents)
20
20
  }
@@ -77,19 +77,35 @@ function executeCreateTests(
77
77
  continue
78
78
  }
79
79
 
80
- if (ignoredSourceDir !== undefined && sourcePath.startsWith(ignoredSourceDir)) {
80
+ if (
81
+ ignoredSourceDir !== undefined &&
82
+ sourcePath.startsWith(ignoredSourceDir)
83
+ ) {
81
84
  continue
82
85
  }
83
86
 
84
- if (fs.existsSync(destinationPath) && fs.statSync(destinationPath).isDirectory() === false) {
87
+ if (
88
+ fs.existsSync(destinationPath) &&
89
+ fs.statSync(destinationPath).isDirectory() === false
90
+ ) {
85
91
  continue
86
92
  }
87
93
 
88
- executeCreateTests(sourcePath, destinationPath, fileContents, ignoredSourceDir, rootSourceDir)
94
+ executeCreateTests(
95
+ sourcePath,
96
+ destinationPath,
97
+ fileContents,
98
+ ignoredSourceDir,
99
+ rootSourceDir
100
+ )
89
101
  continue
90
102
  }
91
103
 
92
- if (entry.isFile() && entry.name.endsWith('.ts') && fs.existsSync(destinationPath) === false) {
104
+ if (
105
+ entry.isFile() &&
106
+ entry.name.endsWith('.ts') &&
107
+ fs.existsSync(destinationPath) === false
108
+ ) {
93
109
  fs.writeFileSync(destinationPath, fileContents)
94
110
  }
95
111
  }
@@ -104,10 +120,12 @@ async function ensureTestsDirectory(testsRootDir: string) {
104
120
  return
105
121
  }
106
122
 
107
- const rl = readline.createInterface({ input, output })
123
+ const rl = readline.createInterface({ input: stdin, output: stdout })
108
124
 
109
125
  try {
110
- const answer = await rl.question(`Tests directory does not exist at ${testsRootDir}. Create it? (y/N) `)
126
+ const answer = await rl.question(
127
+ `Tests directory does not exist at ${testsRootDir}. Create it? (y/N) `
128
+ )
111
129
 
112
130
  if (answer.trim().toLowerCase() !== 'y') {
113
131
  return false
@@ -121,7 +139,7 @@ async function ensureTestsDirectory(testsRootDir: string) {
121
139
  }
122
140
 
123
141
  async function main(program: typeof import('commander').program) {
124
- const templatesDir = path.join(import.meta.dirname, '..', 'templates')
142
+ const templatesDir = path.join(import.meta.dirname!, '..', 'templates')
125
143
 
126
144
  const options = program.opts()
127
145
 
@@ -182,7 +200,9 @@ async function main(program: typeof import('commander').program) {
182
200
  const testsDir = path.join(testsRootDir, path.basename(sourceDir))
183
201
 
184
202
  if (testsDir === sourceDir) {
185
- program.error('Tests destination directory cannot be the same as the source directory')
203
+ program.error(
204
+ 'Tests destination directory cannot be the same as the source directory'
205
+ )
186
206
  }
187
207
 
188
208
  executeCreateTests(sourceDir, testsDir, testsTemplateContents, testsRootDir)
@@ -198,7 +218,10 @@ program
198
218
  .option('-P, --project <name>', "creates a new project with it's shared directory")
199
219
  .option('-C, --context <name>', 'creates a new context')
200
220
  .option('-R, --react', 'creates a React context with --context')
201
- .option('-T, --tests <path>', 'creates a .ts tests structure from an existing directory')
221
+ .option(
222
+ '-T, --tests <path>',
223
+ 'creates a .ts tests structure from an existing directory'
224
+ )
202
225
  .option('--dir <path>', 'sets the directory to create the new item')
203
226
  .parse(process.argv)
204
227
 
@@ -1,4 +1,5 @@
1
1
  // Ports are exports from the context root level
2
+ // you can delete this file and create your own ports file in the context root level
2
3
 
3
4
  export function example(): void {
4
5
  // ...
@@ -0,0 +1,56 @@
1
+ type Generic = Record<string, unknown>
2
+
3
+ export interface Listable {
4
+ all(): Generic | Promise<Generic[]>
5
+ }
6
+
7
+ /**
8
+ * @description Declares a filtering operation over plain source records.
9
+ */
10
+ export interface Filterable {
11
+ filter(selector: unknown): Generic | Promise<Generic[]>
12
+ }
13
+
14
+ /**
15
+ * @description Declares a sorting operation over plain source records.
16
+ */
17
+ export interface Sortable {
18
+ sort(selector: unknown): Generic | Promise<Generic[]>
19
+ }
20
+
21
+ /**
22
+ * @description Declares a creation operation for plain source records.
23
+ */
24
+ export interface Creatable {
25
+ create(data: unknown): unknown
26
+ }
27
+
28
+ /**
29
+ * @description Declares an update operation that selects source records and applies new plain data.
30
+ */
31
+ export interface Updatable {
32
+ update(selector: unknown, data: unknown): unknown
33
+ }
34
+
35
+ /**
36
+ * @description Declares a deletion operation over source records selected by plain criteria.
37
+ */
38
+ export interface Deletable {
39
+ delete(selector: unknown): unknown
40
+ }
41
+
42
+ /**
43
+ * @description Declares an aggregation operation over source records.
44
+ */
45
+ export interface Aggregatable {
46
+ aggregate(selector: unknown): unknown
47
+ }
48
+
49
+ /**
50
+ * @description Declares operations for selecting or preloading relationships from a data source.
51
+ */
52
+ export interface Relatable {
53
+ selectRelated(...args: unknown[]): unknown
54
+
55
+ prefetchRelated(...args: unknown[]): unknown
56
+ }
@@ -1,66 +1,9 @@
1
- /**
2
- * @description Declares a filtering operation over plain source records.
3
- */
4
- export interface Filterable<S = Record<string, unknown>> {
5
- filter(selector: S): Promise<Array<S>>
6
- }
7
-
8
- /**
9
- * @description Declares a sorting operation over plain source records.
10
- */
11
- export interface Sortable<S = Record<string, unknown>> {
12
- sort(selector: S): Promise<Array<S>>
13
- }
14
-
15
- /**
16
- * @description Declares a creation operation for plain source records.
17
- */
18
- export interface Creatable<D = Record<string, unknown>> {
19
- create(data: D): Promise<unknown>
20
- }
21
-
22
- /**
23
- * @description Declares an update operation that selects source records and applies new plain data.
24
- */
25
- export interface Updatable<S = Record<string, unknown>, D = Record<string, unknown>> {
26
- update(selector: S, data: D): Promise<unknown>
27
- }
28
-
29
- /**
30
- * @description Declares a deletion operation over source records selected by plain criteria.
31
- */
32
- export interface Deletable<S = Record<string, unknown>> {
33
- delete(selector: S): Promise<unknown>
34
- }
35
-
36
- /**
37
- * @description Declares an aggregation operation over source records.
38
- */
39
- export interface Aggregatable<S = Record<string, unknown>> {
40
- aggregate(selector: S): Promise<S>
41
- }
42
-
43
- /**
44
- * @description Declares operations for selecting or preloading relationships from a data source.
45
- */
46
- export interface Relatable {
47
- selectRelated(...args: unknown[]): unknown
48
-
49
- prefetchRelated(...args: unknown[]): unknown
50
- }
51
-
52
1
  /**
53
2
  * @description Operates on a data source using plain objects and arrays.
54
3
  * It exposes the raw data without transforming it.
55
4
  */
56
5
  export abstract class DataManager<T = Record<string, unknown>> {
57
6
  [property: string]: unknown
58
-
59
- public none(): Array<T> {
60
- return []
61
- }
62
-
63
- public abstract all(): Promise<Array<T>>
64
7
  } //:: class
65
8
 
66
9
  /**
@@ -1,29 +1,18 @@
1
1
  import { type DataManager } from './managers.js'
2
2
  import { type DriverAdapter } from './drivers.js'
3
3
 
4
+ type Generic = Record<string, unknown>
5
+
4
6
  /**
5
7
  * @description Acts as an intermediary between plain source data and domain objects.
6
8
  * It transforms records into domain representations and can translate them back when needed.
7
9
  */
8
- export abstract class Repository<
9
- DataShape extends Record<string, unknown> = Record<string, unknown>,
10
- EntityShape extends Record<string, unknown> = Record<string, unknown>
11
- > {
10
+ export abstract class Repository<RawDataShape = Generic, EntityShape = Generic> {
12
11
  [property: string]: unknown
13
12
 
14
- public constructor(public readonly driver: DriverAdapter<DataManager<DataShape>>) {}
15
-
16
- public async all(): Promise<Array<EntityShape>> {
17
- const connection = await this.driver.connect()
18
- const raw = await connection.all()
19
- const entities = this.transformList(raw)
20
- await this.driver.disconnect()
21
- return entities
22
- }
23
-
24
- protected transformList(data: Array<DataShape>): Array<EntityShape> {
25
- return data.map(this.transform)
26
- }
13
+ public constructor(
14
+ public readonly driver: DriverAdapter<DataManager<RawDataShape>>
15
+ ) {}
27
16
 
28
- protected abstract transform(data: DataShape): EntityShape
17
+ protected abstract transform(data: RawDataShape): EntityShape
29
18
  } //:: class