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 @@
|
|
|
1
|
+
{"version":3,"file":"request-logger.d.ts","sourceRoot":"","sources":["../src/request-logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAKD,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,IAAI,CAwBtE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — request-logger.ts
|
|
3
|
+
*
|
|
4
|
+
* Drop-in request/response logging middleware.
|
|
5
|
+
* Logs every incoming request and framework-managed REST/RPC responses.
|
|
6
|
+
*/
|
|
7
|
+
import { onRequest, onResponse } from "./middleware.js";
|
|
8
|
+
import { logger, generateRequestId } from "./logger.js";
|
|
9
|
+
const _KEY_START = "__mates_log_start";
|
|
10
|
+
const _KEY_ID = "__mates_log_id";
|
|
11
|
+
export function requestLogger(options = {}) {
|
|
12
|
+
const skip = options.skip ?? [];
|
|
13
|
+
onRequest((c) => {
|
|
14
|
+
const url = new URL(c.req.raw.url);
|
|
15
|
+
if (skip.some((pattern) => pattern.test(url.pathname)))
|
|
16
|
+
return;
|
|
17
|
+
const requestId = generateRequestId();
|
|
18
|
+
c.set(_KEY_ID, requestId);
|
|
19
|
+
c.set(_KEY_START, performance.now());
|
|
20
|
+
c.resHeaders["x-request-id"] = requestId;
|
|
21
|
+
logger.withRequest(requestId).info(`→ ${c.req.method} ${url.pathname}`, {
|
|
22
|
+
method: c.req.method,
|
|
23
|
+
path: url.pathname,
|
|
24
|
+
ip: resolveIp(c),
|
|
25
|
+
...(url.search ? { query: url.search } : {}),
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
onResponse((c) => {
|
|
29
|
+
const status = typeof c.resStatus === "number" ? c.resStatus : 200;
|
|
30
|
+
logOutcome(c, status);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function logOutcome(c, status) {
|
|
34
|
+
const requestId = c.get(_KEY_ID);
|
|
35
|
+
const startTime = c.get(_KEY_START);
|
|
36
|
+
if (!requestId || startTime === undefined)
|
|
37
|
+
return;
|
|
38
|
+
const ms = Number((performance.now() - startTime).toFixed(1));
|
|
39
|
+
const log = logger.withRequest(requestId);
|
|
40
|
+
if (status >= 500)
|
|
41
|
+
log.error(`← ${status}`, { status, ms });
|
|
42
|
+
else if (status >= 400)
|
|
43
|
+
log.warn(`← ${status}`, { status, ms });
|
|
44
|
+
else
|
|
45
|
+
log.info(`← ${status}`, { status, ms });
|
|
46
|
+
}
|
|
47
|
+
function resolveIp(c) {
|
|
48
|
+
return (c.reqHeaders["cf-connecting-ip"]?.trim() ??
|
|
49
|
+
c.reqHeaders["x-forwarded-for"]
|
|
50
|
+
?.split(",")[0]
|
|
51
|
+
.trim() ??
|
|
52
|
+
c.reqHeaders["x-real-ip"]?.trim() ??
|
|
53
|
+
"unknown");
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=request-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-logger.js","sourceRoot":"","sources":["../src/request-logger.ts"],"names":[],"mappings":"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"}
|
package/dist/rest.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — rest.ts
|
|
3
|
+
*
|
|
4
|
+
* REST router — Hono-style single-ctx per handler.
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from "./ctx.js";
|
|
7
|
+
export type RestMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS" | "HEAD";
|
|
8
|
+
export type RestHandler = (c: Context) => Response | void | Promise<Response | void>;
|
|
9
|
+
export declare function clearRestRoutes(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Match and run a REST route for the given request.
|
|
12
|
+
* Called by server.ts after request middleware, before RPC.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export declare function matchAndRunRest(c: Context): Promise<Response | null>;
|
|
16
|
+
export declare const rest: {
|
|
17
|
+
get: (path: string, handler: RestHandler) => void;
|
|
18
|
+
post: (path: string, handler: RestHandler) => void;
|
|
19
|
+
put: (path: string, handler: RestHandler) => void;
|
|
20
|
+
patch: (path: string, handler: RestHandler) => void;
|
|
21
|
+
delete: (path: string, handler: RestHandler) => void;
|
|
22
|
+
options: (path: string, handler: RestHandler) => void;
|
|
23
|
+
head: (path: string, handler: RestHandler) => void;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=rest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,MAAM,GACN,KAAK,GACL,OAAO,GACP,QAAQ,GACR,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CACxB,CAAC,EAAE,OAAO,KACP,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAchD,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAqB1E;AAaD,eAAO,MAAM,IAAI;gBACH,MAAM,WAAW,WAAW,KAAG,IAAI;iBAElC,MAAM,WAAW,WAAW,KAAG,IAAI;gBAEpC,MAAM,WAAW,WAAW,KAAG,IAAI;kBAEjC,MAAM,WAAW,WAAW,KAAG,IAAI;mBAElC,MAAM,WAAW,WAAW,KAAG,IAAI;oBAElC,MAAM,WAAW,WAAW,KAAG,IAAI;iBAEtC,MAAM,WAAW,WAAW,KAAG,IAAI;CAEjD,CAAC"}
|
package/dist/rest.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — rest.ts
|
|
3
|
+
*
|
|
4
|
+
* REST router — Hono-style single-ctx per handler.
|
|
5
|
+
*/
|
|
6
|
+
let _restRoutes = [];
|
|
7
|
+
export function clearRestRoutes() {
|
|
8
|
+
_restRoutes = [];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Match and run a REST route for the given request.
|
|
12
|
+
* Called by server.ts after request middleware, before RPC.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export async function matchAndRunRest(c) {
|
|
16
|
+
const method = c.req.method.toUpperCase();
|
|
17
|
+
for (const route of _restRoutes) {
|
|
18
|
+
if (route.method !== method)
|
|
19
|
+
continue;
|
|
20
|
+
const params = _matchRoute(route, c.req.path);
|
|
21
|
+
if (!params)
|
|
22
|
+
continue;
|
|
23
|
+
// Clone context with route params injected
|
|
24
|
+
const routeCtx = Object.assign(Object.create(Object.getPrototypeOf(c)), c, {
|
|
25
|
+
req: { ...c.req, params, param: (name) => params[name] },
|
|
26
|
+
});
|
|
27
|
+
const returned = await route.handler(routeCtx);
|
|
28
|
+
if (returned instanceof Response)
|
|
29
|
+
return returned;
|
|
30
|
+
const impl = routeCtx;
|
|
31
|
+
return impl._response?.() ?? new Response(null, { status: 204 });
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
// ─── Registration ─────────────────────────────────────────────────────────────
|
|
36
|
+
function _register(method, pattern, handler) {
|
|
37
|
+
const compiled = _compileRoute(method, pattern, handler);
|
|
38
|
+
_restRoutes.push(compiled);
|
|
39
|
+
}
|
|
40
|
+
export const rest = {
|
|
41
|
+
get: (path, handler) => _register("GET", path, handler),
|
|
42
|
+
post: (path, handler) => _register("POST", path, handler),
|
|
43
|
+
put: (path, handler) => _register("PUT", path, handler),
|
|
44
|
+
patch: (path, handler) => _register("PATCH", path, handler),
|
|
45
|
+
delete: (path, handler) => _register("DELETE", path, handler),
|
|
46
|
+
options: (path, handler) => _register("OPTIONS", path, handler),
|
|
47
|
+
head: (path, handler) => _register("HEAD", path, handler),
|
|
48
|
+
};
|
|
49
|
+
// ─── Route compilation ────────────────────────────────────────────────────────
|
|
50
|
+
function _compileRoute(method, pattern, handler) {
|
|
51
|
+
const normalized = _normalizePath(pattern);
|
|
52
|
+
const paramNames = [];
|
|
53
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
54
|
+
const regexParts = parts.map((part) => {
|
|
55
|
+
if (part.startsWith(":")) {
|
|
56
|
+
const name = part.slice(1);
|
|
57
|
+
if (!name)
|
|
58
|
+
throw new Error(`Invalid REST route pattern: ${pattern}`);
|
|
59
|
+
paramNames.push(name);
|
|
60
|
+
return "([^/]+)";
|
|
61
|
+
}
|
|
62
|
+
if (part === "*") {
|
|
63
|
+
paramNames.push("*");
|
|
64
|
+
return "(.*)";
|
|
65
|
+
}
|
|
66
|
+
return _escapeRegex(part);
|
|
67
|
+
});
|
|
68
|
+
const regex = new RegExp(`^/${regexParts.join("/")}/?$`);
|
|
69
|
+
return { method, pattern: normalized, regex, paramNames, handler };
|
|
70
|
+
}
|
|
71
|
+
function _matchRoute(route, pathname) {
|
|
72
|
+
const match = route.regex.exec(_normalizePath(pathname));
|
|
73
|
+
if (!match)
|
|
74
|
+
return null;
|
|
75
|
+
const params = {};
|
|
76
|
+
for (let i = 0; i < route.paramNames.length; i += 1) {
|
|
77
|
+
try {
|
|
78
|
+
params[route.paramNames[i]] = decodeURIComponent(match[i + 1] ?? "");
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Malformed percent-encoding — treat as no match
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return params;
|
|
86
|
+
}
|
|
87
|
+
function _normalizePath(path) {
|
|
88
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
89
|
+
}
|
|
90
|
+
function _escapeRegex(value) {
|
|
91
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=rest.js.map
|
package/dist/rest.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"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"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-ssr — router.ts
|
|
3
|
+
*
|
|
4
|
+
* Scans the pages directory and builds a route table.
|
|
5
|
+
* Matches incoming URL pathnames to a page file + extracted params.
|
|
6
|
+
*
|
|
7
|
+
* Routing rules:
|
|
8
|
+
* src/pages/index.ts → /
|
|
9
|
+
* src/pages/about.ts → /about
|
|
10
|
+
* src/pages/blog/index.ts → /blog
|
|
11
|
+
* src/pages/blog/[slug].ts → /blog/:slug → params: { slug: "hello" }
|
|
12
|
+
* src/pages/[...all].ts → /* (catch-all / 404 fallback)
|
|
13
|
+
*
|
|
14
|
+
* Page file exports:
|
|
15
|
+
* default export → the page Component (required)
|
|
16
|
+
* export const layout → layout Component wrapping this page (optional)
|
|
17
|
+
* export const meta → { title?, description? } for <head> (optional)
|
|
18
|
+
*/
|
|
19
|
+
export interface RouteEntry {
|
|
20
|
+
/** Absolute path to the page file on disk. */
|
|
21
|
+
filePath: string;
|
|
22
|
+
/**
|
|
23
|
+
* URL pattern used for matching, e.g. "/blog/:slug".
|
|
24
|
+
* Catch-all routes use the special pattern "/*".
|
|
25
|
+
*/
|
|
26
|
+
pattern: string;
|
|
27
|
+
/**
|
|
28
|
+
* Ordered list of dynamic segment names, e.g. ["slug"] for /blog/:slug.
|
|
29
|
+
* Empty for static routes.
|
|
30
|
+
*/
|
|
31
|
+
paramNames: string[];
|
|
32
|
+
/** True when this is a [...all] catch-all route. */
|
|
33
|
+
isCatchAll: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface MatchResult {
|
|
36
|
+
/** The matched route entry. */
|
|
37
|
+
route: RouteEntry;
|
|
38
|
+
/** Extracted URL params, e.g. { slug: "hello-world" }. */
|
|
39
|
+
params: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Recursively scan `pagesDir` and return a sorted route table.
|
|
43
|
+
*
|
|
44
|
+
* Sort order guarantees correct priority during matching:
|
|
45
|
+
* 1. Static routes before dynamic routes (e.g. /about before /:id)
|
|
46
|
+
* 2. Deeper (more specific) routes before shallower ones
|
|
47
|
+
* 3. Catch-all routes always last
|
|
48
|
+
*/
|
|
49
|
+
export declare function scanRoutes(pagesDir: string): RouteEntry[];
|
|
50
|
+
/**
|
|
51
|
+
* Match a URL pathname against the route table.
|
|
52
|
+
* Returns the first match with extracted params, or null if nothing matches.
|
|
53
|
+
*
|
|
54
|
+
* Call this on every incoming request.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const routes = scanRoutes('./src/pages');
|
|
58
|
+
* const match = matchRoute(routes, '/blog/hello-world');
|
|
59
|
+
* // match.route.pattern === '/blog/:slug'
|
|
60
|
+
* // match.params === { slug: 'hello-world' }
|
|
61
|
+
*/
|
|
62
|
+
export declare function matchRoute(routes: RouteEntry[], pathname: string): MatchResult | null;
|
|
63
|
+
/**
|
|
64
|
+
* Watch the pages directory for changes and call `onChange` when any
|
|
65
|
+
* page file is added, removed, or renamed (not on content edits — those
|
|
66
|
+
* are handled by re-importing the module).
|
|
67
|
+
*
|
|
68
|
+
* Returns a cleanup function that stops watching.
|
|
69
|
+
*/
|
|
70
|
+
export declare function watchRoutes(pagesDir: string, onChange: () => void): () => void;
|
|
71
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,oDAAoD;IACpD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,KAAK,EAAE,UAAU,CAAC;IAClB,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAID;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAazD;AA8HD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAAE,EACpB,QAAQ,EAAE,MAAM,GACf,WAAW,GAAG,IAAI,CAepB;AAyCD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,IAAI,GACnB,MAAM,IAAI,CAUZ"}
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-ssr — router.ts
|
|
3
|
+
*
|
|
4
|
+
* Scans the pages directory and builds a route table.
|
|
5
|
+
* Matches incoming URL pathnames to a page file + extracted params.
|
|
6
|
+
*
|
|
7
|
+
* Routing rules:
|
|
8
|
+
* src/pages/index.ts → /
|
|
9
|
+
* src/pages/about.ts → /about
|
|
10
|
+
* src/pages/blog/index.ts → /blog
|
|
11
|
+
* src/pages/blog/[slug].ts → /blog/:slug → params: { slug: "hello" }
|
|
12
|
+
* src/pages/[...all].ts → /* (catch-all / 404 fallback)
|
|
13
|
+
*
|
|
14
|
+
* Page file exports:
|
|
15
|
+
* default export → the page Component (required)
|
|
16
|
+
* export const layout → layout Component wrapping this page (optional)
|
|
17
|
+
* export const meta → { title?, description? } for <head> (optional)
|
|
18
|
+
*/
|
|
19
|
+
import fs from 'node:fs';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
// ─── Scanner ──────────────────────────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Recursively scan `pagesDir` and return a sorted route table.
|
|
24
|
+
*
|
|
25
|
+
* Sort order guarantees correct priority during matching:
|
|
26
|
+
* 1. Static routes before dynamic routes (e.g. /about before /:id)
|
|
27
|
+
* 2. Deeper (more specific) routes before shallower ones
|
|
28
|
+
* 3. Catch-all routes always last
|
|
29
|
+
*/
|
|
30
|
+
export function scanRoutes(pagesDir) {
|
|
31
|
+
const absDir = path.resolve(pagesDir);
|
|
32
|
+
if (!fs.existsSync(absDir)) {
|
|
33
|
+
throw new Error(`mates-ssr: pages directory not found at "${absDir}".\n` +
|
|
34
|
+
`Make sure pagesDir in your mates.config.ts points to the right folder.`);
|
|
35
|
+
}
|
|
36
|
+
const entries = [];
|
|
37
|
+
collectFiles(absDir, absDir, entries);
|
|
38
|
+
return sortRoutes(entries);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Walk the directory tree and push a RouteEntry for each page file.
|
|
42
|
+
*/
|
|
43
|
+
function collectFiles(baseDir, currentDir, entries) {
|
|
44
|
+
const items = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
45
|
+
for (const item of items) {
|
|
46
|
+
const fullPath = path.join(currentDir, item.name);
|
|
47
|
+
if (item.isDirectory()) {
|
|
48
|
+
collectFiles(baseDir, fullPath, entries);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
// Only .ts and .js files; skip non-page files
|
|
52
|
+
if (!isPageFile(item.name))
|
|
53
|
+
continue;
|
|
54
|
+
const entry = filePathToRoute(baseDir, fullPath);
|
|
55
|
+
if (entry)
|
|
56
|
+
entries.push(entry);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns true if the file should be treated as a page.
|
|
61
|
+
* Skips hidden files, test files, and non-TS/JS files.
|
|
62
|
+
*/
|
|
63
|
+
function isPageFile(filename) {
|
|
64
|
+
if (filename.startsWith('_'))
|
|
65
|
+
return false; // _layout.ts etc. — private
|
|
66
|
+
if (filename.startsWith('.'))
|
|
67
|
+
return false; // hidden files
|
|
68
|
+
if (filename.includes('.test.') || filename.includes('.spec.'))
|
|
69
|
+
return false;
|
|
70
|
+
return /\.(ts|js|tsx|jsx)$/.test(filename);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Convert an absolute file path to a RouteEntry.
|
|
74
|
+
*
|
|
75
|
+
* Examples (baseDir = /project/src/pages):
|
|
76
|
+
* /project/src/pages/index.ts → pattern: /
|
|
77
|
+
* /project/src/pages/about.ts → pattern: /about
|
|
78
|
+
* /project/src/pages/blog/index.ts → pattern: /blog
|
|
79
|
+
* /project/src/pages/blog/[slug].ts → pattern: /blog/:slug
|
|
80
|
+
* /project/src/pages/[...all].ts → pattern: /* (catch-all)
|
|
81
|
+
*/
|
|
82
|
+
function filePathToRoute(baseDir, filePath) {
|
|
83
|
+
// Relative path from pages dir, e.g. "blog/[slug].ts"
|
|
84
|
+
const rel = path.relative(baseDir, filePath);
|
|
85
|
+
// Split into segments without extension
|
|
86
|
+
const withoutExt = rel.replace(/\.(ts|js|tsx|jsx)$/, '');
|
|
87
|
+
const rawSegments = withoutExt.split(path.sep);
|
|
88
|
+
// Drop trailing "index" segment — blog/index → /blog
|
|
89
|
+
const segments = rawSegments[rawSegments.length - 1] === 'index'
|
|
90
|
+
? rawSegments.slice(0, -1)
|
|
91
|
+
: rawSegments;
|
|
92
|
+
const paramNames = [];
|
|
93
|
+
let isCatchAll = false;
|
|
94
|
+
const patternParts = [];
|
|
95
|
+
for (const seg of segments) {
|
|
96
|
+
if (seg.startsWith('[...') && seg.endsWith(']')) {
|
|
97
|
+
// [...all] — catch-all
|
|
98
|
+
isCatchAll = true;
|
|
99
|
+
paramNames.push(seg.slice(4, -1)); // extract "all"
|
|
100
|
+
patternParts.push('*');
|
|
101
|
+
}
|
|
102
|
+
else if (seg.startsWith('[') && seg.endsWith(']')) {
|
|
103
|
+
// [slug] — dynamic segment
|
|
104
|
+
const name = seg.slice(1, -1);
|
|
105
|
+
paramNames.push(name);
|
|
106
|
+
patternParts.push(`:${name}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
patternParts.push(seg);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const pattern = patternParts.length === 0
|
|
113
|
+
? '/'
|
|
114
|
+
: '/' + patternParts.join('/');
|
|
115
|
+
return {
|
|
116
|
+
filePath,
|
|
117
|
+
pattern,
|
|
118
|
+
paramNames,
|
|
119
|
+
isCatchAll,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Sort routes so the most specific match wins:
|
|
124
|
+
* 1. Catch-all routes sink to the bottom
|
|
125
|
+
* 2. Static routes (no params) beat dynamic routes of the same depth
|
|
126
|
+
* 3. Deeper routes beat shallower routes (more segments = more specific)
|
|
127
|
+
*/
|
|
128
|
+
function sortRoutes(entries) {
|
|
129
|
+
return [...entries].sort((a, b) => {
|
|
130
|
+
// Catch-all always last
|
|
131
|
+
if (a.isCatchAll && !b.isCatchAll)
|
|
132
|
+
return 1;
|
|
133
|
+
if (!a.isCatchAll && b.isCatchAll)
|
|
134
|
+
return -1;
|
|
135
|
+
const aSegs = a.pattern.split('/').filter(Boolean).length;
|
|
136
|
+
const bSegs = b.pattern.split('/').filter(Boolean).length;
|
|
137
|
+
// More segments = more specific = higher priority
|
|
138
|
+
if (aSegs !== bSegs)
|
|
139
|
+
return bSegs - aSegs;
|
|
140
|
+
// Same depth: static beats dynamic
|
|
141
|
+
const aDynamic = a.paramNames.length;
|
|
142
|
+
const bDynamic = b.paramNames.length;
|
|
143
|
+
return aDynamic - bDynamic;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// ─── Matcher ──────────────────────────────────────────────────────────────────
|
|
147
|
+
/**
|
|
148
|
+
* Match a URL pathname against the route table.
|
|
149
|
+
* Returns the first match with extracted params, or null if nothing matches.
|
|
150
|
+
*
|
|
151
|
+
* Call this on every incoming request.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* const routes = scanRoutes('./src/pages');
|
|
155
|
+
* const match = matchRoute(routes, '/blog/hello-world');
|
|
156
|
+
* // match.route.pattern === '/blog/:slug'
|
|
157
|
+
* // match.params === { slug: 'hello-world' }
|
|
158
|
+
*/
|
|
159
|
+
export function matchRoute(routes, pathname) {
|
|
160
|
+
// Normalise: strip trailing slash except for "/"
|
|
161
|
+
const normalised = pathname.length > 1 && pathname.endsWith('/')
|
|
162
|
+
? pathname.slice(0, -1)
|
|
163
|
+
: pathname;
|
|
164
|
+
for (const route of routes) {
|
|
165
|
+
const params = tryMatch(route, normalised);
|
|
166
|
+
if (params !== null) {
|
|
167
|
+
return { route, params };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Try to match a single route against a pathname.
|
|
174
|
+
* Returns extracted params on success, or null on no match.
|
|
175
|
+
*/
|
|
176
|
+
function tryMatch(route, pathname) {
|
|
177
|
+
// Catch-all matches everything
|
|
178
|
+
if (route.isCatchAll) {
|
|
179
|
+
return { [route.paramNames[0] ?? 'all']: pathname };
|
|
180
|
+
}
|
|
181
|
+
const routeSegments = route.pattern.split('/').filter(Boolean);
|
|
182
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
183
|
+
// Segment count must match exactly for non-catch-all routes
|
|
184
|
+
if (routeSegments.length !== pathSegments.length)
|
|
185
|
+
return null;
|
|
186
|
+
const params = {};
|
|
187
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
188
|
+
const routeSeg = routeSegments[i];
|
|
189
|
+
const pathSeg = pathSegments[i];
|
|
190
|
+
if (routeSeg.startsWith(':')) {
|
|
191
|
+
// Dynamic segment — capture the value
|
|
192
|
+
params[routeSeg.slice(1)] = decodeURIComponent(pathSeg);
|
|
193
|
+
}
|
|
194
|
+
else if (routeSeg !== pathSeg) {
|
|
195
|
+
// Static segment mismatch
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return params;
|
|
200
|
+
}
|
|
201
|
+
// ─── Hot-reload helper ────────────────────────────────────────────────────────
|
|
202
|
+
/**
|
|
203
|
+
* Watch the pages directory for changes and call `onChange` when any
|
|
204
|
+
* page file is added, removed, or renamed (not on content edits — those
|
|
205
|
+
* are handled by re-importing the module).
|
|
206
|
+
*
|
|
207
|
+
* Returns a cleanup function that stops watching.
|
|
208
|
+
*/
|
|
209
|
+
export function watchRoutes(pagesDir, onChange) {
|
|
210
|
+
const absDir = path.resolve(pagesDir);
|
|
211
|
+
const watcher = fs.watch(absDir, { recursive: true }, (event, filename) => {
|
|
212
|
+
if (!filename)
|
|
213
|
+
return;
|
|
214
|
+
if (!isPageFile(path.basename(filename)))
|
|
215
|
+
return;
|
|
216
|
+
// Only re-scan on add/remove (rename events), not on content changes
|
|
217
|
+
if (event === 'rename')
|
|
218
|
+
onChange();
|
|
219
|
+
});
|
|
220
|
+
return () => watcher.close();
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — rpc-registry.ts
|
|
3
|
+
*
|
|
4
|
+
* Scans server/api/ and registers every exported async function as an RPC endpoint.
|
|
5
|
+
*
|
|
6
|
+
* URL derivation:
|
|
7
|
+
* server/api/users.ts + getUsers → POST /api/users/getUsers
|
|
8
|
+
* server/api/posts/index.ts + getPosts → POST /api/posts/getPosts
|
|
9
|
+
* server/api/auth.ts + login → POST /api/auth/login
|
|
10
|
+
*
|
|
11
|
+
* The URL is also the test/Postman endpoint:
|
|
12
|
+
* POST /api/users/getUsers
|
|
13
|
+
* Content-Type: application/json
|
|
14
|
+
* { "page": 0 }
|
|
15
|
+
*
|
|
16
|
+
* Rules for what gets registered:
|
|
17
|
+
* ✅ Exported async functions
|
|
18
|
+
* ✅ Plain exported functions (warned but registered)
|
|
19
|
+
* ❌ default export (page component convention)
|
|
20
|
+
* ❌ Non-function exports (types, constants)
|
|
21
|
+
* ❌ Reserved names: loader, meta, layout, staticPaths, onConnect, onDisconnect
|
|
22
|
+
* ❌ Functions named "then" or "catch" (conflicts with Promise protocol)
|
|
23
|
+
* ❌ Files starting with _ or containing .test. / .spec.
|
|
24
|
+
*
|
|
25
|
+
* Dev mode:
|
|
26
|
+
* Files are re-imported with a cache-busting timestamp on every rescan.
|
|
27
|
+
* The watcher triggers a rescan on file add/remove/rename.
|
|
28
|
+
* Content edits are picked up because the cache-bust forces a fresh import.
|
|
29
|
+
*/
|
|
30
|
+
export interface RpcEntry {
|
|
31
|
+
/** Full URL path, e.g. /api/users/getUsers */
|
|
32
|
+
url: string;
|
|
33
|
+
/** Absolute path to the source file */
|
|
34
|
+
filePath: string;
|
|
35
|
+
/** Exported function name */
|
|
36
|
+
fnName: string;
|
|
37
|
+
/** The actual function — never reaches the browser */
|
|
38
|
+
fn: (...args: any[]) => Promise<unknown>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Scan server/api/ and populate the registry.
|
|
42
|
+
* Call once at startup. In dev mode, call again after file changes
|
|
43
|
+
* or use watchRpcFunctions() for automatic rescanning.
|
|
44
|
+
*/
|
|
45
|
+
export declare function scanRpcFunctions(apiDir: string, dev?: boolean): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Look up a registered RPC function by its URL.
|
|
48
|
+
* Returns null if not found.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* lookupRpcFn("/api/users/getUsers")
|
|
52
|
+
*/
|
|
53
|
+
export declare function lookupRpcFn(url: string): RpcEntry | null;
|
|
54
|
+
/**
|
|
55
|
+
* Returns all registered RPC entries.
|
|
56
|
+
* Used by the docs generator and startup logging.
|
|
57
|
+
*/
|
|
58
|
+
export declare function listRpcFunctions(): RpcEntry[];
|
|
59
|
+
/**
|
|
60
|
+
* Returns the number of registered RPC functions.
|
|
61
|
+
*/
|
|
62
|
+
export declare function rpcRegistrySize(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Clear the registry. Used before a rescan or in tests.
|
|
65
|
+
*/
|
|
66
|
+
export declare function clearRpcRegistry(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Watch server/api/ for file changes and trigger a rescan.
|
|
69
|
+
* Returns a cleanup function that stops the watcher.
|
|
70
|
+
*
|
|
71
|
+
* Only responds to file add/remove/rename events — content edits are
|
|
72
|
+
* handled by the cache-bust import in dev mode.
|
|
73
|
+
*/
|
|
74
|
+
export declare function watchRpcFunctions(apiDir: string, onChange: (event: string, filename: string) => void): () => void;
|
|
75
|
+
/**
|
|
76
|
+
* Derive the RPC URL for a function exported from a file.
|
|
77
|
+
*
|
|
78
|
+
* Examples (apiDir = /project/server/api):
|
|
79
|
+
* /project/server/api/users.ts + getUsers → /api/users/getUsers
|
|
80
|
+
* /project/server/api/posts/index.ts + getPosts → /api/posts/getPosts
|
|
81
|
+
* /project/server/api/auth.ts + login → /api/auth/login
|
|
82
|
+
*/
|
|
83
|
+
export declare function deriveRpcUrl(apiDir: string, filePath: string, fnName: string): string;
|
|
84
|
+
//# sourceMappingURL=rpc-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-registry.d.ts","sourceRoot":"","sources":["../src/rpc-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAQH,MAAM,WAAW,QAAQ;IACvB,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAgCD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,GAAG,UAAQ,GACV,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAIxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,QAAQ,EAAE,CAE7C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAClD,MAAM,IAAI,CAoBZ;AAID;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,CAoBR"}
|