@meekojs/meeko 0.0.2 → 0.0.4

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 (146) hide show
  1. package/README.md +40 -2
  2. package/dist/autoimports-ts.d.ts +26 -0
  3. package/dist/autoimports-ts.js +127 -0
  4. package/dist/autoimports-ts.js.map +1 -0
  5. package/dist/autoimports.d.ts +21 -0
  6. package/dist/autoimports.js +285 -0
  7. package/dist/autoimports.js.map +1 -0
  8. package/dist/check.js +35 -23
  9. package/dist/check.js.map +1 -0
  10. package/dist/cli.js +59 -19
  11. package/dist/cli.js.map +1 -0
  12. package/dist/compiler/import-graph.d.ts +8 -0
  13. package/dist/compiler/import-graph.js +33 -0
  14. package/dist/compiler/import-graph.js.map +1 -0
  15. package/dist/compiler/mapping.js +1 -0
  16. package/dist/compiler/mapping.js.map +1 -0
  17. package/dist/compiler/project-root.d.ts +2 -0
  18. package/dist/compiler/project-root.js +18 -0
  19. package/dist/compiler/project-root.js.map +1 -0
  20. package/dist/compiler/sfc.js +1 -0
  21. package/dist/compiler/sfc.js.map +1 -0
  22. package/dist/compiler/sourcemap.d.ts +3 -0
  23. package/dist/compiler/sourcemap.js +75 -0
  24. package/dist/compiler/sourcemap.js.map +1 -0
  25. package/dist/compiler/template.js +1 -0
  26. package/dist/compiler/template.js.map +1 -0
  27. package/dist/compiler.js +22 -11
  28. package/dist/compiler.js.map +1 -0
  29. package/dist/devtools-ui/index.js +56 -6
  30. package/dist/devtools-ui/index.js.map +1 -0
  31. package/dist/devtools.d.ts +9 -0
  32. package/dist/devtools.js +16 -6
  33. package/dist/devtools.js.map +1 -0
  34. package/dist/dom.d.ts +17 -6
  35. package/dist/dom.js +86 -19
  36. package/dist/dom.js.map +1 -0
  37. package/dist/framework/check-app.d.ts +5 -0
  38. package/dist/framework/check-app.js +59 -0
  39. package/dist/framework/check-app.js.map +1 -0
  40. package/dist/framework/client.d.ts +45 -0
  41. package/dist/framework/client.js +146 -0
  42. package/dist/framework/client.js.map +1 -0
  43. package/dist/framework/clients.d.ts +82 -0
  44. package/dist/framework/clients.js +182 -0
  45. package/dist/framework/clients.js.map +1 -0
  46. package/dist/framework/config-type.d.ts +10 -0
  47. package/dist/framework/config-type.js +4 -0
  48. package/dist/framework/config-type.js.map +1 -0
  49. package/dist/framework/config.d.ts +15 -0
  50. package/dist/framework/config.js +138 -0
  51. package/dist/framework/config.js.map +1 -0
  52. package/dist/framework/contracts-generate.d.ts +8 -0
  53. package/dist/framework/contracts-generate.js +227 -0
  54. package/dist/framework/contracts-generate.js.map +1 -0
  55. package/dist/framework/generate.d.ts +7 -0
  56. package/dist/framework/generate.js +67 -0
  57. package/dist/framework/generate.js.map +1 -0
  58. package/dist/framework/init.d.ts +2 -0
  59. package/dist/framework/init.js +362 -0
  60. package/dist/framework/init.js.map +1 -0
  61. package/dist/framework/modules.d.ts +22 -0
  62. package/dist/framework/modules.js +29 -0
  63. package/dist/framework/modules.js.map +1 -0
  64. package/dist/framework/page.d.ts +60 -0
  65. package/dist/framework/page.js +42 -0
  66. package/dist/framework/page.js.map +1 -0
  67. package/dist/framework/prerender.d.ts +14 -0
  68. package/dist/framework/prerender.js +104 -0
  69. package/dist/framework/prerender.js.map +1 -0
  70. package/dist/framework/router.d.ts +39 -0
  71. package/dist/framework/router.js +173 -0
  72. package/dist/framework/router.js.map +1 -0
  73. package/dist/framework/server.d.ts +51 -0
  74. package/dist/framework/server.js +192 -0
  75. package/dist/framework/server.js.map +1 -0
  76. package/dist/framework/socket-contracts-generate.d.ts +5 -0
  77. package/dist/framework/socket-contracts-generate.js +159 -0
  78. package/dist/framework/socket-contracts-generate.js.map +1 -0
  79. package/dist/framework/socket.d.ts +70 -0
  80. package/dist/framework/socket.js +150 -0
  81. package/dist/framework/socket.js.map +1 -0
  82. package/dist/framework/state.d.ts +15 -0
  83. package/dist/framework/state.js +72 -0
  84. package/dist/framework/state.js.map +1 -0
  85. package/dist/framework-server/auto-clients.d.ts +3 -0
  86. package/dist/framework-server/auto-clients.js +27 -0
  87. package/dist/framework-server/auto-clients.js.map +1 -0
  88. package/dist/framework-server/context.d.ts +21 -0
  89. package/dist/framework-server/context.js +22 -0
  90. package/dist/framework-server/context.js.map +1 -0
  91. package/dist/framework-server/contracts.d.ts +64 -0
  92. package/dist/framework-server/contracts.js +129 -0
  93. package/dist/framework-server/contracts.js.map +1 -0
  94. package/dist/framework-server/discovery.d.ts +40 -0
  95. package/dist/framework-server/discovery.js +252 -0
  96. package/dist/framework-server/discovery.js.map +1 -0
  97. package/dist/framework-server/local.d.ts +19 -0
  98. package/dist/framework-server/local.js +98 -0
  99. package/dist/framework-server/local.js.map +1 -0
  100. package/dist/framework-server/node-upgrade.d.ts +23 -0
  101. package/dist/framework-server/node-upgrade.js +78 -0
  102. package/dist/framework-server/node-upgrade.js.map +1 -0
  103. package/dist/framework-server/node-websocket.d.ts +16 -0
  104. package/dist/framework-server/node-websocket.js +125 -0
  105. package/dist/framework-server/node-websocket.js.map +1 -0
  106. package/dist/framework-server/openapi.d.ts +17 -0
  107. package/dist/framework-server/openapi.js +118 -0
  108. package/dist/framework-server/openapi.js.map +1 -0
  109. package/dist/framework-server/session-stores.d.ts +66 -0
  110. package/dist/framework-server/session-stores.js +96 -0
  111. package/dist/framework-server/session-stores.js.map +1 -0
  112. package/dist/framework-server/sessions.d.ts +64 -0
  113. package/dist/framework-server/sessions.js +136 -0
  114. package/dist/framework-server/sessions.js.map +1 -0
  115. package/dist/framework-server/socket.d.ts +83 -0
  116. package/dist/framework-server/socket.js +161 -0
  117. package/dist/framework-server/socket.js.map +1 -0
  118. package/dist/framework-server.d.ts +21 -0
  119. package/dist/framework-server.js +12 -0
  120. package/dist/framework-server.js.map +1 -0
  121. package/dist/framework.d.ts +29 -0
  122. package/dist/framework.js +13 -0
  123. package/dist/framework.js.map +1 -0
  124. package/dist/hmr.js +1 -0
  125. package/dist/hmr.js.map +1 -0
  126. package/dist/index.d.ts +3 -3
  127. package/dist/index.js +2 -1
  128. package/dist/index.js.map +1 -0
  129. package/dist/init.d.ts +2 -0
  130. package/dist/init.js +209 -0
  131. package/dist/init.js.map +1 -0
  132. package/dist/internal.js +1 -0
  133. package/dist/internal.js.map +1 -0
  134. package/dist/node.d.ts +12 -0
  135. package/dist/node.js +52 -0
  136. package/dist/node.js.map +1 -0
  137. package/dist/reactivity.d.ts +25 -1
  138. package/dist/reactivity.js +69 -10
  139. package/dist/reactivity.js.map +1 -0
  140. package/dist/server.js +1 -0
  141. package/dist/server.js.map +1 -0
  142. package/dist/types.js +23 -8
  143. package/dist/types.js.map +1 -0
  144. package/dist/vite.js +91 -6
  145. package/dist/vite.js.map +1 -0
  146. package/package.json +19 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, readdir, stat, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\n\n/** Entradas que puede dejar un gestor de paquetes antes de generar el proyecto. */\nconst packageScaffoldEntries = new Set([\"package.json\", \"package-lock.json\", \"pnpm-lock.yaml\", \"pnpm-workspace.yaml\", \"yarn.lock\", \"bun.lock\", \"bun.lockb\", \"node_modules\", \".npmrc\", \".git\"]);\n\n/** Comprueba que un valor JSON sea un objeto de configuración. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Archivos autocontenidos del proyecto inicial, incluidos en la CLI publicada. */\nconst starterFiles: Readonly<Record<string, string>> = {\n \".gitignore\": \"node_modules/\\ndist/\\n.meeko/\\n\",\n \"index.html\": `<!doctype html>\n<html lang=\"es\">\n <head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>Meeko SSR</title></head>\n <body><div id=\"app\"></div><script type=\"module\" src=\"/src/entry-client.ts\"></script></body>\n</html>\n`,\n \"vite.config.ts\": `import { defineConfig } from \"vite\";\nimport { meeko } from \"@meekojs/meeko/vite\";\n\nexport default defineConfig({ plugins: [meeko()] });\n`,\n \"tsconfig.json\": `{\n \"compilerOptions\": {\n \"target\": \"ES2022\", \"module\": \"NodeNext\", \"moduleResolution\": \"NodeNext\",\n \"lib\": [\"ES2022\", \"DOM\"], \"types\": [\"node\", \"vite/client\"],\n \"strict\": true, \"noEmit\": true, \"allowArbitraryExtensions\": true,\n \"rootDirs\": [\"src\", \".meeko/types/src\"],\n \"skipLibCheck\": true\n },\n \"include\": [\"src/**/*.ts\", \"vite.config.ts\", \".meeko/types/routes.d.ts\"]\n}\n`,\n \"src/App.meeko\": `<script lang=\"ts\">\nimport { signal } from \"@meekojs/meeko\";\n\n/** Propiedades transferidas desde el servidor. */\nexport interface Props { initial: number }\n\nconst props = defineProps<Props>();\nconst count = signal(props.initial);\n</script>\n\n<template>\n <main>\n <h1>Meeko SSR</h1>\n <button type=\"button\" on:click=\"() => count.value++\">Contador: {count.value}</button>\n </main>\n</template>\n\n<style scoped>\nmain { max-width: 40rem; margin: 4rem auto; font: 1.2rem system-ui; }\nbutton { cursor: pointer; padding: .65rem 1rem; }\n</style>\n`,\n \"src/entry-server.ts\": `import { serializeJson } from \"@meekojs/meeko\";\nimport { css, renderWithState } from \"./App.meeko\";\n\n/** Genera HTML y estado inicial desde el mismo componente que hidrata el cliente. */\nexport function renderPage(clientSource: string, initial = 1): string {\n const props = { initial };\n const rendered = renderWithState(props);\n return '<!doctype html><html lang=\"es\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Meeko SSR</title><style>'\n + css + '</style></head><body><div id=\"app\">' + rendered.html + '</div><script id=\"meeko-payload\" type=\"application/json\">'\n + serializeJson({ props, state: rendered.state }) + '</script><script type=\"module\" src=\"' + clientSource + '\"></script></body></html>';\n}\n`,\n \"src/entry-client.ts\": `import { hydrate } from \"./App.meeko\";\nimport type { HotState } from \"@meekojs/meeko\";\n\nconst root = document.getElementById(\"app\");\nconst payloadNode = document.getElementById(\"meeko-payload\");\nif (!root || !payloadNode?.textContent) throw new Error(\"Missing SSR root or payload\");\nconst payload: unknown = JSON.parse(payloadNode.textContent);\nif (typeof payload !== \"object\" || payload === null || !(\"props\" in payload) || !(\"state\" in payload)) throw new TypeError(\"Invalid SSR payload\");\nconst { props, state } = payload;\nif (typeof props !== \"object\" || props === null || !(\"initial\" in props) || typeof props.initial !== \"number\" || !Number.isFinite(props.initial)) throw new TypeError(\"Invalid SSR props\");\nif (typeof state !== \"object\" || state === null || !(\"count\" in state) || typeof state.count !== \"number\" || !Number.isFinite(state.count)) throw new TypeError(\"Invalid SSR state\");\nhydrate(root, { initial: props.initial }, { count: state.count } satisfies HotState);\n`,\n \"server.mjs\": `import { createServer } from \"node:http\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, extname, resolve, sep } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { createServer as createViteServer } from \"vite\";\n\nconst root = dirname(fileURLToPath(import.meta.url));\nconst production = process.argv.includes(\"--production\");\nconst vite = production ? undefined : await createViteServer({ root, server: { middlewareMode: true }, appType: \"custom\" });\nconst clientRoot = resolve(root, \"dist/client\");\nlet clientSource = \"/src/entry-client.ts\";\nif (production) {\n const manifest = JSON.parse(await readFile(resolve(clientRoot, \".vite/manifest.json\"), \"utf8\"));\n const entry = manifest[\"index.html\"];\n if (!entry?.file) throw new Error(\"Missing Vite client entry\");\n clientSource = \"/\" + entry.file;\n}\n\nconst contentTypes = { \".js\": \"text/javascript\", \".css\": \"text/css\", \".png\": \"image/png\", \".svg\": \"image/svg+xml\", \".ico\": \"image/x-icon\" };\nconst server = createServer(async (request, response) => {\n try {\n const path = new URL(request.url ?? \"/\", \"http://localhost\").pathname;\n if (path === \"/\") {\n const module = vite ? await vite.ssrLoadModule(\"/src/entry-server.ts\") : await import(pathToFileURL(resolve(root, \"dist/server/entry-server.js\")).href);\n const html = module.renderPage(clientSource);\n response.writeHead(200, { \"content-type\": \"text/html; charset=utf-8\" });\n response.end(vite ? await vite.transformIndexHtml(path, html) : html);\n return;\n }\n if (vite) {\n vite.middlewares(request, response, () => { response.writeHead(404); response.end(); });\n return;\n }\n const file = resolve(clientRoot, \".\" + path);\n if (!file.startsWith(clientRoot + sep)) { response.writeHead(403); response.end(); return; }\n const body = await readFile(file);\n response.writeHead(200, { \"content-type\": contentTypes[extname(file)] ?? \"application/octet-stream\" });\n response.end(body);\n } catch (error) {\n console.error(error);\n response.writeHead(500);\n response.end(\"Internal server error\");\n }\n});\n\nconst port = Number(process.env.PORT ?? 4173);\nserver.listen(port, \"127.0.0.1\", () => console.log(\"http://127.0.0.1:\" + port));\nprocess.on(\"SIGINT\", () => { server.close(); void vite?.close(); });\n`,\n \"README.md\": `# Meeko SSR starter\n\nProyecto inicial con renderizado en servidor e hidratación del mismo componente \\`.meeko\\`.\n\n\\`\\`\\`sh\nnpm install\nnpm run dev\n\\`\\`\\`\n\nAbre http://127.0.0.1:4173. El servidor produce HTML y transfiere las props y señales al navegador.\n\n\\`npm run check\\` genera los tipos del componente y comprueba TypeScript. \\`npm run build\\` compila cliente y servidor; \\`npm start\\` sirve ambas compilaciones con SSR.\n`,\n};\n\n/** Crea un proyecto SSR independiente sin sobrescribir archivos del usuario. */\nexport async function initProject(directory: string): Promise<string> {\n const target = resolve(directory);\n const name = basename(target).toLowerCase().replace(/[^a-z0-9._-]+/g, \"-\").replace(/^[._-]+|[._-]+$/g, \"\") || \"meeko-app\";\n const packageMetadata: unknown = JSON.parse(await readFile(new URL(\"../package.json\", import.meta.url), \"utf8\"));\n if (typeof packageMetadata !== \"object\" || packageMetadata === null || !(\"version\" in packageMetadata) || typeof packageMetadata.version !== \"string\") {\n throw new Error(\"Meeko package version is unavailable\");\n }\n let existingEntries: string[] = [];\n try {\n if (!(await stat(target)).isDirectory()) throw new Error(`Destination is not a directory: ${target}`);\n existingEntries = await readdir(target);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n const unexpected = existingEntries.filter((entry) => !packageScaffoldEntries.has(entry));\n if (unexpected.length > 0 || (existingEntries.length > 0 && !existingEntries.includes(\"package.json\"))) {\n throw new Error(`Destination is not empty: ${target}${unexpected.length > 0 ? ` (${unexpected.join(\", \")})` : \"\"}`);\n }\n const existing: unknown = existingEntries.includes(\"package.json\") ? JSON.parse(await readFile(join(target, \"package.json\"), \"utf8\")) : {};\n if (!isRecord(existing)) throw new Error(`Invalid package.json in ${target}`);\n const existingScripts = existing.scripts ?? {};\n const existingDependencies = existing.dependencies ?? {};\n const existingDevDependencies = existing.devDependencies ?? {};\n const existingEngines = existing.engines ?? {};\n if (!isRecord(existingScripts) || !isRecord(existingDependencies) || !isRecord(existingDevDependencies) || !isRecord(existingEngines)) {\n throw new Error(`Invalid package.json in ${target}`);\n }\n const scripts = {\n dev: \"node server.mjs\",\n check: \"meeko types src/App.meeko && tsc --noEmit\",\n build: \"npm run check && vite build --outDir dist/client --manifest && vite build --ssr src/entry-server.ts --outDir dist/server\",\n start: \"node server.mjs --production\",\n };\n const devDependencies = { \"@types/node\": \"^24.0.0\", typescript: \"^7.0.2\", vite: \"^8.3.5\" };\n for (const command of Object.keys(scripts)) {\n if (command in existingScripts) throw new Error(`Destination already defines the ${command} script: ${target}`);\n }\n if (Object.keys(existingDependencies).some((dependency) => dependency !== \"@meekojs/meeko\") || Object.keys(existingDevDependencies).some((dependency) => !(dependency in devDependencies))) {\n throw new Error(`Destination contains other dependencies: ${target}`);\n }\n const packageFile = JSON.stringify({\n ...existing,\n name: typeof existing.name === \"string\" ? existing.name : name,\n private: true,\n type: \"module\",\n engines: { ...existingEngines, node: \">=24\" },\n scripts: { ...existingScripts, ...scripts },\n dependencies: { ...existingDependencies, \"@meekojs/meeko\": packageMetadata.version },\n devDependencies: { ...existingDevDependencies, ...devDependencies },\n }, null, 2) + \"\\n\";\n await mkdir(target, { recursive: true });\n for (const [filename, content] of Object.entries(starterFiles)) {\n const path = join(target, filename);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, { encoding: \"utf8\", flag: \"wx\" });\n }\n await writeFile(join(target, \"package.json\"), packageFile, { encoding: \"utf8\", flag: existingEntries.includes(\"package.json\") ? \"w\" : \"wx\" });\n return target;\n}\n"]}
