@warlock.js/core 4.15.0 → 5.0.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.
- package/CHANGELOG.md +43 -2
- package/bin/warlock.js +154 -1
- package/esm/application/application.d.mts +65 -1
- package/esm/application/application.d.mts.map +1 -1
- package/esm/application/application.mjs +62 -0
- package/esm/application/application.mjs.map +1 -1
- package/esm/application/index.d.mts +1 -1
- package/esm/cli/cli-commands.manager.mjs +60 -10
- package/esm/cli/cli-commands.manager.mjs.map +1 -1
- package/esm/cli/commands/dev-server.command.mjs +1 -0
- package/esm/cli/commands/dev-server.command.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/handler-signature.check.mjs +40 -0
- package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/index.mjs +4 -2
- package/esm/cli/commands/doctor/checks/index.mjs.map +1 -1
- package/esm/commands/cli-command.d.mts +1 -1
- package/esm/commands/cli-command.d.mts.map +1 -1
- package/esm/commands/cli-command.mjs.map +1 -1
- package/esm/commands/types.d.mts +10 -2
- package/esm/commands/types.d.mts.map +1 -1
- package/esm/config/config-handlers.d.mts +1 -2
- package/esm/config/config-handlers.d.mts.map +1 -1
- package/esm/config/config-handlers.mjs +3 -2
- package/esm/config/config-handlers.mjs.map +1 -1
- package/esm/config/locale-configuration.mjs +29 -0
- package/esm/config/locale-configuration.mjs.map +1 -0
- package/esm/connectors/assert-no-reserved-connector-names.d.mts +7 -0
- package/esm/connectors/assert-no-reserved-connector-names.d.mts.map +1 -0
- package/esm/connectors/assert-no-reserved-connector-names.mjs +44 -0
- package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -0
- package/esm/connectors/assert-unique-connector-names.d.mts +7 -0
- package/esm/connectors/assert-unique-connector-names.d.mts.map +1 -0
- package/esm/connectors/assert-unique-connector-names.mjs +20 -0
- package/esm/connectors/assert-unique-connector-names.mjs.map +1 -0
- package/esm/connectors/connectors-manager.d.mts +38 -0
- package/esm/connectors/connectors-manager.d.mts.map +1 -1
- package/esm/connectors/connectors-manager.mjs +45 -12
- package/esm/connectors/connectors-manager.mjs.map +1 -1
- package/esm/connectors/describe-server-address.mjs +75 -0
- package/esm/connectors/describe-server-address.mjs.map +1 -0
- package/esm/connectors/http-connector.d.mts.map +1 -1
- package/esm/connectors/http-connector.mjs +6 -3
- package/esm/connectors/http-connector.mjs.map +1 -1
- package/esm/connectors/index.d.mts +4 -1
- package/esm/connectors/index.mjs +4 -1
- package/esm/connectors/register-configured-connectors.d.mts +14 -0
- package/esm/connectors/register-configured-connectors.d.mts.map +1 -0
- package/esm/connectors/register-configured-connectors.mjs +99 -0
- package/esm/connectors/register-configured-connectors.mjs.map +1 -0
- package/esm/connectors/socket-connector.d.mts.map +1 -1
- package/esm/connectors/socket-connector.mjs +4 -1
- package/esm/connectors/socket-connector.mjs.map +1 -1
- package/esm/connectors/types.d.mts +76 -1
- package/esm/connectors/types.d.mts.map +1 -1
- package/esm/connectors/types.mjs.map +1 -1
- package/esm/database/models/database-log/database-log.d.mts +50 -2
- package/esm/database/models/database-log/database-log.d.mts.map +1 -1
- package/esm/database/utils.d.mts +2 -2
- package/esm/database/utils.d.mts.map +1 -1
- package/esm/dev-server/development-server.mjs +1 -0
- package/esm/dev-server/development-server.mjs.map +1 -1
- package/esm/dev-server/layer-executor.mjs +2 -1
- package/esm/dev-server/layer-executor.mjs.map +1 -1
- package/esm/dev-server/read-config-ast.mjs +48 -0
- package/esm/dev-server/read-config-ast.mjs.map +1 -0
- package/esm/dev-server/run-typings-generation.mjs +18 -0
- package/esm/dev-server/run-typings-generation.mjs.map +1 -0
- package/esm/dev-server/type-generator.mjs +30 -39
- package/esm/dev-server/type-generator.mjs.map +1 -1
- package/esm/generations/add-command.action.mjs +169 -1
- package/esm/generations/add-command.action.mjs.map +1 -1
- package/esm/generations/stubs.mjs +93 -1
- package/esm/generations/stubs.mjs.map +1 -1
- package/esm/http/context/request-context.d.mts +14 -3
- package/esm/http/context/request-context.d.mts.map +1 -1
- package/esm/http/context/request-context.mjs +11 -1
- package/esm/http/context/request-context.mjs.map +1 -1
- package/esm/http/context/request-memo.d.mts +21 -0
- package/esm/http/context/request-memo.d.mts.map +1 -0
- package/esm/http/context/request-memo.mjs +48 -0
- package/esm/http/context/request-memo.mjs.map +1 -0
- package/esm/http/database/RequestLog.d.mts +164 -2
- package/esm/http/database/RequestLog.d.mts.map +1 -1
- package/esm/http/index.d.mts +6 -5
- package/esm/http/index.mjs +2 -1
- package/esm/http/middleware/cache-response-middleware.d.mts +2 -2
- package/esm/http/middleware/cache-response-middleware.d.mts.map +1 -1
- package/esm/http/middleware/cache-response-middleware.mjs +1 -1
- package/esm/http/middleware/cache-response-middleware.mjs.map +1 -1
- package/esm/http/middleware/concurrency-limit.middleware.mjs +1 -1
- package/esm/http/middleware/concurrency-limit.middleware.mjs.map +1 -1
- package/esm/http/middleware/idempotency.middleware.mjs +1 -1
- package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
- package/esm/http/middleware/index.d.mts +1 -1
- package/esm/http/middleware/index.mjs +1 -1
- package/esm/http/middleware/inject-request-context.d.mts +1 -8
- package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +9 -22
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/middleware/ip-filter.middleware.d.mts +6 -3
- package/esm/http/middleware/ip-filter.middleware.d.mts.map +1 -1
- package/esm/http/middleware/ip-filter.middleware.mjs +7 -4
- package/esm/http/middleware/ip-filter.middleware.mjs.map +1 -1
- package/esm/http/middleware/maintenance.middleware.mjs +1 -1
- package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
- package/esm/http/middleware/max-body-size.middleware.mjs +1 -1
- package/esm/http/middleware/max-body-size.middleware.mjs.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.mjs +1 -1
- package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
- package/esm/http/middleware/utils/idempotency-key.d.mts +0 -14
- package/esm/http/middleware/utils/idempotency-key.d.mts.map +1 -1
- package/esm/http/middleware/utils/idempotency-key.mjs +19 -1
- package/esm/http/middleware/utils/idempotency-key.mjs.map +1 -1
- package/esm/http/request.d.mts +149 -44
- package/esm/http/request.d.mts.map +1 -1
- package/esm/http/request.mjs +132 -43
- package/esm/http/request.mjs.map +1 -1
- package/esm/http/response.mjs +1 -1
- package/esm/http/response.mjs.map +1 -1
- package/esm/http/server.d.mts.map +1 -1
- package/esm/http/server.mjs.map +1 -1
- package/esm/http/types.d.mts +58 -1
- package/esm/http/types.d.mts.map +1 -1
- package/esm/http/uploaded-file.d.mts +51 -19
- package/esm/http/uploaded-file.d.mts.map +1 -1
- package/esm/http/uploaded-file.mjs +36 -8
- package/esm/http/uploaded-file.mjs.map +1 -1
- package/esm/index.d.mts +17 -9
- package/esm/index.mjs +10 -4
- package/esm/production/build-contributions.mjs +115 -0
- package/esm/production/build-contributions.mjs.map +1 -0
- package/esm/production/production-builder.mjs +97 -2
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/resolve-build-config.d.mts +25 -0
- package/esm/production/resolve-build-config.d.mts.map +1 -0
- package/esm/production/resolve-build-config.mjs +43 -1
- package/esm/production/resolve-build-config.mjs.map +1 -1
- package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +1 -1
- package/esm/repositories/adapters/cascade/filter-applicator.mjs +20 -9
- package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
- package/esm/restful/restful.d.mts +29 -8
- package/esm/restful/restful.d.mts.map +1 -1
- package/esm/restful/restful.mjs +31 -13
- package/esm/restful/restful.mjs.map +1 -1
- package/esm/router/describe-route-for-log.mjs +29 -0
- package/esm/router/describe-route-for-log.mjs.map +1 -0
- package/esm/router/index.d.mts +3 -1
- package/esm/router/index.mjs +2 -0
- package/esm/router/log-request-lifecycle.mjs +38 -0
- package/esm/router/log-request-lifecycle.mjs.map +1 -0
- package/esm/router/positional-handler-diagnostics.d.mts +90 -0
- package/esm/router/positional-handler-diagnostics.d.mts.map +1 -0
- package/esm/router/positional-handler-diagnostics.mjs +247 -0
- package/esm/router/positional-handler-diagnostics.mjs.map +1 -0
- package/esm/router/route-registry.d.mts +34 -0
- package/esm/router/route-registry.d.mts.map +1 -0
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +87 -63
- package/esm/router/router.mjs.map +1 -1
- package/esm/router/types.d.mts +23 -5
- package/esm/router/types.d.mts.map +1 -1
- package/esm/storage/storage.d.mts.map +1 -1
- package/esm/storage/storage.mjs +1 -1
- package/esm/storage/storage.mjs.map +1 -1
- package/esm/storage/utils/safe-fetch.d.mts +11 -1
- package/esm/storage/utils/safe-fetch.d.mts.map +1 -1
- package/esm/storage/utils/safe-fetch.mjs +51 -4
- package/esm/storage/utils/safe-fetch.mjs.map +1 -1
- package/esm/tests/vitest-setup.mjs +1 -1
- package/esm/utils/load-environment.mjs +33 -2
- package/esm/utils/load-environment.mjs.map +1 -1
- package/esm/utils/types.d.mts +4 -0
- package/esm/utils/types.d.mts.map +1 -1
- package/esm/validation/validateAll.mjs +4 -1
- package/esm/validation/validateAll.mjs.map +1 -1
- package/esm/validation/validators/file-validator.d.mts +25 -1
- package/esm/validation/validators/file-validator.d.mts.map +1 -1
- package/esm/warlock-config/index.mjs +1 -1
- package/esm/warlock-config/normalize-build-config.mjs.map +1 -1
- package/esm/warlock-config/types.d.mts +36 -2
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/llms-full.txt +179 -23
- package/llms.txt +1 -1
- package/package.json +23 -20
- package/skills/request-memo/SKILL.md +142 -0
- package/skills/use-middleware/SKILL.md +12 -1
- package/skills/use-request-locals/SKILL.md +144 -0
|
@@ -115,7 +115,18 @@ export default {
|
|
|
115
115
|
|
|
116
116
|
`deny` wins over `allow`. If the IP can't be read (empty / unparseable), the request is rejected with 403. Reads via `request.detectIp()`.
|
|
117
117
|
|
|
118
|
-
⚠ **Since 4.13.0 `http.trustProxy` defaults to `false`**, so `request.detectIp()` returns the socket address and **`X-Real-IP` / `X-Forwarded-For` are ignored unless you opt in.**
|
|
118
|
+
⚠ **Since 4.13.0 `http.trustProxy` defaults to `false`**, so `request.detectIp()` returns the socket address and **`X-Real-IP` / `X-Forwarded-For` are ignored unless you opt in.** Before 4.13.0 the default was `true`, which meant any client could set its own forwarding header and be believed.
|
|
119
|
+
|
|
120
|
+
⚠ **Opt in with the narrowest shape your topology allows, not with `true`.** Since 4.15.0 `http.trustProxy` takes a hop count or a trusted-proxy list, and `detectIp()` resolves the chain the same way Fastify's `request.ip` does:
|
|
121
|
+
|
|
122
|
+
| `http.trustProxy` | Client IP |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| `false` *(default)* | Socket peer address |
|
|
125
|
+
| `2` | Walks past the 2 rightmost `X-Forwarded-For` hops — for an edge that **appends** (the usual case: nginx, ALB, most CDNs) |
|
|
126
|
+
| `"10.0.0.0/8"` / `["10.0.0.0/8", "192.168.0.0/16"]` | Walks left while each hop is a listed proxy |
|
|
127
|
+
| `true` | Trusts the whole chain — the leftmost hop, i.e. **whatever the client put there** if your edge appends rather than overwrites |
|
|
128
|
+
|
|
129
|
+
With `true`, any client that can reach the process directly picks its own IP and this allowlist is decorative. `X-Real-IP` is honoured only under `true` — it carries no chain to check a hop count or proxy list against — so if your edge sets only that header, have it set `X-Forwarded-For` too.
|
|
119
130
|
|
|
120
131
|
```ts
|
|
121
132
|
import { middleware } from "@warlock.js/core";
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: use-request-locals
|
|
3
|
+
description: 'Carry typed, server-only data through one HTTP request with `request.locals`, usually written by middleware and read by downstream middleware or controllers. Augment `RequestLocals` in the module that owns each key; v5 no longer permits arbitrary `request.foo` properties. Triggers: `request.locals`, `RequestLocals`, `request.post`, `request.organization`, `Property does not exist on type Request`, `Request index signature`; "attach data to a request", "share middleware data with a controller", "type request locals", "migrate dynamic request properties"; typical type augmentation `declare module "@warlock.js/core" { interface RequestLocals { ... } }`. Skip: computed-on-demand single-flight values and removed `fromRequest` — `@warlock.js/core/request-memo/SKILL.md`; middleware mechanics — `@warlock.js/core/write-middleware/SKILL.md`; authenticated user typing — augment `RequestUser`, not `RequestLocals`; competing patterns: `(request as any).foo`, `request.set()`, module-global mutable state.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Warlock — use typed request locals
|
|
7
|
+
|
|
8
|
+
`request.locals` is the v5 home for private data that middleware writes and downstream code reads during the same request. It is separate from client input and starts as a fresh object on every `Request` instance.
|
|
9
|
+
|
|
10
|
+
## The exact declarations
|
|
11
|
+
|
|
12
|
+
From `core/src/http/types.ts`:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
export interface RequestLocals {}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
From `core/src/http/request.ts`:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
public locals: RequestLocals = {};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`RequestLocals` is intentionally empty and augmentable. It has no index signature: declare owned keys explicitly so reads and writes have their real types instead of `any`.
|
|
25
|
+
|
|
26
|
+
## Migrate a middleware attachment from v4 to v5
|
|
27
|
+
|
|
28
|
+
### Before — v4 dynamic `Request` property
|
|
29
|
+
|
|
30
|
+
```ts title="src/app/observability/middleware/request-timing.middleware.ts"
|
|
31
|
+
import type { Middleware } from "@warlock.js/core";
|
|
32
|
+
|
|
33
|
+
export const requestTimingMiddleware: Middleware = request => {
|
|
34
|
+
request.startedAt = Date.now();
|
|
35
|
+
};
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```ts title="src/app/observability/controllers/timing.controller.ts"
|
|
39
|
+
import type { RequestHandler } from "@warlock.js/core";
|
|
40
|
+
|
|
41
|
+
export const timingController: RequestHandler = async (request, response) => {
|
|
42
|
+
return response.success({ elapsedMs: Date.now() - request.startedAt });
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Those arbitrary properties compiled in v4 because `Request` had a `[key: string]: any` index signature. That signature is gone in v5.
|
|
47
|
+
|
|
48
|
+
### After — v5 typed `request.locals`
|
|
49
|
+
|
|
50
|
+
Declare the key once in the feature that owns and writes it:
|
|
51
|
+
|
|
52
|
+
```ts title="src/app/observability/request-locals.d.ts"
|
|
53
|
+
declare module "@warlock.js/core" {
|
|
54
|
+
interface RequestLocals {
|
|
55
|
+
startedAt?: number;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export {};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Write it in middleware:
|
|
63
|
+
|
|
64
|
+
```ts title="src/app/observability/middleware/request-timing.middleware.ts"
|
|
65
|
+
import type { Middleware } from "@warlock.js/core";
|
|
66
|
+
|
|
67
|
+
export const requestTimingMiddleware: Middleware = ({ request }) => {
|
|
68
|
+
request.locals.startedAt = Date.now();
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Read it downstream:
|
|
73
|
+
|
|
74
|
+
```ts title="src/app/observability/controllers/timing.controller.ts"
|
|
75
|
+
import type { RequestHandler } from "@warlock.js/core";
|
|
76
|
+
|
|
77
|
+
export const timingController: RequestHandler = async ({ request, response }) => {
|
|
78
|
+
const startedAt = request.locals.startedAt;
|
|
79
|
+
|
|
80
|
+
if (startedAt === undefined) {
|
|
81
|
+
return response.serverError({ error: "request timing middleware did not run" });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return response.success({ elapsedMs: Date.now() - startedAt });
|
|
85
|
+
};
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The `?` is honest about runtime ordering: the type exists everywhere, but the value exists only after the middleware runs. Narrow it downstream unless every construction path guarantees initialization and your project deliberately declares the key as required.
|
|
89
|
+
|
|
90
|
+
## Augment with an application type
|
|
91
|
+
|
|
92
|
+
An augmentation file may import the value's type. Keeping the declaration beside the writer makes ownership visible and prevents unrelated packages from claiming the same key.
|
|
93
|
+
|
|
94
|
+
```ts title="src/app/organizations/request-locals.d.ts"
|
|
95
|
+
import type { Organization } from "./models/organization";
|
|
96
|
+
|
|
97
|
+
declare module "@warlock.js/core" {
|
|
98
|
+
interface RequestLocals {
|
|
99
|
+
organization?: Organization;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export {};
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The module specifier must be `"@warlock.js/core"`, matching the public package import whose `RequestLocals` interface is exported. Ensure the `.d.ts` file is included by the application's TypeScript configuration.
|
|
107
|
+
|
|
108
|
+
## What belongs in `locals`
|
|
109
|
+
|
|
110
|
+
Good fits are values explicitly produced by one stage and consumed by later stages:
|
|
111
|
+
|
|
112
|
+
- a resolved organization, session, feature flag, or authorization subject;
|
|
113
|
+
- request timing or tracing metadata;
|
|
114
|
+
- a model loaded by validation or routing middleware;
|
|
115
|
+
- private server state that must not appear in request input.
|
|
116
|
+
|
|
117
|
+
`locals` is not a cache API. If consumers should be able to ask for a value independently and concurrent calls must collapse into one loader, use `requestMemo()` instead.
|
|
118
|
+
|
|
119
|
+
## Isolation from input and other requests
|
|
120
|
+
|
|
121
|
+
`Request` initializes `locals` with `{}` for each new request. Request instances are not pooled, so values cannot carry into the next request.
|
|
122
|
+
|
|
123
|
+
Writing `request.locals.organization` does not affect `request.all()`, `request.input()`, or `request.validated()`. By contrast, `request.set()` writes into the input payload's `all` bag, so it is the wrong replacement for a private v4 attachment.
|
|
124
|
+
|
|
125
|
+
## Choosing the extension surface
|
|
126
|
+
|
|
127
|
+
- Use `request.locals` for per-request data written by middleware and read downstream.
|
|
128
|
+
- Use `requestMemo(key, fn)` for lazily computed, single-flight work scoped to the active request.
|
|
129
|
+
- Augment `Request` itself only for a genuine new typed member that also has a runtime implementation.
|
|
130
|
+
- Augment `RequestUser` for the authenticated `request.user` shape; do not duplicate it under locals merely to work around typing.
|
|
131
|
+
|
|
132
|
+
## Gotchas
|
|
133
|
+
|
|
134
|
+
- **Do not restore `(request as any).post`.** It recreates the exact unchecked behavior v5 removed.
|
|
135
|
+
- **Do not add `[key: string]: any` to `RequestLocals`.** Declare each key with its actual type; otherwise every typo becomes valid again.
|
|
136
|
+
- **Do not centralize keys owned by unrelated features.** The middleware or package that writes a key should own its augmentation.
|
|
137
|
+
- **Do not assume an optional local was initialized.** Middleware registration and ordering are runtime concerns; narrow the value or fail clearly downstream.
|
|
138
|
+
- **Avoid key collisions across augmentations.** Interface merging requires repeated property declarations to agree, but stable feature-prefixed names are clearer for generic metadata.
|
|
139
|
+
|
|
140
|
+
## See also
|
|
141
|
+
|
|
142
|
+
- [`request-memo/SKILL.md`](../request-memo/SKILL.md) — the `fromRequest()` migration and single-flight request memoization.
|
|
143
|
+
- [`write-middleware/SKILL.md`](../write-middleware/SKILL.md) — middleware execution and registration.
|
|
144
|
+
- [`create-controller/SKILL.md`](../create-controller/SKILL.md) — reading locals in downstream controllers.
|