@beignet/core 0.0.48 → 0.0.49
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 +24 -0
- package/README.md +64 -14
- package/dist/client/client.d.ts +0 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +28 -25
- package/dist/client/client.js.map +1 -1
- package/dist/contracts/contract-builder.d.ts +7 -2
- package/dist/contracts/contract-builder.d.ts.map +1 -1
- package/dist/contracts/contract-builder.js +20 -2
- package/dist/contracts/contract-builder.js.map +1 -1
- package/dist/contracts/contract-group.d.ts.map +1 -1
- package/dist/contracts/contract-group.js +1 -0
- package/dist/contracts/contract-group.js.map +1 -1
- package/dist/contracts/contract-like.d.ts +2 -0
- package/dist/contracts/contract-like.d.ts.map +1 -1
- package/dist/contracts/contract-like.js +27 -1
- package/dist/contracts/contract-like.js.map +1 -1
- package/dist/contracts/index.d.ts +4 -0
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +4 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/query-transport.d.ts +126 -0
- package/dist/contracts/query-transport.d.ts.map +1 -0
- package/dist/contracts/query-transport.js +406 -0
- package/dist/contracts/query-transport.js.map +1 -0
- package/dist/contracts/schema-shape.d.ts +11 -0
- package/dist/contracts/schema-shape.d.ts.map +1 -1
- package/dist/contracts/schema-shape.js +13 -0
- package/dist/contracts/schema-shape.js.map +1 -1
- package/dist/contracts/types.d.ts +5 -0
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/contracts/types.js.map +1 -1
- package/dist/openapi/index.d.ts +8 -0
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +79 -5
- package/dist/openapi/index.js.map +1 -1
- package/dist/outbox/index.d.ts +8 -5
- package/dist/outbox/index.d.ts.map +1 -1
- package/dist/outbox/index.js +17 -3
- package/dist/outbox/index.js.map +1 -1
- package/dist/ports/cache.d.ts +9 -1
- package/dist/ports/cache.d.ts.map +1 -1
- package/dist/ports/cache.js +20 -5
- package/dist/ports/cache.js.map +1 -1
- package/dist/ports/index.d.ts +1 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +1 -1
- package/dist/ports/index.js.map +1 -1
- package/dist/query-codec.d.ts +24 -0
- package/dist/query-codec.d.ts.map +1 -1
- package/dist/query-codec.js +207 -72
- package/dist/query-codec.js.map +1 -1
- package/dist/server/hooks/rate-limit.d.ts +16 -8
- package/dist/server/hooks/rate-limit.d.ts.map +1 -1
- package/dist/server/hooks/rate-limit.js +31 -17
- package/dist/server/hooks/rate-limit.js.map +1 -1
- package/dist/server/request-executor.d.ts.map +1 -1
- package/dist/server/request-executor.js +9 -9
- package/dist/server/request-executor.js.map +1 -1
- package/dist/server/request-preparation.d.ts.map +1 -1
- package/dist/server/request-preparation.js +11 -9
- package/dist/server/request-preparation.js.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +2 -0
- package/dist/server/server.js.map +1 -1
- package/dist/server/use-case-route.d.ts +8 -5
- package/dist/server/use-case-route.d.ts.map +1 -1
- package/dist/server/use-case-route.js +44 -17
- package/dist/server/use-case-route.js.map +1 -1
- package/package.json +3 -3
- package/skills/app-architecture/SKILL.md +27 -1
- package/src/client/client.ts +29 -28
- package/src/contracts/contract-builder.ts +32 -2
- package/src/contracts/contract-group.ts +1 -0
- package/src/contracts/contract-like.ts +40 -1
- package/src/contracts/index.ts +23 -0
- package/src/contracts/query-transport.ts +697 -0
- package/src/contracts/schema-shape.ts +24 -0
- package/src/contracts/types.ts +5 -0
- package/src/openapi/index.ts +126 -2
- package/src/outbox/index.ts +26 -5
- package/src/ports/cache.ts +29 -7
- package/src/ports/index.ts +1 -1
- package/src/server/hooks/rate-limit.ts +50 -24
- package/src/server/request-executor.ts +17 -9
- package/src/server/request-preparation.ts +22 -9
- package/src/server/server.ts +2 -0
- package/src/server/use-case-route.ts +62 -23
- package/src/query-codec.ts +0 -130
package/dist/query-codec.js
CHANGED
|
@@ -1,16 +1,86 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
const QUERY_EXTENSION_PREFIX = "~beignet-query:v1:";
|
|
2
|
+
export const QUERY_NESTING_DEPTH_LIMIT = 32;
|
|
3
|
+
const DATE_TIME_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(Z|([+-])(\d{2}):(\d{2}))$/;
|
|
4
|
+
function isLeapYear(year) {
|
|
5
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
6
|
+
}
|
|
7
|
+
function daysInMonth(year, month) {
|
|
8
|
+
if (month === 2)
|
|
9
|
+
return isLeapYear(year) ? 29 : 28;
|
|
10
|
+
return [4, 6, 9, 11].includes(month) ? 30 : 31;
|
|
11
|
+
}
|
|
12
|
+
function decodeDateTime(value) {
|
|
13
|
+
const match = DATE_TIME_PATTERN.exec(value);
|
|
14
|
+
if (!match)
|
|
15
|
+
return undefined;
|
|
16
|
+
const year = Number(match[1]);
|
|
17
|
+
const month = Number(match[2]);
|
|
18
|
+
const day = Number(match[3]);
|
|
19
|
+
const hour = Number(match[4]);
|
|
20
|
+
const minute = Number(match[5]);
|
|
21
|
+
const second = Number(match[6]);
|
|
22
|
+
const offsetHour = match[9] === undefined ? 0 : Number(match[9]);
|
|
23
|
+
const offsetMinute = match[10] === undefined ? 0 : Number(match[10]);
|
|
24
|
+
if (month < 1 ||
|
|
25
|
+
month > 12 ||
|
|
26
|
+
day < 1 ||
|
|
27
|
+
day > daysInMonth(year, month) ||
|
|
28
|
+
hour > 23 ||
|
|
29
|
+
minute > 59 ||
|
|
30
|
+
second > 59 ||
|
|
31
|
+
offsetHour > 23 ||
|
|
32
|
+
offsetMinute > 59) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const date = new Date(value);
|
|
36
|
+
return Number.isFinite(date.getTime()) ? date : undefined;
|
|
37
|
+
}
|
|
38
|
+
function encodeQueryExtension(value) {
|
|
39
|
+
const extension = typeof value === "string" && value.startsWith(QUERY_EXTENSION_PREFIX)
|
|
40
|
+
? { kind: "escaped-string", value }
|
|
41
|
+
: { kind: "empty-preserving", value };
|
|
42
|
+
return `${QUERY_EXTENSION_PREFIX}${JSON.stringify(extension)}`;
|
|
43
|
+
}
|
|
44
|
+
export function decodeQueryExtension(value) {
|
|
45
|
+
if (!value.startsWith(QUERY_EXTENSION_PREFIX)) {
|
|
46
|
+
return { decoded: false, value };
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const extension = JSON.parse(value.slice(QUERY_EXTENSION_PREFIX.length));
|
|
50
|
+
if (!isPlainObject(extension))
|
|
51
|
+
return { decoded: false, value };
|
|
52
|
+
const keys = Object.keys(extension).sort();
|
|
53
|
+
if (keys.length !== 2 || keys[0] !== "kind" || keys[1] !== "value") {
|
|
54
|
+
return { decoded: false, value };
|
|
55
|
+
}
|
|
56
|
+
if (extension.kind === "escaped-string" &&
|
|
57
|
+
typeof extension.value === "string" &&
|
|
58
|
+
extension.value.startsWith(QUERY_EXTENSION_PREFIX)) {
|
|
59
|
+
return { decoded: true, value: extension.value };
|
|
60
|
+
}
|
|
61
|
+
if (extension.kind === "empty-preserving" &&
|
|
62
|
+
isWithinQueryNestingLimit(extension.value) &&
|
|
63
|
+
containsEmptyCollection(extension.value)) {
|
|
64
|
+
return { decoded: true, value: extension.value };
|
|
65
|
+
}
|
|
66
|
+
return { decoded: false, value };
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return { decoded: false, value };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function normalizeQueryValue(value, ancestors, depth = 0) {
|
|
73
|
+
if (depth > QUERY_NESTING_DEPTH_LIMIT) {
|
|
74
|
+
throw new TypeError(`Query value exceeds the maximum nesting depth of ${QUERY_NESTING_DEPTH_LIMIT}.`);
|
|
9
75
|
}
|
|
76
|
+
if (value === null || typeof value === "string")
|
|
77
|
+
return value;
|
|
78
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
79
|
+
return value;
|
|
10
80
|
if (typeof value === "boolean")
|
|
11
|
-
return
|
|
81
|
+
return value;
|
|
12
82
|
if (value instanceof Date && Number.isFinite(value.getTime())) {
|
|
13
|
-
return
|
|
83
|
+
return value.toISOString();
|
|
14
84
|
}
|
|
15
85
|
if (typeof value !== "object" || value === null) {
|
|
16
86
|
throw new TypeError("Query value is not serializable.");
|
|
@@ -21,90 +91,155 @@ function encodeStructuredValue(value, ancestors) {
|
|
|
21
91
|
ancestors.add(value);
|
|
22
92
|
try {
|
|
23
93
|
if (Array.isArray(value)) {
|
|
24
|
-
return
|
|
25
|
-
type: "array",
|
|
26
|
-
value: value.map((entry) => encodeStructuredValue(entry, ancestors)),
|
|
27
|
-
};
|
|
94
|
+
return value.map((entry) => normalizeQueryValue(entry, ancestors, depth + 1));
|
|
28
95
|
}
|
|
29
96
|
const prototype = Object.getPrototypeOf(value);
|
|
30
97
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
31
98
|
throw new TypeError("Query value contains a non-plain object.");
|
|
32
99
|
}
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
encodeStructuredValue(entry, ancestors),
|
|
40
|
-
])),
|
|
41
|
-
};
|
|
100
|
+
return Object.fromEntries(Object.entries(value)
|
|
101
|
+
.filter(([, entry]) => entry !== undefined)
|
|
102
|
+
.map(([key, entry]) => [
|
|
103
|
+
key,
|
|
104
|
+
normalizeQueryValue(entry, ancestors, depth + 1),
|
|
105
|
+
]));
|
|
42
106
|
}
|
|
43
107
|
finally {
|
|
44
108
|
ancestors.delete(value);
|
|
45
109
|
}
|
|
46
110
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return null;
|
|
55
|
-
case "string":
|
|
56
|
-
if (typeof encoded.value === "string")
|
|
57
|
-
return encoded.value;
|
|
58
|
-
break;
|
|
59
|
-
case "number":
|
|
60
|
-
if (typeof encoded.value === "number" && Number.isFinite(encoded.value)) {
|
|
61
|
-
return encoded.value;
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
|
-
case "boolean":
|
|
65
|
-
if (typeof encoded.value === "boolean")
|
|
66
|
-
return encoded.value;
|
|
67
|
-
break;
|
|
68
|
-
case "date": {
|
|
69
|
-
if (typeof encoded.value !== "string")
|
|
70
|
-
break;
|
|
71
|
-
const date = new Date(encoded.value);
|
|
72
|
-
if (Number.isFinite(date.getTime()))
|
|
73
|
-
return date;
|
|
111
|
+
function isWithinQueryNestingLimit(value) {
|
|
112
|
+
const pending = [
|
|
113
|
+
{ value, depth: 0 },
|
|
114
|
+
];
|
|
115
|
+
while (pending.length > 0) {
|
|
116
|
+
const candidate = pending.pop();
|
|
117
|
+
if (!candidate)
|
|
74
118
|
break;
|
|
119
|
+
if (candidate.depth > QUERY_NESTING_DEPTH_LIMIT)
|
|
120
|
+
return false;
|
|
121
|
+
if (typeof candidate.value !== "object" || candidate.value === null) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
for (const entry of Object.values(candidate.value)) {
|
|
125
|
+
pending.push({ value: entry, depth: candidate.depth + 1 });
|
|
75
126
|
}
|
|
76
|
-
case "array":
|
|
77
|
-
if (Array.isArray(encoded.value)) {
|
|
78
|
-
return encoded.value.map(decodeStructuredValue);
|
|
79
|
-
}
|
|
80
|
-
break;
|
|
81
|
-
case "object":
|
|
82
|
-
if (typeof encoded.value === "object" &&
|
|
83
|
-
encoded.value !== null &&
|
|
84
|
-
!Array.isArray(encoded.value)) {
|
|
85
|
-
return Object.fromEntries(Object.entries(encoded.value).map(([key, entry]) => [
|
|
86
|
-
key,
|
|
87
|
-
decodeStructuredValue(entry),
|
|
88
|
-
]));
|
|
89
|
-
}
|
|
90
|
-
break;
|
|
91
127
|
}
|
|
92
|
-
|
|
128
|
+
return true;
|
|
93
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Serialize one query value using ordinary URI scalar values and JSON for
|
|
132
|
+
* structured values. Arrays are normally emitted as repeated parameters by
|
|
133
|
+
* the typed client; direct callers can still encode a complete array here.
|
|
134
|
+
*/
|
|
94
135
|
export function encodeQueryValue(value) {
|
|
95
|
-
|
|
96
|
-
|
|
136
|
+
const normalized = normalizeQueryValue(value, new Set());
|
|
137
|
+
if (typeof normalized === "string") {
|
|
138
|
+
return normalized.startsWith(QUERY_EXTENSION_PREFIX)
|
|
139
|
+
? encodeQueryExtension(normalized)
|
|
140
|
+
: normalized;
|
|
141
|
+
}
|
|
142
|
+
if (typeof normalized === "number" || typeof normalized === "boolean") {
|
|
143
|
+
return String(normalized);
|
|
97
144
|
}
|
|
98
|
-
|
|
145
|
+
if (containsEmptyCollection(normalized)) {
|
|
146
|
+
return encodeQueryExtension(normalized);
|
|
147
|
+
}
|
|
148
|
+
return JSON.stringify(normalized);
|
|
99
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Decode a standard query scalar or JSON value. Request validation applies
|
|
152
|
+
* this only to fields that fail in their raw string form, preserving numeric,
|
|
153
|
+
* boolean, and date-looking strings when the contract expects strings.
|
|
154
|
+
*/
|
|
100
155
|
export function decodeQueryValue(value) {
|
|
101
|
-
|
|
102
|
-
|
|
156
|
+
const extension = decodeQueryExtension(value);
|
|
157
|
+
if (extension.decoded)
|
|
158
|
+
return extension.value;
|
|
103
159
|
try {
|
|
104
|
-
|
|
160
|
+
const decoded = JSON.parse(value);
|
|
161
|
+
return isWithinQueryNestingLimit(decoded) ? decoded : value;
|
|
105
162
|
}
|
|
106
163
|
catch {
|
|
164
|
+
const date = decodeDateTime(value);
|
|
165
|
+
if (date)
|
|
166
|
+
return date;
|
|
107
167
|
return value;
|
|
108
168
|
}
|
|
109
169
|
}
|
|
170
|
+
function isPlainObject(value) {
|
|
171
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const prototype = Object.getPrototypeOf(value);
|
|
175
|
+
return prototype === Object.prototype || prototype === null;
|
|
176
|
+
}
|
|
177
|
+
function containsEmptyCollection(value) {
|
|
178
|
+
if (Array.isArray(value)) {
|
|
179
|
+
return value.length === 0 || value.some(containsEmptyCollection);
|
|
180
|
+
}
|
|
181
|
+
if (!isPlainObject(value))
|
|
182
|
+
return false;
|
|
183
|
+
const entries = Object.values(value);
|
|
184
|
+
return entries.length === 0 || entries.some(containsEmptyCollection);
|
|
185
|
+
}
|
|
186
|
+
function appendDeepObject(params, name, value) {
|
|
187
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
188
|
+
if (entry === undefined)
|
|
189
|
+
continue;
|
|
190
|
+
const nestedName = `${name}[${key}]`;
|
|
191
|
+
if (Array.isArray(entry)) {
|
|
192
|
+
if (containsEmptyCollection(entry)) {
|
|
193
|
+
params.append(nestedName, encodeQueryExtension(entry));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
for (const item of entry) {
|
|
197
|
+
params.append(nestedName, encodeQueryValue(item));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (isPlainObject(entry)) {
|
|
202
|
+
if (Object.keys(entry).length === 0) {
|
|
203
|
+
params.append(nestedName, encodeQueryExtension(entry));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
appendDeepObject(params, nestedName, entry);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
params.append(nestedName, encodeQueryValue(entry));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Append a typed query value using OpenAPI form/explode semantics. Objects use
|
|
216
|
+
* deepObject bracket names and arrays use repeated parameter names. Nested
|
|
217
|
+
* objects and object-valued array entries use Beignet's recursive extension.
|
|
218
|
+
*/
|
|
219
|
+
export function appendQueryValue(params, name, value) {
|
|
220
|
+
// Count the parameter name as the root so the client and server enforce the
|
|
221
|
+
// same bound for deepObject bracket paths.
|
|
222
|
+
const normalized = normalizeQueryValue(value, new Set(), 1);
|
|
223
|
+
if (Array.isArray(normalized)) {
|
|
224
|
+
if (containsEmptyCollection(normalized)) {
|
|
225
|
+
params.append(name, encodeQueryExtension(normalized));
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
for (const entry of normalized) {
|
|
229
|
+
params.append(name, encodeQueryValue(entry));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (isPlainObject(normalized)) {
|
|
235
|
+
if (Object.keys(normalized).length === 0) {
|
|
236
|
+
params.append(name, encodeQueryExtension(normalized));
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
appendDeepObject(params, name, normalized);
|
|
240
|
+
}
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
params.append(name, encodeQueryValue(normalized));
|
|
244
|
+
}
|
|
110
245
|
//# sourceMappingURL=query-codec.js.map
|
package/dist/query-codec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-codec.js","sourceRoot":"","sources":["../src/query-codec.ts"],"names":[],"mappings":"AAAA,MAAM,
|
|
1
|
+
{"version":3,"file":"query-codec.js","sourceRoot":"","sources":["../src/query-codec.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Rate limit hooks for @beignet/core/server
|
|
3
3
|
*/
|
|
4
4
|
import type { RateLimitScope } from "../../contracts/index.js";
|
|
5
|
-
import type
|
|
5
|
+
import { type ActivityActor, type RateLimitPort } from "../../ports/index.js";
|
|
6
6
|
import { type TrustedProxyClientIpSource, type TrustedProxyConfig } from "../trusted-proxy.js";
|
|
7
7
|
import type { HttpRequestLike, ServerHook } from "../types.js";
|
|
8
8
|
/**
|
|
@@ -23,8 +23,9 @@ type EarlyRateLimitScope = Exclude<RateLimitScope, "user">;
|
|
|
23
23
|
* Strategy for resolving the client IP used by `ip`-scoped limits.
|
|
24
24
|
*
|
|
25
25
|
* - `"none"`: do not trust request headers for IP resolution. Every request
|
|
26
|
-
*
|
|
27
|
-
* that declare `ip` scopes without a trusted
|
|
26
|
+
* to one contract shares that contract's unknown-client bucket; this is the
|
|
27
|
+
* explicit opt-out for apps that declare `ip` scopes without a trusted
|
|
28
|
+
* client-IP source.
|
|
28
29
|
* - `"x-forwarded-for-last"`: the last `x-forwarded-for` entry. Use this only
|
|
29
30
|
* when the app is always behind a trusted reverse proxy that appends the
|
|
30
31
|
* socket address.
|
|
@@ -43,7 +44,9 @@ export interface RateLimitOptions<Ctx> {
|
|
|
43
44
|
/**
|
|
44
45
|
* Build a rate-limit key after context exists.
|
|
45
46
|
*
|
|
46
|
-
* This is used for user-scoped limits and any late key strategy.
|
|
47
|
+
* This is used for user-scoped limits and any late key strategy. The
|
|
48
|
+
* returned value is the complete key and is not automatically namespaced by
|
|
49
|
+
* contract.
|
|
47
50
|
*/
|
|
48
51
|
key?: (args: {
|
|
49
52
|
ctx: Ctx;
|
|
@@ -53,7 +56,8 @@ export interface RateLimitOptions<Ctx> {
|
|
|
53
56
|
/**
|
|
54
57
|
* Build a rate-limit key before request parsing and context creation.
|
|
55
58
|
*
|
|
56
|
-
* This is used for global and IP-scoped limits.
|
|
59
|
+
* This is used for global and IP-scoped limits. The returned value is the
|
|
60
|
+
* complete key and is not automatically namespaced by contract.
|
|
57
61
|
*/
|
|
58
62
|
earlyKey?: (args: {
|
|
59
63
|
req: HttpRequestLike;
|
|
@@ -87,7 +91,10 @@ export interface RateLimitOptions<Ctx> {
|
|
|
87
91
|
* The hook reads `contract.metadata.rateLimit`. Global and IP-scoped limits run
|
|
88
92
|
* in `onRequest` before context creation; user-scoped limits run in
|
|
89
93
|
* `beforeHandle` after route hooks have resolved identity and `ctx.actor` is
|
|
90
|
-
* available.
|
|
94
|
+
* available. Default keys include the contract name so unrelated contracts do
|
|
95
|
+
* not share counters. A user-scoped limit without a resolved user actor fails
|
|
96
|
+
* with `AuthUnauthorizedError` instead of falling back to a global bucket.
|
|
97
|
+
* Exceeded limits throw the framework `TooManyRequests` app error
|
|
91
98
|
* with `scope`, `retryAfterSeconds`, and `resetAt` details, and the 429
|
|
92
99
|
* response carries a `Retry-After` header when the limiter reports a reset
|
|
93
100
|
* time. The bucket key is
|
|
@@ -97,11 +104,12 @@ export interface RateLimitOptions<Ctx> {
|
|
|
97
104
|
* `ip`-scoped limits require an explicit `trustedProxy.clientIp`, `ipSource`,
|
|
98
105
|
* or custom `earlyKey`: the hook's `validate` phase fails `createServer(...)`
|
|
99
106
|
* startup when a registered contract declares an `ip` scope without one,
|
|
100
|
-
* instead of silently collapsing all clients into
|
|
107
|
+
* instead of silently collapsing all clients into one shared bucket.
|
|
101
108
|
* Contracts added later through `server.route(...)` are not visible to
|
|
102
109
|
* `validate`, so enforcing an `ip`-scoped limit without a client-IP source
|
|
103
110
|
* throws the same configuration error at request time as a backstop. Pass
|
|
104
|
-
* `ipSource: "none"` to explicitly opt in to
|
|
111
|
+
* `ipSource: "none"` to explicitly opt in to one unknown-client bucket per
|
|
112
|
+
* contract.
|
|
105
113
|
*
|
|
106
114
|
* @param options - Optional key builders and client-IP source.
|
|
107
115
|
* @returns A server hook backed by `ctx.ports.rateLimit`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/server/hooks/rate-limit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/server/hooks/rate-limit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EAEL,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EAExB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,aAAa,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAEF,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,0BAA0B,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,GAAG;IACnC;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE;QACX,GAAG,EAAE,GAAG,CAAC;QACT,GAAG,EAAE,eAAe,CAAC;QACrB,KAAK,EAAE,cAAc,CAAC;KACvB,KAAK,MAAM,CAAC;IACb;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,GAAG,EAAE,eAAe,CAAC;QACrB,KAAK,EAAE,mBAAmB,CAAC;KAC5B,KAAK,MAAM,CAAC;IACb;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AA+ID;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,SAAS,gBAAgB,EAC/D,OAAO,GAAE,gBAAgB,CAAC,GAAG,CAAM,GAClC,UAAU,CAAC,GAAG,EAAE,cAAc,CAAC,CAiGjC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Rate limit hooks for @beignet/core/server
|
|
3
3
|
*/
|
|
4
4
|
import { AppError, httpErrors } from "../../errors/index.js";
|
|
5
|
+
import { AuthUnauthorizedError, } from "../../ports/index.js";
|
|
5
6
|
import { createProviderInstrumentation, } from "../../providers/index.js";
|
|
6
7
|
import { resolveTrustedClientIp, } from "../trusted-proxy.js";
|
|
7
8
|
function resolveClientIp(req, ipSource) {
|
|
@@ -22,31 +23,40 @@ function ipSourceConfigurationError(contractNames) {
|
|
|
22
23
|
return new Error(`createRateLimitHooks(...) has no client IP source configured, but contract(s) ${contractNames} declare an "ip"-scoped rate limit. ` +
|
|
23
24
|
`Set trustedProxy.clientIp or ipSource to a header source written by a trusted edge, ` +
|
|
24
25
|
`for example "x-forwarded-for-last", "x-forwarded-for-first", "x-real-ip", "cf-connecting-ip", or a custom function, ` +
|
|
25
|
-
`or "none" to explicitly accept one shared
|
|
26
|
+
`or "none" to explicitly accept one shared unknown-client bucket per contract.`);
|
|
26
27
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
28
|
+
function namespaceContractKey(contractName, key) {
|
|
29
|
+
const encodedContractName = contractName
|
|
30
|
+
.replaceAll("%", "%25")
|
|
31
|
+
.replaceAll(":", "%3A");
|
|
32
|
+
return `contract:${encodedContractName}:${key}`;
|
|
29
33
|
}
|
|
30
|
-
function
|
|
31
|
-
return `
|
|
34
|
+
function emitUserKey(contractName, userId) {
|
|
35
|
+
return namespaceContractKey(contractName, `user:${userId}`);
|
|
36
|
+
}
|
|
37
|
+
function emitIpKey(contractName, ip) {
|
|
38
|
+
return namespaceContractKey(contractName, `ip:${ip}`);
|
|
32
39
|
}
|
|
33
40
|
function defaultRateLimitKey(args, getClientIp) {
|
|
34
|
-
const { ctx, req, scope } = args;
|
|
35
|
-
if (scope === "user"
|
|
36
|
-
|
|
41
|
+
const { contractName, ctx, req, scope } = args;
|
|
42
|
+
if (scope === "user") {
|
|
43
|
+
if (ctx.actor?.type !== "user" || !ctx.actor.id) {
|
|
44
|
+
throw new AuthUnauthorizedError();
|
|
45
|
+
}
|
|
46
|
+
return emitUserKey(contractName, ctx.actor.id);
|
|
37
47
|
}
|
|
38
48
|
if (scope === "ip") {
|
|
39
49
|
const ip = getClientIp(req) || "unknown";
|
|
40
|
-
return emitIpKey(ip);
|
|
50
|
+
return emitIpKey(contractName, ip);
|
|
41
51
|
}
|
|
42
|
-
return "global";
|
|
52
|
+
return namespaceContractKey(contractName, "global");
|
|
43
53
|
}
|
|
44
54
|
function defaultEarlyRateLimitKey(args, getClientIp) {
|
|
45
55
|
if (args.scope === "ip") {
|
|
46
56
|
const ip = getClientIp(args.req) || "unknown";
|
|
47
|
-
return emitIpKey(ip);
|
|
57
|
+
return emitIpKey(args.contractName, ip);
|
|
48
58
|
}
|
|
49
|
-
return "global";
|
|
59
|
+
return namespaceContractKey(args.contractName, "global");
|
|
50
60
|
}
|
|
51
61
|
async function enforceRateLimit(ports, args) {
|
|
52
62
|
const result = await ports.rateLimit.hit({
|
|
@@ -88,7 +98,10 @@ async function enforceRateLimit(ports, args) {
|
|
|
88
98
|
* The hook reads `contract.metadata.rateLimit`. Global and IP-scoped limits run
|
|
89
99
|
* in `onRequest` before context creation; user-scoped limits run in
|
|
90
100
|
* `beforeHandle` after route hooks have resolved identity and `ctx.actor` is
|
|
91
|
-
* available.
|
|
101
|
+
* available. Default keys include the contract name so unrelated contracts do
|
|
102
|
+
* not share counters. A user-scoped limit without a resolved user actor fails
|
|
103
|
+
* with `AuthUnauthorizedError` instead of falling back to a global bucket.
|
|
104
|
+
* Exceeded limits throw the framework `TooManyRequests` app error
|
|
92
105
|
* with `scope`, `retryAfterSeconds`, and `resetAt` details, and the 429
|
|
93
106
|
* response carries a `Retry-After` header when the limiter reports a reset
|
|
94
107
|
* time. The bucket key is
|
|
@@ -98,11 +111,12 @@ async function enforceRateLimit(ports, args) {
|
|
|
98
111
|
* `ip`-scoped limits require an explicit `trustedProxy.clientIp`, `ipSource`,
|
|
99
112
|
* or custom `earlyKey`: the hook's `validate` phase fails `createServer(...)`
|
|
100
113
|
* startup when a registered contract declares an `ip` scope without one,
|
|
101
|
-
* instead of silently collapsing all clients into
|
|
114
|
+
* instead of silently collapsing all clients into one shared bucket.
|
|
102
115
|
* Contracts added later through `server.route(...)` are not visible to
|
|
103
116
|
* `validate`, so enforcing an `ip`-scoped limit without a client-IP source
|
|
104
117
|
* throws the same configuration error at request time as a backstop. Pass
|
|
105
|
-
* `ipSource: "none"` to explicitly opt in to
|
|
118
|
+
* `ipSource: "none"` to explicitly opt in to one unknown-client bucket per
|
|
119
|
+
* contract.
|
|
106
120
|
*
|
|
107
121
|
* @param options - Optional key builders and client-IP source.
|
|
108
122
|
* @returns A server hook backed by `ctx.ports.rateLimit`.
|
|
@@ -150,7 +164,7 @@ export function createRateLimitHooks(options = {}) {
|
|
|
150
164
|
return undefined;
|
|
151
165
|
}
|
|
152
166
|
const key = options.earlyKey?.({ req, scope }) ??
|
|
153
|
-
defaultEarlyRateLimitKey({ req, scope }, (r) => getClientIp(r, requestInfo, contract.name));
|
|
167
|
+
defaultEarlyRateLimitKey({ req, scope, contractName: contract.name }, (r) => getClientIp(r, requestInfo, contract.name));
|
|
154
168
|
await enforceRateLimit(ports, {
|
|
155
169
|
key,
|
|
156
170
|
limit: rlMeta.max,
|
|
@@ -169,7 +183,7 @@ export function createRateLimitHooks(options = {}) {
|
|
|
169
183
|
return undefined;
|
|
170
184
|
}
|
|
171
185
|
const key = options.key?.({ ctx, req, scope }) ??
|
|
172
|
-
defaultRateLimitKey({ ctx, req, scope }, (r) => getClientIp(r, requestInfo, contract.name));
|
|
186
|
+
defaultRateLimitKey({ ctx, req, scope, contractName: contract.name }, (r) => getClientIp(r, requestInfo, contract.name));
|
|
173
187
|
await enforceRateLimit(ctx.ports, {
|
|
174
188
|
key,
|
|
175
189
|
limit: rlMeta.max,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../../src/server/hooks/rate-limit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../../src/server/hooks/rate-limit.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-executor.d.ts","sourceRoot":"","sources":["../../src/server/request-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAUhE,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAkBlD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EACV,OAAO,EAEP,eAAe,EACf,YAAY,EAEZ,SAAS,EACT,qBAAqB,EACrB,UAAU,EACV,0BAA0B,EAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAUzE,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,0BAA0B,CAAC;AAkBlC,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAsB7D,KAAK,sBAAsB,CAAC,GAAG,IAAI;IACjC,eAAe,CAAC,EAAE,4BAA4B,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC5D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,aAAa,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC3C,iBAAiB,CAAC,EAAE,0BAA0B,CAAC,GAAG,CAAC,CAAC;CACrD,CAAC;AASF,KAAK,eAAe,CAAC,GAAG,EAAE,CAAC,SAAS,kBAAkB,IAAI;IACxD,QAAQ,EAAE,CAAC,CAAC;IACZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACzB;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACzC,CAAC;AAmBF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EACH,UAAU,SAAS,QAAQ,EAC3B,CAAC,SAAS,kBAAkB,EAE5B,OAAO,EAAE,sBAAsB,CAAC,GAAG,CAAC,EACpC,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE;IACd,oBAAoB,EAAE,CACpB,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,kBAAkB,EAC5B,WAAW,EAAE,kBAAkB,KAC5B,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC;IACvD,kBAAkB,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,kBAAkB,CAAC;CAClE,EACD,KAAK,EAAE,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EACpC,UAAU,GAAE,SAAS,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,EAAO,EACtD,gBAAgB,CAAC,EAAE;IACjB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACA,CACD,MAAM,EAAE,eAAe,CAAC,GAAG,EAAE,CAAC,CAAC,EAC/B,GAAG,EAAE,eAAe,EACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACtC,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"request-executor.d.ts","sourceRoot":"","sources":["../../src/server/request-executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAUhE,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAkBlD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EACV,OAAO,EAEP,eAAe,EACf,YAAY,EAEZ,SAAS,EACT,qBAAqB,EACrB,UAAU,EACV,0BAA0B,EAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAUzE,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,0BAA0B,CAAC;AAkBlC,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAsB7D,KAAK,sBAAsB,CAAC,GAAG,IAAI;IACjC,eAAe,CAAC,EAAE,4BAA4B,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC5D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,aAAa,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC3C,iBAAiB,CAAC,EAAE,0BAA0B,CAAC,GAAG,CAAC,CAAC;CACrD,CAAC;AASF,KAAK,eAAe,CAAC,GAAG,EAAE,CAAC,SAAS,kBAAkB,IAAI;IACxD,QAAQ,EAAE,CAAC,CAAC;IACZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACzB;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACzC,CAAC;AAmBF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EACH,UAAU,SAAS,QAAQ,EAC3B,CAAC,SAAS,kBAAkB,EAE5B,OAAO,EAAE,sBAAsB,CAAC,GAAG,CAAC,EACpC,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE;IACd,oBAAoB,EAAE,CACpB,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,kBAAkB,EAC5B,WAAW,EAAE,kBAAkB,KAC5B,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC;IACvD,kBAAkB,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,kBAAkB,CAAC;CAClE,EACD,KAAK,EAAE,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EACpC,UAAU,GAAE,SAAS,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,EAAO,EACtD,gBAAgB,CAAC,EAAE;IACjB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACA,CACD,MAAM,EAAE,eAAe,CAAC,GAAG,EAAE,CAAC,CAAC,EAC/B,GAAG,EAAE,eAAe,EACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACtC,OAAO,CAAC,YAAY,CAAC,CAw5BzB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,QAAQ,GACd,CAAC,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,CAAC,GAAG,SAAS,CAuBzD;AAED,wBAAgB,YAAY,CAC1B,GAAG,EACH,UAAU,SAAS,QAAQ,EAC3B,CAAC,SAAS,kBAAkB,EAE5B,OAAO,EAAE,sBAAsB,CAAC,GAAG,CAAC,EACpC,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE;IACd,oBAAoB,EAAE,CACpB,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,kBAAkB,EAC5B,WAAW,EAAE,kBAAkB,KAC5B,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC;IACvD,kBAAkB,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,kBAAkB,CAAC;CAClE,EACD,QAAQ,EAAE,CAAC,EACX,WAAW,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAC5B,KAAK,EAAE,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EACpC,UAAU,GAAE,SAAS,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,EAAO,EACtD,gBAAgB,CAAC,EAAE;IACjB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,EACD,8BAA8B,CAAC,EAAE,MAAM,GACtC,CACD,GAAG,EAAE,eAAe,EACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACtC,OAAO,CAAC,YAAY,CAAC,CAsBzB"}
|
|
@@ -623,18 +623,18 @@ export function createRequestExecutor(options, finalPorts, contextRuntime, hooks
|
|
|
623
623
|
error,
|
|
624
624
|
owner: "framework",
|
|
625
625
|
};
|
|
626
|
-
finalResponse = normalizeHttpResponse(result.response);
|
|
627
|
-
finalError = result.error;
|
|
628
|
-
finalOwner = responseOwnerFor(finalResponse, result.owner);
|
|
629
|
-
result = await applyTransformHooks(result, true);
|
|
630
|
-
finalResponse = normalizeHttpResponse(result.response);
|
|
631
|
-
finalError = result.error;
|
|
632
|
-
finalOwner = responseOwnerFor(finalResponse, result.owner);
|
|
633
|
-
responseValidation = "not-applicable";
|
|
634
626
|
}
|
|
635
627
|
else {
|
|
636
|
-
|
|
628
|
+
result = await resolveErrorResult(error, result.ctx, pathValue, queryValue, headersValue, bodyValue, { owner: "framework" });
|
|
637
629
|
}
|
|
630
|
+
finalResponse = normalizeHttpResponse(result.response);
|
|
631
|
+
finalError = result.error;
|
|
632
|
+
finalOwner = responseOwnerFor(finalResponse, result.owner);
|
|
633
|
+
result = await applyTransformHooks(result, true);
|
|
634
|
+
finalResponse = normalizeHttpResponse(result.response);
|
|
635
|
+
finalError = result.error;
|
|
636
|
+
finalOwner = responseOwnerFor(finalResponse, result.owner);
|
|
637
|
+
responseValidation = "not-applicable";
|
|
638
638
|
}
|
|
639
639
|
}
|
|
640
640
|
result = await applyResponseFinalizerHooks(result, true, responseValidation);
|