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.
Files changed (202) hide show
  1. package/README.md +311 -0
  2. package/dist/arctic-auth.d.ts +101 -0
  3. package/dist/arctic-auth.d.ts.map +1 -0
  4. package/dist/arctic-auth.js +538 -0
  5. package/dist/arctic-auth.js.map +1 -0
  6. package/dist/asset-manifest.d.ts +14 -0
  7. package/dist/asset-manifest.d.ts.map +1 -0
  8. package/dist/asset-manifest.js +102 -0
  9. package/dist/asset-manifest.js.map +1 -0
  10. package/dist/browser.d.ts +18 -0
  11. package/dist/browser.d.ts.map +1 -0
  12. package/dist/browser.js +25 -0
  13. package/dist/browser.js.map +1 -0
  14. package/dist/build-esbuild.d.ts +29 -0
  15. package/dist/build-esbuild.d.ts.map +1 -0
  16. package/dist/build-esbuild.js +699 -0
  17. package/dist/build-esbuild.js.map +1 -0
  18. package/dist/build-prod.d.ts +126 -0
  19. package/dist/build-prod.d.ts.map +1 -0
  20. package/dist/build-prod.js +1014 -0
  21. package/dist/build-prod.js.map +1 -0
  22. package/dist/cli-new.d.ts +14 -0
  23. package/dist/cli-new.d.ts.map +1 -0
  24. package/dist/cli-new.js +637 -0
  25. package/dist/cli-new.js.map +1 -0
  26. package/dist/client.d.ts +43 -0
  27. package/dist/client.d.ts.map +1 -0
  28. package/dist/client.js +130 -0
  29. package/dist/client.js.map +1 -0
  30. package/dist/cors.d.ts +16 -0
  31. package/dist/cors.d.ts.map +1 -0
  32. package/dist/cors.js +60 -0
  33. package/dist/cors.js.map +1 -0
  34. package/dist/ctx.d.ts +78 -0
  35. package/dist/ctx.d.ts.map +1 -0
  36. package/dist/ctx.js +280 -0
  37. package/dist/ctx.js.map +1 -0
  38. package/dist/dev-watcher.d.ts +23 -0
  39. package/dist/dev-watcher.d.ts.map +1 -0
  40. package/dist/dev-watcher.js +136 -0
  41. package/dist/dev-watcher.js.map +1 -0
  42. package/dist/docs-generator.d.ts +69 -0
  43. package/dist/docs-generator.d.ts.map +1 -0
  44. package/dist/docs-generator.js +557 -0
  45. package/dist/docs-generator.js.map +1 -0
  46. package/dist/docs-page.d.ts +20 -0
  47. package/dist/docs-page.d.ts.map +1 -0
  48. package/dist/docs-page.js +1152 -0
  49. package/dist/docs-page.js.map +1 -0
  50. package/dist/download.d.ts +78 -0
  51. package/dist/download.d.ts.map +1 -0
  52. package/dist/download.js +202 -0
  53. package/dist/download.js.map +1 -0
  54. package/dist/env-loader.d.ts +76 -0
  55. package/dist/env-loader.d.ts.map +1 -0
  56. package/dist/env-loader.js +213 -0
  57. package/dist/env-loader.js.map +1 -0
  58. package/dist/errors.d.ts +146 -0
  59. package/dist/errors.d.ts.map +1 -0
  60. package/dist/errors.js +386 -0
  61. package/dist/errors.js.map +1 -0
  62. package/dist/head.d.ts +31 -0
  63. package/dist/head.d.ts.map +1 -0
  64. package/dist/head.js +245 -0
  65. package/dist/head.js.map +1 -0
  66. package/dist/index.d.ts +30 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +30 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/internal-prefixes.d.ts +16 -0
  71. package/dist/internal-prefixes.d.ts.map +1 -0
  72. package/dist/internal-prefixes.js +16 -0
  73. package/dist/internal-prefixes.js.map +1 -0
  74. package/dist/internal.d.ts +25 -0
  75. package/dist/internal.d.ts.map +1 -0
  76. package/dist/internal.js +25 -0
  77. package/dist/internal.js.map +1 -0
  78. package/dist/jwt.d.ts +166 -0
  79. package/dist/jwt.d.ts.map +1 -0
  80. package/dist/jwt.js +261 -0
  81. package/dist/jwt.js.map +1 -0
  82. package/dist/log.d.ts +44 -0
  83. package/dist/log.d.ts.map +1 -0
  84. package/dist/log.js +66 -0
  85. package/dist/log.js.map +1 -0
  86. package/dist/logger.d.ts +76 -0
  87. package/dist/logger.d.ts.map +1 -0
  88. package/dist/logger.js +138 -0
  89. package/dist/logger.js.map +1 -0
  90. package/dist/main-runner.d.ts +59 -0
  91. package/dist/main-runner.d.ts.map +1 -0
  92. package/dist/main-runner.js +157 -0
  93. package/dist/main-runner.js.map +1 -0
  94. package/dist/mates-auth.d.ts +82 -0
  95. package/dist/mates-auth.d.ts.map +1 -0
  96. package/dist/mates-auth.js +323 -0
  97. package/dist/mates-auth.js.map +1 -0
  98. package/dist/middleware.d.ts +30 -0
  99. package/dist/middleware.d.ts.map +1 -0
  100. package/dist/middleware.js +67 -0
  101. package/dist/middleware.js.map +1 -0
  102. package/dist/project-resolver.d.ts +102 -0
  103. package/dist/project-resolver.d.ts.map +1 -0
  104. package/dist/project-resolver.js +271 -0
  105. package/dist/project-resolver.js.map +1 -0
  106. package/dist/rate-limit.d.ts +37 -0
  107. package/dist/rate-limit.d.ts.map +1 -0
  108. package/dist/rate-limit.js +109 -0
  109. package/dist/rate-limit.js.map +1 -0
  110. package/dist/redirect.d.ts +84 -0
  111. package/dist/redirect.d.ts.map +1 -0
  112. package/dist/redirect.js +105 -0
  113. package/dist/redirect.js.map +1 -0
  114. package/dist/renderer.d.ts +91 -0
  115. package/dist/renderer.d.ts.map +1 -0
  116. package/dist/renderer.js +630 -0
  117. package/dist/renderer.js.map +1 -0
  118. package/dist/request-logger.d.ts +12 -0
  119. package/dist/request-logger.d.ts.map +1 -0
  120. package/dist/request-logger.js +55 -0
  121. package/dist/request-logger.js.map +1 -0
  122. package/dist/rest.d.ts +25 -0
  123. package/dist/rest.d.ts.map +1 -0
  124. package/dist/rest.js +93 -0
  125. package/dist/rest.js.map +1 -0
  126. package/dist/router.d.ts +71 -0
  127. package/dist/router.d.ts.map +1 -0
  128. package/dist/router.js +222 -0
  129. package/dist/router.js.map +1 -0
  130. package/dist/rpc-registry.d.ts +84 -0
  131. package/dist/rpc-registry.d.ts.map +1 -0
  132. package/dist/rpc-registry.js +271 -0
  133. package/dist/rpc-registry.js.map +1 -0
  134. package/dist/rpc-runner.d.ts +82 -0
  135. package/dist/rpc-runner.d.ts.map +1 -0
  136. package/dist/rpc-runner.js +564 -0
  137. package/dist/rpc-runner.js.map +1 -0
  138. package/dist/sanitize.d.ts +61 -0
  139. package/dist/sanitize.d.ts.map +1 -0
  140. package/dist/sanitize.js +193 -0
  141. package/dist/sanitize.js.map +1 -0
  142. package/dist/security-headers.d.ts +114 -0
  143. package/dist/security-headers.d.ts.map +1 -0
  144. package/dist/security-headers.js +121 -0
  145. package/dist/security-headers.js.map +1 -0
  146. package/dist/server-fn.d.ts +323 -0
  147. package/dist/server-fn.d.ts.map +1 -0
  148. package/dist/server-fn.js +373 -0
  149. package/dist/server-fn.js.map +1 -0
  150. package/dist/server-public.d.ts +13 -0
  151. package/dist/server-public.d.ts.map +1 -0
  152. package/dist/server-public.js +12 -0
  153. package/dist/server-public.js.map +1 -0
  154. package/dist/server-timeout.d.ts +38 -0
  155. package/dist/server-timeout.d.ts.map +1 -0
  156. package/dist/server-timeout.js +46 -0
  157. package/dist/server-timeout.js.map +1 -0
  158. package/dist/server.d.ts +100 -0
  159. package/dist/server.d.ts.map +1 -0
  160. package/dist/server.js +1218 -0
  161. package/dist/server.js.map +1 -0
  162. package/dist/socket-router.d.ts +153 -0
  163. package/dist/socket-router.d.ts.map +1 -0
  164. package/dist/socket-router.js +612 -0
  165. package/dist/socket-router.js.map +1 -0
  166. package/dist/sso.d.ts +90 -0
  167. package/dist/sso.d.ts.map +1 -0
  168. package/dist/sso.js +261 -0
  169. package/dist/sso.js.map +1 -0
  170. package/dist/ssr-context.d.ts +49 -0
  171. package/dist/ssr-context.d.ts.map +1 -0
  172. package/dist/ssr-context.js +85 -0
  173. package/dist/ssr-context.js.map +1 -0
  174. package/dist/ssr-globals.d.ts +32 -0
  175. package/dist/ssr-globals.d.ts.map +1 -0
  176. package/dist/ssr-globals.js +1010 -0
  177. package/dist/ssr-globals.js.map +1 -0
  178. package/dist/ssr-template.d.ts +73 -0
  179. package/dist/ssr-template.d.ts.map +1 -0
  180. package/dist/ssr-template.js +507 -0
  181. package/dist/ssr-template.js.map +1 -0
  182. package/dist/stack-mapper.d.ts +25 -0
  183. package/dist/stack-mapper.d.ts.map +1 -0
  184. package/dist/stack-mapper.js +139 -0
  185. package/dist/stack-mapper.js.map +1 -0
  186. package/dist/stream.d.ts +89 -0
  187. package/dist/stream.d.ts.map +1 -0
  188. package/dist/stream.js +299 -0
  189. package/dist/stream.js.map +1 -0
  190. package/dist/upload.d.ts +69 -0
  191. package/dist/upload.d.ts.map +1 -0
  192. package/dist/upload.js +110 -0
  193. package/dist/upload.js.map +1 -0
  194. package/dist/validate.d.ts +58 -0
  195. package/dist/validate.d.ts.map +1 -0
  196. package/dist/validate.js +89 -0
  197. package/dist/validate.js.map +1 -0
  198. package/dist/verify-package.d.ts +3 -0
  199. package/dist/verify-package.d.ts.map +1 -0
  200. package/dist/verify-package.js +128 -0
  201. package/dist/verify-package.js.map +1 -0
  202. 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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest.js","sourceRoot":"","sources":["../src/rest.ts"],"names":[],"mappings":"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"}
@@ -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"}