mates-fullstack 1.0.0-beta.1
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 +311 -0
- package/dist/arctic-auth.d.ts +101 -0
- package/dist/arctic-auth.d.ts.map +1 -0
- package/dist/arctic-auth.js +538 -0
- package/dist/arctic-auth.js.map +1 -0
- package/dist/asset-manifest.d.ts +14 -0
- package/dist/asset-manifest.d.ts.map +1 -0
- package/dist/asset-manifest.js +102 -0
- package/dist/asset-manifest.js.map +1 -0
- package/dist/browser.d.ts +18 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +25 -0
- package/dist/browser.js.map +1 -0
- package/dist/build-esbuild.d.ts +29 -0
- package/dist/build-esbuild.d.ts.map +1 -0
- package/dist/build-esbuild.js +699 -0
- package/dist/build-esbuild.js.map +1 -0
- package/dist/build-prod.d.ts +126 -0
- package/dist/build-prod.d.ts.map +1 -0
- package/dist/build-prod.js +1014 -0
- package/dist/build-prod.js.map +1 -0
- package/dist/cli-new.d.ts +14 -0
- package/dist/cli-new.d.ts.map +1 -0
- package/dist/cli-new.js +637 -0
- package/dist/cli-new.js.map +1 -0
- package/dist/client.d.ts +43 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +130 -0
- package/dist/client.js.map +1 -0
- package/dist/cors.d.ts +16 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +60 -0
- package/dist/cors.js.map +1 -0
- package/dist/ctx.d.ts +78 -0
- package/dist/ctx.d.ts.map +1 -0
- package/dist/ctx.js +280 -0
- package/dist/ctx.js.map +1 -0
- package/dist/dev-watcher.d.ts +23 -0
- package/dist/dev-watcher.d.ts.map +1 -0
- package/dist/dev-watcher.js +136 -0
- package/dist/dev-watcher.js.map +1 -0
- package/dist/docs-generator.d.ts +69 -0
- package/dist/docs-generator.d.ts.map +1 -0
- package/dist/docs-generator.js +557 -0
- package/dist/docs-generator.js.map +1 -0
- package/dist/docs-page.d.ts +20 -0
- package/dist/docs-page.d.ts.map +1 -0
- package/dist/docs-page.js +1152 -0
- package/dist/docs-page.js.map +1 -0
- package/dist/download.d.ts +78 -0
- package/dist/download.d.ts.map +1 -0
- package/dist/download.js +202 -0
- package/dist/download.js.map +1 -0
- package/dist/env-loader.d.ts +76 -0
- package/dist/env-loader.d.ts.map +1 -0
- package/dist/env-loader.js +213 -0
- package/dist/env-loader.js.map +1 -0
- package/dist/errors.d.ts +146 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +386 -0
- package/dist/errors.js.map +1 -0
- package/dist/head.d.ts +31 -0
- package/dist/head.d.ts.map +1 -0
- package/dist/head.js +245 -0
- package/dist/head.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/internal-prefixes.d.ts +16 -0
- package/dist/internal-prefixes.d.ts.map +1 -0
- package/dist/internal-prefixes.js +16 -0
- package/dist/internal-prefixes.js.map +1 -0
- package/dist/internal.d.ts +25 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +25 -0
- package/dist/internal.js.map +1 -0
- package/dist/jwt.d.ts +166 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +261 -0
- package/dist/jwt.js.map +1 -0
- package/dist/log.d.ts +44 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +66 -0
- package/dist/log.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +138 -0
- package/dist/logger.js.map +1 -0
- package/dist/main-runner.d.ts +59 -0
- package/dist/main-runner.d.ts.map +1 -0
- package/dist/main-runner.js +157 -0
- package/dist/main-runner.js.map +1 -0
- package/dist/mates-auth.d.ts +82 -0
- package/dist/mates-auth.d.ts.map +1 -0
- package/dist/mates-auth.js +323 -0
- package/dist/mates-auth.js.map +1 -0
- package/dist/middleware.d.ts +30 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +67 -0
- package/dist/middleware.js.map +1 -0
- package/dist/project-resolver.d.ts +102 -0
- package/dist/project-resolver.d.ts.map +1 -0
- package/dist/project-resolver.js +271 -0
- package/dist/project-resolver.js.map +1 -0
- package/dist/rate-limit.d.ts +37 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +109 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/redirect.d.ts +84 -0
- package/dist/redirect.d.ts.map +1 -0
- package/dist/redirect.js +105 -0
- package/dist/redirect.js.map +1 -0
- package/dist/renderer.d.ts +91 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +630 -0
- package/dist/renderer.js.map +1 -0
- package/dist/request-logger.d.ts +12 -0
- package/dist/request-logger.d.ts.map +1 -0
- package/dist/request-logger.js +55 -0
- package/dist/request-logger.js.map +1 -0
- package/dist/rest.d.ts +25 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +93 -0
- package/dist/rest.js.map +1 -0
- package/dist/router.d.ts +71 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +222 -0
- package/dist/router.js.map +1 -0
- package/dist/rpc-registry.d.ts +84 -0
- package/dist/rpc-registry.d.ts.map +1 -0
- package/dist/rpc-registry.js +271 -0
- package/dist/rpc-registry.js.map +1 -0
- package/dist/rpc-runner.d.ts +82 -0
- package/dist/rpc-runner.d.ts.map +1 -0
- package/dist/rpc-runner.js +564 -0
- package/dist/rpc-runner.js.map +1 -0
- package/dist/sanitize.d.ts +61 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +193 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/security-headers.d.ts +114 -0
- package/dist/security-headers.d.ts.map +1 -0
- package/dist/security-headers.js +121 -0
- package/dist/security-headers.js.map +1 -0
- package/dist/server-fn.d.ts +323 -0
- package/dist/server-fn.d.ts.map +1 -0
- package/dist/server-fn.js +373 -0
- package/dist/server-fn.js.map +1 -0
- package/dist/server-public.d.ts +13 -0
- package/dist/server-public.d.ts.map +1 -0
- package/dist/server-public.js +12 -0
- package/dist/server-public.js.map +1 -0
- package/dist/server-timeout.d.ts +38 -0
- package/dist/server-timeout.d.ts.map +1 -0
- package/dist/server-timeout.js +46 -0
- package/dist/server-timeout.js.map +1 -0
- package/dist/server.d.ts +100 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1218 -0
- package/dist/server.js.map +1 -0
- package/dist/socket-router.d.ts +153 -0
- package/dist/socket-router.d.ts.map +1 -0
- package/dist/socket-router.js +612 -0
- package/dist/socket-router.js.map +1 -0
- package/dist/sso.d.ts +90 -0
- package/dist/sso.d.ts.map +1 -0
- package/dist/sso.js +261 -0
- package/dist/sso.js.map +1 -0
- package/dist/ssr-context.d.ts +49 -0
- package/dist/ssr-context.d.ts.map +1 -0
- package/dist/ssr-context.js +85 -0
- package/dist/ssr-context.js.map +1 -0
- package/dist/ssr-globals.d.ts +32 -0
- package/dist/ssr-globals.d.ts.map +1 -0
- package/dist/ssr-globals.js +1010 -0
- package/dist/ssr-globals.js.map +1 -0
- package/dist/ssr-template.d.ts +73 -0
- package/dist/ssr-template.d.ts.map +1 -0
- package/dist/ssr-template.js +507 -0
- package/dist/ssr-template.js.map +1 -0
- package/dist/stack-mapper.d.ts +25 -0
- package/dist/stack-mapper.d.ts.map +1 -0
- package/dist/stack-mapper.js +139 -0
- package/dist/stack-mapper.js.map +1 -0
- package/dist/stream.d.ts +89 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +299 -0
- package/dist/stream.js.map +1 -0
- package/dist/upload.d.ts +69 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +110 -0
- package/dist/upload.js.map +1 -0
- package/dist/validate.d.ts +58 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +89 -0
- package/dist/validate.js.map +1 -0
- package/dist/verify-package.d.ts +3 -0
- package/dist/verify-package.d.ts.map +1 -0
- package/dist/verify-package.js +128 -0
- package/dist/verify-package.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — middleware.ts
|
|
3
|
+
*/
|
|
4
|
+
import type { Context } from "./ctx.js";
|
|
5
|
+
export type RequestHook = (c: Context) => Response | void | Promise<Response | void>;
|
|
6
|
+
export type ResponseHook = (c: Context) => void | Promise<void>;
|
|
7
|
+
export type BeforeRPCHook = (data: Record<string, unknown>, c: Context) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
8
|
+
export interface AfterRPCInfo {
|
|
9
|
+
moduleId: string;
|
|
10
|
+
fnName: string;
|
|
11
|
+
duration: number;
|
|
12
|
+
}
|
|
13
|
+
export type AfterRPCHook = (result: unknown, c: Context, info: AfterRPCInfo) => unknown | Promise<unknown>;
|
|
14
|
+
export declare function onRequest(hook: RequestHook): void;
|
|
15
|
+
export declare function onResponse(hook: ResponseHook): void;
|
|
16
|
+
export declare function onBeforeRPC(hook: BeforeRPCHook): void;
|
|
17
|
+
export declare function onAfterRPC(hook: AfterRPCHook): void;
|
|
18
|
+
export declare function runRequestHooks(c: Context): Promise<RequestHookResult>;
|
|
19
|
+
export declare function runResponseHooks(c: Context): Promise<void>;
|
|
20
|
+
export declare function runBeforeRPCHooks(data: Record<string, unknown>, c: Context): Promise<Record<string, unknown>>;
|
|
21
|
+
export declare function runAfterRPCHooks(result: unknown, c: Context, info: AfterRPCInfo): Promise<unknown>;
|
|
22
|
+
export interface RequestHookResult {
|
|
23
|
+
response: Response | null;
|
|
24
|
+
}
|
|
25
|
+
export declare function clearMiddleware(): void;
|
|
26
|
+
export declare function middlewareStats(): {
|
|
27
|
+
request: number;
|
|
28
|
+
response: number;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,MAAM,WAAW,GAAG,CACxB,CAAC,EAAE,OAAO,KACP,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAEhD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhE,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,CAAC,EAAE,OAAO,KACP,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,YAAY,GAAG,CACzB,MAAM,EAAE,OAAO,EACf,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,YAAY,KACf,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAOhC,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAEjD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAEnD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAErD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAEnD;AAED,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAM5E;AAED,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQhE;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,CAAC,EAAE,OAAO,GACT,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,OAAO,EACf,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC3B;AAED,wBAAgB,eAAe,IAAI,IAAI,CAKtC;AAED,wBAAgB,eAAe,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAEvE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — middleware.ts
|
|
3
|
+
*/
|
|
4
|
+
import { devError } from "./log.js";
|
|
5
|
+
let _requestHooks = [];
|
|
6
|
+
let _responseHooks = [];
|
|
7
|
+
let _beforeRPCHooks = [];
|
|
8
|
+
let _afterRPCHooks = [];
|
|
9
|
+
export function onRequest(hook) {
|
|
10
|
+
_requestHooks.push(hook);
|
|
11
|
+
}
|
|
12
|
+
export function onResponse(hook) {
|
|
13
|
+
_responseHooks.push(hook);
|
|
14
|
+
}
|
|
15
|
+
export function onBeforeRPC(hook) {
|
|
16
|
+
_beforeRPCHooks.push(hook);
|
|
17
|
+
}
|
|
18
|
+
export function onAfterRPC(hook) {
|
|
19
|
+
_afterRPCHooks.push(hook);
|
|
20
|
+
}
|
|
21
|
+
export async function runRequestHooks(c) {
|
|
22
|
+
for (const hook of _requestHooks) {
|
|
23
|
+
const result = await hook(c);
|
|
24
|
+
if (result instanceof Response)
|
|
25
|
+
return { response: result };
|
|
26
|
+
}
|
|
27
|
+
return { response: null };
|
|
28
|
+
}
|
|
29
|
+
export async function runResponseHooks(c) {
|
|
30
|
+
for (const hook of _responseHooks) {
|
|
31
|
+
try {
|
|
32
|
+
await hook(c);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
devError(`onResponse hook error: ${err?.message ?? err}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export async function runBeforeRPCHooks(data, c) {
|
|
40
|
+
let current = data;
|
|
41
|
+
for (const hook of _beforeRPCHooks) {
|
|
42
|
+
current = await hook(current, c);
|
|
43
|
+
}
|
|
44
|
+
return current;
|
|
45
|
+
}
|
|
46
|
+
export async function runAfterRPCHooks(result, c, info) {
|
|
47
|
+
let current = result;
|
|
48
|
+
for (const hook of _afterRPCHooks) {
|
|
49
|
+
try {
|
|
50
|
+
current = await hook(current, c, info);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
devError(`onAfterRPC hook error: ${err?.message ?? err}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return current;
|
|
57
|
+
}
|
|
58
|
+
export function clearMiddleware() {
|
|
59
|
+
_requestHooks = [];
|
|
60
|
+
_responseHooks = [];
|
|
61
|
+
_beforeRPCHooks = [];
|
|
62
|
+
_afterRPCHooks = [];
|
|
63
|
+
}
|
|
64
|
+
export function middlewareStats() {
|
|
65
|
+
return { request: _requestHooks.length, response: _responseHooks.length };
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAyBpC,IAAI,aAAa,GAAkB,EAAE,CAAC;AACtC,IAAI,cAAc,GAAmB,EAAE,CAAC;AACxC,IAAI,eAAe,GAAoB,EAAE,CAAC;AAC1C,IAAI,cAAc,GAAmB,EAAE,CAAC;AAExC,MAAM,UAAU,SAAS,CAAC,IAAiB;IACzC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAkB;IAC3C,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAmB;IAC7C,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAkB;IAC3C,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,CAAU;IAC9C,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,MAAM,YAAY,QAAQ;YAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC9D,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,CAAU;IAC/C,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,QAAQ,CAAC,0BAA0B,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA6B,EAC7B,CAAU;IAEV,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAe,EACf,CAAU,EACV,IAAkB;IAElB,IAAI,OAAO,GAAG,MAAM,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,QAAQ,CAAC,0BAA0B,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAMD,MAAM,UAAU,eAAe;IAC7B,aAAa,GAAG,EAAE,CAAC;IACnB,cAAc,GAAG,EAAE,CAAC;IACpB,eAAe,GAAG,EAAE,CAAC;IACrB,cAAc,GAAG,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — project-resolver.ts
|
|
3
|
+
*
|
|
4
|
+
* Convention-based project path resolution. No mates.config.ts needed.
|
|
5
|
+
*
|
|
6
|
+
* The framework infers all paths from the project folder structure:
|
|
7
|
+
*
|
|
8
|
+
* my-app/
|
|
9
|
+
* ├── client/
|
|
10
|
+
* │ ├── components/
|
|
11
|
+
* │ ├── styles/
|
|
12
|
+
* │ ├── App.ts ← root SPA component with Router()
|
|
13
|
+
* │ └── client.ts ← browser hydration entry point
|
|
14
|
+
* ├── server/
|
|
15
|
+
* │ ├── api/ ← RPC functions
|
|
16
|
+
* │ ├── socket/ ← WebSocket handlers
|
|
17
|
+
* │ ├── helpers/ ← server-only utilities (never scanned)
|
|
18
|
+
* │ └── main.ts ← per-request middleware hook
|
|
19
|
+
* ├── shared/
|
|
20
|
+
* │ └── types/ ← shared TypeScript types
|
|
21
|
+
* └── public/ ← static assets
|
|
22
|
+
*
|
|
23
|
+
* All paths are absolute. Missing directories are null — the framework
|
|
24
|
+
* gracefully disables the corresponding feature rather than crashing.
|
|
25
|
+
*/
|
|
26
|
+
export interface ResolvedPaths {
|
|
27
|
+
/** Absolute path to the project root (directory containing package.json). */
|
|
28
|
+
projectRoot: string;
|
|
29
|
+
/**
|
|
30
|
+
* client/App.ts (or .js) — the root SPA component.
|
|
31
|
+
* The server imports this and renders it directly for every SSR request.
|
|
32
|
+
* pathAtom is set to the request pathname before rendering so the
|
|
33
|
+
* app's Router() renders the correct page.
|
|
34
|
+
* null if not found (SSR disabled).
|
|
35
|
+
*/
|
|
36
|
+
appFile: string | null;
|
|
37
|
+
/** client/client.ts (or .js) — browser entry point. null if not found. */
|
|
38
|
+
clientEntry: string | null;
|
|
39
|
+
/** public/ — static assets served as-is. null if not found. */
|
|
40
|
+
publicDir: string | null;
|
|
41
|
+
/** server/api/ — RPC function registry. null if not found. */
|
|
42
|
+
apiDir: string | null;
|
|
43
|
+
/** server/socket/ — WebSocket handlers. null if not found. */
|
|
44
|
+
socketDir: string | null;
|
|
45
|
+
/**
|
|
46
|
+
* server/helpers/ — server-only utilities.
|
|
47
|
+
* Never scanned for routes. Never entered the browser bundle.
|
|
48
|
+
* null if not found (no warning — it's optional).
|
|
49
|
+
*/
|
|
50
|
+
helpersDir: string | null;
|
|
51
|
+
/** server/main.ts (or .js) — per-request hook. null if not present. */
|
|
52
|
+
mainFile: string | null;
|
|
53
|
+
/** shared/ — types and constants shared by both sides. null if not found. */
|
|
54
|
+
sharedDir: string | null;
|
|
55
|
+
/** shared/types/ — TypeScript types. null if not found. */
|
|
56
|
+
sharedTypesDir: string | null;
|
|
57
|
+
/** dist/ — output directory for production builds and SSG. */
|
|
58
|
+
outDir: string;
|
|
59
|
+
/** HTTP port. process.env.PORT → 3000 fallback. */
|
|
60
|
+
port: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve all project paths from the project root.
|
|
64
|
+
*
|
|
65
|
+
* @param projectRoot - Absolute path to the project root.
|
|
66
|
+
* Usually the result of findProjectRoot(process.cwd()).
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveProjectPaths(projectRoot: string): ResolvedPaths;
|
|
69
|
+
export declare function resolveProductionRuntimePaths(sourcePaths: ResolvedPaths): ResolvedPaths;
|
|
70
|
+
/**
|
|
71
|
+
* Walk up from `startDir` until a directory containing `package.json` is found.
|
|
72
|
+
* Returns the absolute path to that directory.
|
|
73
|
+
*
|
|
74
|
+
* @throws Error if no package.json is found before the filesystem root.
|
|
75
|
+
*/
|
|
76
|
+
export declare function findProjectRoot(startDir: string): string;
|
|
77
|
+
/**
|
|
78
|
+
* Log warnings for missing directories that affect core features.
|
|
79
|
+
* Called once at startup after resolving paths.
|
|
80
|
+
*/
|
|
81
|
+
export declare function warnMissingPaths(paths: ResolvedPaths, log: (msg: string) => void): void;
|
|
82
|
+
/**
|
|
83
|
+
* Returns a human-readable summary of resolved paths for startup logging.
|
|
84
|
+
*/
|
|
85
|
+
export declare function formatPaths(paths: ResolvedPaths): string;
|
|
86
|
+
/**
|
|
87
|
+
* Resolve the path to the mates package in the project's node_modules.
|
|
88
|
+
*
|
|
89
|
+
* Tries multiple resolution strategies:
|
|
90
|
+
* 1. projectRoot/node_modules/mates/dist/index.esm.js
|
|
91
|
+
* 2. Standard Node.js module resolution from projectRoot
|
|
92
|
+
* 3. Standard Node.js module resolution from __dirname (mates-fullstack itself)
|
|
93
|
+
*
|
|
94
|
+
* @throws Error if mates cannot be found.
|
|
95
|
+
*/
|
|
96
|
+
export declare function findMatesPath(projectRoot: string): string;
|
|
97
|
+
/**
|
|
98
|
+
* Returns true if `suspectedChild` is inside `parent`.
|
|
99
|
+
* Used to prevent path traversal attacks in static file serving.
|
|
100
|
+
*/
|
|
101
|
+
export declare function isPathInside(parent: string, suspectedChild: string): boolean;
|
|
102
|
+
//# sourceMappingURL=project-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-resolver.d.ts","sourceRoot":"","sources":["../src/project-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAQH,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB,2DAA2D;IAC3D,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IAEf,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;CACd;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CA+DtE;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,aAAa,GACzB,aAAa,CAqBf;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoBxD;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GACzB,IAAI,CAqBN;AAID;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAexD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAgDzD;AAcD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAI5E"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — project-resolver.ts
|
|
3
|
+
*
|
|
4
|
+
* Convention-based project path resolution. No mates.config.ts needed.
|
|
5
|
+
*
|
|
6
|
+
* The framework infers all paths from the project folder structure:
|
|
7
|
+
*
|
|
8
|
+
* my-app/
|
|
9
|
+
* ├── client/
|
|
10
|
+
* │ ├── components/
|
|
11
|
+
* │ ├── styles/
|
|
12
|
+
* │ ├── App.ts ← root SPA component with Router()
|
|
13
|
+
* │ └── client.ts ← browser hydration entry point
|
|
14
|
+
* ├── server/
|
|
15
|
+
* │ ├── api/ ← RPC functions
|
|
16
|
+
* │ ├── socket/ ← WebSocket handlers
|
|
17
|
+
* │ ├── helpers/ ← server-only utilities (never scanned)
|
|
18
|
+
* │ └── main.ts ← per-request middleware hook
|
|
19
|
+
* ├── shared/
|
|
20
|
+
* │ └── types/ ← shared TypeScript types
|
|
21
|
+
* └── public/ ← static assets
|
|
22
|
+
*
|
|
23
|
+
* All paths are absolute. Missing directories are null — the framework
|
|
24
|
+
* gracefully disables the corresponding feature rather than crashing.
|
|
25
|
+
*/
|
|
26
|
+
import fs from "node:fs";
|
|
27
|
+
import path from "node:path";
|
|
28
|
+
import { devWarn } from "./log.js";
|
|
29
|
+
// ─── Resolver ─────────────────────────────────────────────────────────────────
|
|
30
|
+
/**
|
|
31
|
+
* Resolve all project paths from the project root.
|
|
32
|
+
*
|
|
33
|
+
* @param projectRoot - Absolute path to the project root.
|
|
34
|
+
* Usually the result of findProjectRoot(process.cwd()).
|
|
35
|
+
*/
|
|
36
|
+
export function resolveProjectPaths(projectRoot) {
|
|
37
|
+
const abs = (...parts) => path.resolve(projectRoot, ...parts);
|
|
38
|
+
// ── client/ ──────────────────────────────────────────────────────────────────────
|
|
39
|
+
const appFile = _existsFile(abs("client", "App.ts"))
|
|
40
|
+
? abs("client", "App.ts")
|
|
41
|
+
: _existsFile(abs("client", "App.js"))
|
|
42
|
+
? abs("client", "App.js")
|
|
43
|
+
: null;
|
|
44
|
+
const clientEntry = _existsFile(abs("client", "client.ts"))
|
|
45
|
+
? abs("client", "client.ts")
|
|
46
|
+
: _existsFile(abs("client", "client.js"))
|
|
47
|
+
? abs("client", "client.js")
|
|
48
|
+
: null;
|
|
49
|
+
// ── server/ ───────────────────────────────────────────────────────────────
|
|
50
|
+
const apiDir = _existsDir(abs("server", "api")) ? abs("server", "api") : null;
|
|
51
|
+
const socketDir = _existsDir(abs("server", "socket"))
|
|
52
|
+
? abs("server", "socket")
|
|
53
|
+
: null;
|
|
54
|
+
const helpersDir = _existsDir(abs("server", "helpers"))
|
|
55
|
+
? abs("server", "helpers")
|
|
56
|
+
: null;
|
|
57
|
+
const mainFile = _existsFile(abs("server", "main.ts"))
|
|
58
|
+
? abs("server", "main.ts")
|
|
59
|
+
: _existsFile(abs("server", "main.js"))
|
|
60
|
+
? abs("server", "main.js")
|
|
61
|
+
: null;
|
|
62
|
+
// ── shared/ ───────────────────────────────────────────────────────────────
|
|
63
|
+
const sharedDir = _existsDir(abs("shared")) ? abs("shared") : null;
|
|
64
|
+
const sharedTypesDir = _existsDir(abs("shared", "types"))
|
|
65
|
+
? abs("shared", "types")
|
|
66
|
+
: null;
|
|
67
|
+
// ── public/ ───────────────────────────────────────────────────────────────
|
|
68
|
+
const publicDir = _existsDir(abs("public")) ? abs("public") : null;
|
|
69
|
+
// ── dist/ (always resolved, may not exist yet) ────────────────────────────
|
|
70
|
+
const outDir = abs("dist");
|
|
71
|
+
// ── Port ──────────────────────────────────────────────────────────────────
|
|
72
|
+
const port = _resolvePort();
|
|
73
|
+
return {
|
|
74
|
+
projectRoot,
|
|
75
|
+
appFile,
|
|
76
|
+
clientEntry,
|
|
77
|
+
publicDir,
|
|
78
|
+
apiDir,
|
|
79
|
+
socketDir,
|
|
80
|
+
helpersDir,
|
|
81
|
+
mainFile,
|
|
82
|
+
sharedDir,
|
|
83
|
+
sharedTypesDir,
|
|
84
|
+
outDir,
|
|
85
|
+
port,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function resolveProductionRuntimePaths(sourcePaths) {
|
|
89
|
+
const serverDir = path.join(sourcePaths.outDir, "server");
|
|
90
|
+
const publicDir = path.join(sourcePaths.outDir, "public");
|
|
91
|
+
const appFile = path.join(serverDir, "App.js");
|
|
92
|
+
const mainFile = path.join(serverDir, "main.js");
|
|
93
|
+
const apiDir = path.join(serverDir, "api");
|
|
94
|
+
const socketDir = path.join(serverDir, "socket");
|
|
95
|
+
const sharedDir = path.join(serverDir, "shared");
|
|
96
|
+
const sharedTypesDir = path.join(sharedDir, "types");
|
|
97
|
+
return {
|
|
98
|
+
...sourcePaths,
|
|
99
|
+
appFile: _existsFile(appFile) ? appFile : null,
|
|
100
|
+
publicDir: _existsDir(publicDir) ? publicDir : null,
|
|
101
|
+
apiDir: _existsDir(apiDir) ? apiDir : null,
|
|
102
|
+
socketDir: _existsDir(socketDir) ? socketDir : null,
|
|
103
|
+
helpersDir: null,
|
|
104
|
+
mainFile: _existsFile(mainFile) ? mainFile : null,
|
|
105
|
+
sharedDir: _existsDir(sharedDir) ? sharedDir : null,
|
|
106
|
+
sharedTypesDir: _existsDir(sharedTypesDir) ? sharedTypesDir : null,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Walk up from `startDir` until a directory containing `package.json` is found.
|
|
111
|
+
* Returns the absolute path to that directory.
|
|
112
|
+
*
|
|
113
|
+
* @throws Error if no package.json is found before the filesystem root.
|
|
114
|
+
*/
|
|
115
|
+
export function findProjectRoot(startDir) {
|
|
116
|
+
let current = path.resolve(startDir);
|
|
117
|
+
while (true) {
|
|
118
|
+
if (_existsFile(path.join(current, "package.json"))) {
|
|
119
|
+
return current;
|
|
120
|
+
}
|
|
121
|
+
const parent = path.dirname(current);
|
|
122
|
+
// Reached filesystem root without finding package.json
|
|
123
|
+
if (parent === current) {
|
|
124
|
+
throw new Error(`mates-fullstack: could not find package.json in "${startDir}" or any parent directory.\n` +
|
|
125
|
+
`Make sure you are running from inside your project.`);
|
|
126
|
+
}
|
|
127
|
+
current = parent;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// ─── Startup warnings ─────────────────────────────────────────────────────────
|
|
131
|
+
/**
|
|
132
|
+
* Log warnings for missing directories that affect core features.
|
|
133
|
+
* Called once at startup after resolving paths.
|
|
134
|
+
*/
|
|
135
|
+
export function warnMissingPaths(paths, log) {
|
|
136
|
+
if (!paths.appFile) {
|
|
137
|
+
log("warn: client/App.ts not found — SSR is disabled. " +
|
|
138
|
+
"Create client/App.ts with your root Router() component.");
|
|
139
|
+
}
|
|
140
|
+
if (!paths.clientEntry) {
|
|
141
|
+
log("warn: client/client.ts not found — no browser entry point. " +
|
|
142
|
+
"Create client/client.ts that calls renderX(App, ...).");
|
|
143
|
+
}
|
|
144
|
+
if (!paths.apiDir) {
|
|
145
|
+
log("warn: server/api/ not found — RPC functions are disabled. " +
|
|
146
|
+
"Create server/api/ to define server functions.");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// ─── Path utilities ───────────────────────────────────────────────────────────
|
|
150
|
+
/**
|
|
151
|
+
* Returns a human-readable summary of resolved paths for startup logging.
|
|
152
|
+
*/
|
|
153
|
+
export function formatPaths(paths) {
|
|
154
|
+
const lines = [
|
|
155
|
+
` project root : ${paths.projectRoot}`,
|
|
156
|
+
` port : ${paths.port}`,
|
|
157
|
+
` app : ${paths.appFile ?? "(SSR disabled)"}`,
|
|
158
|
+
` client entry : ${paths.clientEntry ?? "(not found)"}`,
|
|
159
|
+
` api (RPC) : ${paths.apiDir ?? "(disabled)"}`,
|
|
160
|
+
` socket : ${paths.socketDir ?? "(none)"}`,
|
|
161
|
+
` helpers : ${paths.helpersDir ?? "(none)"}`,
|
|
162
|
+
` main.ts : ${paths.mainFile ?? "(none)"}`,
|
|
163
|
+
` shared : ${paths.sharedDir ?? "(none)"}`,
|
|
164
|
+
` public : ${paths.publicDir ?? "(none)"}`,
|
|
165
|
+
` out : ${paths.outDir}`,
|
|
166
|
+
];
|
|
167
|
+
return lines.join("\n");
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Resolve the path to the mates package in the project's node_modules.
|
|
171
|
+
*
|
|
172
|
+
* Tries multiple resolution strategies:
|
|
173
|
+
* 1. projectRoot/node_modules/mates/dist/index.esm.js
|
|
174
|
+
* 2. Standard Node.js module resolution from projectRoot
|
|
175
|
+
* 3. Standard Node.js module resolution from __dirname (mates-fullstack itself)
|
|
176
|
+
*
|
|
177
|
+
* @throws Error if mates cannot be found.
|
|
178
|
+
*/
|
|
179
|
+
export function findMatesPath(projectRoot) {
|
|
180
|
+
// Find mates package.json, then use the ESM entry (module field) if available.
|
|
181
|
+
// Using the same file that user ESM code resolves to is critical for module identity —
|
|
182
|
+
// two different file paths = two different module instances = hooks break.
|
|
183
|
+
const pkgJsonPath = _findPackageJson("mates", projectRoot);
|
|
184
|
+
if (pkgJsonPath) {
|
|
185
|
+
const pkgDir = path.dirname(pkgJsonPath);
|
|
186
|
+
try {
|
|
187
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
|
|
188
|
+
// Prefer ESM entry: exports["."]["import"] > module > main
|
|
189
|
+
const esmEntry = pkg.exports?.["."]?.["import"] ?? pkg.module ?? pkg.main;
|
|
190
|
+
if (esmEntry) {
|
|
191
|
+
const resolved = path.resolve(pkgDir, esmEntry);
|
|
192
|
+
if (_existsFile(resolved)) {
|
|
193
|
+
// Resolve symlinks — critical for module identity in ESM cache
|
|
194
|
+
try {
|
|
195
|
+
return fs.realpathSync(resolved);
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return resolved;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
/* fall through */
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Fallback: look for ESM dist directly
|
|
208
|
+
const direct = path.join(projectRoot, "node_modules", "mates", "dist", "index.esm.js");
|
|
209
|
+
if (_existsFile(direct))
|
|
210
|
+
return direct;
|
|
211
|
+
// Fallback: resolve CJS from mates-fullstack's location
|
|
212
|
+
try {
|
|
213
|
+
return require.resolve("mates");
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
/* fall through */
|
|
217
|
+
}
|
|
218
|
+
throw new Error(`mates-fullstack: could not find the "mates" package.\n` +
|
|
219
|
+
`Make sure mates is installed: npm install mates`);
|
|
220
|
+
}
|
|
221
|
+
function _findPackageJson(pkgName, fromDir) {
|
|
222
|
+
const candidates = [
|
|
223
|
+
path.join(fromDir, "node_modules", pkgName, "package.json"),
|
|
224
|
+
path.join(fromDir, "..", "node_modules", pkgName, "package.json"),
|
|
225
|
+
path.join(fromDir, "..", "..", "node_modules", pkgName, "package.json"),
|
|
226
|
+
];
|
|
227
|
+
for (const c of candidates) {
|
|
228
|
+
if (_existsFile(path.resolve(c)))
|
|
229
|
+
return path.resolve(c);
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Returns true if `suspectedChild` is inside `parent`.
|
|
235
|
+
* Used to prevent path traversal attacks in static file serving.
|
|
236
|
+
*/
|
|
237
|
+
export function isPathInside(parent, suspectedChild) {
|
|
238
|
+
const rel = path.relative(parent, suspectedChild);
|
|
239
|
+
// If the relative path starts with ".." or is absolute, it's outside
|
|
240
|
+
return !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
241
|
+
}
|
|
242
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
243
|
+
function _existsDir(p) {
|
|
244
|
+
try {
|
|
245
|
+
return fs.statSync(p).isDirectory();
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function _existsFile(p) {
|
|
252
|
+
try {
|
|
253
|
+
return fs.statSync(p).isFile();
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function _resolvePort() {
|
|
260
|
+
const envPort = process.env.PORT;
|
|
261
|
+
if (envPort) {
|
|
262
|
+
const parsed = parseInt(envPort, 10);
|
|
263
|
+
if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {
|
|
264
|
+
return parsed;
|
|
265
|
+
}
|
|
266
|
+
// Invalid PORT env var — warn and fall through to default
|
|
267
|
+
devWarn(`invalid PORT="${envPort}" — using default 3000`);
|
|
268
|
+
}
|
|
269
|
+
return 3000;
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=project-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-resolver.js","sourceRoot":"","sources":["../src/project-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Context } from "./ctx.js";
|
|
2
|
+
export interface RateLimitOptions {
|
|
3
|
+
/** Maximum requests allowed per window. */
|
|
4
|
+
max: number;
|
|
5
|
+
/** Window size. Number = seconds. String = "30s", "1m", "15m", "1h", "1d". Default: "1m". */
|
|
6
|
+
window?: number | string;
|
|
7
|
+
/**
|
|
8
|
+
* Derive a rate-limit key from the context.
|
|
9
|
+
* Default: client IP from X-Forwarded-For / X-Real-IP headers.
|
|
10
|
+
*/
|
|
11
|
+
key?: (c: Context) => string;
|
|
12
|
+
/** Error message when limit is exceeded. Default: "Too many requests". */
|
|
13
|
+
message?: string;
|
|
14
|
+
/** HTTP status code when limit is exceeded. Default: 429. */
|
|
15
|
+
statusCode?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Only apply rate limiting to requests whose path starts with this prefix.
|
|
18
|
+
* When omitted, all requests are rate-limited.
|
|
19
|
+
*
|
|
20
|
+
* @example pathPrefix: "/auth" — only limit OAuth and login routes
|
|
21
|
+
*/
|
|
22
|
+
pathPrefix?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Register a sliding-window rate limiter for all (or prefixed) requests.
|
|
26
|
+
*
|
|
27
|
+
* Call once at module level in server/main.ts.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // Limit all requests to 100 per minute per IP
|
|
31
|
+
* rateLimit({ max: 100, window: "1m" });
|
|
32
|
+
*
|
|
33
|
+
* // Tighter limit on auth routes
|
|
34
|
+
* rateLimit({ max: 10, window: "15m", pathPrefix: "/auth" });
|
|
35
|
+
*/
|
|
36
|
+
export declare function rateLimit(options: RateLimitOptions): void;
|
|
37
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAmDzD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { onRequest } from "./middleware.js";
|
|
2
|
+
/**
|
|
3
|
+
* Register a sliding-window rate limiter for all (or prefixed) requests.
|
|
4
|
+
*
|
|
5
|
+
* Call once at module level in server/main.ts.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Limit all requests to 100 per minute per IP
|
|
9
|
+
* rateLimit({ max: 100, window: "1m" });
|
|
10
|
+
*
|
|
11
|
+
* // Tighter limit on auth routes
|
|
12
|
+
* rateLimit({ max: 10, window: "15m", pathPrefix: "/auth" });
|
|
13
|
+
*/
|
|
14
|
+
export function rateLimit(options) {
|
|
15
|
+
const windowMs = parseWindow(options.window ?? "1m") * 1000;
|
|
16
|
+
const max = options.max;
|
|
17
|
+
const message = options.message ?? "Too many requests";
|
|
18
|
+
const statusCode = options.statusCode ?? 429;
|
|
19
|
+
const pathPrefix = options.pathPrefix;
|
|
20
|
+
const getKey = options.key ?? defaultKey;
|
|
21
|
+
const store = new Map();
|
|
22
|
+
onRequest((c) => {
|
|
23
|
+
if (pathPrefix) {
|
|
24
|
+
const pathname = new URL(c.req.raw.url).pathname;
|
|
25
|
+
if (!pathname.startsWith(pathPrefix))
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const key = getKey(c);
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
let record = store.get(key);
|
|
31
|
+
if (!record || now > record.resetAt) {
|
|
32
|
+
record = { count: 0, resetAt: now + windowMs };
|
|
33
|
+
store.set(key, record);
|
|
34
|
+
}
|
|
35
|
+
record.count++;
|
|
36
|
+
// Evict expired entries when the store grows large
|
|
37
|
+
if (store.size > 10000) {
|
|
38
|
+
for (const [k, v] of store) {
|
|
39
|
+
if (now > v.resetAt)
|
|
40
|
+
store.delete(k);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const remaining = Math.max(0, max - record.count);
|
|
44
|
+
const resetSecs = Math.ceil(record.resetAt / 1000);
|
|
45
|
+
const retryAfter = Math.ceil((record.resetAt - now) / 1000);
|
|
46
|
+
if (record.count > max) {
|
|
47
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
48
|
+
status: statusCode,
|
|
49
|
+
headers: {
|
|
50
|
+
"content-type": "application/json",
|
|
51
|
+
"retry-after": String(retryAfter),
|
|
52
|
+
"x-ratelimit-limit": String(max),
|
|
53
|
+
"x-ratelimit-remaining": "0",
|
|
54
|
+
"x-ratelimit-reset": String(resetSecs),
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function defaultKey(c) {
|
|
61
|
+
// Only trust forwarding headers when trustProxy is enabled.
|
|
62
|
+
// Otherwise, attackers can spoof their rate-limit identity.
|
|
63
|
+
if (c.trustProxy) {
|
|
64
|
+
const forwarded = c.reqHeaders["x-forwarded-for"];
|
|
65
|
+
if (forwarded)
|
|
66
|
+
return forwarded.split(",")[0].trim();
|
|
67
|
+
const realIp = c.reqHeaders["x-real-ip"];
|
|
68
|
+
if (realIp)
|
|
69
|
+
return realIp.trim();
|
|
70
|
+
const cfIp = c.reqHeaders["cf-connecting-ip"];
|
|
71
|
+
if (cfIp)
|
|
72
|
+
return cfIp.trim();
|
|
73
|
+
}
|
|
74
|
+
// Fallback: socket remote address
|
|
75
|
+
try {
|
|
76
|
+
// Access the raw Node.js IncomingMessage's socket address
|
|
77
|
+
const raw = c.req?.raw;
|
|
78
|
+
if (raw && typeof raw === "object") {
|
|
79
|
+
if (typeof raw.socket?.remoteAddress === "string") {
|
|
80
|
+
return raw.socket.remoteAddress;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
/* ignore */
|
|
86
|
+
}
|
|
87
|
+
return "unknown";
|
|
88
|
+
}
|
|
89
|
+
function parseWindow(value) {
|
|
90
|
+
if (typeof value === "number")
|
|
91
|
+
return Math.floor(value);
|
|
92
|
+
const str = value.trim();
|
|
93
|
+
if (/^\d+$/.test(str))
|
|
94
|
+
return Number(str);
|
|
95
|
+
const match = str.match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d)$/i);
|
|
96
|
+
if (!match) {
|
|
97
|
+
throw new Error(`[mates-fullstack] rateLimit: invalid window "${value}". Use a number (seconds) or a string like "30s", "15m", "1h".`);
|
|
98
|
+
}
|
|
99
|
+
const amount = Number(match[1]);
|
|
100
|
+
const unit = match[2].toLowerCase();
|
|
101
|
+
const multipliers = {
|
|
102
|
+
s: 1,
|
|
103
|
+
m: 60,
|
|
104
|
+
h: 3600,
|
|
105
|
+
d: 86400,
|
|
106
|
+
};
|
|
107
|
+
return Math.floor(amount * multipliers[unit]);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"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"}
|