@c9up/ream 0.1.33 → 0.2.0

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 (215) hide show
  1. package/dist/Application.d.ts +68 -0
  2. package/dist/Application.d.ts.map +1 -1
  3. package/dist/Application.js +142 -6
  4. package/dist/Application.js.map +1 -1
  5. package/dist/ConfigLoader.d.ts +4 -0
  6. package/dist/ConfigLoader.d.ts.map +1 -1
  7. package/dist/ConfigLoader.js +0 -8
  8. package/dist/ConfigLoader.js.map +1 -1
  9. package/dist/HealthCheck.d.ts +14 -7
  10. package/dist/HealthCheck.d.ts.map +1 -1
  11. package/dist/HealthCheck.js +21 -12
  12. package/dist/HealthCheck.js.map +1 -1
  13. package/dist/HttpKernel.d.ts +12 -0
  14. package/dist/HttpKernel.d.ts.map +1 -1
  15. package/dist/HttpKernel.js +15 -4
  16. package/dist/HttpKernel.js.map +1 -1
  17. package/dist/Ignitor.d.ts +8 -0
  18. package/dist/Ignitor.d.ts.map +1 -1
  19. package/dist/Ignitor.js +11 -0
  20. package/dist/Ignitor.js.map +1 -1
  21. package/dist/bodyparser/BodyParserMiddleware.d.ts +13 -2
  22. package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
  23. package/dist/bodyparser/BodyParserMiddleware.js +50 -30
  24. package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
  25. package/dist/bodyparser/MultipartFile.d.ts +65 -6
  26. package/dist/bodyparser/MultipartFile.d.ts.map +1 -1
  27. package/dist/bodyparser/MultipartFile.js +100 -7
  28. package/dist/bodyparser/MultipartFile.js.map +1 -1
  29. package/dist/console/BaseCommand.d.ts +8 -1
  30. package/dist/console/BaseCommand.d.ts.map +1 -1
  31. package/dist/console/BaseCommand.js +1 -1
  32. package/dist/console/BaseCommand.js.map +1 -1
  33. package/dist/console/Kernel.d.ts +15 -0
  34. package/dist/console/Kernel.d.ts.map +1 -1
  35. package/dist/console/Kernel.js +17 -0
  36. package/dist/console/Kernel.js.map +1 -1
  37. package/dist/directories.d.ts +52 -0
  38. package/dist/directories.d.ts.map +1 -0
  39. package/dist/directories.js +38 -0
  40. package/dist/directories.js.map +1 -0
  41. package/dist/events/Emitter.d.ts +49 -6
  42. package/dist/events/Emitter.d.ts.map +1 -1
  43. package/dist/events/Emitter.js +117 -7
  44. package/dist/events/Emitter.js.map +1 -1
  45. package/dist/events/EventsBuffer.d.ts +47 -0
  46. package/dist/events/EventsBuffer.d.ts.map +1 -0
  47. package/dist/events/EventsBuffer.js +107 -0
  48. package/dist/events/EventsBuffer.js.map +1 -0
  49. package/dist/events/index.d.ts +2 -0
  50. package/dist/events/index.d.ts.map +1 -1
  51. package/dist/events/index.js +1 -0
  52. package/dist/events/index.js.map +1 -1
  53. package/dist/health/BaseCheck.d.ts +19 -0
  54. package/dist/health/BaseCheck.d.ts.map +1 -0
  55. package/dist/health/BaseCheck.js +24 -0
  56. package/dist/health/BaseCheck.js.map +1 -0
  57. package/dist/health/HealthChecks.d.ts +15 -0
  58. package/dist/health/HealthChecks.d.ts.map +1 -0
  59. package/dist/health/HealthChecks.js +69 -0
  60. package/dist/health/HealthChecks.js.map +1 -0
  61. package/dist/health/Result.d.ts +27 -0
  62. package/dist/health/Result.d.ts.map +1 -0
  63. package/dist/health/Result.js +55 -0
  64. package/dist/health/Result.js.map +1 -0
  65. package/dist/health/checks/DiskSpaceCheck.d.ts +29 -0
  66. package/dist/health/checks/DiskSpaceCheck.d.ts.map +1 -0
  67. package/dist/health/checks/DiskSpaceCheck.js +58 -0
  68. package/dist/health/checks/DiskSpaceCheck.js.map +1 -0
  69. package/dist/health/checks/MemoryHeapCheck.d.ts +21 -0
  70. package/dist/health/checks/MemoryHeapCheck.d.ts.map +1 -0
  71. package/dist/health/checks/MemoryHeapCheck.js +55 -0
  72. package/dist/health/checks/MemoryHeapCheck.js.map +1 -0
  73. package/dist/health/checks/MemoryRSSCheck.d.ts +21 -0
  74. package/dist/health/checks/MemoryRSSCheck.d.ts.map +1 -0
  75. package/dist/health/checks/MemoryRSSCheck.js +55 -0
  76. package/dist/health/checks/MemoryRSSCheck.js.map +1 -0
  77. package/dist/health/checks/memory.d.ts +24 -0
  78. package/dist/health/checks/memory.d.ts.map +1 -0
  79. package/dist/health/checks/memory.js +88 -0
  80. package/dist/health/checks/memory.js.map +1 -0
  81. package/dist/health/index.d.ts +9 -0
  82. package/dist/health/index.d.ts.map +1 -0
  83. package/dist/health/index.js +8 -0
  84. package/dist/health/index.js.map +1 -0
  85. package/dist/health/tracing.d.ts +12 -0
  86. package/dist/health/tracing.d.ts.map +1 -0
  87. package/dist/health/tracing.js +11 -0
  88. package/dist/health/tracing.js.map +1 -0
  89. package/dist/health/types.d.ts +51 -0
  90. package/dist/health/types.d.ts.map +1 -0
  91. package/dist/health/types.js +5 -0
  92. package/dist/health/types.js.map +1 -0
  93. package/dist/helpers/bytes.d.ts +28 -0
  94. package/dist/helpers/bytes.d.ts.map +1 -0
  95. package/dist/helpers/bytes.js +63 -0
  96. package/dist/helpers/bytes.js.map +1 -0
  97. package/dist/helpers/string.d.ts +4 -0
  98. package/dist/helpers/string.d.ts.map +1 -1
  99. package/dist/helpers/string.js +2 -0
  100. package/dist/helpers/string.js.map +1 -1
  101. package/dist/http/HttpContext.d.ts +38 -2
  102. package/dist/http/HttpContext.d.ts.map +1 -1
  103. package/dist/http/HttpContext.js +81 -3
  104. package/dist/http/HttpContext.js.map +1 -1
  105. package/dist/http/Request.d.ts +57 -3
  106. package/dist/http/Request.d.ts.map +1 -1
  107. package/dist/http/Request.js +51 -38
  108. package/dist/http/Request.js.map +1 -1
  109. package/dist/http/Response.d.ts +82 -2
  110. package/dist/http/Response.d.ts.map +1 -1
  111. package/dist/http/Response.js +240 -13
  112. package/dist/http/Response.js.map +1 -1
  113. package/dist/http/SseStream.d.ts +10 -0
  114. package/dist/http/SseStream.d.ts.map +1 -1
  115. package/dist/http/SseStream.js.map +1 -1
  116. package/dist/index.d.ts +7 -2
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +4 -1
  119. package/dist/index.js.map +1 -1
  120. package/dist/migrations/MigrationRegistry.d.ts +28 -0
  121. package/dist/migrations/MigrationRegistry.d.ts.map +1 -0
  122. package/dist/migrations/MigrationRegistry.js +41 -0
  123. package/dist/migrations/MigrationRegistry.js.map +1 -0
  124. package/dist/migrations/types.d.ts +64 -0
  125. package/dist/migrations/types.d.ts.map +1 -0
  126. package/dist/migrations/types.js +15 -0
  127. package/dist/migrations/types.js.map +1 -0
  128. package/dist/router/Router.d.ts +112 -9
  129. package/dist/router/Router.d.ts.map +1 -1
  130. package/dist/router/Router.js +206 -28
  131. package/dist/router/Router.js.map +1 -1
  132. package/dist/security/CookieSigner.d.ts +43 -4
  133. package/dist/security/CookieSigner.d.ts.map +1 -1
  134. package/dist/security/CookieSigner.js +68 -10
  135. package/dist/security/CookieSigner.js.map +1 -1
  136. package/dist/session/Session.d.ts +46 -1
  137. package/dist/session/Session.d.ts.map +1 -1
  138. package/dist/session/Session.js +57 -4
  139. package/dist/session/Session.js.map +1 -1
  140. package/dist/session/SessionMiddleware.d.ts.map +1 -1
  141. package/dist/session/SessionMiddleware.js +19 -9
  142. package/dist/session/SessionMiddleware.js.map +1 -1
  143. package/dist/session/drivers/CookieDriver.d.ts +1 -1
  144. package/dist/session/drivers/CookieDriver.d.ts.map +1 -1
  145. package/dist/session/drivers/CookieDriver.js +3 -3
  146. package/dist/session/drivers/CookieDriver.js.map +1 -1
  147. package/dist/session/drivers/DatabaseDriver.d.ts +1 -1
  148. package/dist/session/drivers/DatabaseDriver.d.ts.map +1 -1
  149. package/dist/session/drivers/DatabaseDriver.js +2 -2
  150. package/dist/session/drivers/DatabaseDriver.js.map +1 -1
  151. package/dist/session/drivers/FileDriver.d.ts +1 -1
  152. package/dist/session/drivers/FileDriver.d.ts.map +1 -1
  153. package/dist/session/drivers/FileDriver.js +7 -5
  154. package/dist/session/drivers/FileDriver.js.map +1 -1
  155. package/dist/session/drivers/MemoryDriver.d.ts +1 -1
  156. package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
  157. package/dist/session/drivers/MemoryDriver.js +1 -1
  158. package/dist/session/drivers/MemoryDriver.js.map +1 -1
  159. package/dist/session/drivers/RedisDriver.d.ts +1 -1
  160. package/dist/session/drivers/RedisDriver.d.ts.map +1 -1
  161. package/dist/session/drivers/RedisDriver.js +11 -4
  162. package/dist/session/drivers/RedisDriver.js.map +1 -1
  163. package/events.win32-x64-msvc.node +0 -0
  164. package/index.darwin-arm64.node +0 -0
  165. package/index.darwin-x64.node +0 -0
  166. package/index.linux-arm64-gnu.node +0 -0
  167. package/index.linux-x64-gnu.node +0 -0
  168. package/index.win32-x64-msvc.node +0 -0
  169. package/package.json +5 -2
  170. package/scheduler.win32-x64-msvc.node +0 -0
  171. package/src/Application.ts +169 -6
  172. package/src/ConfigLoader.ts +6 -0
  173. package/src/HealthCheck.ts +27 -14
  174. package/src/HttpKernel.ts +27 -4
  175. package/src/Ignitor.ts +17 -0
  176. package/src/bodyparser/BodyParserMiddleware.ts +70 -36
  177. package/src/bodyparser/MultipartFile.ts +125 -8
  178. package/src/console/BaseCommand.ts +8 -1
  179. package/src/console/Kernel.ts +18 -0
  180. package/src/directories.ts +81 -0
  181. package/src/events/Emitter.ts +129 -13
  182. package/src/events/EventsBuffer.ts +131 -0
  183. package/src/events/index.ts +7 -0
  184. package/src/health/BaseCheck.ts +30 -0
  185. package/src/health/HealthChecks.ts +83 -0
  186. package/src/health/Result.ts +69 -0
  187. package/src/health/checks/DiskSpaceCheck.ts +69 -0
  188. package/src/health/checks/MemoryHeapCheck.ts +68 -0
  189. package/src/health/checks/MemoryRSSCheck.ts +68 -0
  190. package/src/health/checks/memory.ts +115 -0
  191. package/src/health/index.ts +13 -0
  192. package/src/health/tracing.ts +15 -0
  193. package/src/health/types.ts +51 -0
  194. package/src/helpers/bytes.ts +71 -0
  195. package/src/helpers/string.ts +2 -0
  196. package/src/http/HttpContext.ts +86 -4
  197. package/src/http/Request.ts +82 -10
  198. package/src/http/Response.ts +283 -14
  199. package/src/http/SseStream.ts +10 -0
  200. package/src/index.ts +27 -1
  201. package/src/migrations/MigrationRegistry.ts +49 -0
  202. package/src/migrations/types.ts +68 -0
  203. package/src/router/Router.ts +241 -32
  204. package/src/security/CookieSigner.ts +92 -18
  205. package/src/session/Session.ts +71 -5
  206. package/src/session/SessionMiddleware.ts +19 -9
  207. package/src/session/drivers/CookieDriver.ts +4 -4
  208. package/src/session/drivers/DatabaseDriver.ts +3 -3
  209. package/src/session/drivers/FileDriver.ts +8 -6
  210. package/src/session/drivers/MemoryDriver.ts +2 -2
  211. package/src/session/drivers/RedisDriver.ts +12 -5
  212. package/tsconfig.app.json +13 -13
  213. package/tsconfig.base.json +19 -0
  214. package/tsconfig.client.json +16 -0
  215. package/tsconfig.package.json +15 -0