package/dist/internal.js CHANGED
@@ -9,3 +9,4 @@ export { attributeValue, escapeHtml, renderAttribute, serializeJson } from "./se
9
9
  export { bindAttribute, bindComponent, bindEvent, bindFor, bindIf, bindText, keyToken, renderComponent, renderFor, renderIf, withStateSnapshot } from "./dom.js";
10
10
  export { enableHotModule, registerHotInstance, registerHotScope, replaceHotModule, replaceHotStyle, restoreSignals, snapshotSignals } from "./hmr.js";
11
11
  export { registerDevtoolsInstance } from "./devtools.js";
12
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEjK,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEtJ,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC","sourcesContent":["/**\n * Contrato del runtime generado por el compilador Meeko.\n *\n * Esta ruta es interna y puede cambiar junto con el compilador. Las aplicaciones\n * deben importar las API documentadas desde la raíz del paquete.\n */\nexport { createRoot } from \"./reactivity.js\";\nexport { attributeValue, escapeHtml, renderAttribute, serializeJson } from \"./server.js\";\nexport { bindAttribute, bindComponent, bindEvent, bindFor, bindIf, bindText, keyToken, renderComponent, renderFor, renderIf, withStateSnapshot } from \"./dom.js\";\nexport type { ComponentModule, ComponentRelease, DomScope } from \"./dom.js\";\nexport { enableHotModule, registerHotInstance, registerHotScope, replaceHotModule, replaceHotStyle, restoreSignals, snapshotSignals } from \"./hmr.js\";\nexport type { HotComponent, HotState } from \"./hmr.js\";\nexport { registerDevtoolsInstance } from \"./devtools.js\";\n"]}
package/dist/node.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ export { discoverRoutes, createFrameworkHandler } from "./framework/server.js";
3
+ export type { FrameworkHandlerOptions, PageModule, PageRoute, PageRequestContext } from "./framework/server.js";
4
+ export { composeFrameworkRoutes } from "./framework/modules.js";
5
+ export { discoverConfiguredRoutes, loadMeekoConfig, resolveConfigSources, readMeekoConfigSync } from "./framework/config.js";
6
+ export type { MeekoConfig, ConfigSource } from "./framework/config.js";
7
+ export type { RouteLayer, RouteModule, ComposeRoutesOptions } from "./framework/modules.js";
8
+ export { prerenderRoutes, prerenderProject } from "./framework/prerender.js";
9
+ export type { PrerenderOptions } from "./framework/prerender.js";
10
+ export * from "./framework-server.js";
11
+ /** Adapts a portable Fetch handler to Node 24's HTTP server callback. */
12
+ export declare function toNodeListener(handler: (request: Request) => Promise<Response> | Response): (request: IncomingMessage, response: ServerResponse) => void;
package/dist/node.js ADDED
@@ -0,0 +1,52 @@
1
+ import { Readable } from "node:stream";
2
+ import { TLSSocket } from "node:tls";
3
+ export { discoverRoutes, createFrameworkHandler } from "./framework/server.js";
4
+ export { composeFrameworkRoutes } from "./framework/modules.js";
5
+ export { discoverConfiguredRoutes, loadMeekoConfig, resolveConfigSources, readMeekoConfigSync } from "./framework/config.js";
6
+ export { prerenderRoutes, prerenderProject } from "./framework/prerender.js";
7
+ export * from "./framework-server.js";
8
+ /** Adapts a portable Fetch handler to Node 24's HTTP server callback. */
9
+ export function toNodeListener(handler) {
10
+ return (incoming, outgoing) => {
11
+ void (async () => {
12
+ const controller = new AbortController();
13
+ const abort = () => controller.abort();
14
+ incoming.once("aborted", abort);
15
+ outgoing.once("close", abort);
16
+ try {
17
+ const authority = incoming.headers.host ?? "localhost";
18
+ const protocol = incoming.socket instanceof TLSSocket ? "https" : "http";
19
+ const url = new URL(incoming.url ?? "/", `${protocol}://${authority}`);
20
+ const method = incoming.method ?? "GET";
21
+ const headers = new Headers();
22
+ for (const [name, value] of Object.entries(incoming.headers)) {
23
+ if (value !== undefined)
24
+ headers.set(name, Array.isArray(value) ? value.join(", ") : value);
25
+ }
26
+ const hasBody = method !== "GET" && method !== "HEAD";
27
+ const request = new Request(url, {
28
+ method, headers, signal: controller.signal,
29
+ ...(hasBody ? { body: Readable.toWeb(incoming), duplex: "half" } : {}),
30
+ });
31
+ const result = await handler(request);
32
+ outgoing.writeHead(result.status, Object.fromEntries(result.headers));
33
+ if (method === "HEAD" || !result.body) {
34
+ outgoing.end();
35
+ return;
36
+ }
37
+ for await (const chunk of result.body)
38
+ outgoing.write(chunk);
39
+ outgoing.end();
40
+ }
41
+ finally {
42
+ incoming.off("aborted", abort);
43
+ outgoing.off("close", abort);
44
+ }
45
+ })().catch(() => {
46
+ if (!outgoing.headersSent)
47
+ outgoing.writeHead(500, { "content-type": "text/plain; charset=utf-8" });
48
+ outgoing.end("Internal server error");
49
+ });
50
+ };
51
+ }
52
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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","sourcesContent":["import { Readable } from \"node:stream\";\nimport { TLSSocket } from \"node:tls\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport { discoverRoutes, createFrameworkHandler } from \"./framework/server.js\";\nexport type { FrameworkHandlerOptions, PageModule, PageRoute, PageRequestContext } from \"./framework/server.js\";\nexport { composeFrameworkRoutes } from \"./framework/modules.js\";\nexport { discoverConfiguredRoutes, loadMeekoConfig, resolveConfigSources, readMeekoConfigSync } from \"./framework/config.js\";\nexport type { MeekoConfig, ConfigSource } from \"./framework/config.js\";\nexport type { RouteLayer, RouteModule, ComposeRoutesOptions } from \"./framework/modules.js\";\nexport { prerenderRoutes, prerenderProject } from \"./framework/prerender.js\";\nexport type { PrerenderOptions } from \"./framework/prerender.js\";\nexport * from \"./framework-server.js\";\n\n/** Adapts a portable Fetch handler to Node 24's HTTP server callback. */\nexport function toNodeListener(handler: (request: Request) => Promise<Response> | Response): (request: IncomingMessage, response: ServerResponse) => void {\n return (incoming, outgoing) => {\n void (async () => {\n const controller = new AbortController();\n const abort = () => controller.abort();\n incoming.once(\"aborted\", abort);\n outgoing.once(\"close\", abort);\n try {\n const authority = incoming.headers.host ?? \"localhost\";\n const protocol = incoming.socket instanceof TLSSocket ? \"https\" : \"http\";\n const url = new URL(incoming.url ?? \"/\", `${protocol}://${authority}`);\n const method = incoming.method ?? \"GET\";\n const headers = new Headers();\n for (const [name, value] of Object.entries(incoming.headers)) {\n if (value !== undefined) headers.set(name, Array.isArray(value) ? value.join(\", \") : value);\n }\n const hasBody = method !== \"GET\" && method !== \"HEAD\";\n const request = new Request(url, {\n method, headers, signal: controller.signal,\n ...(hasBody ? { body: Readable.toWeb(incoming) as ReadableStream<Uint8Array>, duplex: \"half\" as const } : {}),\n });\n const result = await handler(request);\n outgoing.writeHead(result.status, Object.fromEntries(result.headers));\n if (method === \"HEAD\" || !result.body) { outgoing.end(); return; }\n for await (const chunk of result.body) outgoing.write(chunk);\n outgoing.end();\n } finally {\n incoming.off(\"aborted\", abort);\n outgoing.off(\"close\", abort);\n }\n })().catch(() => {\n if (!outgoing.headersSent) outgoing.writeHead(500, { \"content-type\": \"text/plain; charset=utf-8\" });\n outgoing.end(\"Internal server error\");\n });\n };\n}\n"]}
@@ -6,12 +6,36 @@ export interface ReadonlySignal<T> {
6
6
  export interface Signal<T> extends ReadonlySignal<T> {
7
7
  value: T;
8
8
  }
9
+ /** Clave nominal para compartir un valor tipado entre instancias anidadas. */
10
+ export type ContextKey<T> = symbol & {
11
+ readonly __meekoValue?: (value: T) => T;
12
+ };
13
+ /** Crea una clave única; el tipo no se infiere de un valor global compartido. */
14
+ export declare function createContext<T>(description?: string): ContextKey<T>;
15
+ /** Ubicación de una expresión de plantilla que lee una señal durante desarrollo. */
16
+ export interface EffectSource {
17
+ file: string;
18
+ line: number;
19
+ column: number;
20
+ expression: string;
21
+ kind: "text" | "attribute";
22
+ }
9
23
  /** Identifica señales editables creadas por Meeko para conservarlas durante HMR. */
10
24
  export declare function isWritableSignal(value: unknown): value is Signal<unknown>;
25
+ /** Publica un valor en la instancia activa y sus descendientes. */
26
+ export declare function provide<T>(key: ContextKey<T>, value: T): void;
27
+ /** Lee el proveedor más cercano; falla si falta para evitar un valor implícito. */
28
+ export declare function inject<T>(key: ContextKey<T>): T;
29
+ /** Registers an external resource to be released with the current component root. */
30
+ export declare function onCleanup(release: () => void): void;
11
31
  /** Crea un valor observable. Las escrituras iguales no notifican cambios. */
12
32
  export declare function signal<T>(initial: T): Signal<T>;
13
33
  /** Ejecuta una función cuando cambian las señales leídas por ella. */
14
- export declare function effect(fn: () => void): () => void;
34
+ export declare function effect(fn: () => void, source?: EffectSource): () => void;
35
+ /** Identidad opaca de la raíz reactiva activa; permite aislar instancias anidadas. */
36
+ export declare function currentEffectOwner(): object | undefined;
37
+ /** Devuelve expresiones de plantilla actualmente dependientes de una señal en una raíz. */
38
+ export declare function signalReadSites(value: Signal<unknown>, owner: object | undefined): EffectSource[];
15
39
  /** Deriva un valor de otras señales y lo actualiza cuando cambian. */
16
40
  export declare function computed<T>(fn: () => T): ReadonlySignal<T>;
17
41
  /** Agrupa varias escrituras en una sola ronda de notificaciones. */
@@ -1,5 +1,10 @@
1
+ /** Crea una clave única; el tipo no se infiere de un valor global compartido. */
2
+ export function createContext(description) {
3
+ return Symbol(description);
4
+ }
1
5
  const writableSignals = new WeakSet();
2
6
  const derivedSignals = new WeakSet();
7
+ const effectSources = new WeakMap();
3
8
  /** Identifica señales editables creadas por Meeko para conservarlas durante HMR. */
4
9
  export function isWritableSignal(value) {
5
10
  return typeof value === "object" && value !== null && writableSignals.has(value) && !derivedSignals.has(value);
@@ -9,9 +14,29 @@ let activeOwner;
9
14
  let batchDepth = 0;
10
15
  let flushing = false;
11
16
  const pending = new Set();
17
+ /** Publica un valor en la instancia activa y sus descendientes. */
18
+ export function provide(key, value) {
19
+ if (!activeOwner)
20
+ throw new Error("provide() requires an active component root");
21
+ activeOwner.context.set(key, value);
22
+ }
23
+ /** Lee el proveedor más cercano; falla si falta para evitar un valor implícito. */
24
+ export function inject(key) {
25
+ for (let owner = activeOwner; owner; owner = owner.parent) {
26
+ if (owner.context.has(key))
27
+ return owner.context.get(key);
28
+ }
29
+ throw new Error(`Missing Meeko context${key.description ? `: ${key.description}` : ""}`);
30
+ }
31
+ /** Registers an external resource to be released with the current component root. */
32
+ export function onCleanup(release) {
33
+ if (!activeOwner)
34
+ throw new Error("onCleanup() requires an active component root");
35
+ activeOwner.children.add(release);
36
+ }
12
37
  function detach(observer) {
13
38
  for (const dependency of observer.dependencies)
14
- dependency.subscribers.delete(observer);
39
+ dependency.subscribers?.delete(observer);
15
40
  observer.dependencies.clear();
16
41
  }
17
42
  function flush() {
@@ -37,12 +62,11 @@ function flush() {
37
62
  /** Crea un valor observable. Las escrituras iguales no notifican cambios. */
38
63
  export function signal(initial) {
39
64
  let current = initial;
40
- const subscribers = new Set();
41
65
  const result = {
42
- subscribers,
66
+ subscribers: undefined,
43
67
  get value() {
44
68
  if (activeObserver) {
45
- subscribers.add(activeObserver);
69
+ (result.subscribers ??= new Set()).add(activeObserver);
46
70
  activeObserver.dependencies.add(result);
47
71
  }
48
72
  return current;
@@ -51,8 +75,9 @@ export function signal(initial) {
51
75
  if (Object.is(current, next))
52
76
  return;
53
77
  current = next;
54
- for (const observer of subscribers)
55
- pending.add(observer);
78
+ if (result.subscribers)
79
+ for (const observer of result.subscribers)
80
+ pending.add(observer);
56
81
  flush();
57
82
  },
58
83
  };
@@ -60,7 +85,7 @@ export function signal(initial) {
60
85
  return result;
61
86
  }
62
87
  /** Ejecuta una función cuando cambian las señales leídas por ella. */
63
- export function effect(fn) {
88
+ export function effect(fn, source) {
64
89
  const owner = activeOwner;
65
90
  const observer = {
66
91
  dependencies: new Set(),
@@ -80,6 +105,8 @@ export function effect(fn) {
80
105
  }
81
106
  },
82
107
  };
108
+ if (source)
109
+ effectSources.set(observer, { owner, source });
83
110
  owner?.observers.add(observer);
84
111
  observer.run();
85
112
  return () => {
@@ -89,6 +116,25 @@ export function effect(fn) {
89
116
  owner?.observers.delete(observer);
90
117
  };
91
118
  }
119
+ /** Identidad opaca de la raíz reactiva activa; permite aislar instancias anidadas. */
120
+ export function currentEffectOwner() {
121
+ return activeOwner;
122
+ }
123
+ /** Devuelve expresiones de plantilla actualmente dependientes de una señal en una raíz. */
124
+ export function signalReadSites(value, owner) {
125
+ if (!owner || !isWritableSignal(value))
126
+ return [];
127
+ const sites = new Map();
128
+ for (const observer of value.subscribers ?? []) {
129
+ const metadata = effectSources.get(observer);
130
+ if (observer.disposed || metadata?.owner !== owner || !metadata)
131
+ continue;
132
+ const source = metadata.source;
133
+ const key = `${source.file}\u0000${source.line}\u0000${source.column}\u0000${source.kind}\u0000${source.expression}`;
134
+ sites.set(key, source);
135
+ }
136
+ return [...sites.values()];
137
+ }
92
138
  /** Deriva un valor de otras señales y lo actualiza cuando cambian. */
93
139
  export function computed(fn) {
94
140
  const result = signal(undefined);
@@ -122,12 +168,19 @@ export function untrack(fn) {
122
168
  }
123
169
  /** Asocia efectos a una instancia y entrega una función para liberarlos. */
124
170
  export function createRoot(fn) {
125
- const owner = { observers: new Set(), children: new Set(), parent: activeOwner };
171
+ const owner = { observers: new Set(), children: new Set(), parent: activeOwner, context: new Map() };
126
172
  const previous = activeOwner;
127
173
  activeOwner = owner;
128
174
  const dispose = () => {
129
- for (const child of [...owner.children])
130
- child();
175
+ const failures = [];
176
+ for (const child of [...owner.children]) {
177
+ try {
178
+ child();
179
+ }
180
+ catch (error) {
181
+ failures.push(error);
182
+ }
183
+ }
131
184
  owner.children.clear();
132
185
  for (const observer of owner.observers) {
133
186
  observer.disposed = true;
@@ -135,7 +188,12 @@ export function createRoot(fn) {
135
188
  detach(observer);
136
189
  }
137
190
  owner.observers.clear();
191
+ owner.context.clear();
138
192
  owner.parent?.children.delete(dispose);
193
+ if (failures.length === 1)
194
+ throw failures[0];
195
+ if (failures.length > 1)
196
+ throw new AggregateError(failures, "Meeko root cleanup failed");
139
197
  };
140
198
  owner.parent?.children.add(dispose);
141
199
  try {
@@ -149,3 +207,4 @@ export function createRoot(fn) {
149
207
  activeOwner = previous;
150
208
  }
151
209
  }
210
+ //# sourceMappingURL=reactivity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactivity.js","sourceRoot":"","sources":["../src/reactivity.ts"],"names":[],"mappings":"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","sourcesContent":["/** Señal de solo lectura que registra dependencias al consultar su valor. */\nexport interface ReadonlySignal<T> {\n readonly value: T;\n}\n\n/** Señal cuyo valor puede actualizarse de forma reactiva. */\nexport interface Signal<T> extends ReadonlySignal<T> {\n value: T;\n}\n\n/** Clave nominal para compartir un valor tipado entre instancias anidadas. */\nexport type ContextKey<T> = symbol & { readonly __meekoValue?: (value: T) => T };\n\n/** Crea una clave única; el tipo no se infiere de un valor global compartido. */\nexport function createContext<T>(description?: string): ContextKey<T> {\n return Symbol(description) as ContextKey<T>;\n}\n\n/** Ubicación de una expresión de plantilla que lee una señal durante desarrollo. */\nexport interface EffectSource {\n file: string;\n line: number;\n column: number;\n expression: string;\n kind: \"text\" | \"attribute\";\n}\n\ninterface Observer {\n run: () => void;\n dependencies: Set<InternalSignal<unknown>>;\n disposed: boolean;\n}\n\ninterface Owner {\n observers: Set<Observer>;\n children: Set<() => void>;\n parent: Owner | undefined;\n context: Map<symbol, unknown>;\n}\n\ninterface InternalSignal<T> extends Signal<T> {\n subscribers: Set<Observer> | undefined;\n}\n\nconst writableSignals = new WeakSet<object>();\nconst derivedSignals = new WeakSet<object>();\nconst effectSources = new WeakMap<Observer, { owner: Owner | undefined; source: EffectSource }>();\n\n/** Identifica señales editables creadas por Meeko para conservarlas durante HMR. */\nexport function isWritableSignal(value: unknown): value is Signal<unknown> {\n return typeof value === \"object\" && value !== null && writableSignals.has(value) && !derivedSignals.has(value);\n}\n\nlet activeObserver: Observer | undefined;\nlet activeOwner: Owner | undefined;\nlet batchDepth = 0;\nlet flushing = false;\nconst pending = new Set<Observer>();\n\n/** Publica un valor en la instancia activa y sus descendientes. */\nexport function provide<T>(key: ContextKey<T>, value: T): void {\n if (!activeOwner) throw new Error(\"provide() requires an active component root\");\n activeOwner.context.set(key, value);\n}\n\n/** Lee el proveedor más cercano; falla si falta para evitar un valor implícito. */\nexport function inject<T>(key: ContextKey<T>): T {\n for (let owner = activeOwner; owner; owner = owner.parent) {\n if (owner.context.has(key)) return owner.context.get(key) as T;\n }\n throw new Error(`Missing Meeko context${key.description ? `: ${key.description}` : \"\"}`);\n}\n\n/** Registers an external resource to be released with the current component root. */\nexport function onCleanup(release: () => void): void {\n if (!activeOwner) throw new Error(\"onCleanup() requires an active component root\");\n activeOwner.children.add(release);\n}\n\nfunction detach(observer: Observer): void {\n for (const dependency of observer.dependencies) dependency.subscribers?.delete(observer);\n observer.dependencies.clear();\n}\n\nfunction flush(): void {\n if (flushing || batchDepth > 0) return;\n flushing = true;\n try {\n let iterations = 0;\n while (pending.size > 0) {\n if (++iterations > 1000) throw new Error(\"Reactive update cycle exceeded 1000 iterations\");\n const observers = [...pending];\n pending.clear();\n for (const observer of observers) if (!observer.disposed) observer.run();\n }\n } finally {\n flushing = false;\n }\n}\n\n/** Crea un valor observable. Las escrituras iguales no notifican cambios. */\nexport function signal<T>(initial: T): Signal<T> {\n let current = initial;\n const result: InternalSignal<T> = {\n subscribers: undefined,\n get value() {\n if (activeObserver) {\n (result.subscribers ??= new Set()).add(activeObserver);\n activeObserver.dependencies.add(result as InternalSignal<unknown>);\n }\n return current;\n },\n set value(next: T) {\n if (Object.is(current, next)) return;\n current = next;\n if (result.subscribers) for (const observer of result.subscribers) pending.add(observer);\n flush();\n },\n };\n writableSignals.add(result);\n return result;\n}\n\n/** Ejecuta una función cuando cambian las señales leídas por ella. */\nexport function effect(fn: () => void, source?: EffectSource): () => void {\n const owner = activeOwner;\n const observer: Observer = {\n dependencies: new Set(),\n disposed: false,\n run() {\n detach(observer);\n const previous = activeObserver;\n const previousOwner = activeOwner;\n activeObserver = observer;\n activeOwner = owner;\n try {\n fn();\n } finally {\n activeObserver = previous;\n activeOwner = previousOwner;\n }\n },\n };\n if (source) effectSources.set(observer, { owner, source });\n owner?.observers.add(observer);\n observer.run();\n return () => {\n observer.disposed = true;\n pending.delete(observer);\n detach(observer);\n owner?.observers.delete(observer);\n };\n}\n\n/** Identidad opaca de la raíz reactiva activa; permite aislar instancias anidadas. */\nexport function currentEffectOwner(): object | undefined {\n return activeOwner;\n}\n\n/** Devuelve expresiones de plantilla actualmente dependientes de una señal en una raíz. */\nexport function signalReadSites(value: Signal<unknown>, owner: object | undefined): EffectSource[] {\n if (!owner || !isWritableSignal(value)) return [];\n const sites = new Map<string, EffectSource>();\n for (const observer of (value as InternalSignal<unknown>).subscribers ?? []) {\n const metadata = effectSources.get(observer);\n if (observer.disposed || metadata?.owner !== owner || !metadata) continue;\n const source = metadata.source;\n const key = `${source.file}\\u0000${source.line}\\u0000${source.column}\\u0000${source.kind}\\u0000${source.expression}`;\n sites.set(key, source);\n }\n return [...sites.values()];\n}\n\n/** Deriva un valor de otras señales y lo actualiza cuando cambian. */\nexport function computed<T>(fn: () => T): ReadonlySignal<T> {\n const result = signal<T>(undefined as T);\n derivedSignals.add(result);\n effect(() => {\n result.value = fn();\n });\n return result;\n}\n\n/** Agrupa varias escrituras en una sola ronda de notificaciones. */\nexport function batch<T>(fn: () => T): T {\n batchDepth++;\n try {\n return fn();\n } finally {\n batchDepth--;\n flush();\n }\n}\n\n/** Lee señales sin registrar dependencias en el observador activo. */\nexport function untrack<T>(fn: () => T): T {\n const previous = activeObserver;\n activeObserver = undefined;\n try {\n return fn();\n } finally {\n activeObserver = previous;\n }\n}\n\n/** Asocia efectos a una instancia y entrega una función para liberarlos. */\nexport function createRoot<T>(fn: (dispose: () => void) => T): T {\n const owner: Owner = { observers: new Set(), children: new Set(), parent: activeOwner, context: new Map() };\n const previous = activeOwner;\n activeOwner = owner;\n const dispose = () => {\n const failures: unknown[] = [];\n for (const child of [...owner.children]) {\n try { child(); } catch (error) { failures.push(error); }\n }\n owner.children.clear();\n for (const observer of owner.observers) {\n observer.disposed = true;\n pending.delete(observer);\n detach(observer);\n }\n owner.observers.clear();\n owner.context.clear();\n owner.parent?.children.delete(dispose);\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, \"Meeko root cleanup failed\");\n };\n owner.parent?.children.add(dispose);\n try {\n return fn(dispose);\n } catch (error) {\n dispose();\n throw error;\n } finally {\n activeOwner = previous;\n }\n}\n"]}
package/dist/server.js CHANGED
@@ -77,3 +77,4 @@ export function serializeJson(value) {
77
77
  .replaceAll("\u2028", "\\u2028")
78
78
  .replaceAll("\u2029", "\\u2029");
79
79
  }
80
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["/** Escapa texto dinámico antes de insertarlo en HTML generado por SSR. */\nexport function escapeHtml(value: unknown): string {\n return String(value)\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#39;\");\n}\n\nconst booleanAttributes = new Set([\"allowfullscreen\", \"async\", \"autofocus\", \"autoplay\", \"checked\", \"controls\", \"default\", \"defer\", \"disabled\", \"formnovalidate\", \"hidden\", \"inert\", \"ismap\", \"loop\", \"multiple\", \"muted\", \"nomodule\", \"novalidate\", \"open\", \"playsinline\", \"readonly\", \"required\", \"reversed\", \"selected\"]);\n\n/** Convierte un valor de atributo dinámico en su forma DOM; null lo elimina. */\nexport function attributeValue(name: string, value: unknown): string | null {\n if (booleanAttributes.has(name)) return value ? \"\" : null;\n if (value === null || value === undefined || value === false) return null;\n return String(value);\n}\n\n/** Genera un atributo HTML dinámico con escape seguro para SSR. */\nexport function renderAttribute(name: string, value: unknown): string {\n if (!/^[a-zA-Z_:][a-zA-Z0-9_:.-]*$/.test(name)) throw new TypeError(`Invalid attribute name: ${name}`);\n const resolved = attributeValue(name, value);\n return resolved === null ? \"\" : ` ${name}=\"${escapeHtml(resolved)}\"`;\n}\n\nfunction assertSerializable(value: unknown, path: string, ancestors: WeakSet<object>): void {\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return;\n if (typeof value === \"number\") {\n if (Number.isFinite(value)) return;\n throw new TypeError(`Non-finite number at ${path}`);\n }\n if (typeof value !== \"object\") throw new TypeError(`Non-serializable value at ${path}`);\n if (ancestors.has(value)) throw new TypeError(`Circular reference at ${path}`);\n const prototype: unknown = Object.getPrototypeOf(value);\n if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`Non-plain object at ${path}`);\n }\n if (Object.hasOwn(value, \"toJSON\")) throw new TypeError(`Custom toJSON at ${path}`);\n if (Array.isArray(value)) {\n for (let index = 0; index < value.length; index++) {\n if (!Object.hasOwn(value, index)) throw new TypeError(`Sparse array at ${path}[${index}]`);\n }\n }\n ancestors.add(value);\n try {\n for (const key of Reflect.ownKeys(value)) {\n if (typeof key !== \"string\") throw new TypeError(`Symbol key at ${path}`);\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor?.enumerable) continue;\n if (!(\"value\" in descriptor)) throw new TypeError(`Accessor property at ${path}.${key}`);\n assertSerializable(descriptor.value, `${path}.${key}`, ancestors);\n }\n } finally {\n ancestors.delete(value);\n }\n}\n\n/** Serializa estado y props transferibles al navegador, rechazando valores ambiguos. */\nexport function serializeJson(value: unknown): string {\n assertSerializable(value, \"$\", new WeakSet());\n const json = JSON.stringify(value);\n if (json === undefined) throw new TypeError(\"Value cannot be serialized to JSON\");\n return json\n .replaceAll(\"<\", \"\\\\u003c\")\n .replaceAll(\">\", \"\\\\u003e\")\n .replaceAll(\"&\", \"\\\\u0026\")\n .replaceAll(\"\\u2028\", \"\\\\u2028\")\n .replaceAll(\"\\u2029\", \"\\\\u2029\");\n}\n"]}
package/dist/types.js CHANGED
@@ -1,16 +1,21 @@
1
- import { readFile, writeFile } from "node:fs/promises";
2
- import { dirname, resolve } from "node:path";
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, join, relative, resolve } from "node:path";
3
3
  import ts from "@typescript/typescript6";
4
- import { compile } from "./compiler.js";
4
+ import { compileWithAutoImports } from "./autoimports.js";
5
+ import { moduleSpecifiers, replaceModuleSpecifiers } from "./compiler/import-graph.js";
6
+ import { projectRoot } from "./compiler/project-root.js";
5
7
  /** Genera declaraciones TypeScript para un componente y sus imports .meeko relativos. */
6
8
  export async function generateTypes(source, filename) {
7
9
  if (!filename.endsWith(".meeko"))
8
10
  throw new TypeError("Type generation requires a .meeko input file");
11
+ const root = projectRoot(filename);
12
+ const outputRoot = join(root, ".meeko", "types");
9
13
  const declarations = new Map();
10
14
  async function collect(content, path) {
11
15
  if (declarations.has(path))
12
16
  return;
13
- const generated = compile(content, path).code;
17
+ const target = relative(root, path).split(/[\\/]/)[0] === "server" ? "server" : "client";
18
+ const generated = (await compileWithAutoImports(content, path, {}, target)).code;
14
19
  const result = ts.transpileDeclaration(generated, {
15
20
  fileName: `${path}.ts`,
16
21
  compilerOptions: { declaration: true, emitDeclarationOnly: true },
@@ -19,8 +24,9 @@ export async function generateTypes(source, filename) {
19
24
  if (error)
20
25
  throw new Error(ts.flattenDiagnosticMessageText(error.messageText, "\n"));
21
26
  declarations.set(path, result.outputText);
22
- for (const match of generated.matchAll(/\b(?:from\s*|import\s*)["']([^"']+\.meeko)["']/g)) {
23
- const specifier = match[1];
27
+ for (const { value: specifier } of moduleSpecifiers(generated, path)) {
28
+ if (!specifier.endsWith(".meeko"))
29
+ continue;
24
30
  if (!specifier.startsWith("."))
25
31
  continue;
26
32
  const child = resolve(dirname(path), specifier);
@@ -30,9 +36,18 @@ export async function generateTypes(source, filename) {
30
36
  await collect(source, resolve(filename));
31
37
  const outputs = [];
32
38
  for (const [path, declaration] of declarations) {
33
- const output = path.replace(/\.meeko$/, ".d.meeko.ts");
34
- await writeFile(output, declaration, "utf8");
39
+ const output = join(outputRoot, relative(root, path)).replace(/\.meeko$/, ".d.meeko.ts");
40
+ const rewritten = replaceModuleSpecifiers(declaration, output, ({ value }) => {
41
+ if (!value.startsWith(".") || value.endsWith(".meeko"))
42
+ return value;
43
+ const original = resolve(dirname(path), value);
44
+ const target = relative(dirname(output), original).replaceAll("\\", "/");
45
+ return target.startsWith(".") ? target : `./${target}`;
46
+ });
47
+ await mkdir(dirname(output), { recursive: true });
48
+ await writeFile(output, rewritten, "utf8");
35
49
  outputs.push(output);
36
50
  }
37
51
  return outputs;
38
52
  }
53
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport ts from \"@typescript/typescript6\";\nimport { compileWithAutoImports } from \"./autoimports.js\";\nimport { moduleSpecifiers, replaceModuleSpecifiers } from \"./compiler/import-graph.js\";\nimport { projectRoot } from \"./compiler/project-root.js\";\n\n/** Genera declaraciones TypeScript para un componente y sus imports .meeko relativos. */\nexport async function generateTypes(source: string, filename: string): Promise<string[]> {\n if (!filename.endsWith(\".meeko\")) throw new TypeError(\"Type generation requires a .meeko input file\");\n const root = projectRoot(filename);\n const outputRoot = join(root, \".meeko\", \"types\");\n const declarations = new Map<string, string>();\n async function collect(content: string, path: string): Promise<void> {\n if (declarations.has(path)) return;\n const target = relative(root, path).split(/[\\\\/]/)[0] === \"server\" ? \"server\" : \"client\";\n const generated = (await compileWithAutoImports(content, path, {}, target)).code;\n const result = ts.transpileDeclaration(generated, {\n fileName: `${path}.ts`,\n compilerOptions: { declaration: true, emitDeclarationOnly: true },\n });\n const error = result.diagnostics?.find((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error);\n if (error) throw new Error(ts.flattenDiagnosticMessageText(error.messageText, \"\\n\"));\n declarations.set(path, result.outputText);\n for (const { value: specifier } of moduleSpecifiers(generated, path)) {\n if (!specifier.endsWith(\".meeko\")) continue;\n if (!specifier.startsWith(\".\")) continue;\n const child = resolve(dirname(path), specifier);\n await collect(await readFile(child, \"utf8\"), child);\n }\n }\n await collect(source, resolve(filename));\n const outputs: string[] = [];\n for (const [path, declaration] of declarations) {\n const output = join(outputRoot, relative(root, path)).replace(/\\.meeko$/, \".d.meeko.ts\");\n const rewritten = replaceModuleSpecifiers(declaration, output, ({ value }) => {\n if (!value.startsWith(\".\") || value.endsWith(\".meeko\")) return value;\n const original = resolve(dirname(path), value);\n const target = relative(dirname(output), original).replaceAll(\"\\\\\", \"/\");\n return target.startsWith(\".\") ? target : `./${target}`;\n });\n await mkdir(dirname(output), { recursive: true });\n await writeFile(output, rewritten, \"utf8\");\n outputs.push(output);\n }\n return outputs;\n}\n"]}
package/dist/vite.js CHANGED
@@ -1,33 +1,102 @@
1
1
  import { createHash } from "node:crypto";
2
- import { dirname, resolve } from "node:path";
2
+ import { dirname, isAbsolute, relative, resolve } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { normalizePath, transformWithOxc } from "vite";
5
5
  import { compile } from "./compiler.js";
6
+ import { moduleSpecifiers } from "./compiler/import-graph.js";
7
+ import { sourceMapForCompiled } from "./compiler/sourcemap.js";
8
+ import { discoverAutoImports, transformAutoImports } from "./autoimports.js";
9
+ import { transformTypeScriptAutoImports, typeScriptAutoImportMap } from "./autoimports-ts.js";
10
+ import { discoverConfiguredRoutes } from "./framework/config.js";
6
11
  const stylePrefix = "\0virtual:meeko-style:";
12
+ const pageModules = new Map([
13
+ ["virtual:meeko-client-pages", "client"],
14
+ ["virtual:meeko-server-pages", "server"],
15
+ ["virtual:meeko-server-routes", "routes"],
16
+ ]);
7
17
  const runtimeDirectory = `${normalizePath(dirname(fileURLToPath(import.meta.url)))}/`;
8
18
  /** Transforma componentes .meeko para Vite, tanto en cliente como en SSR. */
9
19
  export function meeko() {
10
20
  let isDev = false;
21
+ let ssrBuild = false;
22
+ let root = "";
11
23
  const styles = new Map();
12
24
  return {
13
25
  name: "meeko:components",
14
26
  enforce: "pre",
15
27
  configResolved(config) {
16
28
  isDev = config.command === "serve";
29
+ ssrBuild = Boolean(config.build.ssr);
30
+ root = config.root;
17
31
  },
18
32
  resolveId(id) {
19
33
  if (id.startsWith("virtual:meeko-style:"))
20
34
  return `\0${id}`;
35
+ if (pageModules.has(id))
36
+ return `\0${id}`;
21
37
  return null;
22
38
  },
23
- load(id) {
39
+ async load(id) {
40
+ const kind = pageModules.get(id.slice(1));
41
+ if (kind) {
42
+ const routes = await discoverConfiguredRoutes(root);
43
+ const files = kind === "routes"
44
+ ? routes.flatMap((route) => route.sidecar ? [route.sidecar] : [])
45
+ : routes.flatMap((route) => [route.file, ...route.layouts, ...(route.error ? [route.error] : [])]);
46
+ const unique = [...new Set(files)];
47
+ const entries = unique.map((file, index) => {
48
+ const path = relative(root, file).replaceAll("\\", "/");
49
+ if (path === ".." || path.startsWith("../") || isAbsolute(path))
50
+ throw new Error(`Page outside Meeko project: ${file}`);
51
+ const specifier = `/${path}`;
52
+ return kind === "client"
53
+ ? `${JSON.stringify(specifier)}: () => import(${JSON.stringify(specifier)})`
54
+ : `${JSON.stringify(specifier)}: module${index}`;
55
+ });
56
+ const imports = kind === "client" ? "" : unique.map((file, index) => {
57
+ const path = relative(root, file).replaceAll("\\", "/");
58
+ return `import * as module${index} from ${JSON.stringify(`/${path}`)};`;
59
+ }).join("\n");
60
+ return `${imports}\nexport const modules = {${entries.join(",")}};`;
61
+ }
24
62
  if (!id.startsWith(stylePrefix) || !id.endsWith(".css"))
25
63
  return null;
26
64
  return styles.get(id) ?? null;
27
65
  },
28
- async transform(source, id) {
29
- if (!id.endsWith(".meeko"))
66
+ async transform(source, id, options) {
67
+ const serverTransform = Boolean(options?.ssr || ssrBuild);
68
+ const normalizedId = normalizePath(resolve(id));
69
+ const normalizedRoot = normalizePath(root);
70
+ const clientModule = !serverTransform && normalizedId.startsWith(`${normalizedRoot}/`);
71
+ if (clientModule && (normalizedId.startsWith(`${normalizedRoot}/server/`) || /\.server\.[cm]?[jt]sx?$/.test(id))) {
72
+ throw new Error(`Server-only module reached the client bundle: ${id}`);
73
+ }
74
+ if (serverTransform && normalizedId.startsWith(`${normalizedRoot}/`) && /\.client\.[cm]?[jt]sx?$/.test(id)) {
75
+ throw new Error(`Client-only module reached the server bundle: ${id}`);
76
+ }
77
+ const checkBoundary = async (code) => {
78
+ if (!clientModule)
79
+ return;
80
+ for (const { value } of moduleSpecifiers(code, id)) {
81
+ const dependency = await this.resolve(value, id, { skipSelf: true });
82
+ if (dependency && normalizePath(dependency.id).startsWith(`${normalizedRoot}/server/`)) {
83
+ throw new Error(`Client module ${id} imports server-only module ${value}`);
84
+ }
85
+ }
86
+ };
87
+ if (!id.endsWith(".meeko")) {
88
+ if (/\.[cm]?[jt]sx?$/.test(id) && clientModule)
89
+ await checkBoundary(source);
90
+ if (/\.[cm]?tsx?$/.test(id) && normalizedId.startsWith(`${normalizedRoot}/`)) {
91
+ const registry = await discoverAutoImports(root);
92
+ const transformed = transformTypeScriptAutoImports(source, id, root, registry);
93
+ if (transformed) {
94
+ await checkBoundary(transformed);
95
+ return { code: transformed, map: typeScriptAutoImportMap(source, transformed, id) };
96
+ }
97
+ }
30
98
  return null;
99
+ }
31
100
  const filename = normalizePath(resolve(id));
32
101
  const result = compile(source, filename, { hot: isDev });
33
102
  const styleId = `${stylePrefix}${createHash("sha256").update(filename).update("\0").update(result.css).digest("hex")}.css`;
@@ -35,13 +104,29 @@ export function meeko() {
35
104
  styles.set(styleId, result.css);
36
105
  const cssImport = result.css ? `\nimport ${JSON.stringify(styleId.slice(1))};` : "";
37
106
  const hotCode = isDev ? `\nif (import.meta.hot) {\n __meeko.enableHotModule(__hotId);\n import.meta.hot.accept((next) => { if (next) __meeko.replaceHotModule(__hotId, next); });\n}\n` : "";
38
- return transformWithOxc(`${result.code}${cssImport}${hotCode}`, `${filename}.ts`, { lang: "ts" });
107
+ const registry = await discoverAutoImports(root);
108
+ const code = transformAutoImports(source, filename, result.code, registry, serverTransform ? "server" : "client");
109
+ await checkBoundary(code);
110
+ const shifted = code.length - result.code.length;
111
+ const mappings = result.mappings.map((mapping) => ({
112
+ ...mapping,
113
+ generatedStart: mapping.generatedStart + shifted,
114
+ generatedEnd: mapping.generatedEnd + shifted,
115
+ }));
116
+ const generated = `${code}${cssImport}${hotCode}`;
117
+ return transformWithOxc(generated, `${filename}.ts`, { lang: "ts" }, sourceMapForCompiled(generated, source, filename, mappings));
39
118
  },
40
119
  handleHotUpdate({ file, server }) {
41
- if (!normalizePath(file).startsWith(runtimeDirectory))
120
+ const normalized = normalizePath(file);
121
+ const relative = normalized.slice(normalizePath(root).length + 1);
122
+ const registrySource = /^(?:app\/(?:components|composables|utils|stores)|shared\/(?:types|schemas|utils|constants|enums)|server\/utils)\//.test(relative);
123
+ const routesSource = /^(?:app\/pages|layers\/|modules\/)/.test(relative) || relative.startsWith("meeko.config.");
124
+ if (!normalized.startsWith(runtimeDirectory) && !registrySource && !routesSource)
42
125
  return;
126
+ server.moduleGraph.invalidateAll();
43
127
  server.ws.send({ type: "full-reload" });
44
128
  return [];
45
129
  },
46
130
  };
47
131
  }
132
+ //# sourceMappingURL=vite.js.map