@meekojs/meeko 0.0.4 → 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 (139) hide show
  1. package/README.md +21 -19
  2. package/dist/autoimports-ts.d.ts +4 -4
  3. package/dist/autoimports-ts.js +86 -30
  4. package/dist/autoimports-ts.js.map +1 -1
  5. package/dist/autoimports.d.ts +2 -2
  6. package/dist/autoimports.js +23 -7
  7. package/dist/autoimports.js.map +1 -1
  8. package/dist/check.js +39 -10
  9. package/dist/check.js.map +1 -1
  10. package/dist/cli.js +37 -4
  11. package/dist/cli.js.map +1 -1
  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/props.d.ts +12 -0
  16. package/dist/compiler/props.js +32 -0
  17. package/dist/compiler/props.js.map +1 -0
  18. package/dist/compiler.js +55 -12
  19. package/dist/compiler.js.map +1 -1
  20. package/dist/component-errors.d.ts +18 -0
  21. package/dist/component-errors.js +65 -0
  22. package/dist/component-errors.js.map +1 -0
  23. package/dist/devtools.js +2 -4
  24. package/dist/devtools.js.map +1 -1
  25. package/dist/dom.d.ts +11 -5
  26. package/dist/dom.js +288 -88
  27. package/dist/dom.js.map +1 -1
  28. package/dist/error-observer.d.ts +6 -0
  29. package/dist/error-observer.js +41 -0
  30. package/dist/error-observer.js.map +1 -0
  31. package/dist/framework/check-app.js +160 -5
  32. package/dist/framework/check-app.js.map +1 -1
  33. package/dist/framework/check-project.d.ts +4 -0
  34. package/dist/framework/check-project.js +42 -0
  35. package/dist/framework/check-project.js.map +1 -0
  36. package/dist/framework/client.d.ts +3 -0
  37. package/dist/framework/client.js +136 -33
  38. package/dist/framework/client.js.map +1 -1
  39. package/dist/framework/clients.js +12 -4
  40. package/dist/framework/clients.js.map +1 -1
  41. package/dist/framework/contracts-generate.js +66 -3
  42. package/dist/framework/contracts-generate.js.map +1 -1
  43. package/dist/framework/init.js +21 -200
  44. package/dist/framework/init.js.map +1 -1
  45. package/dist/framework/middleware.d.ts +14 -0
  46. package/dist/framework/middleware.js +16 -0
  47. package/dist/framework/middleware.js.map +1 -0
  48. package/dist/framework/page-contracts-check.d.ts +8 -0
  49. package/dist/framework/page-contracts-check.js +110 -0
  50. package/dist/framework/page-contracts-check.js.map +1 -0
  51. package/dist/framework/page-contracts-generate.d.ts +2 -0
  52. package/dist/framework/page-contracts-generate.js +94 -0
  53. package/dist/framework/page-contracts-generate.js.map +1 -0
  54. package/dist/framework/page.d.ts +7 -3
  55. package/dist/framework/page.js +3 -1
  56. package/dist/framework/page.js.map +1 -1
  57. package/dist/framework/prerender.js +11 -5
  58. package/dist/framework/prerender.js.map +1 -1
  59. package/dist/framework/project-templates.d.ts +3 -0
  60. package/dist/framework/project-templates.js +119 -0
  61. package/dist/framework/project-templates.js.map +1 -0
  62. package/dist/framework/project.d.ts +9 -0
  63. package/dist/framework/project.js +272 -0
  64. package/dist/framework/project.js.map +1 -0
  65. package/dist/framework/router.d.ts +3 -1
  66. package/dist/framework/router.js +94 -8
  67. package/dist/framework/router.js.map +1 -1
  68. package/dist/framework/server.d.ts +17 -3
  69. package/dist/framework/server.js +71 -24
  70. package/dist/framework/server.js.map +1 -1
  71. package/dist/framework/socket-contracts-generate.js +8 -5
  72. package/dist/framework/socket-contracts-generate.js.map +1 -1
  73. package/dist/framework/socket.d.ts +2 -0
  74. package/dist/framework/socket.js +119 -17
  75. package/dist/framework/socket.js.map +1 -1
  76. package/dist/framework/standard-schema-types.d.ts +7 -0
  77. package/dist/framework/standard-schema-types.js +69 -0
  78. package/dist/framework/standard-schema-types.js.map +1 -0
  79. package/dist/framework/state.d.ts +7 -0
  80. package/dist/framework/state.js +78 -14
  81. package/dist/framework/state.js.map +1 -1
  82. package/dist/framework/styles.d.ts +2 -0
  83. package/dist/framework/styles.js +6 -0
  84. package/dist/framework/styles.js.map +1 -0
  85. package/dist/framework/type-declarations.d.ts +5 -0
  86. package/dist/framework/type-declarations.js +84 -0
  87. package/dist/framework/type-declarations.js.map +1 -0
  88. package/dist/framework-server/contracts.d.ts +11 -2
  89. package/dist/framework-server/contracts.js +62 -7
  90. package/dist/framework-server/contracts.js.map +1 -1
  91. package/dist/framework-server/discovery.d.ts +4 -1
  92. package/dist/framework-server/discovery.js +21 -16
  93. package/dist/framework-server/discovery.js.map +1 -1
  94. package/dist/framework-server/local.d.ts +2 -0
  95. package/dist/framework-server/local.js +5 -3
  96. package/dist/framework-server/local.js.map +1 -1
  97. package/dist/framework-server/middleware.d.ts +4 -0
  98. package/dist/framework-server/middleware.js +56 -0
  99. package/dist/framework-server/middleware.js.map +1 -0
  100. package/dist/framework-server/node-upgrade.js +27 -9
  101. package/dist/framework-server/node-upgrade.js.map +1 -1
  102. package/dist/framework-server/node-websocket.js +4 -2
  103. package/dist/framework-server/node-websocket.js.map +1 -1
  104. package/dist/framework-server/session-stores.d.ts +9 -2
  105. package/dist/framework-server/session-stores.js +37 -11
  106. package/dist/framework-server/session-stores.js.map +1 -1
  107. package/dist/framework-server/sessions.d.ts +6 -0
  108. package/dist/framework-server/sessions.js +41 -10
  109. package/dist/framework-server/sessions.js.map +1 -1
  110. package/dist/framework-server/socket.js +62 -27
  111. package/dist/framework-server/socket.js.map +1 -1
  112. package/dist/framework-server.d.ts +2 -0
  113. package/dist/framework-server.js +1 -0
  114. package/dist/framework-server.js.map +1 -1
  115. package/dist/framework.d.ts +3 -1
  116. package/dist/framework.js +1 -0
  117. package/dist/framework.js.map +1 -1
  118. package/dist/hmr.js +74 -24
  119. package/dist/hmr.js.map +1 -1
  120. package/dist/index.d.ts +2 -0
  121. package/dist/index.js +1 -0
  122. package/dist/index.js.map +1 -1
  123. package/dist/init.js +27 -1
  124. package/dist/init.js.map +1 -1
  125. package/dist/internal.d.ts +2 -2
  126. package/dist/internal.js +2 -2
  127. package/dist/internal.js.map +1 -1
  128. package/dist/node.d.ts +5 -1
  129. package/dist/node.js +80 -10
  130. package/dist/node.js.map +1 -1
  131. package/dist/reactivity.d.ts +12 -3
  132. package/dist/reactivity.js +94 -17
  133. package/dist/reactivity.js.map +1 -1
  134. package/dist/types.d.ts +2 -0
  135. package/dist/types.js +3 -1
  136. package/dist/types.js.map +1 -1
  137. package/dist/vite.js +29 -9
  138. package/dist/vite.js.map +1 -1
  139. package/package.json +2 -2
