exisjs 0.7.11 → 0.7.13

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 (150) hide show
  1. package/README.md +195 -39
  2. package/dist/cli/commands/dev.d.ts +4 -0
  3. package/dist/cli/commands/dev.d.ts.map +1 -1
  4. package/dist/cli/commands/dev.js +136 -32
  5. package/dist/cli/commands/dev.js.map +1 -1
  6. package/dist/cli/commands/run.d.ts +7 -0
  7. package/dist/cli/commands/run.d.ts.map +1 -0
  8. package/dist/cli/commands/run.js +99 -0
  9. package/dist/cli/commands/run.js.map +1 -0
  10. package/dist/cli/index.js +29 -13
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/cli/manifest.d.ts.map +1 -1
  13. package/dist/cli/manifest.js +18 -3
  14. package/dist/cli/manifest.js.map +1 -1
  15. package/dist/cli/routes.d.ts +6 -0
  16. package/dist/cli/routes.d.ts.map +1 -1
  17. package/dist/cli/routes.js +224 -135
  18. package/dist/cli/routes.js.map +1 -1
  19. package/dist/config/config.d.ts +2 -1
  20. package/dist/config/config.d.ts.map +1 -1
  21. package/dist/config/config.js.map +1 -1
  22. package/dist/config/types.d.ts +30 -9
  23. package/dist/config/types.d.ts.map +1 -1
  24. package/dist/database/lifecycle.d.ts +6 -1
  25. package/dist/database/lifecycle.d.ts.map +1 -1
  26. package/dist/database/lifecycle.js +15 -4
  27. package/dist/database/lifecycle.js.map +1 -1
  28. package/dist/decorators/params.d.ts +21 -0
  29. package/dist/decorators/params.d.ts.map +1 -1
  30. package/dist/decorators/params.js +21 -1
  31. package/dist/decorators/params.js.map +1 -1
  32. package/dist/di/container.d.ts +15 -6
  33. package/dist/di/container.d.ts.map +1 -1
  34. package/dist/di/container.js +26 -3
  35. package/dist/di/container.js.map +1 -1
  36. package/dist/di/index.d.ts +1 -1
  37. package/dist/di/index.d.ts.map +1 -1
  38. package/dist/di/index.js.map +1 -1
  39. package/dist/di/inject.d.ts +2 -1
  40. package/dist/di/inject.d.ts.map +1 -1
  41. package/dist/di/inject.js +2 -1
  42. package/dist/di/inject.js.map +1 -1
  43. package/dist/docs/BENCHMARKS.md +4 -4
  44. package/dist/docs/content/README.md +43 -44
  45. package/dist/docs/content/boundaries.mdx +141 -48
  46. package/dist/docs/content/cli/commands.mdx +161 -107
  47. package/dist/docs/content/cli/overview.mdx +61 -46
  48. package/dist/docs/content/cli/usage.mdx +107 -30
  49. package/dist/docs/content/config.mdx +145 -147
  50. package/dist/docs/content/controllers.mdx +193 -464
  51. package/dist/docs/content/cron.mdx +183 -69
  52. package/dist/docs/content/decorators.mdx +449 -154
  53. package/dist/docs/content/errors.mdx +202 -305
  54. package/dist/docs/content/exisjs-mcp.mdx +59 -49
  55. package/dist/docs/content/installation.mdx +243 -157
  56. package/dist/docs/content/introduction.mdx +220 -48
  57. package/dist/docs/content/middleware.mdx +171 -497
  58. package/dist/docs/content/modules.mdx +141 -83
  59. package/dist/docs/content/providers.mdx +216 -180
  60. package/dist/docs/content/requests.mdx +168 -488
  61. package/dist/docs/content/responses.mdx +200 -533
  62. package/dist/docs/content/routing.mdx +239 -558
  63. package/dist/docs/content/security.mdx +233 -57
  64. package/dist/docs/content/structure.mdx +151 -240
  65. package/dist/docs/content/swagger.mdx +192 -91
  66. package/dist/docs/content/testing.mdx +205 -74
  67. package/dist/docs/content/validation.mdx +479 -341
  68. package/dist/docs/reference/README.md +34 -2
  69. package/dist/docs/reference/config.mdx +277 -73
  70. package/dist/docs/reference/context.mdx +197 -106
  71. package/dist/docs/reference/cron.mdx +266 -152
  72. package/dist/docs/reference/database.mdx +135 -53
  73. package/dist/docs/reference/decorators.mdx +234 -116
  74. package/dist/docs/reference/di.mdx +146 -112
  75. package/dist/docs/reference/error.mdx +155 -178
  76. package/dist/docs/reference/exis.mdx +141 -70
  77. package/dist/docs/reference/logger.mdx +110 -126
  78. package/dist/docs/reference/middleware.mdx +235 -158
  79. package/dist/docs/reference/plugin.mdx +136 -64
  80. package/dist/docs/reference/router.mdx +277 -251
  81. package/dist/docs/reference/sanitize.mdx +91 -87
  82. package/dist/docs/reference/swagger.mdx +280 -100
  83. package/dist/docs/reference/testing.mdx +223 -89
  84. package/dist/docs/reference/validator.mdx +194 -206
  85. package/dist/lib/inspect-routes.d.ts +2 -0
  86. package/dist/lib/inspect-routes.d.ts.map +1 -0
  87. package/dist/lib/inspect-routes.js +148 -0
  88. package/dist/lib/inspect-routes.js.map +1 -0
  89. package/dist/lib/start-server.js +13 -8
  90. package/dist/lib/start-server.js.map +1 -1
  91. package/dist/module/module.d.ts +6 -3
  92. package/dist/module/module.d.ts.map +1 -1
  93. package/dist/module/module.js +17 -3
  94. package/dist/module/module.js.map +1 -1
  95. package/dist/router/controller-registrar.d.ts.map +1 -1
  96. package/dist/router/controller-registrar.js +26 -4
  97. package/dist/router/controller-registrar.js.map +1 -1
  98. package/dist/router/scanner/cron-mounter.d.ts.map +1 -1
  99. package/dist/router/scanner/cron-mounter.js +9 -2
  100. package/dist/router/scanner/cron-mounter.js.map +1 -1
  101. package/dist/server/app.d.ts +3 -1
  102. package/dist/server/app.d.ts.map +1 -1
  103. package/dist/server/app.js +29 -8
  104. package/dist/server/app.js.map +1 -1
  105. package/dist/server/define.d.ts.map +1 -1
  106. package/dist/server/define.js +5 -0
  107. package/dist/server/define.js.map +1 -1
  108. package/dist/server/request.d.ts +2 -0
  109. package/dist/server/request.d.ts.map +1 -1
  110. package/dist/server/request.js +11 -0
  111. package/dist/server/request.js.map +1 -1
  112. package/dist/swagger/generator.d.ts.map +1 -1
  113. package/dist/swagger/generator.js +130 -10
  114. package/dist/swagger/generator.js.map +1 -1
  115. package/dist/telemetry/index.d.ts +12 -0
  116. package/dist/telemetry/index.d.ts.map +1 -0
  117. package/dist/telemetry/index.js +121 -0
  118. package/dist/telemetry/index.js.map +1 -0
  119. package/dist/testing/client.d.ts +1 -0
  120. package/dist/testing/client.d.ts.map +1 -1
  121. package/dist/testing/client.js +4 -1
  122. package/dist/testing/client.js.map +1 -1
  123. package/dist/testing/index.d.ts.map +1 -1
  124. package/dist/testing/index.js +20 -4
  125. package/dist/testing/index.js.map +1 -1
  126. package/dist/validator/builder.d.ts +26 -1
  127. package/dist/validator/builder.d.ts.map +1 -1
  128. package/dist/validator/builder.js +31 -0
  129. package/dist/validator/builder.js.map +1 -1
  130. package/dist/validator/engine.d.ts +23 -0
  131. package/dist/validator/engine.d.ts.map +1 -1
  132. package/dist/validator/engine.js +228 -31
  133. package/dist/validator/engine.js.map +1 -1
  134. package/dist/validator/index.d.ts +8 -4
  135. package/dist/validator/index.d.ts.map +1 -1
  136. package/dist/validator/index.js +4 -1
  137. package/dist/validator/index.js.map +1 -1
  138. package/dist/validator/tex-types.d.ts +15 -0
  139. package/dist/validator/tex-types.d.ts.map +1 -1
  140. package/dist/validator/tex-types.js +102 -0
  141. package/dist/validator/tex-types.js.map +1 -1
  142. package/dist/validator/tex.d.ts +1 -1
  143. package/dist/validator/tex.d.ts.map +1 -1
  144. package/dist/validator/tex.js +3 -1
  145. package/dist/validator/tex.js.map +1 -1
  146. package/dist/validator/types.d.ts +1 -0
  147. package/dist/validator/types.d.ts.map +1 -1
  148. package/package.json +47 -14
  149. package/dist/docs/content/dataloader.mdx +0 -170
  150. package/dist/docs/reference/dataloader.mdx +0 -91
