@c9up/ream 0.2.28 → 0.2.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -6
- package/dist/Codemods.d.ts +24 -0
- package/dist/Codemods.d.ts.map +1 -1
- package/dist/Codemods.js +211 -1
- package/dist/Codemods.js.map +1 -1
- package/dist/HttpKernel.d.ts.map +1 -1
- package/dist/HttpKernel.js +17 -5
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +15 -2
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +33 -23
- package/dist/Ignitor.js.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.d.ts +4 -4
- package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.js +41 -11
- package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
- package/dist/bodyparser/MultipartFile.d.ts +21 -15
- package/dist/bodyparser/MultipartFile.d.ts.map +1 -1
- package/dist/bodyparser/MultipartFile.js +40 -58
- package/dist/bodyparser/MultipartFile.js.map +1 -1
- package/dist/bodyparser/parseSize.d.ts +7 -4
- package/dist/bodyparser/parseSize.d.ts.map +1 -1
- package/dist/bodyparser/parseSize.js +12 -17
- package/dist/bodyparser/parseSize.js.map +1 -1
- package/dist/bodyparser/qsParse.d.ts +20 -1
- package/dist/bodyparser/qsParse.d.ts.map +1 -1
- package/dist/bodyparser/qsParse.js +78 -25
- package/dist/bodyparser/qsParse.js.map +1 -1
- package/dist/codemods/source.d.ts +57 -0
- package/dist/codemods/source.d.ts.map +1 -0
- package/dist/codemods/source.js +282 -0
- package/dist/codemods/source.js.map +1 -0
- package/dist/console/prompts.d.ts.map +1 -1
- package/dist/console/prompts.js +3 -1
- package/dist/console/prompts.js.map +1 -1
- package/dist/container/Container.d.ts.map +1 -1
- package/dist/container/Container.js +61 -71
- package/dist/container/Container.js.map +1 -1
- package/dist/events/Emitter.d.ts +12 -0
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +36 -9
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/helix/helpers.d.ts.map +1 -1
- package/dist/events/helix/helpers.js +19 -9
- package/dist/events/helix/helpers.js.map +1 -1
- package/dist/graphql/GraphQLEngine.d.ts +8 -0
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
- package/dist/graphql/GraphQLEngine.js +79 -12
- package/dist/graphql/GraphQLEngine.js.map +1 -1
- package/dist/helpers/MessageBuilder.d.ts +4 -2
- package/dist/helpers/MessageBuilder.d.ts.map +1 -1
- package/dist/helpers/MessageBuilder.js +4 -2
- package/dist/helpers/MessageBuilder.js.map +1 -1
- package/dist/helpers/errors.d.ts +11 -0
- package/dist/helpers/errors.d.ts.map +1 -0
- package/dist/helpers/errors.js +17 -0
- package/dist/helpers/errors.js.map +1 -0
- package/dist/helpers/napi-loader.d.ts.map +1 -1
- package/dist/helpers/napi-loader.js +3 -2
- package/dist/helpers/napi-loader.js.map +1 -1
- package/dist/http/Exception.d.ts +14 -1
- package/dist/http/Exception.d.ts.map +1 -1
- package/dist/http/Exception.js +10 -2
- package/dist/http/Exception.js.map +1 -1
- package/dist/http/HttpContext.d.ts +31 -2
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/HttpContext.js +12 -5
- package/dist/http/HttpContext.js.map +1 -1
- package/dist/http/RedirectBuilder.d.ts +9 -3
- package/dist/http/RedirectBuilder.d.ts.map +1 -1
- package/dist/http/RedirectBuilder.js +43 -37
- package/dist/http/RedirectBuilder.js.map +1 -1
- package/dist/http/Request.d.ts +42 -17
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +80 -58
- package/dist/http/Request.js.map +1 -1
- package/dist/http/Response.d.ts +7 -4
- package/dist/http/Response.d.ts.map +1 -1
- package/dist/http/Response.js +14 -6
- package/dist/http/Response.js.map +1 -1
- package/dist/http/SseStream.js +6 -7
- package/dist/http/SseStream.js.map +1 -1
- package/dist/http/permissions.d.ts +25 -0
- package/dist/http/permissions.d.ts.map +1 -0
- package/dist/http/permissions.js +38 -0
- package/dist/http/permissions.js.map +1 -0
- package/dist/http-client/HttpClient.d.ts +111 -0
- package/dist/http-client/HttpClient.d.ts.map +1 -0
- package/dist/http-client/HttpClient.js +386 -0
- package/dist/http-client/HttpClient.js.map +1 -0
- package/dist/http-client/addresses.d.ts +14 -0
- package/dist/http-client/addresses.d.ts.map +1 -0
- package/dist/http-client/addresses.js +57 -0
- package/dist/http-client/addresses.js.map +1 -0
- package/dist/http-client/fake.d.ts +50 -0
- package/dist/http-client/fake.d.ts.map +1 -0
- package/dist/http-client/fake.js +95 -0
- package/dist/http-client/fake.js.map +1 -0
- package/dist/http-client/index.d.ts +7 -0
- package/dist/http-client/index.d.ts.map +1 -0
- package/dist/http-client/index.js +7 -0
- package/dist/http-client/index.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/Pipeline.d.ts.map +1 -1
- package/dist/middleware/Pipeline.js +6 -3
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/native/generated.d.ts +93 -36
- package/dist/native/generated.d.ts.map +1 -1
- package/dist/profiler/Profiler.d.ts.map +1 -1
- package/dist/profiler/Profiler.js +4 -1
- package/dist/profiler/Profiler.js.map +1 -1
- package/dist/profiler/client.generated.d.ts +5 -0
- package/dist/profiler/client.generated.d.ts.map +1 -0
- package/dist/profiler/client.generated.js +6 -0
- package/dist/profiler/client.generated.js.map +1 -0
- package/dist/profiler/collectors.d.ts +92 -13
- package/dist/profiler/collectors.d.ts.map +1 -1
- package/dist/profiler/collectors.js +106 -19
- package/dist/profiler/collectors.js.map +1 -1
- package/dist/profiler/endpoint.d.ts +2 -1
- package/dist/profiler/endpoint.d.ts.map +1 -1
- package/dist/profiler/endpoint.js +25 -1
- package/dist/profiler/endpoint.js.map +1 -1
- package/dist/profiler/index.d.ts +8 -4
- package/dist/profiler/index.d.ts.map +1 -1
- package/dist/profiler/index.js +11 -4
- package/dist/profiler/index.js.map +1 -1
- package/dist/profiler/middleware.d.ts.map +1 -1
- package/dist/profiler/middleware.js +76 -10
- package/dist/profiler/middleware.js.map +1 -1
- package/dist/profiler/preview.d.ts +17 -0
- package/dist/profiler/preview.d.ts.map +1 -0
- package/dist/profiler/preview.js +100 -0
- package/dist/profiler/preview.js.map +1 -0
- package/dist/profiler/toolbar.d.ts +15 -23
- package/dist/profiler/toolbar.d.ts.map +1 -1
- package/dist/profiler/toolbar.js +25 -91
- package/dist/profiler/toolbar.js.map +1 -1
- package/dist/profiler/types.d.ts +6 -1
- package/dist/profiler/types.d.ts.map +1 -1
- package/dist/router/Router.d.ts +6 -0
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.js +115 -12
- package/dist/router/Router.js.map +1 -1
- package/dist/rpc/RpcProvider.d.ts +6 -0
- package/dist/rpc/RpcProvider.d.ts.map +1 -1
- package/dist/rpc/RpcProvider.js +4 -1
- package/dist/rpc/RpcProvider.js.map +1 -1
- package/dist/rpc/RpcRouter.d.ts +27 -14
- package/dist/rpc/RpcRouter.d.ts.map +1 -1
- package/dist/rpc/RpcRouter.js +97 -40
- package/dist/rpc/RpcRouter.js.map +1 -1
- package/dist/scheduler/Scheduler.js +1 -1
- package/dist/scheduler/Scheduler.js.map +1 -1
- package/dist/scheduler/locks/RedisLockBackend.d.ts.map +1 -1
- package/dist/scheduler/locks/RedisLockBackend.js +13 -2
- package/dist/scheduler/locks/RedisLockBackend.js.map +1 -1
- package/dist/security/CookieSigner.d.ts.map +1 -1
- package/dist/security/CookieSigner.js +32 -8
- package/dist/security/CookieSigner.js.map +1 -1
- package/dist/security/SignedUrl.d.ts.map +1 -1
- package/dist/security/SignedUrl.js +16 -19
- package/dist/security/SignedUrl.js.map +1 -1
- package/dist/server/Server.d.ts +44 -12
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/Server.js +31 -10
- package/dist/server/Server.js.map +1 -1
- package/dist/server/nativeGrpc.d.ts +27 -0
- package/dist/server/nativeGrpc.d.ts.map +1 -0
- package/dist/server/nativeGrpc.js +47 -0
- package/dist/server/nativeGrpc.js.map +1 -0
- package/dist/server/nativeLimits.d.ts +57 -0
- package/dist/server/nativeLimits.d.ts.map +1 -0
- package/dist/server/nativeLimits.js +75 -0
- package/dist/server/nativeLimits.js.map +1 -0
- package/dist/session/Session.d.ts +12 -0
- package/dist/session/Session.d.ts.map +1 -1
- package/dist/session/Session.js +13 -4
- package/dist/session/Session.js.map +1 -1
- package/dist/session/SessionMiddleware.d.ts.map +1 -1
- package/dist/session/SessionMiddleware.js +28 -9
- package/dist/session/SessionMiddleware.js.map +1 -1
- package/dist/session/config.d.ts +5 -0
- package/dist/session/config.d.ts.map +1 -1
- package/dist/session/config.js +8 -0
- package/dist/session/config.js.map +1 -1
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/session/drivers/MemoryDriver.js +26 -7
- package/dist/session/drivers/MemoryDriver.js.map +1 -1
- package/dist/session/errors.d.ts +17 -0
- package/dist/session/errors.d.ts.map +1 -1
- package/dist/session/errors.js +21 -0
- package/dist/session/errors.js.map +1 -1
- package/dist/session/templateTags.d.ts +14 -0
- package/dist/session/templateTags.d.ts.map +1 -1
- package/dist/session/templateTags.js +45 -17
- package/dist/session/templateTags.js.map +1 -1
- package/dist/storage/StaticMiddleware.d.ts.map +1 -1
- package/dist/storage/StaticMiddleware.js +49 -27
- package/dist/storage/StaticMiddleware.js.map +1 -1
- package/dist/testing/ApiResponse.d.ts.map +1 -1
- package/dist/testing/ApiResponse.js +7 -1
- package/dist/testing/ApiResponse.js.map +1 -1
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +16 -4
- package/dist/testing/TestClient.js.map +1 -1
- package/dist/utils/Macroable.d.ts +1 -1
- package/dist/utils/Macroable.js +2 -2
- package/dist/utils/Macroable.js.map +1 -1
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +11 -3
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/Codemods.ts +314 -3
- package/src/HttpKernel.ts +18 -7
- package/src/Ignitor.ts +58 -26
- package/src/bodyparser/BodyParserMiddleware.ts +45 -16
- package/src/bodyparser/MultipartFile.ts +46 -67
- package/src/bodyparser/parseSize.ts +17 -17
- package/src/bodyparser/qsParse.ts +96 -26
- package/src/codemods/source.ts +303 -0
- package/src/console/prompts.ts +3 -1
- package/src/container/Container.ts +97 -81
- package/src/events/Emitter.ts +37 -10
- package/src/events/helix/helpers.ts +24 -19
- package/src/graphql/GraphQLEngine.ts +91 -14
- package/src/helpers/MessageBuilder.ts +4 -2
- package/src/helpers/errors.ts +16 -0
- package/src/helpers/napi-loader.ts +3 -2
- package/src/http/Exception.ts +17 -2
- package/src/http/HttpContext.ts +34 -5
- package/src/http/RedirectBuilder.ts +51 -37
- package/src/http/Request.ts +102 -58
- package/src/http/Response.ts +15 -7
- package/src/http/SseStream.ts +6 -7
- package/src/http/permissions.ts +47 -0
- package/src/http-client/HttpClient.ts +505 -0
- package/src/http-client/addresses.ts +58 -0
- package/src/http-client/fake.ts +141 -0
- package/src/http-client/index.ts +21 -0
- package/src/index.ts +6 -1
- package/src/middleware/Pipeline.ts +7 -3
- package/src/native/generated.ts +106 -48
- package/src/profiler/Profiler.ts +4 -1
- package/src/profiler/client/toolbar.css +595 -0
- package/src/profiler/client/toolbar.js +1299 -0
- package/src/profiler/client.generated.ts +7 -0
- package/src/profiler/collectors.ts +156 -19
- package/src/profiler/endpoint.ts +27 -1
- package/src/profiler/index.ts +17 -3
- package/src/profiler/middleware.ts +74 -9
- package/src/profiler/preview.ts +104 -0
- package/src/profiler/toolbar.ts +28 -91
- package/src/profiler/types.ts +6 -1
- package/src/router/Router.ts +136 -13
- package/src/rpc/RpcProvider.ts +10 -1
- package/src/rpc/RpcRouter.ts +129 -45
- package/src/scheduler/Scheduler.ts +1 -1
- package/src/scheduler/locks/RedisLockBackend.ts +12 -4
- package/src/security/CookieSigner.ts +30 -8
- package/src/security/SignedUrl.ts +18 -17
- package/src/server/Server.ts +60 -12
- package/src/server/nativeGrpc.ts +59 -0
- package/src/server/nativeLimits.ts +111 -0
- package/src/session/Session.ts +29 -4
- package/src/session/SessionMiddleware.ts +30 -10
- package/src/session/config.ts +7 -0
- package/src/session/drivers/MemoryDriver.ts +26 -7
- package/src/session/errors.ts +31 -0
- package/src/session/templateTags.ts +57 -0
- package/src/storage/StaticMiddleware.ts +46 -27
- package/src/testing/ApiResponse.ts +7 -1
- package/src/testing/TestClient.ts +14 -5
- package/src/utils/Macroable.ts +2 -2
- package/scripts/build-napi-types.mjs +0 -69
- package/scripts/copy-napi.mjs +0 -121
- package/scripts/generate-mime.mjs +0 -119
- package/scripts/generate-napi-types.mjs +0 -187
package/src/Codemods.ts
CHANGED
|
@@ -1,9 +1,36 @@
|
|
|
1
1
|
import * as fs from 'node:fs'
|
|
2
2
|
import * as path from 'node:path'
|
|
3
|
+
import {
|
|
4
|
+
appendToLiteral,
|
|
5
|
+
findCall,
|
|
6
|
+
findExportDefaultObject,
|
|
7
|
+
isSingleExpression,
|
|
8
|
+
matchClose,
|
|
9
|
+
properties,
|
|
10
|
+
segments,
|
|
11
|
+
} from './codemods/source.js'
|
|
3
12
|
import { render as renderTemplate, type StubState } from './stubs/template.js'
|
|
4
13
|
|
|
5
14
|
export type { StubState }
|
|
6
15
|
|
|
16
|
+
/** The environments a preload (or provider) entry can be scoped to. */
|
|
17
|
+
export type PreloadEnvironment = 'web' | 'console' | 'test' | 'repl'
|
|
18
|
+
|
|
19
|
+
const PRELOAD_ENVIRONMENTS: readonly PreloadEnvironment[] = ['web', 'console', 'test', 'repl']
|
|
20
|
+
|
|
21
|
+
/** Validation rules a configure hook adds to `start/env.ts`. */
|
|
22
|
+
export interface EnvValidationNode {
|
|
23
|
+
/** Written once, as a banner comment above the rules this call adds. */
|
|
24
|
+
leadingComment?: string
|
|
25
|
+
/** Variable name → rule source, e.g. `{ REDIS_PORT: 'Env.schema.number()' }`. */
|
|
26
|
+
variables: Record<string, string>
|
|
27
|
+
/**
|
|
28
|
+
* Replace a rule the file already has. Off by default, so a rule the user
|
|
29
|
+
* edited survives a re-run; configure hooks pass their `--force` flag.
|
|
30
|
+
*/
|
|
31
|
+
overwrite?: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
7
34
|
export interface Codemods {
|
|
8
35
|
addProvider(importPath: string): Promise<void>
|
|
9
36
|
addMetaFile(pattern: string, reloadServer?: boolean): Promise<void>
|
|
@@ -16,7 +43,12 @@ export interface Codemods {
|
|
|
16
43
|
options?: { force?: boolean },
|
|
17
44
|
): Promise<GeneratedStub>
|
|
18
45
|
registerCommand(importPath: string): Promise<void>
|
|
19
|
-
registerMiddleware(
|
|
46
|
+
registerMiddleware(
|
|
47
|
+
importPath: string,
|
|
48
|
+
options?: { tier?: 'server' | 'router'; position?: MiddlewarePosition },
|
|
49
|
+
): Promise<void>
|
|
50
|
+
defineEnvValidations(definition: EnvValidationNode): Promise<string[]>
|
|
51
|
+
addPreloadFile(modulePath: string, environments?: PreloadEnvironment[]): Promise<void>
|
|
20
52
|
}
|
|
21
53
|
|
|
22
54
|
/** What a stub may interpolate. Scalars only — a stub is text, not a program. */
|
|
@@ -102,6 +134,40 @@ function findTierBlock(
|
|
|
102
134
|
return { start, end: start + closeMatch.index }
|
|
103
135
|
}
|
|
104
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Where a middleware entry goes in its tier's array: at the end (`after`, the
|
|
139
|
+
* default, as the upstream assembler does) or at the head (`before`). Order is
|
|
140
|
+
* execution order, so a middleware that needs another one's work — a CSRF
|
|
141
|
+
* guard reading the session — is appended after it.
|
|
142
|
+
*/
|
|
143
|
+
export type MiddlewarePosition = 'before' | 'after'
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Insert `text` after the last element of the array whose contents span
|
|
147
|
+
* `block`, adding the comma the previous element may lack. A trailing line
|
|
148
|
+
* comment is stepped over so the comma never lands inside it.
|
|
149
|
+
*/
|
|
150
|
+
function appendToArray(
|
|
151
|
+
content: string,
|
|
152
|
+
block: { start: number; end: number },
|
|
153
|
+
text: string,
|
|
154
|
+
): string {
|
|
155
|
+
const inner = content.slice(block.start, block.end)
|
|
156
|
+
const trimmed = inner.trimEnd()
|
|
157
|
+
const insertAt = block.start + trimmed.length
|
|
158
|
+
if (trimmed.trim() === '' || trimmed.endsWith(',')) {
|
|
159
|
+
return `${content.slice(0, insertAt)}${text}${content.slice(insertAt)}`
|
|
160
|
+
}
|
|
161
|
+
const lineStart = trimmed.lastIndexOf('\n') + 1
|
|
162
|
+
const commentAt = trimmed.indexOf('//', lineStart)
|
|
163
|
+
const code = (commentAt === -1 ? trimmed : trimmed.slice(0, commentAt)).trimEnd()
|
|
164
|
+
if (code.trim() === '' || code.endsWith(',')) {
|
|
165
|
+
return `${content.slice(0, insertAt)}${text}${content.slice(insertAt)}`
|
|
166
|
+
}
|
|
167
|
+
const commaAt = block.start + code.length
|
|
168
|
+
return `${content.slice(0, commaAt)},${content.slice(commaAt, insertAt)}${text}${content.slice(insertAt)}`
|
|
169
|
+
}
|
|
170
|
+
|
|
105
171
|
/**
|
|
106
172
|
* Detect line ending (CRLF on Windows checkouts, LF elsewhere) so codemods preserve the file's existing convention.
|
|
107
173
|
* Majority-based: a stray CRLF in an otherwise-LF file must not flip the whole insertion to CRLF.
|
|
@@ -128,6 +194,76 @@ function assertCanonicallyInside(root: string, filePath: string, displayName: st
|
|
|
128
194
|
}
|
|
129
195
|
}
|
|
130
196
|
|
|
197
|
+
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* A module path goes between the quotes of an `import('...')`; anything that
|
|
201
|
+
* could close them, escape or end the line is refused rather than escaped.
|
|
202
|
+
*/
|
|
203
|
+
const SAFE_MODULE_PATH = /^[^'"`\\\r\n\u2028\u2029]+$/
|
|
204
|
+
|
|
205
|
+
const BANNER_RULE = '|----------------------------------------------------------'
|
|
206
|
+
|
|
207
|
+
/** The rules of `definition`, refused before anything is written when unsafe. */
|
|
208
|
+
function assertEnvValidations(definition: EnvValidationNode): void {
|
|
209
|
+
const comment = definition.leadingComment
|
|
210
|
+
if (comment !== undefined && (/[\r\n\u2028\u2029]/.test(comment) || comment.includes('*/'))) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
'[configure] defineEnvValidations: the leading comment must be one line without `*/`',
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
for (const [name, rule] of Object.entries(definition.variables)) {
|
|
216
|
+
if (!ENV_NAME.test(name)) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`[configure] defineEnvValidations: '${name}' is not an environment variable name`,
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
if (typeof rule !== 'string' || !isSingleExpression(rule)) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`[configure] defineEnvValidations: the rule for ${name} is not one complete expression: ${String(rule)}`,
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** The `{` and `}` of the schema object passed to `Env.create`. */
|
|
230
|
+
function locateEnvSchema(content: string): { open: number; close: number } {
|
|
231
|
+
const paren = findCall(content, 'Env.create')
|
|
232
|
+
const parenClose = paren === -1 ? -1 : matchClose(content, paren)
|
|
233
|
+
if (paren === -1 || parenClose === -1) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
'[configure] Could not find an Env.create(...) call in start/env.ts — add the validations by hand.',
|
|
236
|
+
)
|
|
237
|
+
}
|
|
238
|
+
const open = segments(content, paren + 1, parenClose)[1]?.codeStart ?? -1
|
|
239
|
+
const close = content[open] === '{' ? matchClose(content, open) : -1
|
|
240
|
+
if (close === -1) {
|
|
241
|
+
throw new Error(
|
|
242
|
+
'[configure] The second argument of Env.create in start/env.ts is not an object literal — add the validations by hand.',
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
return { open, close }
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** The `{` and `}` of the object `reamrc.ts` exports (through `defineConfig` or bare). */
|
|
249
|
+
function locateRcObject(content: string): { open: number; close: number } | null {
|
|
250
|
+
const paren = findCall(content, 'defineConfig')
|
|
251
|
+
let open = -1
|
|
252
|
+
if (paren !== -1) {
|
|
253
|
+
const parenClose = matchClose(content, paren)
|
|
254
|
+
if (parenClose !== -1) open = segments(content, paren + 1, parenClose)[0]?.codeStart ?? -1
|
|
255
|
+
} else {
|
|
256
|
+
open = findExportDefaultObject(content)
|
|
257
|
+
}
|
|
258
|
+
const close = open !== -1 && content[open] === '{' ? matchClose(content, open) : -1
|
|
259
|
+
return close === -1 ? null : { open, close }
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** The module an rc array element lazily imports. */
|
|
263
|
+
function importedModule(element: string): string | undefined {
|
|
264
|
+
return /import\s*\(\s*(['"])([^'"]*)\1\s*\)/.exec(element)?.[2]
|
|
265
|
+
}
|
|
266
|
+
|
|
131
267
|
export function createCodemods(options?: { force?: boolean; cwd?: string }): Codemods {
|
|
132
268
|
const force = options?.force ?? false
|
|
133
269
|
const root = path.resolve(options?.cwd ?? process.cwd())
|
|
@@ -467,8 +603,14 @@ export function createCodemods(options?: { force?: boolean; cwd?: string }): Cod
|
|
|
467
603
|
*/
|
|
468
604
|
async registerMiddleware(
|
|
469
605
|
importPath: string,
|
|
470
|
-
options?: { tier?: MiddlewareTier },
|
|
606
|
+
options?: { tier?: MiddlewareTier; position?: MiddlewarePosition },
|
|
471
607
|
): Promise<void> {
|
|
608
|
+
const position = options?.position ?? 'after'
|
|
609
|
+
if (position !== 'before' && position !== 'after') {
|
|
610
|
+
throw new Error(
|
|
611
|
+
`[configure] Invalid middleware position: '${String(position)}'. Expected 'before' or 'after'.`,
|
|
612
|
+
)
|
|
613
|
+
}
|
|
472
614
|
const requestedTier = options?.tier ?? 'router'
|
|
473
615
|
if (!isMiddlewareTier(requestedTier)) {
|
|
474
616
|
throw new Error(
|
|
@@ -513,8 +655,177 @@ export function createCodemods(options?: { force?: boolean; cwd?: string }): Cod
|
|
|
513
655
|
|
|
514
656
|
const eol = detectLineEnding(content)
|
|
515
657
|
const entry = ` () => import('${importPath}'),`
|
|
516
|
-
content =
|
|
658
|
+
content =
|
|
659
|
+
position === 'before'
|
|
660
|
+
? `${content.slice(0, targetBlock.start)}${eol}${entry}${content.slice(targetBlock.start)}`
|
|
661
|
+
: appendToArray(content, targetBlock, `${eol}${entry}`)
|
|
517
662
|
fs.writeFileSync(kernelPath, content)
|
|
518
663
|
},
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Add validation rules to the schema `start/env.ts` passes to
|
|
667
|
+
* `Env.create`, so the variables a package writes to `.env` are checked
|
|
668
|
+
* at boot like the app's own.
|
|
669
|
+
*
|
|
670
|
+
* A rule already in the file is left alone, unless `overwrite` is set:
|
|
671
|
+
* the user may have tightened it. Returns the variables kept that way
|
|
672
|
+
* with a rule different from the one asked for, so the caller can say
|
|
673
|
+
* so. The banner comment is written only when the first new rule comes
|
|
674
|
+
* before any variable the file already had.
|
|
675
|
+
*/
|
|
676
|
+
async defineEnvValidations(definition: EnvValidationNode): Promise<string[]> {
|
|
677
|
+
const envPath = path.join(root, 'start', 'env.ts')
|
|
678
|
+
if (!fs.existsSync(envPath)) {
|
|
679
|
+
throw new Error(
|
|
680
|
+
`[configure] start/env.ts not found — cannot add the validations for ${Object.keys(definition.variables).join(', ')}.`,
|
|
681
|
+
)
|
|
682
|
+
}
|
|
683
|
+
assertCanonicallyInside(root, envPath, 'start/env.ts')
|
|
684
|
+
assertEnvValidations(definition)
|
|
685
|
+
|
|
686
|
+
const original = fs.readFileSync(envPath, 'utf8')
|
|
687
|
+
const eol = detectLineEnding(original)
|
|
688
|
+
let content = original
|
|
689
|
+
const schema = locateEnvSchema(content)
|
|
690
|
+
const existing = new Map(
|
|
691
|
+
properties(content, schema.open, schema.close).map((property) => [property.key, property]),
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
const kept: string[] = []
|
|
695
|
+
const replacements: Array<{ start: number; end: number; text: string }> = []
|
|
696
|
+
const additions: Array<[string, string]> = []
|
|
697
|
+
let shouldAddComment = true
|
|
698
|
+
let decorate = false
|
|
699
|
+
for (const [name, rule] of Object.entries(definition.variables)) {
|
|
700
|
+
const property = existing.get(name)
|
|
701
|
+
if (property === undefined) {
|
|
702
|
+
if (additions.length === 0) decorate = shouldAddComment
|
|
703
|
+
shouldAddComment = false
|
|
704
|
+
additions.push([name, rule])
|
|
705
|
+
continue
|
|
706
|
+
}
|
|
707
|
+
shouldAddComment = false
|
|
708
|
+
const current = content.slice(property.valueStart, property.valueEnd)
|
|
709
|
+
if (definition.overwrite) {
|
|
710
|
+
replacements.push({ start: property.valueStart, end: property.valueEnd, text: rule })
|
|
711
|
+
} else if (current.replace(/\s+/g, '') !== rule.replace(/\s+/g, '')) {
|
|
712
|
+
kept.push(name)
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
for (const { start, end, text } of replacements.sort((a, b) => b.start - a.start)) {
|
|
717
|
+
content = `${content.slice(0, start)}${text}${content.slice(end)}`
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
if (additions.length > 0) {
|
|
721
|
+
const { open, close } = locateEnvSchema(content)
|
|
722
|
+
const comment = definition.leadingComment
|
|
723
|
+
content = appendToLiteral(
|
|
724
|
+
content,
|
|
725
|
+
open,
|
|
726
|
+
close,
|
|
727
|
+
eol,
|
|
728
|
+
(indent) => [
|
|
729
|
+
...(decorate && comment !== undefined
|
|
730
|
+
? [
|
|
731
|
+
`${indent}/*`,
|
|
732
|
+
`${indent}${BANNER_RULE}`,
|
|
733
|
+
`${indent}| ${comment}`,
|
|
734
|
+
`${indent}${BANNER_RULE}`,
|
|
735
|
+
`${indent}*/`,
|
|
736
|
+
]
|
|
737
|
+
: []),
|
|
738
|
+
...additions.map(([name, rule]) => `${indent}${name}: ${rule},`),
|
|
739
|
+
],
|
|
740
|
+
decorate,
|
|
741
|
+
)
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
if (content !== original) fs.writeFileSync(envPath, content)
|
|
745
|
+
return kept
|
|
746
|
+
},
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Register a preload file in `reamrc.ts`, appended to `preloads` (the
|
|
750
|
+
* array is created when absent). Listing only some environments writes
|
|
751
|
+
* a `{ file, environment }` entry; none, or all of them, a plain lazy
|
|
752
|
+
* import. A module already in `preloads` is left as it is.
|
|
753
|
+
*/
|
|
754
|
+
async addPreloadFile(modulePath: string, environments?: PreloadEnvironment[]): Promise<void> {
|
|
755
|
+
if (!SAFE_MODULE_PATH.test(modulePath)) {
|
|
756
|
+
throw new Error(`[configure] Unsafe preload module path: ${JSON.stringify(modulePath)}`)
|
|
757
|
+
}
|
|
758
|
+
for (const environment of environments ?? []) {
|
|
759
|
+
if (!PRELOAD_ENVIRONMENTS.includes(environment)) {
|
|
760
|
+
throw new Error(
|
|
761
|
+
`[configure] Unknown environment '${String(environment)}' for preload ${modulePath}. Expected one of ${PRELOAD_ENVIRONMENTS.join(', ')}.`,
|
|
762
|
+
)
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const rcPath = path.join(root, 'reamrc.ts')
|
|
767
|
+
if (!fs.existsSync(rcPath)) {
|
|
768
|
+
throw new Error(
|
|
769
|
+
`[configure] reamrc.ts not found — cannot register preload ${modulePath}. Run 'ream new' first.`,
|
|
770
|
+
)
|
|
771
|
+
}
|
|
772
|
+
assertCanonicallyInside(root, rcPath, 'reamrc.ts')
|
|
773
|
+
|
|
774
|
+
const content = fs.readFileSync(rcPath, 'utf8')
|
|
775
|
+
const eol = detectLineEnding(content)
|
|
776
|
+
const config = locateRcObject(content)
|
|
777
|
+
if (config === null) {
|
|
778
|
+
throw new Error(
|
|
779
|
+
`[configure] Could not find 'defineConfig({ ... })' in reamrc.ts — preload ${modulePath} not added.`,
|
|
780
|
+
)
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Scoped only when it actually leaves an environment out.
|
|
784
|
+
const scope = PRELOAD_ENVIRONMENTS.some(
|
|
785
|
+
(environment) => environments !== undefined && !environments.includes(environment),
|
|
786
|
+
)
|
|
787
|
+
? environments
|
|
788
|
+
: undefined
|
|
789
|
+
const entry = (indent: string): string[] =>
|
|
790
|
+
scope
|
|
791
|
+
? [
|
|
792
|
+
`${indent}{`,
|
|
793
|
+
`${indent} file: () => import('${modulePath}'),`,
|
|
794
|
+
`${indent} environment: [${scope.map((e) => `'${e}'`).join(', ')}],`,
|
|
795
|
+
`${indent}},`,
|
|
796
|
+
]
|
|
797
|
+
: [`${indent}() => import('${modulePath}'),`]
|
|
798
|
+
|
|
799
|
+
const preloads = properties(content, config.open, config.close).find(
|
|
800
|
+
(property) => property.key === 'preloads',
|
|
801
|
+
)
|
|
802
|
+
if (preloads === undefined) {
|
|
803
|
+
fs.writeFileSync(
|
|
804
|
+
rcPath,
|
|
805
|
+
appendToLiteral(content, config.open, config.close, eol, (indent) => [
|
|
806
|
+
`${indent}preloads: [`,
|
|
807
|
+
...entry(`${indent} `),
|
|
808
|
+
`${indent}],`,
|
|
809
|
+
]),
|
|
810
|
+
)
|
|
811
|
+
return
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
const arrayClose =
|
|
815
|
+
content[preloads.valueStart] === '[' ? matchClose(content, preloads.valueStart) : -1
|
|
816
|
+
if (arrayClose === -1) {
|
|
817
|
+
throw new Error(
|
|
818
|
+
`[configure] reamrc.ts declares preloads as something other than an array literal — add ${modulePath} by hand.`,
|
|
819
|
+
)
|
|
820
|
+
}
|
|
821
|
+
const registered = segments(content, preloads.valueStart + 1, arrayClose).some(
|
|
822
|
+
(element) => importedModule(content.slice(element.codeStart, element.end)) === modulePath,
|
|
823
|
+
)
|
|
824
|
+
if (registered) return
|
|
825
|
+
fs.writeFileSync(
|
|
826
|
+
rcPath,
|
|
827
|
+
appendToLiteral(content, preloads.valueStart, arrayClose, eol, entry),
|
|
828
|
+
)
|
|
829
|
+
},
|
|
519
830
|
}
|
|
520
831
|
}
|
package/src/HttpKernel.ts
CHANGED
|
@@ -200,7 +200,7 @@ export function createHttpKernel(
|
|
|
200
200
|
// read decorator metadata via Reflect. Absent for inline-arrow
|
|
201
201
|
// route handlers — that's intentional, decorators only apply
|
|
202
202
|
// to controller methods.
|
|
203
|
-
controller: match.route.controller?.target
|
|
203
|
+
controller: controllerPrototype(match.route.controller?.target),
|
|
204
204
|
action: match.route.controller?.method,
|
|
205
205
|
}
|
|
206
206
|
: { pattern: '', middleware: [] }
|
|
@@ -212,6 +212,7 @@ export function createHttpKernel(
|
|
|
212
212
|
// value bound for this request cannot be seen by any other.
|
|
213
213
|
const resolver = config.container?.createResolver()
|
|
214
214
|
const ctx = new HttpContext(correlationId, reqData, match?.params ?? {}, routeInfo, resolver)
|
|
215
|
+
ctx.subdomains = match?.subdomains ?? {}
|
|
215
216
|
// What Adonis binds on every request's resolver: the context itself, so a
|
|
216
217
|
// controller or service can take `HttpContext` as a constructor dependency.
|
|
217
218
|
resolver?.bindValue(HttpContext, ctx)
|
|
@@ -453,18 +454,25 @@ function createControllerHandler(
|
|
|
453
454
|
// `HttpContext` as a dependency must get this request's, not a stale one.
|
|
454
455
|
const resolve = ctx.containerResolver ?? container
|
|
455
456
|
const instance = resolve ? await resolve.make(controller.target) : new controller.target()
|
|
456
|
-
const method
|
|
457
|
-
|
|
458
|
-
|
|
457
|
+
const method: unknown =
|
|
458
|
+
typeof instance === 'object' && instance !== null
|
|
459
|
+
? Reflect.get(instance, controller.method)
|
|
460
|
+
: undefined
|
|
459
461
|
if (typeof method !== 'function') {
|
|
460
462
|
throw new Error(
|
|
461
463
|
`Controller method '${controller.method}' not found on ${controller.target.name}`,
|
|
462
464
|
)
|
|
463
465
|
}
|
|
464
|
-
await
|
|
466
|
+
await Reflect.apply(method, instance, [ctx])
|
|
465
467
|
}
|
|
466
468
|
}
|
|
467
469
|
|
|
470
|
+
/** A controller class's prototype, where its decorators keep their metadata. */
|
|
471
|
+
function controllerPrototype(target: AnyConstructor | undefined): object | undefined {
|
|
472
|
+
const prototype: unknown = target?.prototype
|
|
473
|
+
return typeof prototype === 'object' && prototype !== null ? prototype : undefined
|
|
474
|
+
}
|
|
475
|
+
|
|
468
476
|
/**
|
|
469
477
|
* Read @Guard, @Role, @Permission metadata from a controller method.
|
|
470
478
|
* Returns empty arrays if no decorators are present.
|
|
@@ -554,8 +562,10 @@ function reconcileRepresentation(
|
|
|
554
562
|
/**
|
|
555
563
|
* Append the development script to an HTML body.
|
|
556
564
|
*
|
|
557
|
-
* Only HTML, and never a stream
|
|
558
|
-
*
|
|
565
|
+
* Only HTML, and never a stream or a base64-encoded body (`sendBuffer`, a
|
|
566
|
+
* buffered download): appending to any of them corrupts it — Rust fails to
|
|
567
|
+
* decode the base64 and the client receives the encoded text — and a page is
|
|
568
|
+
* the only thing that can act on the script anyway.
|
|
559
569
|
* Before `</body>` when there is one, so the script is inside the document
|
|
560
570
|
* rather than trailing after it.
|
|
561
571
|
*/
|
|
@@ -567,6 +577,7 @@ function withDevScript(
|
|
|
567
577
|
): string {
|
|
568
578
|
if (script === undefined || streamId !== undefined || body === '') return body
|
|
569
579
|
if (!(headers['content-type'] ?? '').includes('text/html')) return body
|
|
580
|
+
if (headers['x-ream-body-encoding'] === 'base64') return body
|
|
570
581
|
const closing = body.lastIndexOf('</body>')
|
|
571
582
|
return closing === -1 ? body + script : body.slice(0, closing) + script + body.slice(closing)
|
|
572
583
|
}
|
package/src/Ignitor.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { Application } from './Application.js'
|
|
17
|
+
import type { BodyParserConfig } from './bodyparser/BodyParserMiddleware.js'
|
|
17
18
|
import type { Console } from './console/Console.js'
|
|
18
19
|
import type { CommandLoader, Kernel as ConsoleKernelInstance } from './console/Kernel.js'
|
|
19
20
|
import { type CommandClass, isCommandClass } from './console/types.js'
|
|
@@ -51,13 +52,20 @@ import {
|
|
|
51
52
|
import { Router } from './router/Router.js'
|
|
52
53
|
import { CookieSigner } from './security/CookieSigner.js'
|
|
53
54
|
import { SignedUrl } from './security/SignedUrl.js'
|
|
54
|
-
import { type
|
|
55
|
+
import { cancellableGrpc, type NativeGrpcHandler } from './server/nativeGrpc.js'
|
|
56
|
+
import {
|
|
57
|
+
type NativeBodyLimits,
|
|
58
|
+
type NativeConnectionConfig,
|
|
59
|
+
nativeBodyLimits,
|
|
60
|
+
nativeConnectionConfig,
|
|
61
|
+
} from './server/nativeLimits.js'
|
|
62
|
+
import { type GrpcLimits, Server } from './server/Server.js'
|
|
55
63
|
import { clearApp, setApp } from './services/app.js'
|
|
56
64
|
import { clearEncryption, setEncryption } from './services/encryption.js'
|
|
57
65
|
import { clearLogger, setLogger } from './services/logger.js'
|
|
58
66
|
import { clearRouter, setRouter } from './services/router.js'
|
|
59
67
|
import { clearServer, setServer } from './services/server.js'
|
|
60
|
-
import {
|
|
68
|
+
import { installSessionTemplateTags } from './session/templateTags.js'
|
|
61
69
|
|
|
62
70
|
/** Application environment. */
|
|
63
71
|
/**
|
|
@@ -269,7 +277,9 @@ export function defineConfig(config: ReamrcConfig): ReamrcConfig {
|
|
|
269
277
|
export interface HyperServerLike {
|
|
270
278
|
onRequest(callback: (request: HttpKernelRequest) => Promise<HttpKernelResponse>): void
|
|
271
279
|
/** Optional — present on the real `HyperServer`; required once `server.grpc()` is used. */
|
|
272
|
-
onGrpc?(callback:
|
|
280
|
+
onGrpc?(callback: NativeGrpcHandler, limits?: GrpcLimits): void
|
|
281
|
+
/** Optional — reports the calls a client gave up on; without it no call's signal aborts. */
|
|
282
|
+
onGrpcCancel?(callback: (id: number) => void): void
|
|
273
283
|
/**
|
|
274
284
|
* Optional — present on the real `HyperServer` (Rust-backed), absent on
|
|
275
285
|
* trivial test mocks. Ignitor only calls it when a shield config is set.
|
|
@@ -279,6 +289,10 @@ export interface HyperServerLike {
|
|
|
279
289
|
configureTrustedProxies?(cidrs: string[]): void
|
|
280
290
|
/** Optional — same lifecycle as `configureShield`. */
|
|
281
291
|
configureRateLimit?(config: { max: number; windowSecs: number } | null): void
|
|
292
|
+
/** Optional — same lifecycle as `configureShield`. */
|
|
293
|
+
configureBodyLimits?(config: NativeBodyLimits): void
|
|
294
|
+
/** Optional — same lifecycle as `configureShield`. */
|
|
295
|
+
configureConnections?(config: NativeConnectionConfig): void
|
|
282
296
|
listen(): Promise<void>
|
|
283
297
|
port(): Promise<number>
|
|
284
298
|
close(): Promise<void>
|
|
@@ -287,6 +301,11 @@ export interface HyperServerLike {
|
|
|
287
301
|
// a clean `STREAMING_UNSUPPORTED` error when called on such a host.
|
|
288
302
|
registerStream?(streamId: string): Promise<boolean>
|
|
289
303
|
writeStream?(streamId: string, chunk: string): Promise<boolean>
|
|
304
|
+
/**
|
|
305
|
+
* Byte-exact writes. Without it a download, `response.stream()` or a static
|
|
306
|
+
* file is buffered whole and shipped base64-encoded in one response.
|
|
307
|
+
*/
|
|
308
|
+
writeStreamBytes?(streamId: string, chunk: Uint8Array): Promise<boolean>
|
|
290
309
|
closeStream?(streamId: string): Promise<boolean>
|
|
291
310
|
onStreamDisconnect?(streamId: string, callback: () => void): void
|
|
292
311
|
}
|
|
@@ -684,26 +703,12 @@ export class Ignitor {
|
|
|
684
703
|
|
|
685
704
|
/**
|
|
686
705
|
* Give the template engine `@error` / `@errors` / `@inputError` /
|
|
687
|
-
* `@flashMessage`, as AdonisJS's session plugin does
|
|
688
|
-
*
|
|
689
|
-
*
|
|
690
|
-
* on it, and an app with no template layer simply skips this.
|
|
706
|
+
* `@flashMessage`, as AdonisJS's session plugin does — through the engine
|
|
707
|
+
* package's module singleton, guarded by `usingInker` (see
|
|
708
|
+
* `installSessionTemplateTags`). An app with no template layer skips this.
|
|
691
709
|
*/
|
|
692
710
|
async #registerSessionTemplateTags(): Promise<void> {
|
|
693
|
-
|
|
694
|
-
if (!this.#app.container.has(token)) continue
|
|
695
|
-
const binding: unknown = await this.#app.container.resolve(token)
|
|
696
|
-
for (const candidate of [binding, Reflect.get(Object(binding), '_templates')]) {
|
|
697
|
-
const register = Reflect.get(Object(candidate), 'registerTag')
|
|
698
|
-
if (typeof register !== 'function') continue
|
|
699
|
-
registerSessionTemplateTags({
|
|
700
|
-
registerTag: (tag) => {
|
|
701
|
-
register.call(candidate, tag)
|
|
702
|
-
},
|
|
703
|
-
})
|
|
704
|
-
return
|
|
705
|
-
}
|
|
706
|
-
}
|
|
711
|
+
await installSessionTemplateTags(this.#app.usingInker === true)
|
|
707
712
|
}
|
|
708
713
|
|
|
709
714
|
async #phaseRegister(): Promise<void> {
|
|
@@ -874,6 +879,12 @@ export class Ignitor {
|
|
|
874
879
|
return {
|
|
875
880
|
registerStream: server.registerStream.bind(server),
|
|
876
881
|
writeStream: server.writeStream.bind(server),
|
|
882
|
+
// The byte channel is what lets a download be streamed rather
|
|
883
|
+
// than read whole into memory; a host without it still gets SSE.
|
|
884
|
+
writeStreamBytes:
|
|
885
|
+
typeof server.writeStreamBytes === 'function'
|
|
886
|
+
? server.writeStreamBytes.bind(server)
|
|
887
|
+
: undefined,
|
|
877
888
|
closeStream: server.closeStream.bind(server),
|
|
878
889
|
onStreamDisconnect: server.onStreamDisconnect.bind(server),
|
|
879
890
|
}
|
|
@@ -914,7 +925,9 @@ export class Ignitor {
|
|
|
914
925
|
{ hint: 'Use the native HyperServer, or a test server that implements onGrpc().' },
|
|
915
926
|
)
|
|
916
927
|
}
|
|
917
|
-
|
|
928
|
+
const calls = cancellableGrpc(grpc)
|
|
929
|
+
this.#_httpServer.onGrpcCancel?.(calls.onCancel)
|
|
930
|
+
this.#_httpServer.onGrpc(calls.onCall, this.#server.getGrpcLimits())
|
|
918
931
|
}
|
|
919
932
|
// Pre-resolve client IPs in Rust from the trusted-proxy CIDRs before
|
|
920
933
|
// listen. Security filtering itself lives in @c9up/blackhole.
|
|
@@ -925,6 +938,19 @@ export class Ignitor {
|
|
|
925
938
|
) {
|
|
926
939
|
this.#_httpServer.configureTrustedProxies([...trustedProxies])
|
|
927
940
|
}
|
|
941
|
+
// Body limits from `config/bodyparser.ts`, enforced while the native
|
|
942
|
+
// server reads a body: nothing past them is ever buffered.
|
|
943
|
+
const bodyparser = this.#app.config.get<BodyParserConfig>('bodyparser')
|
|
944
|
+
if (bodyparser && typeof this.#_httpServer.configureBodyLimits === 'function') {
|
|
945
|
+
this.#_httpServer.configureBodyLimits(nativeBodyLimits(bodyparser))
|
|
946
|
+
}
|
|
947
|
+
// AdonisJS `config/app.ts` → `http: { headersTimeout, requestTimeout,
|
|
948
|
+
// keepAliveTimeout }`, plus `maxConnections`.
|
|
949
|
+
if (typeof this.#_httpServer.configureConnections === 'function') {
|
|
950
|
+
this.#_httpServer.configureConnections(
|
|
951
|
+
nativeConnectionConfig(this.#app.config.get<unknown>('app.http')),
|
|
952
|
+
)
|
|
953
|
+
}
|
|
928
954
|
await this.#_httpServer.listen()
|
|
929
955
|
|
|
930
956
|
// Whoever opened the socket closes it. `app.terminate()` runs the
|
|
@@ -1006,7 +1032,7 @@ export class Ignitor {
|
|
|
1006
1032
|
'File change detected — a process restart is required to apply it (`ream dev` restarts automatically).',
|
|
1007
1033
|
severity: 'info',
|
|
1008
1034
|
timestamp: new Date().toISOString(),
|
|
1009
|
-
}
|
|
1035
|
+
})
|
|
1010
1036
|
},
|
|
1011
1037
|
logger: {
|
|
1012
1038
|
info: (msg) =>
|
|
@@ -1016,7 +1042,7 @@ export class Ignitor {
|
|
|
1016
1042
|
message: msg,
|
|
1017
1043
|
severity: 'info',
|
|
1018
1044
|
timestamp: new Date().toISOString(),
|
|
1019
|
-
}
|
|
1045
|
+
}),
|
|
1020
1046
|
},
|
|
1021
1047
|
})
|
|
1022
1048
|
}
|
|
@@ -1399,7 +1425,13 @@ export class Ignitor {
|
|
|
1399
1425
|
const events = this.#app.container.has('events')
|
|
1400
1426
|
? await this.#app.container.resolve<Emitter>('events')
|
|
1401
1427
|
: { on: () => undefined }
|
|
1402
|
-
|
|
1428
|
+
// Imported here, at start, rather than at the top: the barrel imports this
|
|
1429
|
+
// module, and its `VERSION` is what the release bump rewrites.
|
|
1430
|
+
const { VERSION } = await import('./index.js')
|
|
1431
|
+
this.#profiler = createProfiler(events, [], {
|
|
1432
|
+
version: VERSION,
|
|
1433
|
+
environment: process.env.REAM_ENV ?? process.env.NODE_ENV ?? 'development',
|
|
1434
|
+
})
|
|
1403
1435
|
}
|
|
1404
1436
|
|
|
1405
1437
|
#profiler?: Profiler
|
|
@@ -1453,7 +1485,7 @@ export class Ignitor {
|
|
|
1453
1485
|
message,
|
|
1454
1486
|
severity: kind === 'error' ? 'critical' : 'info',
|
|
1455
1487
|
timestamp: new Date().toISOString(),
|
|
1456
|
-
}
|
|
1488
|
+
})
|
|
1457
1489
|
}
|
|
1458
1490
|
}
|
|
1459
1491
|
|