@@ -1,8 +1,11 @@
1
- import { readdir, stat } from "node:fs/promises";
1
+ import { randomUUID } from "node:crypto";
2
+ import { lstat, readdir, stat } from "node:fs/promises";
2
3
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
3
4
  import { escapeHtml, serializeJson } from "../server.js";
4
5
  import { withRequestContext } from "../framework-server/context.js";
6
+ import { ApiError, errorResponse, normalizeServerError, observeServerError } from "../framework-server/contracts.js";
5
7
  import { PageInputError, pageSearchObject, validatePageInputs } from "./page.js";
8
+ import { runRouteMiddleware } from "./middleware.js";
6
9
  import { StateStore, withStateStore } from "./state.js";
7
10
  import { createRouteManifest, matchRoute } from "./router.js";
8
11
  function routeId(relativeFile) {
@@ -27,6 +30,7 @@ export async function discoverRoutes(projectRoot) {
27
30
  }
28
31
  await walk(pagesRoot);
29
32
  const appShell = resolve(projectRoot, "app", "app.meeko");
33
+ const defaultLayout = resolve(projectRoot, "app", "layouts", "default.meeko");
30
34
  let hasAppShell = false;
31
35
  try {
32
36
  hasAppShell = (await stat(appShell)).isFile();
@@ -35,12 +39,25 @@ export async function discoverRoutes(projectRoot) {
35
39
  if (error.code !== "ENOENT")
36
40
  throw error;
37
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
+ }
38
53
  const routes = [];
39
54
  for (const file of files) {
40
55
  if (!file.endsWith(".meeko") || basename(file).startsWith("+"))
41
56
  continue;
42
57
  const directory = dirname(file);
43
58
  const layouts = hasAppShell ? [appShell] : [];
59
+ if (hasDefaultLayout)
60
+ layouts.push(defaultLayout);
44
61
  let cursor = pagesRoot;
45
62
  const relativeDirectory = relative(pagesRoot, directory);
46
63
  if (files.has(join(cursor, "+layout.meeko")))
@@ -74,32 +91,43 @@ export async function discoverRoutes(projectRoot) {
74
91
  }
75
92
  return createRouteManifest(routes);
76
93
  }
77
- /** Portable Fetch handler. Node adapters can pass their Request directly. */
78
94
  export function createFrameworkHandler(options) {
79
95
  return async (request) => {
96
+ const fallbackRequestId = randomUUID();
80
97
  if (request.method !== "GET" && request.method !== "HEAD")
81
- return new Response(null, { status: 405, headers: { Allow: "GET, HEAD" } });
82
- const url = new URL(request.url);
83
- const match = matchRoute(options.routes, url.pathname);
84
- if (!match)
85
- return new Response("Not Found", { status: 404 });
98
+ return new Response(null, {
99
+ status: 405, headers: { Allow: "GET, HEAD", "x-request-id": fallbackRequestId, "cache-control": "no-store" },
100
+ });
86
101
  const stateStore = new StateStore();
102
+ let errorRoute;
87
103
  let requestContext;
88
104
  const finish = (response) => {
89
- if (!requestContext)
90
- return response;
91
105
  const headers = new Headers(response.headers);
92
- headers.set("x-request-id", requestContext.requestId);
93
- headers.set("x-meeko-csrf-token", requestContext.session.current?.csrfToken ?? "");
94
- if (requestContext.session.cookieHeader)
95
- headers.append("set-cookie", requestContext.session.cookieHeader);
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
+ }
96
112
  return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
97
113
  };
98
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;
99
122
  requestContext = await options.createContext?.(request);
100
123
  if (requestContext && requestContext.request !== request)
101
124
  throw new TypeError("Request context belongs to another request");
102
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);
103
131
  const sidecar = match.route.sidecar && options.loadRoute ? await options.loadRoute(match.route.sidecar) : undefined;
104
132
  const validated = await validatePageInputs(sidecar, match.params, pageSearchObject(url.searchParams));
105
133
  const context = {
@@ -166,26 +194,45 @@ export function createFrameworkHandler(options) {
166
194
  catch (error) {
167
195
  if (error instanceof Response)
168
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
+ }
169
207
  if (error instanceof PageInputError)
170
208
  return finish(new Response(error.code, {
171
209
  status: 400, headers: { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" },
172
210
  }));
173
- if (match.route.error) {
211
+ const errorFile = errorRoute;
212
+ if (errorFile) {
174
213
  try {
175
- const errorPage = await options.loadPage(match.route.error);
176
- const errorRendered = withStateStore(stateStore, () => errorPage.renderWithState({
177
- status: 500, message: "Internal Server Error",
178
- }));
179
- const document = `<!doctype html><html><head><meta charset="utf-8"><title>Error</title></head><body><div id="app">${errorRendered.html}</div></body></html>`;
180
- return finish(new Response(request.method === "HEAD" ? null : document, {
181
- status: 500, headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" },
182
- }));
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();
183
227
  }
184
- catch {
228
+ catch (failure) {
229
+ report(failure);
185
230
  // The error route failed; keep private errors out of the response.
186
231
  }
187
232
  }
188
- return finish(new Response(request.method === "HEAD" ? null : "Internal Server Error", { status: 500 }));
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
+ }));
189
236
  }
190
237
  };
191
238
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/framework/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { 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 { PageInputError, pageSearchObject, validatePageInputs } from \"./page.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 let hasAppShell = false;\n try { hasAppShell = (await stat(appShell)).isFile(); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error; }\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 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\" | \"client\";\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 {\n readonly routes: readonly RouteRecord[];\n readonly loadPage: (file: string) => Promise<PageModule>;\n readonly loadRoute?: (file: string) => Promise<PageRoute>;\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 /** 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/** Portable Fetch handler. Node adapters can pass their Request directly. */\nexport function createFrameworkHandler(options: FrameworkHandlerOptions): (request: Request) => Promise<Response> {\n return async (request) => {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") return new Response(null, { status: 405, headers: { Allow: \"GET, HEAD\" } });\n const url = new URL(request.url);\n const match = matchRoute(options.routes, url.pathname);\n if (!match) return new Response(\"Not Found\", { status: 404 });\n const stateStore = new StateStore();\n let requestContext: RequestContext | undefined;\n const finish = (response: Response): Response => {\n if (!requestContext) return response;\n const headers = new Headers(response.headers);\n headers.set(\"x-request-id\", requestContext.requestId);\n headers.set(\"x-meeko-csrf-token\", requestContext.session.current?.csrfToken ?? \"\");\n if (requestContext.session.cookieHeader) headers.append(\"set-cookie\", requestContext.session.cookieHeader);\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers });\n };\n try {\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 sidecar = match.route.sidecar && options.loadRoute ? await options.loadRoute(match.route.sidecar) : 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 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 if (match.route.error) {\n try {\n const errorPage = await options.loadPage(match.route.error);\n const errorRendered = withStateStore(stateStore, () => errorPage.renderWithState({\n status: 500, message: \"Internal Server Error\",\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: 500, headers: { \"content-type\": \"text/html; charset=utf-8\", \"cache-control\": \"no-store\" },\n }));\n } catch {\n // The error route failed; keep private errors out of the response.\n }\n }\n return finish(new Response(request.method === \"HEAD\" ? null : \"Internal Server Error\", { status: 500 }));\n }\n };\n}\n"]}
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"]}
@@ -2,6 +2,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
3
3
  import ts from "@typescript/typescript6";
4
4
  import { discoverServerManifest } from "../framework-server/discovery.js";
5
+ import { standardSchemaTypes } from "./standard-schema-types.js";
5
6
  function inside(parent, child) {
6
7
  const path = relative(parent, child);
7
8
  return path === "" || (path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute(path));
@@ -53,11 +54,10 @@ function property(object, name) {
53
54
  return undefined;
54
55
  return ts.isPropertyAssignment(entry) ? entry.initializer : ts.isShorthandPropertyAssignment(entry) ? entry.name : undefined;
55
56
  }
56
- function publicSchemas(file, root, options) {
57
- const source = ts.sys.readFile(file);
58
- if (source === undefined)
57
+ function publicSchemas(file, root, options, program, checker) {
58
+ const ast = program.getSourceFile(file);
59
+ if (!ast)
59
60
  throw new Error(`${file}: Socket channel file missing`);
60
- const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);
61
61
  const imports = new Map();
62
62
  for (const statement of ast.statements) {
63
63
  if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier))
@@ -110,6 +110,7 @@ function publicSchemas(file, root, options) {
110
110
  const exported = imported.exported === "*" ? member : imported.exported;
111
111
  if (!exported || (member && imported.exported !== "*"))
112
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`));
113
114
  validateSharedGraph(imported.file, root, shared, options, seen);
114
115
  if (result[event])
115
116
  throw new Error(`${file}: duplicate Socket event ${name}.${event}`);
@@ -125,7 +126,9 @@ export async function generateSocketContracts(projectRoot) {
125
126
  const manifest = await discoverServerManifest(root);
126
127
  const output = join(root, ".meeko", "generated", "socket-contracts.ts");
127
128
  const options = compilerOptions(root);
128
- const channels = (manifest.socket ?? []).map((endpoint) => ({ name: endpoint.name, schemas: publicSchemas(endpoint.file, root, options) }));
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) }));
129
132
  const sources = [...new Set(channels.flatMap(({ schemas }) => [...Object.values(schemas.clientToServer), ...Object.values(schemas.serverToClient)].map((entry) => entry.file)))].sort();
130
133
  const aliases = new Map(sources.map((file, index) => [file, `__schema${index}`]));
131
134
  const lines = sources.map((file) => {
@@ -1 +1 @@
1
- {"version":3,"file":"socket-contracts-generate.js","sourceRoot":"","sources":["../../src/framework/socket-contracts-generate.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport ts from \"@typescript/typescript6\";\nimport { discoverServerManifest } from \"../framework-server/discovery.js\";\n\ninterface ImportedSymbol { file: string; exported: string; }\ninterface SchemaReference { file: string; exported: string; }\n\nfunction inside(parent: string, child: string): boolean {\n const path = relative(parent, child);\n return path === \"\" || (path !== \"..\" && !path.startsWith(`..${sep}`) && !isAbsolute(path));\n}\n\nfunction compilerOptions(root: string): ts.CompilerOptions {\n const config = ts.findConfigFile(root, ts.sys.fileExists, \"tsconfig.json\");\n if (!config) return { module: ts.ModuleKind.NodeNext, moduleResolution: ts.ModuleResolutionKind.NodeNext };\n const loaded = ts.readConfigFile(config, ts.sys.readFile);\n if (loaded.error) throw new Error(ts.flattenDiagnosticMessageText(loaded.error.messageText, \"\\n\"));\n return ts.parseJsonConfigFileContent(loaded.config, ts.sys, dirname(config)).options;\n}\n\nfunction resolveImport(specifier: string, importer: string, options: ts.CompilerOptions): string {\n const target = ts.resolveModuleName(specifier, importer, options, ts.sys).resolvedModule?.resolvedFileName;\n if (!target) throw new Error(`${importer}: unresolved import ${specifier}`);\n return target;\n}\n\nfunction validateSharedGraph(file: string, root: string, shared: string, options: ts.CompilerOptions, seen: Set<string>): void {\n if (seen.has(file)) return;\n seen.add(file);\n if (!inside(shared, file)) throw new Error(`${file}: public Socket schema must stay inside shared/`);\n const source = ts.sys.readFile(file);\n if (source === undefined) throw new Error(`${file}: Socket schema file missing`);\n const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);\n const check = (specifier: string): void => {\n const target = resolveImport(specifier, file, options);\n if (inside(root, target) && !relative(root, target).split(sep).includes(\"node_modules\")) validateSharedGraph(target, root, shared, options, seen);\n };\n for (const statement of ast.statements) {\n if ((ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) check(statement.moduleSpecifier.text);\n }\n const visit = (node: ts.Node): void => {\n if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument) && ts.isStringLiteral(node.argument.literal)) check(node.argument.literal.text);\n ts.forEachChild(node, visit);\n };\n visit(ast);\n}\n\nfunction property(object: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined {\n 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);\n if (!entry) return undefined;\n return ts.isPropertyAssignment(entry) ? entry.initializer : ts.isShorthandPropertyAssignment(entry) ? entry.name : undefined;\n}\n\nfunction publicSchemas(file: string, root: string, options: ts.CompilerOptions): { clientToServer: Record<string, SchemaReference>; serverToClient: Record<string, SchemaReference> } {\n const source = ts.sys.readFile(file);\n if (source === undefined) throw new Error(`${file}: Socket channel file missing`);\n const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);\n const imports = new Map<string, ImportedSymbol>();\n for (const statement of ast.statements) {\n if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue;\n const clause = statement.importClause;\n if (!clause || clause.isTypeOnly) continue;\n const target = resolveImport(statement.moduleSpecifier.text, file, options);\n if (clause.name) imports.set(clause.name.text, { file: target, exported: \"default\" });\n if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {\n for (const element of clause.namedBindings.elements) {\n if (!element.isTypeOnly) imports.set(element.name.text, { file: target, exported: element.propertyName?.text ?? element.name.text });\n }\n }\n if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) imports.set(clause.namedBindings.name.text, { file: target, exported: \"*\" });\n }\n const assignment = ast.statements.find((statement): statement is ts.ExportAssignment => ts.isExportAssignment(statement) && !statement.isExportEquals);\n const call = assignment?.expression;\n if (!call || !ts.isCallExpression(call) || !ts.isIdentifier(call.expression) || call.expression.text !== \"defineSocketChannel\" || !call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) {\n throw new Error(`${file}: public Socket contract requires export default defineSocketChannel({...})`);\n }\n const shared = join(root, \"shared\");\n const seen = new Set<string>();\n const direction = (name: \"clientToServer\" | \"serverToClient\"): Record<string, SchemaReference> => {\n const object = property(call.arguments[0] as ts.ObjectLiteralExpression, name);\n if (!object || !ts.isObjectLiteralExpression(object)) throw new Error(`${file}: ${name} must be a static object`);\n const result: Record<string, SchemaReference> = Object.create(null);\n for (const entry of object.properties) {\n if (!ts.isPropertyAssignment(entry) || !(ts.isIdentifier(entry.name) || ts.isStringLiteral(entry.name))) throw new Error(`${file}: ${name} requires named schema properties`);\n const event = entry.name.text;\n const value = entry.initializer;\n let local: string;\n let member: string | undefined;\n if (ts.isIdentifier(value)) local = value.text;\n else if (ts.isPropertyAccessExpression(value) && ts.isIdentifier(value.expression)) { local = value.expression.text; member = value.name.text; }\n else throw new Error(`${file}: ${name}.${event} must reference an imported shared schema`);\n const imported = imports.get(local);\n if (!imported || !inside(shared, imported.file)) throw new Error(`${file}: ${name}.${event} must come from shared/`);\n const exported = imported.exported === \"*\" ? member : imported.exported;\n if (!exported || (member && imported.exported !== \"*\")) throw new Error(`${file}: ${name}.${event} must reference one shared export`);\n validateSharedGraph(imported.file, root, shared, options, seen);\n if (result[event]) throw new Error(`${file}: duplicate Socket event ${name}.${event}`);\n result[event] = { file: imported.file, exported };\n }\n return result;\n };\n return { clientToServer: direction(\"clientToServer\"), serverToClient: direction(\"serverToClient\") };\n}\n\n/** Emits browser-safe, inferred Socket contracts from server channel definitions. */\nexport async function generateSocketContracts(projectRoot: string): Promise<{ file: string; count: number }> {\n const root = resolve(projectRoot);\n const manifest = await discoverServerManifest(root);\n const output = join(root, \".meeko\", \"generated\", \"socket-contracts.ts\");\n const options = compilerOptions(root);\n const channels = (manifest.socket ?? []).map((endpoint) => ({ name: endpoint.name, schemas: publicSchemas(endpoint.file, root, options) }));\n const sources = [...new Set(channels.flatMap(({ schemas }) => [...Object.values(schemas.clientToServer), ...Object.values(schemas.serverToClient)].map((entry) => entry.file)))].sort();\n const aliases = new Map(sources.map((file, index) => [file, `__schema${index}`]));\n const lines = sources.map((file) => {\n const target = relative(dirname(output), file).replaceAll(\"\\\\\", \"/\").replace(/\\.(?:ts|mts|cts)$/, (suffix) => suffix === \".mts\" ? \".mjs\" : suffix === \".cts\" ? \".cjs\" : \".js\");\n return `import * as ${aliases.get(file)} from ${JSON.stringify(target.startsWith(\".\") ? target : `./${target}`)};`;\n });\n lines.push(\"export const socketContracts = {\");\n for (const channel of channels) {\n lines.push(` ${JSON.stringify(channel.name)}: {`);\n for (const direction of [\"clientToServer\", \"serverToClient\"] as const) {\n lines.push(` ${direction}: {`);\n for (const [event, schema] of Object.entries(channel.schemas[direction])) lines.push(` ${JSON.stringify(event)}: ${aliases.get(schema.file)}[${JSON.stringify(schema.exported)}],`);\n lines.push(\" },\");\n }\n lines.push(\" },\");\n }\n lines.push(\"} as const;\", \"\");\n const code = lines.join(\"\\n\");\n let previous: string | undefined;\n try { previous = await readFile(output, \"utf8\"); } catch { /* First generation. */ }\n if (previous !== code) { await mkdir(dirname(output), { recursive: true }); await writeFile(output, code); }\n return { file: output, count: channels.length };\n}\n"]}
1
+ {"version":3,"file":"socket-contracts-generate.js","sourceRoot":"","sources":["../../src/framework/socket-contracts-generate.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport ts from \"@typescript/typescript6\";\nimport { discoverServerManifest } from \"../framework-server/discovery.js\";\nimport { standardSchemaTypes } from \"./standard-schema-types.js\";\n\ninterface ImportedSymbol { file: string; exported: string; }\ninterface SchemaReference { file: string; exported: string; }\n\nfunction inside(parent: string, child: string): boolean {\n const path = relative(parent, child);\n return path === \"\" || (path !== \"..\" && !path.startsWith(`..${sep}`) && !isAbsolute(path));\n}\n\nfunction compilerOptions(root: string): ts.CompilerOptions {\n const config = ts.findConfigFile(root, ts.sys.fileExists, \"tsconfig.json\");\n if (!config) return { module: ts.ModuleKind.NodeNext, moduleResolution: ts.ModuleResolutionKind.NodeNext };\n const loaded = ts.readConfigFile(config, ts.sys.readFile);\n if (loaded.error) throw new Error(ts.flattenDiagnosticMessageText(loaded.error.messageText, \"\\n\"));\n return ts.parseJsonConfigFileContent(loaded.config, ts.sys, dirname(config)).options;\n}\n\nfunction resolveImport(specifier: string, importer: string, options: ts.CompilerOptions): string {\n const target = ts.resolveModuleName(specifier, importer, options, ts.sys).resolvedModule?.resolvedFileName;\n if (!target) throw new Error(`${importer}: unresolved import ${specifier}`);\n return target;\n}\n\nfunction validateSharedGraph(file: string, root: string, shared: string, options: ts.CompilerOptions, seen: Set<string>): void {\n if (seen.has(file)) return;\n seen.add(file);\n if (!inside(shared, file)) throw new Error(`${file}: public Socket schema must stay inside shared/`);\n const source = ts.sys.readFile(file);\n if (source === undefined) throw new Error(`${file}: Socket schema file missing`);\n const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);\n const check = (specifier: string): void => {\n const target = resolveImport(specifier, file, options);\n if (inside(root, target) && !relative(root, target).split(sep).includes(\"node_modules\")) validateSharedGraph(target, root, shared, options, seen);\n };\n for (const statement of ast.statements) {\n if ((ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)) check(statement.moduleSpecifier.text);\n }\n const visit = (node: ts.Node): void => {\n if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument) && ts.isStringLiteral(node.argument.literal)) check(node.argument.literal.text);\n ts.forEachChild(node, visit);\n };\n visit(ast);\n}\n\nfunction property(object: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined {\n 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);\n if (!entry) return undefined;\n return ts.isPropertyAssignment(entry) ? entry.initializer : ts.isShorthandPropertyAssignment(entry) ? entry.name : undefined;\n}\n\nfunction publicSchemas(file: string, root: string, options: ts.CompilerOptions, program: ts.Program, checker: ts.TypeChecker): { clientToServer: Record<string, SchemaReference>; serverToClient: Record<string, SchemaReference> } {\n const ast = program.getSourceFile(file);\n if (!ast) throw new Error(`${file}: Socket channel file missing`);\n const imports = new Map<string, ImportedSymbol>();\n for (const statement of ast.statements) {\n if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue;\n const clause = statement.importClause;\n if (!clause || clause.isTypeOnly) continue;\n const target = resolveImport(statement.moduleSpecifier.text, file, options);\n if (clause.name) imports.set(clause.name.text, { file: target, exported: \"default\" });\n if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {\n for (const element of clause.namedBindings.elements) {\n if (!element.isTypeOnly) imports.set(element.name.text, { file: target, exported: element.propertyName?.text ?? element.name.text });\n }\n }\n if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) imports.set(clause.namedBindings.name.text, { file: target, exported: \"*\" });\n }\n const assignment = ast.statements.find((statement): statement is ts.ExportAssignment => ts.isExportAssignment(statement) && !statement.isExportEquals);\n const call = assignment?.expression;\n if (!call || !ts.isCallExpression(call) || !ts.isIdentifier(call.expression) || call.expression.text !== \"defineSocketChannel\" || !call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) {\n throw new Error(`${file}: public Socket contract requires export default defineSocketChannel({...})`);\n }\n const shared = join(root, \"shared\");\n const seen = new Set<string>();\n const direction = (name: \"clientToServer\" | \"serverToClient\"): Record<string, SchemaReference> => {\n const object = property(call.arguments[0] as ts.ObjectLiteralExpression, name);\n if (!object || !ts.isObjectLiteralExpression(object)) throw new Error(`${file}: ${name} must be a static object`);\n const result: Record<string, SchemaReference> = Object.create(null);\n for (const entry of object.properties) {\n if (!ts.isPropertyAssignment(entry) || !(ts.isIdentifier(entry.name) || ts.isStringLiteral(entry.name))) throw new Error(`${file}: ${name} requires named schema properties`);\n const event = entry.name.text;\n const value = entry.initializer;\n let local: string;\n let member: string | undefined;\n if (ts.isIdentifier(value)) local = value.text;\n else if (ts.isPropertyAccessExpression(value) && ts.isIdentifier(value.expression)) { local = value.expression.text; member = value.name.text; }\n else throw new Error(`${file}: ${name}.${event} must reference an imported shared schema`);\n const imported = imports.get(local);\n if (!imported || !inside(shared, imported.file)) throw new Error(`${file}: ${name}.${event} must come from shared/`);\n const exported = imported.exported === \"*\" ? member : imported.exported;\n if (!exported || (member && imported.exported !== \"*\")) throw new Error(`${file}: ${name}.${event} must reference one shared export`);\n standardSchemaTypes(value, checker, () => new Error(`${file}: ${name}.${event} must expose concrete Standard Schema input and output types`));\n validateSharedGraph(imported.file, root, shared, options, seen);\n if (result[event]) throw new Error(`${file}: duplicate Socket event ${name}.${event}`);\n result[event] = { file: imported.file, exported };\n }\n return result;\n };\n return { clientToServer: direction(\"clientToServer\"), serverToClient: direction(\"serverToClient\") };\n}\n\n/** Emits browser-safe, inferred Socket contracts from server channel definitions. */\nexport async function generateSocketContracts(projectRoot: string): Promise<{ file: string; count: number }> {\n const root = resolve(projectRoot);\n const manifest = await discoverServerManifest(root);\n const output = join(root, \".meeko\", \"generated\", \"socket-contracts.ts\");\n const options = compilerOptions(root);\n const program = ts.createProgram((manifest.socket ?? []).map((endpoint) => endpoint.file), { ...options, noEmit: true });\n const checker = program.getTypeChecker();\n const channels = (manifest.socket ?? []).map((endpoint) => ({ name: endpoint.name, schemas: publicSchemas(endpoint.file, root, options, program, checker) }));\n const sources = [...new Set(channels.flatMap(({ schemas }) => [...Object.values(schemas.clientToServer), ...Object.values(schemas.serverToClient)].map((entry) => entry.file)))].sort();\n const aliases = new Map(sources.map((file, index) => [file, `__schema${index}`]));\n const lines = sources.map((file) => {\n const target = relative(dirname(output), file).replaceAll(\"\\\\\", \"/\").replace(/\\.(?:ts|mts|cts)$/, (suffix) => suffix === \".mts\" ? \".mjs\" : suffix === \".cts\" ? \".cjs\" : \".js\");\n return `import * as ${aliases.get(file)} from ${JSON.stringify(target.startsWith(\".\") ? target : `./${target}`)};`;\n });\n lines.push(\"export const socketContracts = {\");\n for (const channel of channels) {\n lines.push(` ${JSON.stringify(channel.name)}: {`);\n for (const direction of [\"clientToServer\", \"serverToClient\"] as const) {\n lines.push(` ${direction}: {`);\n for (const [event, schema] of Object.entries(channel.schemas[direction])) lines.push(` ${JSON.stringify(event)}: ${aliases.get(schema.file)}[${JSON.stringify(schema.exported)}],`);\n lines.push(\" },\");\n }\n lines.push(\" },\");\n }\n lines.push(\"} as const;\", \"\");\n const code = lines.join(\"\\n\");\n let previous: string | undefined;\n try { previous = await readFile(output, \"utf8\"); } catch { /* First generation. */ }\n if (previous !== code) { await mkdir(dirname(output), { recursive: true }); await writeFile(output, code); }\n return { file: output, count: channels.length };\n}\n"]}
@@ -49,6 +49,8 @@ export interface SocketClientOptions {
49
49
  readonly maxRetryMs?: number;
50
50
  readonly maxMessageBytes?: number;
51
51
  readonly webSocketFactory?: (url: string) => WebSocket;
52
+ /** Receives invalid inbound messages and consumer listener failures. */
53
+ readonly onError?: (error: unknown) => void;
52
54
  }
53
55
  export interface SocketRegistryOptions extends SocketClientOptions {
54
56
  /** HTTP(S) or WS(S) base URL. Defaults to the current browser origin. */
@@ -1,4 +1,6 @@
1
- import { onCleanup, signal } from "../reactivity.js";
1
+ import { currentEffectOwner, onCleanup, signal } from "../reactivity.js";
2
+ import { logClientError, observeCallback } from "../error-observer.js";
3
+ import { currentAppErrorChannel, currentComponentErrorHandler } from "../component-errors.js";
2
4
  import { serializeJson } from "../server.js";
3
5
  function socketUrl(name, options) {
4
6
  if (typeof window === "undefined")
@@ -33,21 +35,71 @@ export function createSocketClient(url, contract, options = {}) {
33
35
  let retry;
34
36
  let attempts = 0;
35
37
  let closed = false;
38
+ const reportError = (error) => {
39
+ if (!options.onError) {
40
+ logClientError("Meeko socket client error", error);
41
+ return;
42
+ }
43
+ observeCallback(() => options.onError(error), (observerError) => logClientError("Meeko socket error observer failed", error, observerError));
44
+ };
45
+ const setState = (next) => {
46
+ try {
47
+ state.value = next;
48
+ }
49
+ catch (error) {
50
+ reportError(error);
51
+ }
52
+ };
53
+ const closePeer = (peer, code, reason) => {
54
+ try {
55
+ peer?.close(code, reason);
56
+ }
57
+ catch (error) {
58
+ reportError(error);
59
+ }
60
+ };
61
+ const scheduleRetry = () => {
62
+ if (closed)
63
+ return;
64
+ const delay = Math.min((options.retryMs ?? 500) * 2 ** attempts++, options.maxRetryMs ?? 30_000);
65
+ retry = setTimeout(() => {
66
+ retry = undefined;
67
+ try {
68
+ connect();
69
+ }
70
+ catch (error) {
71
+ reportError(error);
72
+ setState("closed");
73
+ scheduleRetry();
74
+ }
75
+ }, delay);
76
+ };
36
77
  const connect = () => {
37
78
  if (closed)
38
79
  return;
39
- state.value = "connecting";
80
+ setState("connecting");
40
81
  const peer = factory(url);
41
82
  socket = peer;
83
+ let transportErrorReported = false;
42
84
  peer.addEventListener("open", () => { if (peer === socket) {
43
85
  attempts = 0;
44
- state.value = "open";
86
+ setState("open");
45
87
  } });
88
+ peer.addEventListener("error", () => {
89
+ if (peer !== socket || closed || transportErrorReported)
90
+ return;
91
+ transportErrorReported = true;
92
+ reportError(new Error("Socket transport error"));
93
+ });
46
94
  peer.addEventListener("message", (message) => {
47
- if (peer !== socket || typeof message.data !== "string" || new TextEncoder().encode(message.data).byteLength > maxBytes) {
95
+ if (peer !== socket || closed)
96
+ return;
97
+ if (typeof message.data !== "string" || new TextEncoder().encode(message.data).byteLength > maxBytes) {
98
+ reportError(new RangeError("Socket message too large or not text"));
48
99
  closed = true;
49
- state.value = "closed";
50
- peer.close(1009, "Message too large");
100
+ setState("closed");
101
+ listeners.clear();
102
+ closePeer(peer, 1009, "Message too large");
51
103
  return;
52
104
  }
53
105
  void (async () => {
@@ -58,20 +110,33 @@ export function createSocketClient(url, contract, options = {}) {
58
110
  if (!schema)
59
111
  throw new TypeError("Unknown socket event");
60
112
  const value = await validate(schema, decoded.payload);
61
- for (const listener of listeners.get(decoded.event) ?? [])
62
- listener(value);
63
- })().catch(() => { closed = true; state.value = "closed"; peer.close(1008, "Invalid event"); });
113
+ if (peer !== socket || closed)
114
+ return;
115
+ for (const listener of listeners.get(decoded.event) ?? []) {
116
+ if (peer !== socket || closed)
117
+ return;
118
+ observeCallback(() => listener(value), reportError);
119
+ }
120
+ })().catch((error) => {
121
+ if (peer !== socket || closed)
122
+ return;
123
+ reportError(error);
124
+ closed = true;
125
+ setState("closed");
126
+ listeners.clear();
127
+ closePeer(peer, 1008, "Invalid event");
128
+ });
64
129
  });
65
130
  peer.addEventListener("close", (event) => {
66
131
  if (peer !== socket || closed)
67
132
  return;
68
- state.value = "closed";
133
+ setState("closed");
69
134
  if ([1008, 1009].includes(event.code)) {
70
135
  closed = true;
136
+ listeners.clear();
71
137
  return;
72
138
  }
73
- const delay = Math.min((options.retryMs ?? 500) * 2 ** attempts++, options.maxRetryMs ?? 30_000);
74
- retry = setTimeout(connect, delay);
139
+ scheduleRetry();
75
140
  });
76
141
  };
77
142
  connect();
@@ -95,18 +160,23 @@ export function createSocketClient(url, contract, options = {}) {
95
160
  const set = listeners.get(event) ?? new Set();
96
161
  set.add(listener);
97
162
  listeners.set(event, set);
98
- return () => { set.delete(listener); if (set.size === 0)
163
+ const unsubscribe = () => { set.delete(listener); if (set.size === 0)
99
164
  listeners.delete(event); };
165
+ if (currentEffectOwner())
166
+ onCleanup(unsubscribe);
167
+ return unsubscribe;
100
168
  },
101
169
  close() {
102
- if (closed)
170
+ if (closed) {
171
+ listeners.clear();
103
172
  return;
173
+ }
104
174
  closed = true;
105
175
  if (retry)
106
176
  clearTimeout(retry);
107
- socket?.close(1000, "Client closed");
177
+ closePeer(socket, 1000, "Client closed");
108
178
  listeners.clear();
109
- state.value = "closed";
179
+ setState("closed");
110
180
  },
111
181
  };
112
182
  }
@@ -114,7 +184,8 @@ export function createSocketClient(url, contract, options = {}) {
114
184
  export function useSocket(url, contract, options = {}) {
115
185
  if (typeof window === "undefined")
116
186
  throw new Error("useSocket() is only available in the browser");
117
- const client = createSocketClient(url, contract, options);
187
+ const onError = options.onError ?? currentComponentErrorHandler();
188
+ const client = createSocketClient(url, contract, onError ? { ...options, onError } : options);
118
189
  try {
119
190
  onCleanup(() => client.close());
120
191
  }
@@ -129,9 +200,40 @@ export function createSocketRegistry(contracts, options = {}) {
129
200
  const result = Object.create(null);
130
201
  for (const name of Object.keys(contracts)) {
131
202
  let client;
203
+ const appClients = new WeakMap();
204
+ const rootClients = new WeakMap();
132
205
  Object.defineProperty(result, name, {
133
206
  enumerable: true,
134
207
  get() {
208
+ const channel = currentAppErrorChannel();
209
+ if (channel) {
210
+ let scoped = appClients.get(channel);
211
+ if (!scoped) {
212
+ const onError = options.onError ?? ((error) => {
213
+ const handler = channel.current();
214
+ if (handler)
215
+ return handler(error);
216
+ logClientError("Meeko socket client error", error);
217
+ });
218
+ scoped = createSocketClient(socketUrl(name, options), contracts[name], { ...options, onError });
219
+ appClients.set(channel, scoped);
220
+ const owned = scoped;
221
+ channel.track(() => { owned.close(); appClients.delete(channel); });
222
+ }
223
+ return scoped;
224
+ }
225
+ const owner = currentEffectOwner();
226
+ if (owner) {
227
+ let scoped = rootClients.get(owner);
228
+ if (!scoped) {
229
+ const onError = options.onError ?? currentComponentErrorHandler();
230
+ scoped = createSocketClient(socketUrl(name, options), contracts[name], onError ? { ...options, onError } : options);
231
+ rootClients.set(owner, scoped);
232
+ const owned = scoped;
233
+ onCleanup(() => { owned.close(); rootClients.delete(owner); });
234
+ }
235
+ return scoped;
236
+ }
135
237
  if (!client)
136
238
  client = createSocketClient(socketUrl(name, options), contracts[name], options);
137
239
  return client;