@@ -1,170 +0,0 @@
1
- ---
2
- nextUrl: "/docs/security"
3
- nextTitle: "Security & Auth"
4
- ---
5
-
6
- # Dataloader (N+1 Queries)
7
-
8
- The **N+1 problem** is a common performance issue in backend development. It occurs when your code executes one query to fetch a list of items (e.g. 100 Posts), and then executes $N$ additional queries to fetch related data (e.g. 100 separate queries for each Post's Author).
9
-
10
- ExisJS ships with a native `Dataloader` implementation (inspired by GraphQL/Facebook's DataLoader) built directly into the core framework. It automatically **batches** and **caches** requests over a single tick of the Node.js event loop.
11
-
12
- ---
13
-
14
- ## 1. Defining Loaders
15
-
16
- The best practice in ExisJS is to define a central registry of Dataloaders that are **securely scoped to the current HTTP Request** (to prevent data leaking between different users).
17
-
18
- ExisJS provides `defineLoaders` to create this context-aware registry.
19
-
20
- ```typescript filename="src/loaders.ts"
21
- import { Dataloader, defineLoaders } from 'exisjs/dataloader'
22
- import { getRequest } from 'exisjs/router'
23
- import { db } from './db'
24
-
25
- export const { loaderMiddleware, getLoaders } = defineLoaders({
26
- // 1. Author Loader
27
- authorLoader: () => new Dataloader<number, any>(async (keys) => {
28
- // You can access the current HTTP Request anywhere using getRequest()
29
- const req = getRequest()
30
- const authToken = req.headers.authorization
31
-
32
- // This function will only be called ONCE per event-loop tick,
33
- // receiving an array of all requested Author IDs: e.g. [1, 2, 3]
34
- const authors = await db.authors.findMany({
35
- where: { id: { in: keys } }
36
- })
37
-
38
- // You MUST return an array of results in the EXACT same order as the keys
39
- return keys.map(key => authors.find(a => a.id === key) || new Error('Not found'))
40
- }),
41
-
42
- // 2. Comments Loader
43
- commentsLoader: () => new Dataloader<number, any[]>(async (keys) => {
44
- const comments = await db.comments.findMany({
45
- where: { postId: { in: keys } }
46
- })
47
-
48
- // Group comments by postId
49
- return keys.map(key => comments.filter(c => c.postId === key))
50
- })
51
- })
52
- ```
53
-
54
- ---
55
-
56
- ## 2. Registering the Middleware
57
-
58
- `defineLoaders` returns a `loaderMiddleware`. You must register this middleware so that ExisJS can securely inject a fresh, isolated instance of your Dataloaders into every incoming request.
59
-
60
- Because ExisJS uses lazy-initialization, there is **zero performance penalty** for routes that don't actually use the loaders.
61
-
62
- #### Functional Paradigm
63
-
64
- ```typescript filename="src/http/server.ts"
65
- import { exis } from 'exisjs'
66
- import { loaderMiddleware } from '../loaders'
67
-
68
- export default exis({
69
- async onStart(app) {
70
- // Register globally for all routes
71
- app.use(loaderMiddleware)
72
- }
73
- })
74
- ```
75
-
76
- #### Class-Based (OOP) Paradigm
77
-
78
- ```typescript filename="src/http/server.ts"
79
- import { Server } from 'exisjs/decorators'
80
- import { loaderMiddleware } from '../loaders'
81
- import type { App } from 'exisjs'
82
-
83
- @Server()
84
- export default class RootServer {
85
- async onStart(app: App) {
86
- // Register globally for all routes
87
- app.use(loaderMiddleware)
88
- }
89
- }
90
- ```
91
-
92
- ---
93
-
94
- ## 3. Using Dataloader in Routes
95
-
96
- Anywhere in your application (Routes, Controllers, Services), you can call `getLoaders()` to retrieve the securely isolated loaders for the *current* request.
97
-
98
- #### Functional Paradigm
99
-
100
- ```typescript filename="src/http/posts/route.ts"
101
- import { controller, route } from 'exisjs/router'
102
- import { getLoaders } from '../../loaders'
103
-
104
- export default controller({
105
- list: route.get('/', {
106
- async handle() {
107
- // 1. Fetch 100 posts (1 Query)
108
- const posts = await db.posts.findMany()
109
-
110
- const { authorLoader } = getLoaders()
111
-
112
- // 2. Loop through 100 posts and call .load()
113
- const postsWithAuthors = await Promise.all(
114
- posts.map(async (post) => {
115
- // Instead of firing 100 queries to the database,
116
- // Dataloader queues them up and fires exactly ONE batched query.
117
- const author = await authorLoader.load(post.authorId)
118
- return { ...post, author }
119
- })
120
- )
121
-
122
- return postsWithAuthors
123
- // Total Queries: 2 (Not 101)
124
- }
125
- })
126
- })
127
- ```
128
-
129
- #### Class-Based (OOP) Paradigm
130
-
131
- ```typescript filename="src/http/posts/route.ts"
132
- import { Controller, Get } from 'exisjs/decorators'
133
- import { getLoaders } from '../../loaders'
134
-
135
- @Controller()
136
- export default class PostsController {
137
- @Get('/')
138
- async list() {
139
- // 1. Fetch 100 posts (1 Query)
140
- const posts = await db.posts.findMany()
141
-
142
- const { authorLoader } = getLoaders()
143
-
144
- // 2. Loop through 100 posts and call .load()
145
- const postsWithAuthors = await Promise.all(
146
- posts.map(async (post) => {
147
- // Instead of firing 100 queries to the database,
148
- // Dataloader queues them up and fires exactly ONE batched query.
149
- const author = await authorLoader.load(post.authorId)
150
- return { ...post, author }
151
- })
152
- )
153
-
154
- return postsWithAuthors
155
- // Total Queries: 2 (Not 101)
156
- }
157
- }
158
- ```
159
-
160
- ---
161
-
162
- ## API Reference (`exisjs/dataloader`)
163
-
164
- The `Dataloader` class exposes the standard, battle-tested API:
165
-
166
- - **`load(key: K): Promise<V>`**: Queues a key to be fetched and returns a Promise.
167
- - **`loadMany(keys: K[]): Promise<V[]>`**: Equivalent to calling `Promise.all(keys.map(k => load(k)))`.
168
- - **`clear(key: K): this`**: Clears the cached result for a specific key.
169
- - **`clearAll(): this`**: Clears the entire cache for this dataloader instance.
170
- - **`prime(key: K, value: V): this`**: Primes the cache with a predefined value, preventing the batch function from being called for that key.
@@ -1,91 +0,0 @@
1
- ---
2
- title: "Data Loader"
3
- description: "Strict API Reference for the N+1 batching utility."
4
- ---
5
-
6
- # Data Loader (`exisjs/dataloader`)
7
-
8
- This document provides the strict API signatures and TypeScript interfaces exported by the `exisjs/dataloader` module. For high-level guides on solving N+1 query problems, see the [Data Loader Guide](/docs/dataloader).
9
-
10
- ---
11
-
12
- ## `Dataloader<K, V, C>` Class
13
-
14
- The `Dataloader` class batches and caches requests to a backend data source.
15
-
16
- ```typescript
17
- import { Dataloader } from 'exisjs/dataloader'
18
-
19
- class Dataloader<K, V, C = K> {
20
- constructor(batchFn: BatchLoadFn<K, V>, options?: DataloaderOptions<K, C>)
21
-
22
- // Enqueues a key to be batched, returning a Promise that resolves to the value
23
- load(key: K): Promise<V>
24
-
25
- // Loads multiple keys, returning an array of Promises
26
- loadMany(keys: readonly K[]): Promise<V[]>
27
-
28
- // Clears the value at `key` from the cache
29
- clear(key: K): this
30
-
31
- // Clears all values from the cache
32
- clearAll(): this
33
-
34
- // Primes the cache with a predefined value or Error for a specific key
35
- prime(key: K, value: V | Error): this
36
- }
37
- ```
38
-
39
- ### `BatchLoadFn<K, V>`
40
-
41
- The function responsible for loading the batched keys. **It must return an array of values (or Errors) that are precisely the same length and in the exact same order as the provided keys array.**
42
-
43
- ```typescript
44
- type BatchLoadFn<K, V> = (
45
- keys: readonly K[]
46
- ) => Promise<readonly (V | Error)[]>
47
- ```
48
-
49
- ### `DataloaderOptions<K, C>`
50
-
51
- ```typescript
52
- interface DataloaderOptions<K, C = K> {
53
- // Whether to cache resolved keys within this Dataloader instance. Default: true
54
- cache?: boolean
55
-
56
- // The maximum number of keys to include in a single batch. Default: 1000
57
- maxBatchSize?: number
58
-
59
- // A function to generate a unique cache key from the provided load key
60
- cacheKeyFn?: (key: K) => C
61
- }
62
- ```
63
-
64
- ---
65
-
66
- ## Context Registry (`defineLoaders`)
67
-
68
- Because `Dataloader` instances are inherently stateful (they cache data), they **must not** be shared across different HTTP requests, or else users might read each other's cached data.
69
-
70
- The `defineLoaders` function securely isolates Dataloader instances per-request by binding them to the ExisJS asynchronous context.
71
-
72
- ```typescript
73
- import { defineLoaders } from 'exisjs/dataloader'
74
-
75
- function defineLoaders<
76
- T extends Record<string, () => Dataloader<any, any>>
77
- >(factories: T): {
78
- // Middleware to register onto your router/app
79
- loaderMiddleware: (req, res, next) => void;
80
-
81
- // Hook to retrieve the isolated loaders anywhere in the request lifecycle
82
- getLoaders: () => { [K in keyof T]: ReturnType<T[K]> }
83
- }
84
- ```
85
-
86
- ### Usage Signature
87
- ```typescript
88
- const { loaderMiddleware, getLoaders } = defineLoaders({
89
- userLoader: () => new Dataloader(async (keys) => { /* ... */ })
90
- })
91
- ```