theokit 0.48.7 → 0.48.9
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 +86 -0
- package/dist/{actions-virtual-module-GB5FWUPS.js → actions-virtual-module-LB4NGONI.js} +2 -3
- package/dist/{actions-virtual-module-GB5FWUPS.js.map → actions-virtual-module-LB4NGONI.js.map} +1 -1
- package/dist/{agent-47XWDGIR.js → agent-SK4TOO6M.js} +2 -2
- package/dist/{app-typed-client-5QDNHANF.js → app-typed-client-G3J5G7E5.js} +2 -3
- package/dist/{app-typed-client-5QDNHANF.js.map → app-typed-client-G3J5G7E5.js.map} +1 -1
- package/dist/{build-4CAGKYYT.js → build-FMRO4W4Q.js} +4 -4
- package/dist/{chunk-H6YBKIUN.js → chunk-BIVCP6X5.js} +575 -161
- package/dist/chunk-BIVCP6X5.js.map +1 -0
- package/dist/{chunk-UDPJP42U.js → chunk-GPX7I5ZY.js} +31 -4
- package/dist/chunk-GPX7I5ZY.js.map +1 -0
- package/dist/{chunk-3GUXSNHY.js → chunk-GRI4XHBJ.js} +86 -3
- package/dist/chunk-GRI4XHBJ.js.map +1 -0
- package/dist/{chunk-A4ZEP3FE.js → chunk-GVW5EKEU.js} +11 -2
- package/dist/chunk-GVW5EKEU.js.map +1 -0
- package/dist/{chunk-AXQF3I4L.js → chunk-Q2S2IGSM.js} +40 -123
- package/dist/chunk-Q2S2IGSM.js.map +1 -0
- package/dist/{chunk-GH32R55S.js → chunk-S433N3CT.js} +2 -2
- package/dist/{chunk-JZ25BBLP.js → chunk-SO64VQOD.js} +4 -4
- package/dist/chunk-V7MTRM6Q.js +90 -0
- package/dist/chunk-V7MTRM6Q.js.map +1 -0
- package/dist/{chunk-XSCZWSE3.js → chunk-YML4ZDFA.js} +11 -2
- package/dist/chunk-YML4ZDFA.js.map +1 -0
- package/dist/cli/index.js +19 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cookies-QWVS7OGS.js +23 -0
- package/dist/{dev-F67X4F5E.js → dev-P2MODWTG.js} +6 -7
- package/dist/{dev-F67X4F5E.js.map → dev-P2MODWTG.js.map} +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/{info-MSBQ72EM.js → info-XW7HGUPH.js} +3 -3
- package/dist/{internal-api-ICU7ITJD.js → internal-api-V5L65YSJ.js} +7 -9
- package/dist/{load-config-2LP2OEKD.js → load-config-VKD6LKWU.js} +3 -3
- package/dist/{mcp-AJHKPAU4.js → mcp-EQHTPQ2L.js} +3 -3
- package/dist/{openapi-FWNYHB6T.js → openapi-HZXR335W.js} +3 -3
- package/dist/{routes-6AMNVFMI.js → routes-OLNQX7CT.js} +3 -3
- package/dist/{schema-Z3Y7SFLE.js → schema-ZO3OSWVG.js} +2 -2
- package/dist/server/index.js +1 -1
- package/dist/server/rate-limit/index.d.ts +49 -1
- package/dist/server/rate-limit/index.js +1 -1
- package/dist/{start-IITIEJTY.js → start-KR2JJR7K.js} +149 -20
- package/dist/start-KR2JJR7K.js.map +1 -0
- package/dist/vite-plugin/index.js +1 -1
- package/dist/{vite-plugin-MXHY6MSV.js → vite-plugin-EQMDMDXV.js} +6 -7
- package/dist/vite-plugin-EQMDMDXV.js.map +1 -0
- package/package.json +11 -1
- package/dist/chunk-3GUXSNHY.js.map +0 -1
- package/dist/chunk-7CQ6DEWZ.js +0 -421
- package/dist/chunk-7CQ6DEWZ.js.map +0 -1
- package/dist/chunk-A4ZEP3FE.js.map +0 -1
- package/dist/chunk-AXQF3I4L.js.map +0 -1
- package/dist/chunk-H6YBKIUN.js.map +0 -1
- package/dist/chunk-UDPJP42U.js.map +0 -1
- package/dist/chunk-XSCZWSE3.js.map +0 -1
- package/dist/start-IITIEJTY.js.map +0 -1
- /package/dist/{agent-47XWDGIR.js.map → agent-SK4TOO6M.js.map} +0 -0
- /package/dist/{build-4CAGKYYT.js.map → build-FMRO4W4Q.js.map} +0 -0
- /package/dist/{chunk-GH32R55S.js.map → chunk-S433N3CT.js.map} +0 -0
- /package/dist/{chunk-JZ25BBLP.js.map → chunk-SO64VQOD.js.map} +0 -0
- /package/dist/{internal-api-ICU7ITJD.js.map → cookies-QWVS7OGS.js.map} +0 -0
- /package/dist/{info-MSBQ72EM.js.map → info-XW7HGUPH.js.map} +0 -0
- /package/dist/{load-config-2LP2OEKD.js.map → internal-api-V5L65YSJ.js.map} +0 -0
- /package/dist/{schema-Z3Y7SFLE.js.map → load-config-VKD6LKWU.js.map} +0 -0
- /package/dist/{mcp-AJHKPAU4.js.map → mcp-EQHTPQ2L.js.map} +0 -0
- /package/dist/{openapi-FWNYHB6T.js.map → openapi-HZXR335W.js.map} +0 -0
- /package/dist/{routes-6AMNVFMI.js.map → routes-OLNQX7CT.js.map} +0 -0
- /package/dist/{vite-plugin-MXHY6MSV.js.map → schema-ZO3OSWVG.js.map} +0 -0
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
} from "./chunk-GEQJAFSV.js";
|
|
6
6
|
import {
|
|
7
7
|
loadConfig
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-S433N3CT.js";
|
|
9
9
|
import "./chunk-HBU2GIMZ.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-GVW5EKEU.js";
|
|
11
11
|
import "./chunk-7VPQHEAJ.js";
|
|
12
12
|
import {
|
|
13
13
|
scanServerActions,
|
|
@@ -62,4 +62,4 @@ async function routesCommand() {
|
|
|
62
62
|
export {
|
|
63
63
|
routesCommand
|
|
64
64
|
};
|
|
65
|
-
//# sourceMappingURL=routes-
|
|
65
|
+
//# sourceMappingURL=routes-OLNQX7CT.js.map
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
securityHeadersSchema,
|
|
7
7
|
storageSchema,
|
|
8
8
|
theoConfigSchema
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GVW5EKEU.js";
|
|
10
10
|
import "./chunk-7VPQHEAJ.js";
|
|
11
11
|
export {
|
|
12
12
|
cacheSchema,
|
|
@@ -15,4 +15,4 @@ export {
|
|
|
15
15
|
storageSchema,
|
|
16
16
|
theoConfigSchema
|
|
17
17
|
};
|
|
18
|
-
//# sourceMappingURL=schema-
|
|
18
|
+
//# sourceMappingURL=schema-ZO3OSWVG.js.map
|
package/dist/server/index.js
CHANGED
|
@@ -4,6 +4,41 @@ import { R as RateLimitStore } from '../../rate-limit-store-BEJnhWdw.js';
|
|
|
4
4
|
export { I as InMemoryStore, a as RateLimitState } from '../../rate-limit-store-BEJnhWdw.js';
|
|
5
5
|
import { IncomingMessage } from 'node:http';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Resolves the address a rate-limit bucket should be keyed on.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this is not just `req.socket.remoteAddress`
|
|
11
|
+
*
|
|
12
|
+
* Behind any reverse proxy — Caddy, nginx, a load balancer, an ingress controller — the socket
|
|
13
|
+
* address is the PROXY's, identical for every visitor on the internet. Keying buckets on it gives
|
|
14
|
+
* the whole world one shared budget, so the first few requests each minute exhaust it and everyone
|
|
15
|
+
* else is refused. That is worse than no limiting: a limit meant to stop one abusive client becomes
|
|
16
|
+
* a denial of service any single client can trigger for everybody.
|
|
17
|
+
*
|
|
18
|
+
* ## Why it is opt-in
|
|
19
|
+
*
|
|
20
|
+
* `x-forwarded-for` is a request header, and a request header is whatever the client typed. Reading
|
|
21
|
+
* it without being told to would let anyone bypass the limiter by rotating a forged value — a
|
|
22
|
+
* one-line `curl -H`. So the default is to trust nothing and use the socket.
|
|
23
|
+
*
|
|
24
|
+
* ## Why the RIGHTMOST entry
|
|
25
|
+
*
|
|
26
|
+
* Each proxy APPENDS the address that connected to it. A client that sends `x-forwarded-for: 1.2.3.4`
|
|
27
|
+
* through one proxy produces `1.2.3.4, <real client>` — the forgery lands on the left, and the entry
|
|
28
|
+
* the trusted proxy wrote is last. Counting from the right therefore skips exactly the hops the
|
|
29
|
+
* operator vouched for, and everything a client can influence stays to the left of where we look.
|
|
30
|
+
*
|
|
31
|
+
* This mirrors the `'trusted-proxy'` policy in `adapters/web-shim.ts`, which documents the same rule
|
|
32
|
+
* for the Web-Request runtimes.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* How many proxies sit in front of the app.
|
|
36
|
+
*
|
|
37
|
+
* `false` (the default) trusts nothing and uses the socket address. `true` means one trusted proxy.
|
|
38
|
+
* A number names the hop count for a longer chain — a CDN in front of your own proxy is `2`.
|
|
39
|
+
*/
|
|
40
|
+
type TrustProxy = boolean | number;
|
|
41
|
+
|
|
7
42
|
/**
|
|
8
43
|
* T2.2 — Per-route + per-user rate limiting.
|
|
9
44
|
*
|
|
@@ -29,6 +64,19 @@ interface RouteRateLimitConfig {
|
|
|
29
64
|
cookieName?: string;
|
|
30
65
|
/** Optional shared store (for multi-route correlation). Default per-limiter InMemoryStore. */
|
|
31
66
|
store?: RateLimitStore;
|
|
67
|
+
/**
|
|
68
|
+
* How many reverse proxies sit in front of the app, for `keyBy: 'ip'`. Default `false` — trust
|
|
69
|
+
* none and key on the socket address.
|
|
70
|
+
*
|
|
71
|
+
* Set this whenever the app is behind Caddy, nginx, a load balancer or an ingress controller:
|
|
72
|
+
* without it every visitor keys on the proxy's address and shares one bucket, so a handful of
|
|
73
|
+
* requests exhausts the budget for the entire internet. With it, the client address is read from
|
|
74
|
+
* `x-forwarded-for` counting in from the right, past exactly the hops declared here.
|
|
75
|
+
*
|
|
76
|
+
* Leaving it off by default is deliberate — `x-forwarded-for` is client-writable, and honouring it
|
|
77
|
+
* uninvited turns the limiter into a one-header bypass. See `client-ip.ts`.
|
|
78
|
+
*/
|
|
79
|
+
trustProxy?: TrustProxy;
|
|
32
80
|
}
|
|
33
81
|
/**
|
|
34
82
|
* Test whether `path` matches `pattern`. String patterns are compared
|
|
@@ -44,7 +92,7 @@ declare function matchRoutePattern(path: string, pattern: string | RegExp): bool
|
|
|
44
92
|
* we fall back to IP so anonymous users still get rate-limited rather
|
|
45
93
|
* than sharing an empty bucket.
|
|
46
94
|
*/
|
|
47
|
-
declare function deriveKey(req: IncomingMessage, keyBy: KeyByMode, cookieName: string): Promise<string>;
|
|
95
|
+
declare function deriveKey(req: IncomingMessage, keyBy: KeyByMode, cookieName: string, trustProxy?: TrustProxy): Promise<string>;
|
|
48
96
|
/**
|
|
49
97
|
* Per-route rate limiter factory. Returns a sync checker compatible with
|
|
50
98
|
* the existing api-middleware shape.
|
|
@@ -3,10 +3,14 @@ import "tsx/esm";
|
|
|
3
3
|
import {
|
|
4
4
|
CONTROLLER_MANIFEST_FILE
|
|
5
5
|
} from "./chunk-47CINLWF.js";
|
|
6
|
+
import {
|
|
7
|
+
parseCookieHeader
|
|
8
|
+
} from "./chunk-V7MTRM6Q.js";
|
|
6
9
|
import {
|
|
7
10
|
preflightNodeAndBindings
|
|
8
11
|
} from "./chunk-KTMQUYED.js";
|
|
9
12
|
import {
|
|
13
|
+
applyNonceToInlineScripts,
|
|
10
14
|
extractHeadTags,
|
|
11
15
|
handleAgentApproval,
|
|
12
16
|
injectIntoHead,
|
|
@@ -14,30 +18,30 @@ import {
|
|
|
14
18
|
resolveTransformer,
|
|
15
19
|
serveAgentAuxRoute,
|
|
16
20
|
writeWebResponseToServerResponse
|
|
17
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GRI4XHBJ.js";
|
|
18
22
|
import "./chunk-2CVV6CNN.js";
|
|
19
23
|
import {
|
|
20
24
|
findRootDiv
|
|
21
25
|
} from "./chunk-3PWQQWT6.js";
|
|
22
26
|
import {
|
|
23
27
|
loadConfig
|
|
24
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-S433N3CT.js";
|
|
25
29
|
import {
|
|
26
30
|
loadEnv
|
|
27
31
|
} from "./chunk-HBU2GIMZ.js";
|
|
28
|
-
import "./chunk-
|
|
32
|
+
import "./chunk-GVW5EKEU.js";
|
|
29
33
|
import "./chunk-7VPQHEAJ.js";
|
|
30
34
|
import {
|
|
35
|
+
InMemoryStore,
|
|
31
36
|
buildSecurityHeaders,
|
|
32
37
|
createPluginRunnerFromConfig,
|
|
33
38
|
createProductionLoader,
|
|
34
|
-
createRateLimiter,
|
|
35
39
|
executeAction,
|
|
36
40
|
executeRoute,
|
|
37
41
|
findSuggestion,
|
|
38
42
|
generateNonce,
|
|
39
43
|
mountAgent
|
|
40
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-BIVCP6X5.js";
|
|
41
45
|
import {
|
|
42
46
|
getApprovalRegistry,
|
|
43
47
|
resolveProvider
|
|
@@ -96,6 +100,131 @@ async function serveReservedRoute(pathname, routes = {}) {
|
|
|
96
100
|
return null;
|
|
97
101
|
}
|
|
98
102
|
|
|
103
|
+
// src/server/rate-limit/client-ip.ts
|
|
104
|
+
function hopCount(trustProxy) {
|
|
105
|
+
if (trustProxy === true) return 1;
|
|
106
|
+
if (trustProxy === false) return 0;
|
|
107
|
+
return trustProxy;
|
|
108
|
+
}
|
|
109
|
+
function headerValue(req, name) {
|
|
110
|
+
const raw = req.headers[name];
|
|
111
|
+
if (Array.isArray(raw)) return raw[raw.length - 1];
|
|
112
|
+
return raw;
|
|
113
|
+
}
|
|
114
|
+
function resolveClientIp(req, trustProxy = false) {
|
|
115
|
+
const socketAddress = req.socket?.remoteAddress ?? "unknown";
|
|
116
|
+
const hops = hopCount(trustProxy);
|
|
117
|
+
if (hops < 1) return socketAddress;
|
|
118
|
+
const forwarded = headerValue(req, "x-forwarded-for");
|
|
119
|
+
if (forwarded) {
|
|
120
|
+
const entries = forwarded.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
121
|
+
const index = entries.length - hops;
|
|
122
|
+
if (index >= 0 && index < entries.length) return entries[index];
|
|
123
|
+
}
|
|
124
|
+
const realIp = headerValue(req, "x-real-ip");
|
|
125
|
+
if (realIp) return realIp.trim();
|
|
126
|
+
return socketAddress;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/server/rate-limit/rate-limit-per-route.ts
|
|
130
|
+
function normalizePath(input) {
|
|
131
|
+
const noQuery = input.split("?")[0];
|
|
132
|
+
if (noQuery.length > 1 && noQuery.endsWith("/")) return noQuery.slice(0, -1);
|
|
133
|
+
return noQuery;
|
|
134
|
+
}
|
|
135
|
+
function matchRoutePattern(path, pattern) {
|
|
136
|
+
const canonical = normalizePath(path);
|
|
137
|
+
if (typeof pattern === "string") {
|
|
138
|
+
return canonical === normalizePath(pattern);
|
|
139
|
+
}
|
|
140
|
+
pattern.lastIndex = 0;
|
|
141
|
+
return pattern.test(canonical);
|
|
142
|
+
}
|
|
143
|
+
async function hashFragment(input) {
|
|
144
|
+
const buf = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
|
|
145
|
+
const bytes = new Uint8Array(buf);
|
|
146
|
+
let bin = "";
|
|
147
|
+
for (const b of bytes) bin += String.fromCharCode(b);
|
|
148
|
+
const b64url = btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
149
|
+
return b64url.slice(0, 16);
|
|
150
|
+
}
|
|
151
|
+
function readCookie(req, name) {
|
|
152
|
+
return parseCookieHeader(req.headers.cookie ?? void 0).get(name);
|
|
153
|
+
}
|
|
154
|
+
async function deriveKey(req, keyBy, cookieName, trustProxy = false) {
|
|
155
|
+
if (typeof keyBy === "function") return keyBy(req);
|
|
156
|
+
const ip = resolveClientIp(req, trustProxy);
|
|
157
|
+
switch (keyBy) {
|
|
158
|
+
case "session": {
|
|
159
|
+
const cookie = readCookie(req, cookieName);
|
|
160
|
+
return cookie ? `session:${await hashFragment(cookie)}` : `ip:${ip}`;
|
|
161
|
+
}
|
|
162
|
+
case "user": {
|
|
163
|
+
const userId = req.user?.id;
|
|
164
|
+
return userId ? `user:${userId}` : `ip:${ip}`;
|
|
165
|
+
}
|
|
166
|
+
case "ip":
|
|
167
|
+
default:
|
|
168
|
+
return `ip:${ip}`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function createRouteRateLimiter(config) {
|
|
172
|
+
const isFlat = "windowMs" in config && "max" in config && !("default" in config) && !("routes" in config);
|
|
173
|
+
const cfg = isFlat ? { default: config } : config;
|
|
174
|
+
const store = cfg.store ?? new InMemoryStore();
|
|
175
|
+
if (!(store instanceof InMemoryStore)) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
"createRouteRateLimiter: async RateLimitStore implementations require a dedicated async middleware path. Use the InMemoryStore default for the sync facade."
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
const inMemoryStore = store;
|
|
181
|
+
const keyBy = cfg.keyBy ?? "ip";
|
|
182
|
+
const cookieName = cfg.cookieName ?? "theo_session";
|
|
183
|
+
const trustProxy = cfg.trustProxy ?? false;
|
|
184
|
+
const patternList = [];
|
|
185
|
+
if (cfg.routes) {
|
|
186
|
+
for (const [pattern, c] of Object.entries(cfg.routes)) patternList.push([pattern, c]);
|
|
187
|
+
}
|
|
188
|
+
if (cfg.routePatterns) {
|
|
189
|
+
for (const tuple of cfg.routePatterns) patternList.push(tuple);
|
|
190
|
+
}
|
|
191
|
+
return async function checkRouteRateLimit(req) {
|
|
192
|
+
const url = req.url ?? "";
|
|
193
|
+
let matched;
|
|
194
|
+
for (const [pattern, c] of patternList) {
|
|
195
|
+
if (matchRoutePattern(url, pattern)) {
|
|
196
|
+
matched = c;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const effective = matched ?? cfg.default;
|
|
201
|
+
if (!effective) {
|
|
202
|
+
return { limited: false, headers: {} };
|
|
203
|
+
}
|
|
204
|
+
const bucketSuffix = typeof matched === "undefined" ? "*default*" : normalizePath(url);
|
|
205
|
+
const key = `${await deriveKey(req, keyBy, cookieName, trustProxy)}|${bucketSuffix}`;
|
|
206
|
+
const state = inMemoryStore.incrSync(key, effective.windowMs);
|
|
207
|
+
if (state.count > effective.max) {
|
|
208
|
+
const retryAfter = Math.ceil((state.resetAt - Date.now()) / 1e3);
|
|
209
|
+
return {
|
|
210
|
+
limited: true,
|
|
211
|
+
headers: {
|
|
212
|
+
"X-RateLimit-Limit": String(effective.max),
|
|
213
|
+
"X-RateLimit-Remaining": "0",
|
|
214
|
+
"Retry-After": String(retryAfter)
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
limited: false,
|
|
220
|
+
headers: {
|
|
221
|
+
"X-RateLimit-Limit": String(effective.max),
|
|
222
|
+
"X-RateLimit-Remaining": String(Math.max(0, effective.max - state.count))
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
99
228
|
// src/cli/commands/start/assert-sdk-compatible.ts
|
|
100
229
|
import { readFileSync } from "fs";
|
|
101
230
|
import { createRequire } from "module";
|
|
@@ -201,7 +330,7 @@ async function configureStorageManagerFromConfig(storageConfig) {
|
|
|
201
330
|
if (storageConfig === void 0 || storageConfig === null) return;
|
|
202
331
|
try {
|
|
203
332
|
const { getStorageManager } = await import("./storage-manager-3O5PDO6O.js");
|
|
204
|
-
const { storageSchema } = await import("./schema-
|
|
333
|
+
const { storageSchema } = await import("./schema-ZO3OSWVG.js");
|
|
205
334
|
const parsed = storageSchema.parse(storageConfig);
|
|
206
335
|
getStorageManager().configure(parsed);
|
|
207
336
|
} catch (err) {
|
|
@@ -358,9 +487,9 @@ async function loadCompiledController(absPath) {
|
|
|
358
487
|
return await import(pathToFileURL(absPath).href);
|
|
359
488
|
}
|
|
360
489
|
var X_REQUEST_ID = "x-request-id";
|
|
361
|
-
function applyRateLimit(c, method) {
|
|
490
|
+
async function applyRateLimit(c, method) {
|
|
362
491
|
if (!c.rateLimiter) return false;
|
|
363
|
-
const check = c.rateLimiter(c.req);
|
|
492
|
+
const check = await c.rateLimiter(c.req);
|
|
364
493
|
for (const [k, v] of Object.entries(check.headers)) c.res.setHeader(k, v);
|
|
365
494
|
if (check.limited) {
|
|
366
495
|
sendError(c.res, "RATE_LIMITED", "Too many requests", 429, void 0, c.requestId);
|
|
@@ -378,7 +507,7 @@ function applyRateLimit(c, method) {
|
|
|
378
507
|
async function tryServeAction(c) {
|
|
379
508
|
if (!c.url.startsWith("/api/__actions/")) return false;
|
|
380
509
|
c.res.setHeader(X_REQUEST_ID, c.requestId);
|
|
381
|
-
if (applyRateLimit(c, c.req.method ?? "POST")) return true;
|
|
510
|
+
if (await applyRateLimit(c, c.req.method ?? "POST")) return true;
|
|
382
511
|
const pathAfterPrefix = c.url.slice("/api/__actions/".length).split("?")[0];
|
|
383
512
|
const segments = pathAfterPrefix.split("/").filter(Boolean);
|
|
384
513
|
if (segments.length < 2) {
|
|
@@ -467,7 +596,7 @@ async function tryServeAgent(c) {
|
|
|
467
596
|
const urlPath = c.url.split("?")[0];
|
|
468
597
|
if (isApprovalPath(urlPath)) {
|
|
469
598
|
c.res.setHeader(X_REQUEST_ID, c.requestId);
|
|
470
|
-
if (applyRateLimit(c, c.req.method ?? "POST")) return true;
|
|
599
|
+
if (await applyRateLimit(c, c.req.method ?? "POST")) return true;
|
|
471
600
|
const method2 = (c.req.method ?? "POST").toUpperCase();
|
|
472
601
|
if (method2 !== "POST") {
|
|
473
602
|
sendError(
|
|
@@ -518,7 +647,7 @@ async function tryServeAgent(c) {
|
|
|
518
647
|
const agent = c.cachedAgents.find((a) => a.agentPath === urlPath);
|
|
519
648
|
if (!agent) return false;
|
|
520
649
|
c.res.setHeader(X_REQUEST_ID, c.requestId);
|
|
521
|
-
if (applyRateLimit(c, c.req.method ?? "POST")) return true;
|
|
650
|
+
if (await applyRateLimit(c, c.req.method ?? "POST")) return true;
|
|
522
651
|
const method = (c.req.method ?? "POST").toUpperCase();
|
|
523
652
|
if (method !== "POST") {
|
|
524
653
|
sendError(
|
|
@@ -570,7 +699,7 @@ async function tryServeAgent(c) {
|
|
|
570
699
|
async function tryServeApiRoute(c) {
|
|
571
700
|
if (!c.url.startsWith("/api/")) return false;
|
|
572
701
|
c.res.setHeader(X_REQUEST_ID, c.requestId);
|
|
573
|
-
if (applyRateLimit(c, c.req.method ?? "GET")) return true;
|
|
702
|
+
if (await applyRateLimit(c, c.req.method ?? "GET")) return true;
|
|
574
703
|
const match = matchRoute(c.url, c.cachedRoutes);
|
|
575
704
|
if (!match) {
|
|
576
705
|
if (c.controllersDistDir !== void 0) {
|
|
@@ -702,23 +831,24 @@ function send500(res, custom500Html) {
|
|
|
702
831
|
res.end(custom500Html ?? "<h1>500 \u2014 Server Error</h1>");
|
|
703
832
|
}
|
|
704
833
|
}
|
|
705
|
-
function withHoistedHead(htmlHead, ssrHtml) {
|
|
834
|
+
function withHoistedHead(htmlHead, ssrHtml, nonce) {
|
|
706
835
|
const { html, headTags } = extractHeadTags(ssrHtml);
|
|
707
|
-
|
|
836
|
+
const head = applyNonceToInlineScripts(injectIntoHead(htmlHead, headTags), nonce);
|
|
837
|
+
return { head, body: html };
|
|
708
838
|
}
|
|
709
839
|
function buildSsrHtml(ctx, result, nonce) {
|
|
710
840
|
if (typeof result === "string") {
|
|
711
|
-
const { head, body } = withHoistedHead(ctx.htmlHead, result);
|
|
841
|
+
const { head, body } = withHoistedHead(ctx.htmlHead, result, nonce);
|
|
712
842
|
return head + body + ctx.htmlTail;
|
|
713
843
|
}
|
|
714
844
|
if (isSsrRenderResult(result)) {
|
|
715
845
|
const rendered = asSsrRenderResult(result);
|
|
716
846
|
const dataJson = JSON.stringify(rendered.hydrationData).replace(/</g, "\\u003c");
|
|
717
847
|
const hydrationScript = `<script${nonce ? ` nonce="${nonce}"` : ""}>window.__staticRouterHydrationData=${dataJson}</script>`;
|
|
718
|
-
const { head, body } = withHoistedHead(ctx.htmlHead, rendered.html);
|
|
848
|
+
const { head, body } = withHoistedHead(ctx.htmlHead, rendered.html, nonce);
|
|
719
849
|
return head + body + hydrationScript + ctx.htmlTail;
|
|
720
850
|
}
|
|
721
|
-
return ctx.htmlHead + ctx.htmlTail;
|
|
851
|
+
return applyNonceToInlineScripts(ctx.htmlHead, nonce) + ctx.htmlTail;
|
|
722
852
|
}
|
|
723
853
|
async function handleSsrStreaming(ctx, req, res, url, nonce) {
|
|
724
854
|
if (!ctx.ssrStreamingEnabled || !ctx.ssrRenderStreaming) return false;
|
|
@@ -880,8 +1010,7 @@ async function startCommand(options) {
|
|
|
880
1010
|
wsRoutes: cachedWsRoutes,
|
|
881
1011
|
agents: cachedAgents
|
|
882
1012
|
} = loadRoutesAndActions(distDir, serverDir, config.agentsDir);
|
|
883
|
-
const
|
|
884
|
-
const rateLimiter = flatRateLimit ? createRateLimiter(flatRateLimit) : null;
|
|
1013
|
+
const rateLimiter = config.rateLimit ? createRouteRateLimiter(config.rateLimit) : null;
|
|
885
1014
|
const ssr = await setupSsr({
|
|
886
1015
|
distDir,
|
|
887
1016
|
indexHtml,
|
|
@@ -938,4 +1067,4 @@ export {
|
|
|
938
1067
|
resolveSsrEntry,
|
|
939
1068
|
startCommand
|
|
940
1069
|
};
|
|
941
|
-
//# sourceMappingURL=start-
|
|
1070
|
+
//# sourceMappingURL=start-KR2JJR7K.js.map
|