@meekojs/meeko 0.0.3 → 0.1.0

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 (188) hide show
  1. package/README.md +35 -16
  2. package/dist/autoimports-ts.d.ts +26 -0
  3. package/dist/autoimports-ts.js +183 -0
  4. package/dist/autoimports-ts.js.map +1 -0
  5. package/dist/autoimports.d.ts +21 -0
  6. package/dist/autoimports.js +301 -0
  7. package/dist/autoimports.js.map +1 -0
  8. package/dist/check.js +74 -33
  9. package/dist/check.js.map +1 -0
  10. package/dist/cli.js +67 -5
  11. package/dist/cli.js.map +1 -0
  12. package/dist/compiler/events.d.ts +2 -0
  13. package/dist/compiler/events.js +6 -0
  14. package/dist/compiler/events.js.map +1 -0
  15. package/dist/compiler/import-graph.d.ts +8 -0
  16. package/dist/compiler/import-graph.js +33 -0
  17. package/dist/compiler/import-graph.js.map +1 -0
  18. package/dist/compiler/mapping.js +1 -0
  19. package/dist/compiler/mapping.js.map +1 -0
  20. package/dist/compiler/project-root.d.ts +2 -0
  21. package/dist/compiler/project-root.js +18 -0
  22. package/dist/compiler/project-root.js.map +1 -0
  23. package/dist/compiler/props.d.ts +12 -0
  24. package/dist/compiler/props.js +32 -0
  25. package/dist/compiler/props.js.map +1 -0
  26. package/dist/compiler/sfc.js +1 -0
  27. package/dist/compiler/sfc.js.map +1 -0
  28. package/dist/compiler/sourcemap.d.ts +3 -0
  29. package/dist/compiler/sourcemap.js +75 -0
  30. package/dist/compiler/sourcemap.js.map +1 -0
  31. package/dist/compiler/template.js +1 -0
  32. package/dist/compiler/template.js.map +1 -0
  33. package/dist/compiler.js +66 -17
  34. package/dist/compiler.js.map +1 -0
  35. package/dist/component-errors.d.ts +18 -0
  36. package/dist/component-errors.js +65 -0
  37. package/dist/component-errors.js.map +1 -0
  38. package/dist/devtools-ui/index.js +1 -0
  39. package/dist/devtools-ui/index.js.map +1 -0
  40. package/dist/devtools.js +3 -4
  41. package/dist/devtools.js.map +1 -0
  42. package/dist/dom.d.ts +18 -5
  43. package/dist/dom.js +295 -90
  44. package/dist/dom.js.map +1 -0
  45. package/dist/error-observer.d.ts +6 -0
  46. package/dist/error-observer.js +41 -0
  47. package/dist/error-observer.js.map +1 -0
  48. package/dist/framework/check-app.d.ts +5 -0
  49. package/dist/framework/check-app.js +214 -0
  50. package/dist/framework/check-app.js.map +1 -0
  51. package/dist/framework/check-project.d.ts +4 -0
  52. package/dist/framework/check-project.js +42 -0
  53. package/dist/framework/check-project.js.map +1 -0
  54. package/dist/framework/client.d.ts +48 -0
  55. package/dist/framework/client.js +249 -0
  56. package/dist/framework/client.js.map +1 -0
  57. package/dist/framework/clients.d.ts +82 -0
  58. package/dist/framework/clients.js +190 -0
  59. package/dist/framework/clients.js.map +1 -0
  60. package/dist/framework/config-type.d.ts +10 -0
  61. package/dist/framework/config-type.js +4 -0
  62. package/dist/framework/config-type.js.map +1 -0
  63. package/dist/framework/config.d.ts +15 -0
  64. package/dist/framework/config.js +138 -0
  65. package/dist/framework/config.js.map +1 -0
  66. package/dist/framework/contracts-generate.d.ts +8 -0
  67. package/dist/framework/contracts-generate.js +290 -0
  68. package/dist/framework/contracts-generate.js.map +1 -0
  69. package/dist/framework/generate.d.ts +7 -0
  70. package/dist/framework/generate.js +67 -0
  71. package/dist/framework/generate.js.map +1 -0
  72. package/dist/framework/init.d.ts +2 -0
  73. package/dist/framework/init.js +183 -0
  74. package/dist/framework/init.js.map +1 -0
  75. package/dist/framework/middleware.d.ts +14 -0
  76. package/dist/framework/middleware.js +16 -0
  77. package/dist/framework/middleware.js.map +1 -0
  78. package/dist/framework/modules.d.ts +22 -0
  79. package/dist/framework/modules.js +29 -0
  80. package/dist/framework/modules.js.map +1 -0
  81. package/dist/framework/page-contracts-check.d.ts +8 -0
  82. package/dist/framework/page-contracts-check.js +110 -0
  83. package/dist/framework/page-contracts-check.js.map +1 -0
  84. package/dist/framework/page-contracts-generate.d.ts +2 -0
  85. package/dist/framework/page-contracts-generate.js +94 -0
  86. package/dist/framework/page-contracts-generate.js.map +1 -0
  87. package/dist/framework/page.d.ts +64 -0
  88. package/dist/framework/page.js +44 -0
  89. package/dist/framework/page.js.map +1 -0
  90. package/dist/framework/prerender.d.ts +14 -0
  91. package/dist/framework/prerender.js +110 -0
  92. package/dist/framework/prerender.js.map +1 -0
  93. package/dist/framework/project-templates.d.ts +3 -0
  94. package/dist/framework/project-templates.js +119 -0
  95. package/dist/framework/project-templates.js.map +1 -0
  96. package/dist/framework/project.d.ts +9 -0
  97. package/dist/framework/project.js +272 -0
  98. package/dist/framework/project.js.map +1 -0
  99. package/dist/framework/router.d.ts +41 -0
  100. package/dist/framework/router.js +259 -0
  101. package/dist/framework/router.js.map +1 -0
  102. package/dist/framework/server.d.ts +65 -0
  103. package/dist/framework/server.js +239 -0
  104. package/dist/framework/server.js.map +1 -0
  105. package/dist/framework/socket-contracts-generate.d.ts +5 -0
  106. package/dist/framework/socket-contracts-generate.js +162 -0
  107. package/dist/framework/socket-contracts-generate.js.map +1 -0
  108. package/dist/framework/socket.d.ts +72 -0
  109. package/dist/framework/socket.js +252 -0
  110. package/dist/framework/socket.js.map +1 -0
  111. package/dist/framework/standard-schema-types.d.ts +7 -0
  112. package/dist/framework/standard-schema-types.js +69 -0
  113. package/dist/framework/standard-schema-types.js.map +1 -0
  114. package/dist/framework/state.d.ts +22 -0
  115. package/dist/framework/state.js +136 -0
  116. package/dist/framework/state.js.map +1 -0
  117. package/dist/framework/styles.d.ts +2 -0
  118. package/dist/framework/styles.js +6 -0
  119. package/dist/framework/styles.js.map +1 -0
  120. package/dist/framework/type-declarations.d.ts +5 -0
  121. package/dist/framework/type-declarations.js +84 -0
  122. package/dist/framework/type-declarations.js.map +1 -0
  123. package/dist/framework-server/auto-clients.d.ts +3 -0
  124. package/dist/framework-server/auto-clients.js +27 -0
  125. package/dist/framework-server/auto-clients.js.map +1 -0
  126. package/dist/framework-server/context.d.ts +21 -0
  127. package/dist/framework-server/context.js +22 -0
  128. package/dist/framework-server/context.js.map +1 -0
  129. package/dist/framework-server/contracts.d.ts +73 -0
  130. package/dist/framework-server/contracts.js +184 -0
  131. package/dist/framework-server/contracts.js.map +1 -0
  132. package/dist/framework-server/discovery.d.ts +43 -0
  133. package/dist/framework-server/discovery.js +257 -0
  134. package/dist/framework-server/discovery.js.map +1 -0
  135. package/dist/framework-server/local.d.ts +21 -0
  136. package/dist/framework-server/local.js +100 -0
  137. package/dist/framework-server/local.js.map +1 -0
  138. package/dist/framework-server/middleware.d.ts +4 -0
  139. package/dist/framework-server/middleware.js +56 -0
  140. package/dist/framework-server/middleware.js.map +1 -0
  141. package/dist/framework-server/node-upgrade.d.ts +23 -0
  142. package/dist/framework-server/node-upgrade.js +96 -0
  143. package/dist/framework-server/node-upgrade.js.map +1 -0
  144. package/dist/framework-server/node-websocket.d.ts +16 -0
  145. package/dist/framework-server/node-websocket.js +127 -0
  146. package/dist/framework-server/node-websocket.js.map +1 -0
  147. package/dist/framework-server/openapi.d.ts +17 -0
  148. package/dist/framework-server/openapi.js +118 -0
  149. package/dist/framework-server/openapi.js.map +1 -0
  150. package/dist/framework-server/session-stores.d.ts +73 -0
  151. package/dist/framework-server/session-stores.js +122 -0
  152. package/dist/framework-server/session-stores.js.map +1 -0
  153. package/dist/framework-server/sessions.d.ts +70 -0
  154. package/dist/framework-server/sessions.js +167 -0
  155. package/dist/framework-server/sessions.js.map +1 -0
  156. package/dist/framework-server/socket.d.ts +83 -0
  157. package/dist/framework-server/socket.js +196 -0
  158. package/dist/framework-server/socket.js.map +1 -0
  159. package/dist/framework-server.d.ts +23 -0
  160. package/dist/framework-server.js +13 -0
  161. package/dist/framework-server.js.map +1 -0
  162. package/dist/framework.d.ts +31 -0
  163. package/dist/framework.js +14 -0
  164. package/dist/framework.js.map +1 -0
  165. package/dist/hmr.js +75 -24
  166. package/dist/hmr.js.map +1 -0
  167. package/dist/index.d.ts +5 -3
  168. package/dist/index.js +3 -1
  169. package/dist/index.js.map +1 -0
  170. package/dist/init.js +31 -3
  171. package/dist/init.js.map +1 -0
  172. package/dist/internal.d.ts +2 -2
  173. package/dist/internal.js +3 -2
  174. package/dist/internal.js.map +1 -0
  175. package/dist/node.d.ts +16 -0
  176. package/dist/node.js +122 -0
  177. package/dist/node.js.map +1 -0
  178. package/dist/reactivity.d.ts +22 -1
  179. package/dist/reactivity.js +132 -18
  180. package/dist/reactivity.js.map +1 -0
  181. package/dist/server.js +1 -0
  182. package/dist/server.js.map +1 -0
  183. package/dist/types.d.ts +2 -0
  184. package/dist/types.js +26 -9
  185. package/dist/types.js.map +1 -0
  186. package/dist/vite.js +112 -7
  187. package/dist/vite.js.map +1 -0
  188. package/package.json +15 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/framework/router.ts"],"names":[],"mappings":"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","sourcesContent":["import { observeCallback } from \"../error-observer.js\";\n\n/** A route manifest is shared by the server renderer and browser navigator. */\nexport interface RouteRecord {\n readonly id: string;\n readonly file: string;\n readonly layouts: readonly string[];\n readonly error?: string;\n readonly sidecar?: string;\n}\n\nexport interface RouteMatch {\n readonly route: RouteRecord;\n readonly params: Readonly<Record<string, string>>;\n}\n\ntype Segment = { kind: \"static\" | \"param\" | \"rest\"; value: string };\n\nfunction segments(id: string): Segment[] {\n if (!id.startsWith(\"/\")) throw new TypeError(`Route must start with /: ${id}`);\n return id.split(\"/\").slice(1).filter(Boolean).map((part, index, all) => {\n if (/^\\[\\.\\.\\.[A-Za-z_$][\\w$]*\\]$/.test(part)) {\n if (index !== all.length - 1) throw new TypeError(`Catch-all must be final: ${id}`);\n return { kind: \"rest\", value: part.slice(4, -1) };\n }\n if (/^\\[[A-Za-z_$][\\w$]*\\]$/.test(part)) return { kind: \"param\", value: part.slice(1, -1) };\n if (part.includes(\"[\") || part.includes(\"]\")) throw new TypeError(`Invalid route segment: ${part}`);\n return { kind: \"static\", value: part };\n });\n}\n\nfunction rank(id: string): number[] {\n return segments(id).map((part) => part.kind === \"static\" ? 3 : part.kind === \"param\" ? 2 : 1);\n}\n\nfunction compareRoute(a: RouteRecord, b: RouteRecord): number {\n const left = rank(a.id);\n const right = rank(b.id);\n for (let index = 0; index < Math.max(left.length, right.length); index++) {\n const score = (right[index] ?? 0) - (left[index] ?? 0);\n if (score) return score;\n }\n return a.id.localeCompare(b.id);\n}\n\nfunction collisionKey(id: string): string {\n return segments(id).map((part) => part.kind === \"static\" ? part.value : part.kind === \"param\" ? \"[]\" : \"[...]\").join(\"/\");\n}\n\nfunction decodePart(part: string): string | undefined {\n try {\n const value = decodeURIComponent(part);\n return value.includes(\"/\") || value.includes(\"\\\\\") || value === \".\" || value === \"..\" ? undefined : value;\n } catch {\n return undefined;\n }\n}\n\n/** Validates collisions before sorting static routes ahead of parameters. */\nexport function createRouteManifest(routes: readonly RouteRecord[]): readonly RouteRecord[] {\n const keys = new Map<string, string>();\n for (const route of routes) {\n const key = collisionKey(route.id);\n const previous = keys.get(key);\n if (previous) throw new Error(`Route collision: ${previous} and ${route.file} both resolve to ${key || \"/\"}`);\n keys.set(key, route.file);\n }\n return Object.freeze([...routes].sort(compareRoute));\n}\n\n/** Resolves a URL against the same manifest used for SSR and client navigation. */\nexport function matchRoute(routes: readonly RouteRecord[], pathname: string): RouteMatch | undefined {\n if (!pathname.startsWith(\"/\")) return undefined;\n const raw = pathname.split(\"/\").slice(1).filter(Boolean);\n const path = raw.map(decodePart);\n if (path.some((part) => part === undefined)) return undefined;\n for (const route of routes) {\n const pattern = segments(route.id);\n const params: Record<string, string> = {};\n let index = 0;\n let matched = true;\n for (const part of pattern) {\n if (part.kind === \"rest\") {\n if (index === path.length) { matched = false; break; }\n params[part.value] = path.slice(index).join(\"/\");\n index = path.length;\n break;\n }\n const value = path[index++];\n if (value === undefined || (part.kind === \"static\" && part.value !== value)) { matched = false; break; }\n if (part.kind === \"param\") params[part.value] = value;\n }\n if (matched && index === path.length) return { route, params };\n }\n return undefined;\n}\n\n/** Builds a URL from a manifest route and rejects absent or extra parameters. */\nexport function href(routes: readonly RouteRecord[], id: string, options: {\n params?: Readonly<Record<string, string>>;\n search?: Readonly<Record<string, string | number | boolean | null | undefined>>;\n} = {}): string {\n if (!routes.some((route) => route.id === id)) throw new Error(`Unknown route: ${id}`);\n const params = options.params ?? {};\n const used = new Set<string>();\n const path = segments(id).map((part) => {\n if (part.kind === \"static\") return encodeURIComponent(part.value);\n const value = params[part.value];\n if (!value) throw new Error(`Missing route parameter: ${part.value}`);\n used.add(part.value);\n if (part.kind === \"rest\") {\n const pieces = value.split(\"/\");\n if (pieces.some((piece) => !piece || piece === \".\" || piece === \"..\")) throw new Error(`Invalid catch-all parameter: ${part.value}`);\n return pieces.map(encodeURIComponent).join(\"/\");\n }\n if (value.includes(\"/\") || value === \".\" || value === \"..\") throw new Error(`Invalid route parameter: ${part.value}`);\n return encodeURIComponent(value);\n });\n for (const key of Object.keys(params)) if (!used.has(key)) throw new Error(`Unknown route parameter: ${key}`);\n const url = new URL(path.length ? `/${path.join(\"/\")}` : \"/\", \"http://meeko.local\");\n for (const [key, value] of Object.entries(options.search ?? {})) if (value !== null && value !== undefined) url.searchParams.set(key, String(value));\n return url.pathname + url.search;\n}\n\nexport interface NavigationContext {\n readonly url: URL;\n readonly match: RouteMatch;\n readonly signal: AbortSignal;\n /** Longest prefix shared with the previous route's layout chain. */\n readonly retainedLayouts: number;\n}\n\nexport interface Navigator {\n navigate(to: string, options?: { replace?: boolean }): Promise<boolean>;\n dispose(): void;\n}\n\n/** Browser events cannot return a navigation promise, so surface failures safely. */\nexport function reportNavigationError(browser: Window, error: unknown, observer?: (error: unknown) => void): void {\n const logger = (browser as Window & { console?: { error(...args: unknown[]): void } }).console ?? console;\n const reportObserverFailure = (observerError: unknown) => {\n try { logger.error(\"Meeko navigation error observer failed\", observerError, error); }\n catch { /* A broken console must not produce an unhandled rejection. */ }\n };\n if (observer) observeCallback(() => observer(error), reportObserverFailure);\n else observeCallback(() => logger.error(\"Meeko navigation failed\", error), () => {});\n}\n\n/**\n * The host owns actual DOM outlet rendering. Its callback receives layout\n * identity so it can retain matching layout instances and release exited ones.\n */\nexport function createNavigator(routes: readonly RouteRecord[], render: (context: NavigationContext) => Promise<void | boolean> | void | boolean, browser: Window = window, onError?: (error: unknown) => void): Navigator {\n let current = matchRoute(routes, browser.location.pathname);\n let currentUrl = browser.location.href;\n let pending: AbortController | undefined;\n let disposed = false;\n const navigate = async (to: string, options: { replace?: boolean } = {}): Promise<boolean> => {\n if (disposed) throw new Error(\"Navigator disposed\");\n const url = new URL(to, browser.location.href);\n if (url.origin !== browser.location.origin) throw new TypeError(\"External navigation is not a Meeko route\");\n const match = matchRoute(routes, url.pathname);\n if (!match) {\n if (options.replace && browser.location.href === url.href) {\n try { browser.history.replaceState(null, \"\", currentUrl); }\n catch (historyError) {\n try { browser.location.replace(currentUrl); }\n catch (recoveryError) {\n throw new AggregateError([historyError, recoveryError], \"Meeko history and URL recovery failed\");\n }\n throw historyError;\n }\n }\n return false;\n }\n pending?.abort();\n const controller = new AbortController();\n pending = controller;\n let retainedLayouts = 0;\n if (current) {\n while (current.route.layouts[retainedLayouts] === match.route.layouts[retainedLayouts]\n && retainedLayouts < current.route.layouts.length\n && retainedLayouts < match.route.layouts.length) retainedLayouts++;\n }\n let result: void | boolean;\n try { result = await render({ url, match, signal: controller.signal, retainedLayouts }); }\n catch (error) {\n if (pending === controller) pending = undefined;\n if (options.replace && !controller.signal.aborted && !disposed && browser.location.href === url.href) {\n try { browser.history.replaceState(null, \"\", currentUrl); }\n catch (historyError) {\n try { browser.location.replace(currentUrl); }\n catch (recoveryError) {\n throw new AggregateError([error, historyError, recoveryError], \"Meeko navigation and URL recovery failed\");\n }\n throw new AggregateError([error, historyError], \"Meeko navigation and history recovery failed\");\n }\n }\n throw error;\n }\n if (result === false) {\n if (pending === controller) pending = undefined;\n if (options.replace && !controller.signal.aborted && browser.location.href === url.href) {\n try { browser.history.replaceState(null, \"\", currentUrl); }\n catch (historyError) {\n try { browser.location.replace(currentUrl); }\n catch (recoveryError) {\n throw new AggregateError([historyError, recoveryError], \"Meeko history and URL recovery failed\");\n }\n throw historyError;\n }\n }\n return false;\n }\n if (controller.signal.aborted || disposed) return false;\n try {\n if (options.replace) browser.history.replaceState(null, \"\", url);\n else browser.history.pushState(null, \"\", url);\n } catch (error) {\n if (pending === controller) pending = undefined;\n try { browser.location.replace(currentUrl); }\n catch (recoveryError) {\n throw new AggregateError([error, recoveryError], \"Meeko history update and navigation recovery failed\");\n }\n throw error;\n }\n current = match;\n currentUrl = url.href;\n pending = undefined;\n return true;\n };\n const onPop = () => {\n void navigate(browser.location.href, { replace: true }).catch((error: unknown) => reportNavigationError(browser, error, onError));\n };\n browser.addEventListener(\"popstate\", onPop);\n return {\n navigate,\n dispose() {\n disposed = true;\n pending?.abort();\n browser.removeEventListener(\"popstate\", onPop);\n },\n };\n}\n"]}