@@ -79,13 +79,13 @@ export class RedisDriver {
79
79
  const client = await this.#client();
80
80
  const raw = await client.get(this.#key(sessionId));
81
81
  if (raw === null)
82
- return {};
82
+ return null;
83
83
  try {
84
84
  const parsed = JSON.parse(raw);
85
- return isPlainRecord(parsed) ? parsed : {};
85
+ return isPlainRecord(parsed) ? parsed : null;
86
86
  }
87
87
  catch {
88
- return {};
88
+ return null;
89
89
  }
90
90
  }
91
91
  async write(sessionId, data, ttl) {
@@ -125,7 +125,14 @@ export class RedisDriver {
125
125
  stale.push(id);
126
126
  continue;
127
127
  }
128
- sessions.push({ id, data: await this.read(id) });
128
+ // The EXISTS check above already established the key is there; a null
129
+ // here means it expired in the gap, and that device is no longer active.
130
+ const data = await this.read(id);
131
+ if (data === null) {
132
+ stale.push(id);
133
+ continue;
134
+ }
135
+ sessions.push({ id, data });
129
136
  }
130
137
  if (stale.length > 0)
131
138
  await client.srem(key, ...stale);
@@ -1 +1 @@
1
- {"version":3,"file":"RedisDriver.js","sourceRoot":"","sources":["../../../src/session/drivers/RedisDriver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RedisDriver.js","sourceRoot":"","sources":["../../../src/session/drivers/RedisDriver.ts"],"names":[],"mappings":"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"}
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c9up/ream",
3
- "version": "0.1.33",
3
+ "version": "0.2.0",
4
4
  "description": "Ream — Rust-powered Node.js application framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -136,7 +136,10 @@
136
136
  "scripts",
137
137
  "src",
138
138
  "swcrc.app.json",
139
- "tsconfig.app.json"
139
+ "tsconfig.app.json",
140
+ "tsconfig.base.json",
141
+ "tsconfig.package.json",
142
+ "tsconfig.client.json"
140
143
  ],
141
144
  "dependencies": {
142
145
  "etag": "^1.8.1",
Binary file
@@ -13,10 +13,11 @@
13
13
  * @implements FR17, FR20
14
14
  */
15
15
 
16
- import { join } from 'node:path'
16
+ import { join, relative } from 'node:path'
17
17
  import { fileURLToPath } from 'node:url'
18
18
  import { ConfigStore } from './ConfigLoader.js'
19
19
  import { Container } from './container/Container.js'
20
+ import { type DirectoriesNode, directories as defaultDirectories } from './directories.js'
20
21
  import type { AppContext, ProviderContract } from './Provider.js'
21
22
  import { callProviderPhase } from './Provider.js'
22
23
 
@@ -32,6 +33,7 @@ export class Application implements AppContext {
32
33
  readonly container: Container
33
34
  readonly config: ConfigStore
34
35
  #appRoot?: URL
36
+ #directories: DirectoriesNode = { ...defaultDirectories }
35
37
  private providers: ProviderContract[] = []
36
38
  private _booted = false
37
39
  #mode: ApplicationMode = 'run'
@@ -92,32 +94,193 @@ export class Application implements AppContext {
92
94
 
93
95
  /** Absolute path to a file/dir inside the project root. */
94
96
  makePath(...paths: string[]): string {
97
+ return join(fileURLToPath(this.#requireAppRoot()), ...paths)
98
+ }
99
+
100
+ /**
101
+ * A URL to a file/dir inside the project root, where {@link makePath} gives
102
+ * a path. What an importer wants.
103
+ */
104
+ makeURL(...paths: string[]): URL {
105
+ // Joined with '/', not `path.join`: a URL keeps forward slashes on every
106
+ // platform, and `join` would hand Windows a backslash-separated href.
107
+ return new URL(paths.join('/'), this.#requireAppRoot())
108
+ }
109
+
110
+ /** Turn an absolute path back into one relative to the project root. */
111
+ relativePath(absolutePath: string): string {
112
+ return relative(fileURLToPath(this.#requireAppRoot()), absolutePath)
113
+ }
114
+
115
+ #requireAppRoot(): URL {
95
116
  if (!this.#appRoot) {
96
117
  throw new Error(
97
118
  'Application.makePath: app root is not set — construct the Ignitor with `new Ignitor(new URL("../", import.meta.url))`.',
98
119
  )
99
120
  }
100
- return join(fileURLToPath(this.#appRoot), ...paths)
121
+ return this.#appRoot
122
+ }
123
+
124
+ /**
125
+ * The conventional directory layout, `reamrc.ts` overrides merged over the
126
+ * defaults. Every helper below reads it, so moving a directory is declared
127
+ * once.
128
+ */
129
+ get directories(): DirectoriesNode {
130
+ return this.#directories
131
+ }
132
+
133
+ /**
134
+ * Feed the loaded rc file to the application (AdonisJS `rcContents`).
135
+ *
136
+ * Today it reads one key, `directories`, merged over the defaults; the rest
137
+ * of the rc file is consumed by the Ignitor and the CLI, which own providers,
138
+ * preloads, commands and test suites.
139
+ */
140
+ rcContents(value: { directories?: Partial<DirectoriesNode> }): this {
141
+ if (value.directories) {
142
+ // Skip the undefined entries a `Partial` may carry: spreading them would
143
+ // blank a default rather than leave it alone.
144
+ for (const [key, path] of Object.entries(value.directories)) {
145
+ if (path !== undefined) this.#directories[key] = path
146
+ }
147
+ }
148
+ return this
149
+ }
150
+
151
+ /** Resolve inside one of the conventional directories. */
152
+ #inDirectory(key: keyof DirectoriesNode, paths: string[]): string {
153
+ return this.makePath(this.#directories[key], ...paths)
101
154
  }
102
155
 
103
156
  /** Absolute path inside the `config/` directory. */
104
157
  configPath(...paths: string[]): string {
105
- return this.makePath('config', ...paths)
158
+ return this.#inDirectory('config', paths)
106
159
  }
107
160
 
108
161
  /** Absolute path inside the `database/migrations/` directory. */
109
162
  migrationsPath(...paths: string[]): string {
110
- return this.makePath('database', 'migrations', ...paths)
163
+ return this.#inDirectory('migrations', paths)
111
164
  }
112
165
 
113
166
  /** Absolute path inside the `tmp/` directory. */
114
167
  tmpPath(...paths: string[]): string {
115
- return this.makePath('tmp', ...paths)
168
+ return this.#inDirectory('tmp', paths)
116
169
  }
117
170
 
118
171
  /** Absolute path inside the `public/` directory. */
119
172
  publicPath(...paths: string[]): string {
120
- return this.makePath('public', ...paths)
173
+ return this.#inDirectory('public', paths)
174
+ }
175
+
176
+ /** Absolute path inside the `providers/` directory. */
177
+ providersPath(...paths: string[]): string {
178
+ return this.#inDirectory('providers', paths)
179
+ }
180
+
181
+ /** Absolute path inside the `database/factories/` directory. */
182
+ factoriesPath(...paths: string[]): string {
183
+ return this.#inDirectory('factories', paths)
184
+ }
185
+
186
+ /** Absolute path inside the `database/seeders/` directory. */
187
+ seedersPath(...paths: string[]): string {
188
+ return this.#inDirectory('seeders', paths)
189
+ }
190
+
191
+ /** Absolute path inside the `resources/lang/` directory. */
192
+ languageFilesPath(...paths: string[]): string {
193
+ return this.#inDirectory('languageFiles', paths)
194
+ }
195
+
196
+ /** Absolute path inside the `resources/views/` directory. */
197
+ viewsPath(...paths: string[]): string {
198
+ return this.#inDirectory('views', paths)
199
+ }
200
+
201
+ /** Absolute path inside the `start/` directory. */
202
+ startPath(...paths: string[]): string {
203
+ return this.#inDirectory('start', paths)
204
+ }
205
+
206
+ /** Absolute path inside the `contracts/` directory. */
207
+ contractsPath(...paths: string[]): string {
208
+ return this.#inDirectory('contracts', paths)
209
+ }
210
+
211
+ /** Absolute path inside the `app/controllers/` directory. */
212
+ httpControllersPath(...paths: string[]): string {
213
+ return this.#inDirectory('httpControllers', paths)
214
+ }
215
+
216
+ /** Absolute path inside the `app/models/` directory. */
217
+ modelsPath(...paths: string[]): string {
218
+ return this.#inDirectory('models', paths)
219
+ }
220
+
221
+ /** Absolute path inside the `app/services/` directory. */
222
+ servicesPath(...paths: string[]): string {
223
+ return this.#inDirectory('services', paths)
224
+ }
225
+
226
+ /** Absolute path inside the `app/exceptions/` directory. */
227
+ exceptionsPath(...paths: string[]): string {
228
+ return this.#inDirectory('exceptions', paths)
229
+ }
230
+
231
+ /** Absolute path inside the `app/mailers/` directory. */
232
+ mailersPath(...paths: string[]): string {
233
+ return this.#inDirectory('mailers', paths)
234
+ }
235
+
236
+ /** Absolute path inside the `app/mails/` directory. */
237
+ mailsPath(...paths: string[]): string {
238
+ return this.#inDirectory('mails', paths)
239
+ }
240
+
241
+ /** Absolute path inside the `app/middleware/` directory. */
242
+ middlewarePath(...paths: string[]): string {
243
+ return this.#inDirectory('middleware', paths)
244
+ }
245
+
246
+ /** Absolute path inside the `app/policies/` directory. */
247
+ policiesPath(...paths: string[]): string {
248
+ return this.#inDirectory('policies', paths)
249
+ }
250
+
251
+ /** Absolute path inside the `app/validators/` directory. */
252
+ validatorsPath(...paths: string[]): string {
253
+ return this.#inDirectory('validators', paths)
254
+ }
255
+
256
+ /** Absolute path inside the `commands/` directory. */
257
+ commandsPath(...paths: string[]): string {
258
+ return this.#inDirectory('commands', paths)
259
+ }
260
+
261
+ /** Absolute path inside the `app/events/` directory. */
262
+ eventsPath(...paths: string[]): string {
263
+ return this.#inDirectory('events', paths)
264
+ }
265
+
266
+ /** Absolute path inside the `app/listeners/` directory. */
267
+ listenersPath(...paths: string[]): string {
268
+ return this.#inDirectory('listeners', paths)
269
+ }
270
+
271
+ /** Absolute path inside the `app/transformers/` directory. */
272
+ transformersPath(...paths: string[]): string {
273
+ return this.#inDirectory('transformers', paths)
274
+ }
275
+
276
+ /** Absolute path inside the generated-client directory (`.ream/client`). */
277
+ generatedClientPath(...paths: string[]): string {
278
+ return this.#inDirectory('generatedClient', paths)
279
+ }
280
+
281
+ /** Absolute path inside the generated-server directory (`.ream/server`). */
282
+ generatedServerPath(...paths: string[]): string {
283
+ return this.#inDirectory('generatedServer', paths)
121
284
  }
122
285
 
123
286
  // ─── Environment ──────────────────────────────────────────
@@ -24,6 +24,9 @@ export class ConfigStore {
24
24
  * Read a value by dot-notation key, returning `defaultValue` when the path
25
25
  * is absent or resolves to `undefined` (AdonisJS `config.get`).
26
26
  */
27
+ get<T = unknown>(key: string): T | undefined
28
+ get<T = unknown>(key: string, defaultValue: T): T
29
+ get<T = unknown>(key: string, defaultValue?: T): T | undefined
27
30
  get<T = unknown>(key: string, defaultValue?: T): T | undefined {
28
31
  // Untyped store: the caller declares the shape it configured (same
29
32
  // contract as `@adonisjs/config`, whose `get<T>` returns the loose value).
@@ -70,6 +73,9 @@ export class ConfigStore {
70
73
  * Read an environment variable with optional default.
71
74
  * @implements FR19
72
75
  */
76
+ export function env(key: string): string | undefined
77
+ export function env(key: string, defaultValue: string): string
78
+ export function env(key: string, defaultValue?: string): string | undefined
73
79
  export function env(key: string, defaultValue?: string): string | undefined {
74
80
  return process.env[key] ?? defaultValue
75
81
  }
@@ -27,24 +27,24 @@ const DEFAULT_CHECK_TIMEOUT = 5000
27
27
  * Manages health check registrations and produces aggregated status.
28
28
  */
29
29
  export class HealthCheck {
30
- private checkers: Map<string, HealthChecker> = new Map()
31
- private startTime = Date.now()
32
- private checkTimeout: number
30
+ readonly #checkers: Map<string, HealthChecker> = new Map()
31
+ readonly #startTime = Date.now()
32
+ readonly #checkTimeout: number
33
33
 
34
34
  constructor(options?: { checkTimeout?: number }) {
35
- this.checkTimeout = options?.checkTimeout ?? DEFAULT_CHECK_TIMEOUT
35
+ this.#checkTimeout = options?.checkTimeout ?? DEFAULT_CHECK_TIMEOUT
36
36
  }
37
37
 
38
38
  /** Register a health checker. */
39
39
  register(name: string, checker: HealthChecker): void {
40
- this.checkers.set(name, checker)
40
+ this.#checkers.set(name, checker)
41
41
  }
42
42
 
43
43
  /** Run all health checks and return aggregated status. */
44
44
  async check(): Promise<HealthStatus> {
45
45
  const checks: HealthCheckResult[] = []
46
46
 
47
- for (const [name, checker] of this.checkers) {
47
+ for (const [name, checker] of this.#checkers) {
48
48
  const start = Date.now()
49
49
  try {
50
50
  const result = await Promise.race([
@@ -52,8 +52,8 @@ export class HealthCheck {
52
52
  new Promise<never>((_, reject) =>
53
53
  setTimeout(
54
54
  () =>
55
- reject(new Error(`Health check '${name}' timed out after ${this.checkTimeout}ms`)),
56
- this.checkTimeout,
55
+ reject(new Error(`Health check '${name}' timed out after ${this.#checkTimeout}ms`)),
56
+ this.#checkTimeout,
57
57
  ),
58
58
  ),
59
59
  ])
@@ -76,21 +76,34 @@ export class HealthCheck {
76
76
 
77
77
  return {
78
78
  status: hasError ? 'error' : hasWarn ? 'degraded' : 'ok',
79
- uptime: Math.floor((Date.now() - this.startTime) / 1000),
79
+ uptime: Math.floor((Date.now() - this.#startTime) / 1000),
80
80
  timestamp: new Date().toISOString(),
81
81
  checks,
82
82
  }
83
83
  }
84
84
 
85
- /** Create the /health route handler. Returns 200 for ok, 503 for degraded/error. */
85
+ /**
86
+ * Create the /health route handler. Returns 200 for ok, 503 otherwise.
87
+ *
88
+ * The parameter is the narrowest shape a real `HttpContext` satisfies, so
89
+ * this can be mounted straight on a route. It used to assign
90
+ * `ctx.response.status` and `ctx.response.body` as PROPERTIES, which no Ream
91
+ * response has ever had — mounted for real it would have answered an empty
92
+ * 200 to every probe, marking a dead app healthy. Its only test built a fake
93
+ * context in that invented shape, so nothing caught it.
94
+ */
86
95
  handler(): (ctx: {
87
- response: { status: number; headers: Record<string, string>; body: string }
96
+ response: {
97
+ status(code: number): unknown
98
+ header(key: string, value: string): unknown
99
+ json(body: unknown): unknown
100
+ }
88
101
  }) => Promise<void> {
89
102
  return async (ctx) => {
90
103
  const health = await this.check()
91
- ctx.response.status = health.status === 'ok' ? 200 : 503
92
- ctx.response.headers['content-type'] = 'application/json'
93
- ctx.response.body = JSON.stringify(health)
104
+ ctx.response.status(health.status === 'ok' ? 200 : 503)
105
+ ctx.response.header('content-type', 'application/json')
106
+ ctx.response.json(health)
94
107
  }
95
108
  }
96
109
  }
package/src/HttpKernel.ts CHANGED
@@ -49,6 +49,18 @@ export interface HttpKernelConfig {
49
49
  * could rewrite itself into a DELETE.
50
50
  */
51
51
  allowMethodSpoofing?: boolean
52
+ /**
53
+ * Default callback name for `response.jsonp()` (AdonisJS
54
+ * `http.jsonpCallbackName`). Falls back to `callback`.
55
+ */
56
+ jsonpCallbackName?: string
57
+ /**
58
+ * Ceiling on a buffered response body, in bytes. Default 100MB — the same the
59
+ * Rust layer caps an incoming body at. Responses are not streamed yet, so the
60
+ * body is held whole in memory; this is what stops a large one growing until
61
+ * the process dies with no message.
62
+ */
63
+ maxResponseBytes?: number
52
64
  }
53
65
 
54
66
  export interface HttpKernelResponse {
@@ -170,6 +182,12 @@ export function createHttpKernel(
170
182
  // What Adonis binds on every request's resolver: the context itself, so a
171
183
  // controller or service can take `HttpContext` as a constructor dependency.
172
184
  resolver?.bindValue(HttpContext, ctx)
185
+ if (config.jsonpCallbackName !== undefined) {
186
+ ctx.response.setJsonpCallbackName(config.jsonpCallbackName)
187
+ }
188
+ if (config.maxResponseBytes !== undefined) {
189
+ ctx.response.setMaxBodyBytes(config.maxResponseBytes)
190
+ }
173
191
  if (config.allowMethodSpoofing === true) {
174
192
  // Was never wired: the setter existed but nothing called it, so a
175
193
  // migrated config asking for spoofing got a `_method` field that did
@@ -322,8 +340,13 @@ export function createHttpKernel(
322
340
  // the HyperServer keeps feeding a dead stream slot forever.
323
341
  await ctx.response.abortStream()
324
342
  try {
325
- await handler.handle(error, ctx)
343
+ // REPORT first, then handle — the AdonisJS order
344
+ // (`#requestErrorResponder`: `await report(error, ctx)` before
345
+ // `handle`). Handling first meant a throwing `handle()` fell into the
346
+ // catch below and the error was never reported: it vanished from the
347
+ // logs and the operator saw only "ExceptionHandler failed".
326
348
  await handler.report(error, ctx)
349
+ await handler.handle(error, ctx)
327
350
  } catch (handlerError) {
328
351
  console.error('ExceptionHandler failed:', handlerError)
329
352
  ctx.response
@@ -403,9 +426,9 @@ function readControllerGuardMetadata(
403
426
  }
404
427
 
405
428
  async function serializeResponse(ctx: HttpContext): Promise<HttpKernelResponse> {
406
- // A body still being drained by `response.stream()` — upstream returns void
407
- // there, so a migrated controller does not await it.
408
- await ctx.response.settle()
429
+ // The terminal step, as AdonisJS' server calls `response.finish()`: it
430
+ // stamps the request id and waits for a body still being produced.
431
+ await ctx.response.finish()
409
432
  const streamId = ctx.response.getStreamId()
410
433
  return {
411
434
  status: ctx.response.getStatus(),
package/src/Ignitor.ts CHANGED
@@ -17,6 +17,7 @@ import { Application } from './Application.js'
17
17
  import type { Console } from './console/Console.js'
18
18
  import type { CommandLoader, Kernel as ConsoleKernelInstance } from './console/Kernel.js'
19
19
  import { type CommandClass, isCommandClass } from './console/types.js'
20
+ import type { DirectoriesNode } from './directories.js'
20
21
  import type { ErrorEvent } from './ErrorBoundary.js'
21
22
  import { ErrorBoundary } from './ErrorBoundary.js'
22
23
  import { loadEnvFiles } from './env/loadEnvFiles.js'
@@ -32,6 +33,7 @@ import { ExceptionHandler } from './http/Exception.js'
32
33
  import { HttpContext } from './http/HttpContext.js'
33
34
  import type { MiddlewareFunction } from './middleware/Pipeline.js'
34
35
  import { MiddlewareRegistry } from './middleware/Pipeline.js'
36
+ import { MigrationRegistry } from './migrations/MigrationRegistry.js'
35
37
  import type { AppContext, ProviderContract } from './Provider.js'
36
38
  import { callProviderPhase } from './Provider.js'
37
39
  import { Router } from './router/Router.js'
@@ -64,6 +66,11 @@ export interface ReamrcConfig {
64
66
  environment?: string[]
65
67
  }
66
68
  >
69
+ /**
70
+ * Override the conventional directory layout. Merged over the defaults, so
71
+ * only the directories that moved need naming.
72
+ */
73
+ directories?: Partial<DirectoriesNode>
67
74
  commands?: Array<() => Promise<unknown>>
68
75
  /**
69
76
  * Command shorthands — Console's `commandsAliases`. The value is the command the
@@ -207,6 +214,8 @@ export class Ignitor {
207
214
  private router: Router
208
215
  private server: Server
209
216
  private middleware: MiddlewareRegistry
217
+ /** Where each data package registers its migration runner. See `MigrationRegistry`. */
218
+ private migrations: MigrationRegistry
210
219
  private errorBoundary: ErrorBoundary
211
220
  private _httpServer?: HyperServerLike
212
221
  private config: IgnitorConfig
@@ -248,12 +257,17 @@ export class Ignitor {
248
257
  this.router = new Router()
249
258
  this.server = new Server(this.router)
250
259
  this.middleware = new MiddlewareRegistry()
260
+ this.migrations = new MigrationRegistry()
251
261
  this.errorBoundary = new ErrorBoundary((event) => this.handleError(event), this.isDevMode())
252
262
 
253
263
  // Register framework services in container
254
264
  this.app.container.singleton('router', () => this.router)
255
265
  this.app.container.singleton('server', () => this.server)
256
266
  this.app.container.singleton('middleware', () => this.middleware)
267
+ // Always bound, even with no data package: an EMPTY registry is what lets
268
+ // the CLI tell "this app has no migrations" from "this app predates the
269
+ // registry" and say something useful in each case.
270
+ this.app.container.singleton('migrations', () => this.migrations)
257
271
  this.app.container.singleton('app', () => this.app)
258
272
  // The HttpContext CLASS, so an integration provider can extend it the way
259
273
  // AdonisJS does — `HttpContext.getter('view', …)` is how the view layer
@@ -325,6 +339,9 @@ export class Ignitor {
325
339
  */
326
340
  useRcFile(reamrc: ReamrcConfig): this {
327
341
  this.reamrc = reamrc
342
+ // Hand the app its directory overrides now rather than at boot: a path
343
+ // helper called from a provider's register() must already see them.
344
+ this.app.rcContents(reamrc)
328
345
  return this
329
346
  }
330
347