@@ -0,0 +1,65 @@
1
+ import type { RequestContext } from "../framework-server/context.js";
2
+ import type { ServerFetch } from "../framework-server/context.js";
3
+ import type { RouteMiddleware } from "./middleware.js";
4
+ import type { PageSchema } from "./page.js";
5
+ import { StateStore } from "./state.js";
6
+ import type { RouteRecord } from "./router.js";
7
+ /** Discovers pages once; the returned manifest is safe to serialize for the browser. */
8
+ export declare function discoverRoutes(projectRoot: string): Promise<readonly RouteRecord[]>;
9
+ export interface PageModule {
10
+ css?: string;
11
+ renderWithState(props: Record<string, unknown>): {
12
+ html: string;
13
+ state: Record<string, unknown>;
14
+ };
15
+ renderToString?(props: Record<string, unknown>): string;
16
+ }
17
+ export interface PageRoute {
18
+ params?: PageSchema;
19
+ search?: PageSchema;
20
+ load?: (context: PageRequestContext) => Promise<unknown> | unknown;
21
+ head?: (context: PageRequestContext & {
22
+ data: unknown;
23
+ }) => {
24
+ title?: string;
25
+ };
26
+ render?: "ssr" | "prerender";
27
+ prerenderEntries?: readonly Readonly<Record<string, string>>[] | (() => Promise<readonly Readonly<Record<string, string>>[]>);
28
+ }
29
+ export interface PageRequestContext {
30
+ readonly request: Request;
31
+ readonly params: Readonly<Record<string, unknown>>;
32
+ readonly search: Readonly<Record<string, unknown>>;
33
+ readonly searchParams: URLSearchParams;
34
+ readonly signal: AbortSignal;
35
+ /** Public state transferred from this request to its browser app instance. */
36
+ readonly state: StateStore;
37
+ /** Present when the host supplies a per-request context. */
38
+ readonly context?: RequestContext;
39
+ }
40
+ export interface FrameworkHandlerOptions<Route = PageRoute> {
41
+ readonly routes: readonly RouteRecord[];
42
+ readonly loadPage: (file: string) => Promise<PageModule>;
43
+ readonly loadRoute?: (file: string) => Promise<Route>;
44
+ /** Isomorphic route middleware, evaluated before the route sidecar loader. */
45
+ readonly loadMiddleware?: () => Promise<readonly RouteMiddleware[]>;
46
+ readonly createContext?: (request: Request) => RequestContext | Promise<RequestContext>;
47
+ /** Optional in-process dispatcher for automatic API/RPC calls during SSR. */
48
+ readonly serverFetch?: ServerFetch;
49
+ /** Receives internal page failures with the request ID; never sent to the browser. */
50
+ readonly onError?: (error: unknown, requestId: string) => void;
51
+ /** Optional host layout renderer; default composition uses <component is="props.outlet"/>. */
52
+ readonly renderLayout?: (file: string, children: string, context: PageRequestContext) => Promise<string> | string;
53
+ readonly clientEntry?: string;
54
+ }
55
+ /** A typed sidecar may narrow callback arguments after its schemas validate them. */
56
+ type TypedPageRoute = Omit<PageRoute, "load" | "head"> & {
57
+ load?: (context: never) => Promise<unknown> | unknown;
58
+ head?: (context: never) => {
59
+ title?: string;
60
+ };
61
+ };
62
+ /** Portable Fetch handler. Node adapters can pass their Request directly. */
63
+ export declare function createFrameworkHandler(options: FrameworkHandlerOptions): (request: Request) => Promise<Response>;
64
+ export declare function createFrameworkHandler<Route extends TypedPageRoute>(options: FrameworkHandlerOptions<Route>): (request: Request) => Promise<Response>;
65
+ export {};
@@ -0,0 +1,239 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { lstat, readdir, stat } from "node:fs/promises";
3
+ import { basename, dirname, join, relative, resolve, sep } from "node:path";
4
+ import { escapeHtml, serializeJson } from "../server.js";
5
+ import { withRequestContext } from "../framework-server/context.js";
6
+ import { ApiError, errorResponse, normalizeServerError, observeServerError } from "../framework-server/contracts.js";
7
+ import { PageInputError, pageSearchObject, validatePageInputs } from "./page.js";
8
+ import { runRouteMiddleware } from "./middleware.js";
9
+ import { StateStore, withStateStore } from "./state.js";
10
+ import { createRouteManifest, matchRoute } from "./router.js";
11
+ function routeId(relativeFile) {
12
+ const parts = relativeFile.slice(0, -".meeko".length).split(sep);
13
+ if (parts.at(-1) === "index")
14
+ parts.pop();
15
+ const visible = parts.filter((part) => !/^\([^/()]+\)$/.test(part));
16
+ return visible.length ? `/${visible.join("/")}` : "/";
17
+ }
18
+ /** Discovers pages once; the returned manifest is safe to serialize for the browser. */
19
+ export async function discoverRoutes(projectRoot) {
20
+ const pagesRoot = resolve(projectRoot, "app", "pages");
21
+ const files = new Set();
22
+ async function walk(directory) {
23
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
24
+ const path = join(directory, entry.name);
25
+ if (entry.isDirectory())
26
+ await walk(path);
27
+ else if (entry.isFile())
28
+ files.add(path);
29
+ }
30
+ }
31
+ await walk(pagesRoot);
32
+ const appShell = resolve(projectRoot, "app", "app.meeko");
33
+ const defaultLayout = resolve(projectRoot, "app", "layouts", "default.meeko");
34
+ let hasAppShell = false;
35
+ try {
36
+ hasAppShell = (await stat(appShell)).isFile();
37
+ }
38
+ catch (error) {
39
+ if (error.code !== "ENOENT")
40
+ throw error;
41
+ }
42
+ let hasDefaultLayout = false;
43
+ try {
44
+ hasDefaultLayout = (await lstat(defaultLayout)).isFile();
45
+ }
46
+ catch (error) {
47
+ if (error.code !== "ENOENT")
48
+ throw error;
49
+ }
50
+ if (hasDefaultLayout && files.has(join(pagesRoot, "+layout.meeko"))) {
51
+ throw new Error(`Both ${defaultLayout} and ${join(pagesRoot, "+layout.meeko")} define the root layout`);
52
+ }
53
+ const routes = [];
54
+ for (const file of files) {
55
+ if (!file.endsWith(".meeko") || basename(file).startsWith("+"))
56
+ continue;
57
+ const directory = dirname(file);
58
+ const layouts = hasAppShell ? [appShell] : [];
59
+ if (hasDefaultLayout)
60
+ layouts.push(defaultLayout);
61
+ let cursor = pagesRoot;
62
+ const relativeDirectory = relative(pagesRoot, directory);
63
+ if (files.has(join(cursor, "+layout.meeko")))
64
+ layouts.push(join(cursor, "+layout.meeko"));
65
+ if (relativeDirectory)
66
+ for (const segment of relativeDirectory.split(sep)) {
67
+ cursor = join(cursor, segment);
68
+ if (files.has(join(cursor, "+layout.meeko")))
69
+ layouts.push(join(cursor, "+layout.meeko"));
70
+ }
71
+ let error;
72
+ let errorCursor = directory;
73
+ while (errorCursor.startsWith(pagesRoot)) {
74
+ const candidate = join(errorCursor, "+error.meeko");
75
+ if (files.has(candidate)) {
76
+ error = candidate;
77
+ break;
78
+ }
79
+ if (errorCursor === pagesRoot)
80
+ break;
81
+ errorCursor = dirname(errorCursor);
82
+ }
83
+ const sidecar = file.slice(0, -".meeko".length) + ".route.ts";
84
+ routes.push({
85
+ id: routeId(relative(pagesRoot, file)),
86
+ file,
87
+ layouts,
88
+ ...(error ? { error } : {}),
89
+ ...(files.has(sidecar) ? { sidecar } : {}),
90
+ });
91
+ }
92
+ return createRouteManifest(routes);
93
+ }
94
+ export function createFrameworkHandler(options) {
95
+ return async (request) => {
96
+ const fallbackRequestId = randomUUID();
97
+ if (request.method !== "GET" && request.method !== "HEAD")
98
+ return new Response(null, {
99
+ status: 405, headers: { Allow: "GET, HEAD", "x-request-id": fallbackRequestId, "cache-control": "no-store" },
100
+ });
101
+ const stateStore = new StateStore();
102
+ let errorRoute;
103
+ let requestContext;
104
+ const finish = (response) => {
105
+ const headers = new Headers(response.headers);
106
+ headers.set("x-request-id", requestContext?.requestId ?? fallbackRequestId);
107
+ if (requestContext) {
108
+ headers.set("x-meeko-csrf-token", requestContext.session.current?.csrfToken ?? "");
109
+ if (requestContext.session.cookieHeader)
110
+ headers.append("set-cookie", requestContext.session.cookieHeader);
111
+ }
112
+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
113
+ };
114
+ try {
115
+ const url = new URL(request.url);
116
+ const match = matchRoute(options.routes, url.pathname);
117
+ if (!match)
118
+ return finish(new Response("Not Found", {
119
+ status: 404, headers: { "cache-control": "no-store" },
120
+ }));
121
+ errorRoute = match.route.error;
122
+ requestContext = await options.createContext?.(request);
123
+ if (requestContext && requestContext.request !== request)
124
+ throw new TypeError("Request context belongs to another request");
125
+ const render = async () => {
126
+ const middlewareResponse = options.loadMiddleware && await runRouteMiddleware(await options.loadMiddleware(), {
127
+ url, match, signal: request.signal, phase: "server", request,
128
+ });
129
+ if (middlewareResponse)
130
+ return finish(middlewareResponse);
131
+ const sidecar = match.route.sidecar && options.loadRoute ? await options.loadRoute(match.route.sidecar) : undefined;
132
+ const validated = await validatePageInputs(sidecar, match.params, pageSearchObject(url.searchParams));
133
+ const context = {
134
+ request, params: validated.params, search: validated.search, searchParams: url.searchParams, signal: request.signal, state: stateStore,
135
+ ...(requestContext ? { context: requestContext } : {}),
136
+ };
137
+ const data = sidecar?.load ? await sidecar.load(context) : undefined;
138
+ if (data instanceof Response)
139
+ return finish(data);
140
+ const props = {
141
+ params: validated.params,
142
+ search: validated.search,
143
+ ...(data === undefined ? {} : { data }),
144
+ };
145
+ let module = await options.loadPage(match.route.file);
146
+ const styles = [];
147
+ if (module.css)
148
+ styles.push(module.css);
149
+ let input = props;
150
+ let rendered;
151
+ if (options.renderLayout) {
152
+ rendered = withStateStore(stateStore, () => module.renderWithState(input));
153
+ for (const layout of [...match.route.layouts].reverse()) {
154
+ const layoutModule = await options.loadPage(layout);
155
+ if (layoutModule.css)
156
+ styles.unshift(layoutModule.css);
157
+ rendered = { html: await options.renderLayout(layout, rendered.html, context), state: rendered.state };
158
+ }
159
+ }
160
+ else {
161
+ for (const layout of [...match.route.layouts].reverse()) {
162
+ const child = module;
163
+ const childInput = input;
164
+ const outlet = {
165
+ renderWithState: () => child.renderWithState(childInput),
166
+ renderToString: () => child.renderToString?.(childInput) ?? child.renderWithState(childInput).html,
167
+ hydrateScope: () => { throw new Error("Server outlet cannot hydrate"); },
168
+ };
169
+ module = await options.loadPage(layout);
170
+ if (module.css)
171
+ styles.unshift(module.css);
172
+ input = { outlet };
173
+ }
174
+ rendered = withStateStore(stateStore, () => module.renderWithState(input));
175
+ }
176
+ const head = sidecar?.head?.({ ...context, data });
177
+ const title = head?.title ? `<title>${escapeHtml(head.title)}</title>` : "";
178
+ const styleTags = [...new Set(styles)].map((css) => `<style>${css.replaceAll("<", "\\3C ")}</style>`).join("");
179
+ const payload = serializeJson({ route: match.route.id, props, state: rendered.state, sharedState: stateStore.snapshot() });
180
+ if (request.headers.get("accept")?.split(",").some((value) => value.trim().startsWith("application/meeko+json"))) {
181
+ return finish(new Response(request.method === "HEAD" ? null : payload, {
182
+ status: 200, headers: { "content-type": "application/meeko+json; charset=utf-8", "cache-control": "no-store" },
183
+ }));
184
+ }
185
+ const script = options.clientEntry ? `<script type="module" src="${escapeHtml(options.clientEntry)}"></script>` : "";
186
+ const csrfMeta = requestContext?.session.current ? `<meta name="meeko-csrf-token" content="${escapeHtml(requestContext.session.current.csrfToken)}">` : "";
187
+ const document = `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="data:,">${csrfMeta}${styleTags}${title}</head><body><div id="app">${rendered.html}</div><script id="meeko-payload" type="application/json">${payload}</script>${script}</body></html>`;
188
+ return finish(new Response(request.method === "HEAD" ? null : document, {
189
+ status: 200, headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" },
190
+ }));
191
+ };
192
+ return requestContext ? await withRequestContext(requestContext, options.serverFetch, render) : await render();
193
+ }
194
+ catch (error) {
195
+ if (error instanceof Response)
196
+ return finish(error);
197
+ const known = error instanceof PageInputError ? new ApiError(error.code, 400) : normalizeServerError(error);
198
+ const requestId = requestContext?.requestId ?? fallbackRequestId;
199
+ const report = (failure) => {
200
+ observeServerError(failure, requestId, options.onError);
201
+ };
202
+ if (known.status >= 500)
203
+ report(error);
204
+ if (request.headers.get("accept")?.split(",").some((value) => value.trim().startsWith("application/meeko+json"))) {
205
+ return finish(errorResponse(known, requestId));
206
+ }
207
+ if (error instanceof PageInputError)
208
+ return finish(new Response(error.code, {
209
+ status: 400, headers: { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" },
210
+ }));
211
+ const errorFile = errorRoute;
212
+ if (errorFile) {
213
+ try {
214
+ const renderError = async () => {
215
+ const errorPage = await options.loadPage(errorFile);
216
+ const errorRendered = withStateStore(stateStore, () => errorPage.renderWithState({
217
+ status: known.status, message: known.status >= 500 ? "Internal Server Error" : known.code,
218
+ }));
219
+ const document = `<!doctype html><html><head><meta charset="utf-8"><title>Error</title></head><body><div id="app">${errorRendered.html}</div></body></html>`;
220
+ return finish(new Response(request.method === "HEAD" ? null : document, {
221
+ status: known.status, headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" },
222
+ }));
223
+ };
224
+ return requestContext
225
+ ? await withRequestContext(requestContext, options.serverFetch, renderError)
226
+ : await renderError();
227
+ }
228
+ catch (failure) {
229
+ report(failure);
230
+ // The error route failed; keep private errors out of the response.
231
+ }
232
+ }
233
+ return finish(new Response(request.method === "HEAD" ? null : known.status >= 500 ? "Internal Server Error" : known.code, {
234
+ status: known.status, headers: { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" },
235
+ }));
236
+ }
237
+ };
238
+ }
239
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/framework/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { lstat, readdir, stat } from \"node:fs/promises\";\nimport { basename, dirname, join, relative, resolve, sep } from \"node:path\";\nimport { escapeHtml, serializeJson } from \"../server.js\";\nimport type { RequestContext } from \"../framework-server/context.js\";\nimport { withRequestContext } from \"../framework-server/context.js\";\nimport type { ServerFetch } from \"../framework-server/context.js\";\nimport { ApiError, errorResponse, normalizeServerError, observeServerError } from \"../framework-server/contracts.js\";\nimport { PageInputError, pageSearchObject, validatePageInputs } from \"./page.js\";\nimport { runRouteMiddleware } from \"./middleware.js\";\nimport type { RouteMiddleware } from \"./middleware.js\";\nimport type { PageSchema } from \"./page.js\";\nimport { StateStore, withStateStore } from \"./state.js\";\nimport { createRouteManifest, matchRoute } from \"./router.js\";\nimport type { RouteRecord } from \"./router.js\";\n\nfunction routeId(relativeFile: string): string {\n const parts = relativeFile.slice(0, -\".meeko\".length).split(sep);\n if (parts.at(-1) === \"index\") parts.pop();\n const visible = parts.filter((part) => !/^\\([^/()]+\\)$/.test(part));\n return visible.length ? `/${visible.join(\"/\")}` : \"/\";\n}\n\n/** Discovers pages once; the returned manifest is safe to serialize for the browser. */\nexport async function discoverRoutes(projectRoot: string): Promise<readonly RouteRecord[]> {\n const pagesRoot = resolve(projectRoot, \"app\", \"pages\");\n const files = new Set<string>();\n async function walk(directory: string): Promise<void> {\n for (const entry of await readdir(directory, { withFileTypes: true })) {\n const path = join(directory, entry.name);\n if (entry.isDirectory()) await walk(path);\n else if (entry.isFile()) files.add(path);\n }\n }\n await walk(pagesRoot);\n const appShell = resolve(projectRoot, \"app\", \"app.meeko\");\n const defaultLayout = resolve(projectRoot, \"app\", \"layouts\", \"default.meeko\");\n let hasAppShell = false;\n try { hasAppShell = (await stat(appShell)).isFile(); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error; }\n let hasDefaultLayout = false;\n try { hasDefaultLayout = (await lstat(defaultLayout)).isFile(); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error; }\n if (hasDefaultLayout && files.has(join(pagesRoot, \"+layout.meeko\"))) {\n throw new Error(`Both ${defaultLayout} and ${join(pagesRoot, \"+layout.meeko\")} define the root layout`);\n }\n const routes: RouteRecord[] = [];\n for (const file of files) {\n if (!file.endsWith(\".meeko\") || basename(file).startsWith(\"+\")) continue;\n const directory = dirname(file);\n const layouts: string[] = hasAppShell ? [appShell] : [];\n if (hasDefaultLayout) layouts.push(defaultLayout);\n let cursor = pagesRoot;\n const relativeDirectory = relative(pagesRoot, directory);\n if (files.has(join(cursor, \"+layout.meeko\"))) layouts.push(join(cursor, \"+layout.meeko\"));\n if (relativeDirectory) for (const segment of relativeDirectory.split(sep)) {\n cursor = join(cursor, segment);\n if (files.has(join(cursor, \"+layout.meeko\"))) layouts.push(join(cursor, \"+layout.meeko\"));\n }\n let error: string | undefined;\n let errorCursor = directory;\n while (errorCursor.startsWith(pagesRoot)) {\n const candidate = join(errorCursor, \"+error.meeko\");\n if (files.has(candidate)) { error = candidate; break; }\n if (errorCursor === pagesRoot) break;\n errorCursor = dirname(errorCursor);\n }\n const sidecar = file.slice(0, -\".meeko\".length) + \".route.ts\";\n routes.push({\n id: routeId(relative(pagesRoot, file)),\n file,\n layouts,\n ...(error ? { error } : {}),\n ...(files.has(sidecar) ? { sidecar } : {}),\n });\n }\n return createRouteManifest(routes);\n}\n\nexport interface PageModule {\n css?: string;\n renderWithState(props: Record<string, unknown>): { html: string; state: Record<string, unknown> };\n renderToString?(props: Record<string, unknown>): string;\n}\n\nexport interface PageRoute {\n params?: PageSchema;\n search?: PageSchema;\n load?: (context: PageRequestContext) => Promise<unknown> | unknown;\n head?: (context: PageRequestContext & { data: unknown }) => { title?: string };\n render?: \"ssr\" | \"prerender\";\n prerenderEntries?: readonly Readonly<Record<string, string>>[] | (() => Promise<readonly Readonly<Record<string, string>>[]>);\n}\n\nexport interface PageRequestContext {\n readonly request: Request;\n readonly params: Readonly<Record<string, unknown>>;\n readonly search: Readonly<Record<string, unknown>>;\n readonly searchParams: URLSearchParams;\n readonly signal: AbortSignal;\n /** Public state transferred from this request to its browser app instance. */\n readonly state: StateStore;\n /** Present when the host supplies a per-request context. */\n readonly context?: RequestContext;\n}\n\nexport interface FrameworkHandlerOptions<Route = PageRoute> {\n readonly routes: readonly RouteRecord[];\n readonly loadPage: (file: string) => Promise<PageModule>;\n readonly loadRoute?: (file: string) => Promise<Route>;\n /** Isomorphic route middleware, evaluated before the route sidecar loader. */\n readonly loadMiddleware?: () => Promise<readonly RouteMiddleware[]>;\n readonly createContext?: (request: Request) => RequestContext | Promise<RequestContext>;\n /** Optional in-process dispatcher for automatic API/RPC calls during SSR. */\n readonly serverFetch?: ServerFetch;\n /** Receives internal page failures with the request ID; never sent to the browser. */\n readonly onError?: (error: unknown, requestId: string) => void;\n /** Optional host layout renderer; default composition uses <component is=\"props.outlet\"/>. */\n readonly renderLayout?: (file: string, children: string, context: PageRequestContext) => Promise<string> | string;\n readonly clientEntry?: string;\n}\n\n/** A typed sidecar may narrow callback arguments after its schemas validate them. */\ntype TypedPageRoute = Omit<PageRoute, \"load\" | \"head\"> & {\n load?: (context: never) => Promise<unknown> | unknown;\n head?: (context: never) => { title?: string };\n};\n\n/** Portable Fetch handler. Node adapters can pass their Request directly. */\nexport function createFrameworkHandler(options: FrameworkHandlerOptions): (request: Request) => Promise<Response>;\nexport function createFrameworkHandler<Route extends TypedPageRoute>(options: FrameworkHandlerOptions<Route>): (request: Request) => Promise<Response>;\nexport function createFrameworkHandler(options: FrameworkHandlerOptions<unknown>): (request: Request) => Promise<Response> {\n return async (request) => {\n const fallbackRequestId = randomUUID();\n if (request.method !== \"GET\" && request.method !== \"HEAD\") return new Response(null, {\n status: 405, headers: { Allow: \"GET, HEAD\", \"x-request-id\": fallbackRequestId, \"cache-control\": \"no-store\" },\n });\n const stateStore = new StateStore();\n let errorRoute: string | undefined;\n let requestContext: RequestContext | undefined;\n const finish = (response: Response): Response => {\n const headers = new Headers(response.headers);\n headers.set(\"x-request-id\", requestContext?.requestId ?? fallbackRequestId);\n if (requestContext) {\n headers.set(\"x-meeko-csrf-token\", requestContext.session.current?.csrfToken ?? \"\");\n if (requestContext.session.cookieHeader) headers.append(\"set-cookie\", requestContext.session.cookieHeader);\n }\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers });\n };\n try {\n const url = new URL(request.url);\n const match = matchRoute(options.routes, url.pathname);\n if (!match) return finish(new Response(\"Not Found\", {\n status: 404, headers: { \"cache-control\": \"no-store\" },\n }));\n errorRoute = match.route.error;\n requestContext = await options.createContext?.(request);\n if (requestContext && requestContext.request !== request) throw new TypeError(\"Request context belongs to another request\");\n const render = async (): Promise<Response> => {\n const middlewareResponse = options.loadMiddleware && await runRouteMiddleware(await options.loadMiddleware(), {\n url, match, signal: request.signal, phase: \"server\", request,\n });\n if (middlewareResponse) return finish(middlewareResponse);\n const sidecar = match.route.sidecar && options.loadRoute ? await options.loadRoute(match.route.sidecar) as PageRoute : undefined;\n const validated = await validatePageInputs(sidecar, match.params, pageSearchObject(url.searchParams));\n const context: PageRequestContext = {\n request, params: validated.params, search: validated.search, searchParams: url.searchParams, signal: request.signal, state: stateStore,\n ...(requestContext ? { context: requestContext } : {}),\n };\n const data = sidecar?.load ? await sidecar.load(context) : undefined;\n if (data instanceof Response) return finish(data);\n const props: Record<string, unknown> = {\n params: validated.params,\n search: validated.search,\n ...(data === undefined ? {} : { data }),\n };\n let module = await options.loadPage(match.route.file);\n const styles: string[] = [];\n if (module.css) styles.push(module.css);\n let input = props;\n let rendered: ReturnType<PageModule[\"renderWithState\"]>;\n if (options.renderLayout) {\n rendered = withStateStore(stateStore, () => module.renderWithState(input));\n for (const layout of [...match.route.layouts].reverse()) {\n const layoutModule = await options.loadPage(layout);\n if (layoutModule.css) styles.unshift(layoutModule.css);\n rendered = { html: await options.renderLayout(layout, rendered.html, context), state: rendered.state };\n }\n } else {\n for (const layout of [...match.route.layouts].reverse()) {\n const child = module;\n const childInput = input;\n const outlet = {\n renderWithState: () => child.renderWithState(childInput),\n renderToString: () => child.renderToString?.(childInput) ?? child.renderWithState(childInput).html,\n hydrateScope: () => { throw new Error(\"Server outlet cannot hydrate\"); },\n };\n module = await options.loadPage(layout);\n if (module.css) styles.unshift(module.css);\n input = { outlet };\n }\n rendered = withStateStore(stateStore, () => module.renderWithState(input));\n }\n const head = sidecar?.head?.({ ...context, data });\n const title = head?.title ? `<title>${escapeHtml(head.title)}</title>` : \"\";\n const styleTags = [...new Set(styles)].map((css) => `<style>${css.replaceAll(\"<\", \"\\\\3C \")}</style>`).join(\"\");\n const payload = serializeJson({ route: match.route.id, props, state: rendered.state, sharedState: stateStore.snapshot() });\n if (request.headers.get(\"accept\")?.split(\",\").some((value) => value.trim().startsWith(\"application/meeko+json\"))) {\n return finish(new Response(request.method === \"HEAD\" ? null : payload, {\n status: 200, headers: { \"content-type\": \"application/meeko+json; charset=utf-8\", \"cache-control\": \"no-store\" },\n }));\n }\n const script = options.clientEntry ? `<script type=\"module\" src=\"${escapeHtml(options.clientEntry)}\"></script>` : \"\";\n const csrfMeta = requestContext?.session.current ? `<meta name=\"meeko-csrf-token\" content=\"${escapeHtml(requestContext.session.current.csrfToken)}\">` : \"\";\n const document = `<!doctype html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><link rel=\"icon\" href=\"data:,\">${csrfMeta}${styleTags}${title}</head><body><div id=\"app\">${rendered.html}</div><script id=\"meeko-payload\" type=\"application/json\">${payload}</script>${script}</body></html>`;\n return finish(new Response(request.method === \"HEAD\" ? null : document, {\n status: 200, headers: { \"content-type\": \"text/html; charset=utf-8\", \"cache-control\": \"no-store\" },\n }));\n };\n return requestContext ? await withRequestContext(requestContext, options.serverFetch, render) : await render();\n } catch (error) {\n if (error instanceof Response) return finish(error);\n const known = error instanceof PageInputError ? new ApiError(error.code, 400) : normalizeServerError(error);\n const requestId = requestContext?.requestId ?? fallbackRequestId;\n const report = (failure: unknown): void => {\n observeServerError(failure, requestId, options.onError);\n };\n if (known.status >= 500) report(error);\n if (request.headers.get(\"accept\")?.split(\",\").some((value) => value.trim().startsWith(\"application/meeko+json\"))) {\n return finish(errorResponse(known, requestId));\n }\n if (error instanceof PageInputError) return finish(new Response(error.code, {\n status: 400, headers: { \"content-type\": \"text/plain; charset=utf-8\", \"cache-control\": \"no-store\" },\n }));\n const errorFile = errorRoute;\n if (errorFile) {\n try {\n const renderError = async (): Promise<Response> => {\n const errorPage = await options.loadPage(errorFile);\n const errorRendered = withStateStore(stateStore, () => errorPage.renderWithState({\n status: known.status, message: known.status >= 500 ? \"Internal Server Error\" : known.code,\n }));\n const document = `<!doctype html><html><head><meta charset=\"utf-8\"><title>Error</title></head><body><div id=\"app\">${errorRendered.html}</div></body></html>`;\n return finish(new Response(request.method === \"HEAD\" ? null : document, {\n status: known.status, headers: { \"content-type\": \"text/html; charset=utf-8\", \"cache-control\": \"no-store\" },\n }));\n };\n return requestContext\n ? await withRequestContext(requestContext, options.serverFetch, renderError)\n : await renderError();\n } catch (failure) {\n report(failure);\n // The error route failed; keep private errors out of the response.\n }\n }\n return finish(new Response(request.method === \"HEAD\" ? null : known.status >= 500 ? \"Internal Server Error\" : known.code, {\n status: known.status, headers: { \"content-type\": \"text/plain; charset=utf-8\", \"cache-control\": \"no-store\" },\n }));\n }\n };\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /** Emits browser-safe, inferred Socket contracts from server channel definitions. */
2
+ export declare function generateSocketContracts(projectRoot: string): Promise<{
3
+ file: string;
4
+ count: number;
5
+ }>;
@@ -0,0 +1,162 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
3
+ import ts from "@typescript/typescript6";
4
+ import { discoverServerManifest } from "../framework-server/discovery.js";
5
+ import { standardSchemaTypes } from "./standard-schema-types.js";
6
+ function inside(parent, child) {
7
+ const path = relative(parent, child);
8
+ return path === "" || (path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute(path));
9
+ }
10
+ function compilerOptions(root) {
11
+ const config = ts.findConfigFile(root, ts.sys.fileExists, "tsconfig.json");
12
+ if (!config)
13
+ return { module: ts.ModuleKind.NodeNext, moduleResolution: ts.ModuleResolutionKind.NodeNext };
14
+ const loaded = ts.readConfigFile(config, ts.sys.readFile);
15
+ if (loaded.error)
16
+ throw new Error(ts.flattenDiagnosticMessageText(loaded.error.messageText, "\n"));
17
+ return ts.parseJsonConfigFileContent(loaded.config, ts.sys, dirname(config)).options;
18
+ }
19
+ function resolveImport(specifier, importer, options) {
20
+ const target = ts.resolveModuleName(specifier, importer, options, ts.sys).resolvedModule?.resolvedFileName;
21
+ if (!target)
22
+ throw new Error(`${importer}: unresolved import ${specifier}`);
23
+ return target;
24
+ }
25
+ function validateSharedGraph(file, root, shared, options, seen) {
26
+ if (seen.has(file))
27
+ return;
28
+ seen.add(file);
29
+ if (!inside(shared, file))
30
+ throw new Error(`${file}: public Socket schema must stay inside shared/`);
31
+ const source = ts.sys.readFile(file);
32
+ if (source === undefined)
33
+ throw new Error(`${file}: Socket schema file missing`);
34
+ const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);
35
+ const check = (specifier) => {
36
+ const target = resolveImport(specifier, file, options);
37
+ if (inside(root, target) && !relative(root, target).split(sep).includes("node_modules"))
38
+ validateSharedGraph(target, root, shared, options, seen);
39
+ };
40
+ for (const statement of ast.statements) {
41
+ if ((ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier))
42
+ check(statement.moduleSpecifier.text);
43
+ }
44
+ const visit = (node) => {
45
+ if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument) && ts.isStringLiteral(node.argument.literal))
46
+ check(node.argument.literal.text);
47
+ ts.forEachChild(node, visit);
48
+ };
49
+ visit(ast);
50
+ }
51
+ function property(object, name) {
52
+ const entry = object.properties.find((candidate) => (ts.isPropertyAssignment(candidate) || ts.isShorthandPropertyAssignment(candidate)) && candidate.name && (ts.isIdentifier(candidate.name) || ts.isStringLiteral(candidate.name)) && candidate.name.text === name);
53
+ if (!entry)
54
+ return undefined;
55
+ return ts.isPropertyAssignment(entry) ? entry.initializer : ts.isShorthandPropertyAssignment(entry) ? entry.name : undefined;
56
+ }
57
+ function publicSchemas(file, root, options, program, checker) {
58
+ const ast = program.getSourceFile(file);
59
+ if (!ast)
60
+ throw new Error(`${file}: Socket channel file missing`);
61
+ const imports = new Map();
62
+ for (const statement of ast.statements) {
63
+ if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier))
64
+ continue;
65
+ const clause = statement.importClause;
66
+ if (!clause || clause.isTypeOnly)
67
+ continue;
68
+ const target = resolveImport(statement.moduleSpecifier.text, file, options);
69
+ if (clause.name)
70
+ imports.set(clause.name.text, { file: target, exported: "default" });
71
+ if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
72
+ for (const element of clause.namedBindings.elements) {
73
+ if (!element.isTypeOnly)
74
+ imports.set(element.name.text, { file: target, exported: element.propertyName?.text ?? element.name.text });
75
+ }
76
+ }
77
+ if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings))
78
+ imports.set(clause.namedBindings.name.text, { file: target, exported: "*" });
79
+ }
80
+ const assignment = ast.statements.find((statement) => ts.isExportAssignment(statement) && !statement.isExportEquals);
81
+ const call = assignment?.expression;
82
+ if (!call || !ts.isCallExpression(call) || !ts.isIdentifier(call.expression) || call.expression.text !== "defineSocketChannel" || !call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) {
83
+ throw new Error(`${file}: public Socket contract requires export default defineSocketChannel({...})`);
84
+ }
85
+ const shared = join(root, "shared");
86
+ const seen = new Set();
87
+ const direction = (name) => {
88
+ const object = property(call.arguments[0], name);
89
+ if (!object || !ts.isObjectLiteralExpression(object))
90
+ throw new Error(`${file}: ${name} must be a static object`);
91
+ const result = Object.create(null);
92
+ for (const entry of object.properties) {
93
+ if (!ts.isPropertyAssignment(entry) || !(ts.isIdentifier(entry.name) || ts.isStringLiteral(entry.name)))
94
+ throw new Error(`${file}: ${name} requires named schema properties`);
95
+ const event = entry.name.text;
96
+ const value = entry.initializer;
97
+ let local;
98
+ let member;
99
+ if (ts.isIdentifier(value))
100
+ local = value.text;
101
+ else if (ts.isPropertyAccessExpression(value) && ts.isIdentifier(value.expression)) {
102
+ local = value.expression.text;
103
+ member = value.name.text;
104
+ }
105
+ else
106
+ throw new Error(`${file}: ${name}.${event} must reference an imported shared schema`);
107
+ const imported = imports.get(local);
108
+ if (!imported || !inside(shared, imported.file))
109
+ throw new Error(`${file}: ${name}.${event} must come from shared/`);
110
+ const exported = imported.exported === "*" ? member : imported.exported;
111
+ if (!exported || (member && imported.exported !== "*"))
112
+ throw new Error(`${file}: ${name}.${event} must reference one shared export`);
113
+ standardSchemaTypes(value, checker, () => new Error(`${file}: ${name}.${event} must expose concrete Standard Schema input and output types`));
114
+ validateSharedGraph(imported.file, root, shared, options, seen);
115
+ if (result[event])
116
+ throw new Error(`${file}: duplicate Socket event ${name}.${event}`);
117
+ result[event] = { file: imported.file, exported };
118
+ }
119
+ return result;
120
+ };
121
+ return { clientToServer: direction("clientToServer"), serverToClient: direction("serverToClient") };
122
+ }
123
+ /** Emits browser-safe, inferred Socket contracts from server channel definitions. */
124
+ export async function generateSocketContracts(projectRoot) {
125
+ const root = resolve(projectRoot);
126
+ const manifest = await discoverServerManifest(root);
127
+ const output = join(root, ".meeko", "generated", "socket-contracts.ts");
128
+ const options = compilerOptions(root);
129
+ const program = ts.createProgram((manifest.socket ?? []).map((endpoint) => endpoint.file), { ...options, noEmit: true });
130
+ const checker = program.getTypeChecker();
131
+ const channels = (manifest.socket ?? []).map((endpoint) => ({ name: endpoint.name, schemas: publicSchemas(endpoint.file, root, options, program, checker) }));
132
+ const sources = [...new Set(channels.flatMap(({ schemas }) => [...Object.values(schemas.clientToServer), ...Object.values(schemas.serverToClient)].map((entry) => entry.file)))].sort();
133
+ const aliases = new Map(sources.map((file, index) => [file, `__schema${index}`]));
134
+ const lines = sources.map((file) => {
135
+ const target = relative(dirname(output), file).replaceAll("\\", "/").replace(/\.(?:ts|mts|cts)$/, (suffix) => suffix === ".mts" ? ".mjs" : suffix === ".cts" ? ".cjs" : ".js");
136
+ return `import * as ${aliases.get(file)} from ${JSON.stringify(target.startsWith(".") ? target : `./${target}`)};`;
137
+ });
138
+ lines.push("export const socketContracts = {");
139
+ for (const channel of channels) {
140
+ lines.push(` ${JSON.stringify(channel.name)}: {`);
141
+ for (const direction of ["clientToServer", "serverToClient"]) {
142
+ lines.push(` ${direction}: {`);
143
+ for (const [event, schema] of Object.entries(channel.schemas[direction]))
144
+ lines.push(` ${JSON.stringify(event)}: ${aliases.get(schema.file)}[${JSON.stringify(schema.exported)}],`);
145
+ lines.push(" },");
146
+ }
147
+ lines.push(" },");
148
+ }
149
+ lines.push("} as const;", "");
150
+ const code = lines.join("\n");
151
+ let previous;
152
+ try {
153
+ previous = await readFile(output, "utf8");
154
+ }
155
+ catch { /* First generation. */ }
156
+ if (previous !== code) {
157
+ await mkdir(dirname(output), { recursive: true });
158
+ await writeFile(output, code);
159
+ }
160
+ return { file: output, count: channels.length };
161
+ }
162
+ //# sourceMappingURL=socket-contracts-generate.js.map