@bobtail.software/b-ssr 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,32 +1,32 @@
1
- import se from"fast-glob";import{unlink as ie,writeFile as oe}from"fs/promises";import C from"path";import{Node as q,Project as ae,SyntaxKind as i,ts as L}from"ts-morph";var I="virtual:b-ssr-rpc-universal:";function pe(c){let g=c.replace(/[^a-zA-Z0-9]+(.)?/g,(v,f)=>f?f.toUpperCase():"");return g.charAt(0).toLowerCase()+g.slice(1)}function H(c,g,v){let f=C.basename(v,".mts"),F=g.replace(/:[a-zA-Z0-9_]+/g,"").replace(/\//g," "),b=`${c} ${F} ${f}`;return pe(b)}function xe(c={}){let{routerPattern:g="src-ts/routers/**/*.mts",tsConfigFilePath:v="tsconfig.json"}=c,f=new Map,F=new ae({tsConfigFilePath:v});async function b(r){try{let S=function(e,o){if(e.getSymbol()?.getName()==="Promise"){let T=e.getAwaitedType();if(T)return`Promise<${S(T,o)}>`}let s=e.getAliasSymbol()??e.getSymbol();if(s?.getName()==="__object")return e.getText(o,L.TypeFormatFlags.NoTruncation|L.TypeFormatFlags.InTypeAlias);if(!s)return e.getText(o,L.TypeFormatFlags.NoTruncation);let p=s.getDeclarations()[0];if(!p)return s.getName();let l=p.getSourceFile();if(l.getFilePath()===t.getFilePath())return s.getName();if(l.isInNodeModules())return e.getText(o,L.TypeFormatFlags.NoTruncation);let m=C.relative(C.dirname(O),l.getFilePath()).replace(/\\/g,"/"),h=m.startsWith(".")?m:`./${m}`,a=s.getName();return M.has(h)||M.set(h,new Set),M.get(h)?.add(a),a},k=function(e){let o;if(q.isFunctionLikeDeclaration(e)||q.isArrowFunction(e)){let s=e.getDescendantsOfKind(i.ReturnStatement);for(let p of s){let l=p.getExpression();if(l?.isKind(i.SatisfiesExpression)){o=l.getTypeNode()?.getType();break}}}if(o)return S(o,e);{let s=e.getType().getCallSignatures();if(s.length>0){let p=s[0]?.getReturnType();return S(p,e)}}return"unknown"};var u=S,n=k;let t=F.addSourceFileAtPath(r);await t.refreshFromFileSystem(),F.resolveSourceFileDependencies();let P=t.getDescendantsOfKind(i.CallExpression),V=P.filter(e=>e.getExpression().getText().endsWith(".addRpcRoute")),W=P.filter(e=>e.getExpression().getText().endsWith(".addRenderRoute")),O=r.replace(/\.mts$/,".d.ts");if(V.length===0&&W.length===0){f.delete(C.resolve(r)),await ie(O).catch(()=>{});return}let E=[],M=new Map;V.forEach(e=>{let[o,s]=e.getArguments();if(!o?.isKind(i.StringLiteral))return;let p=o.getLiteralValue(),l="",m="unknown",h="unknown",a="unknown",T="unknown",x=!1;if(s?.isKind(i.ObjectLiteralExpression)){let N=s,_=N.getProperty("prefix");if(_?.isKind(i.PropertyAssignment)){let d=_.getInitializer();if(d?.isKind(i.StringLiteral))l=d.getLiteralValue();else if(d?.isKind(i.Identifier)){let A=d.getSymbol(),$=A?.getAliasedSymbol()??A;if($){let y=$.getDeclarations()[0];if(q.isVariableDeclaration(y)){let w=y.getInitializer();w?.isKind(i.StringLiteral)&&(l=w.getLiteralValue())}}}}let Z=N.getProperty("schema");if(Z?.isKind(i.PropertyAssignment)){let d=Z.getInitializerIfKind(i.ObjectLiteralExpression);if(d){let A=d.getProperty("consumes");if(A?.isKind(i.PropertyAssignment)){let y=A.getInitializer();q.isArrayLiteralExpression(y)&&(x=y.getElements().some(w=>w.isKind(i.StringLiteral)&&w.getLiteralValue()==="multipart/form-data"))}let $=y=>{let w=d.getProperty(y);if(w?.isKind(i.PropertyAssignment)){let R=w.getInitializer();if(R){let B=R.getType().getProperty("_output");if(B){let ne=B.getTypeAtLocation(R).getApparentType();return S(ne,R)}}}return"unknown"};if(m=$("params"),h=$("querystring"),a=$("body"),x){let y="{ file: File }";a!=="unknown"&&a.trim().startsWith("{")?a=`(${a} & ${y})`:a=y}}}let G=N.getProperty("handler");if(G?.isKind(i.PropertyAssignment)){let d=G.getInitializer();d&&(T=k(d))}}let te=C.join(l,"rpc",p),re=H("rpc",l,p);E.push({type:"rpc",name:re,url:p,rpcUrl:te,paramsType:m,queryType:h,bodyType:a,returnType:T,isMultipart:x})}),W.forEach(e=>{let[o,s]=e.getArguments();if(!o?.isKind(i.StringLiteral))return;let p=o.getLiteralValue(),l="unknown",m="";if(s?.isKind(i.ObjectLiteralExpression)){let a=s.getProperty("prefix");if(a?.isKind(i.PropertyAssignment)){let x=a.getInitializer();x?.isKind(i.StringLiteral)&&(m=x.getLiteralValue())}let T=s.getProperty("handler");if(T?.isKind(i.PropertyAssignment)){let x=T.getInitializer();x&&(l=k(x))}}let h=H("loader",m,p);if(h!=="loader"){let a=`${m}/loader${p}`;E.push({type:"loader",name:h,returnType:l,url:p,loaderUrl:a})}});let j=[];for(let[e,o]of M.entries()){let s=[...o].sort().join(", ");j.push(`import type { ${s} } from "${e}";`)}let K=[];E.forEach(e=>{e.type==="rpc"?K.push(X(e)):e.type==="loader"&&K.push(`export declare const ${e.name}: (ssrContext?: { req?: any, reply?: any, params?: any, query?: any, body?: any }) => ${e.returnType};`)});let Q=`// Este archivo es generado por el plugin de b-ssr y no debe ser editado manualmente.
1
+ import ne from"fast-glob";import{access as se,unlink as H,writeFile as ie}from"fs/promises";import P from"path";import{Node as I,Project as oe,SyntaxKind as o,ts as O}from"ts-morph";var R="virtual:b-ssr-rpc-universal:";function ae(l){let u=l.replace(/[^a-zA-Z0-9]+(.)?/g,(b,m)=>m?m.toUpperCase():"");return u.charAt(0).toLowerCase()+u.slice(1)}function X(l,u,b){let m=P.basename(b,".mts"),F=u.replace(/:[a-zA-Z0-9_]+/g,"").replace(/\//g," "),C=`${l} ${F} ${m}`;return ae(C)}function ye(l={}){let{routerPattern:u="src-ts/routers/**/*.mts",tsConfigFilePath:b="tsconfig.json"}=l,m=new Map,F=new oe({tsConfigFilePath:b,skipAddingFilesFromTsConfig:!0});async function C(n){try{let A=function(e,s){if(e.getSymbol()?.getName()==="Promise"){let x=e.getAwaitedType();if(x)return`Promise<${A(x,s)}>`}let i=e.getAliasSymbol()??e.getSymbol();if(i?.getName()==="__object")return e.getText(s,O.TypeFormatFlags.NoTruncation|O.TypeFormatFlags.InTypeAlias);if(!i)return e.getText(s,O.TypeFormatFlags.NoTruncation);let a=i.getDeclarations()[0];if(!a)return i.getName();let p=a.getSourceFile();if(p.getFilePath()===t.getFilePath())return i.getName();if(p.isInNodeModules())return e.getText(s,O.TypeFormatFlags.NoTruncation);let d=P.relative(P.dirname(q),p.getFilePath()).replace(/\\/g,"/"),y=d.startsWith(".")?d:`./${d}`,c=i.getName();return E.has(y)||E.set(y,new Set),E.get(y)?.add(c),c},k=function(e){let s;if(I.isFunctionLikeDeclaration(e)||I.isArrowFunction(e)){let i=e.getDescendantsOfKind(o.ReturnStatement);for(let a of i){let p=a.getExpression();if(p?.isKind(o.SatisfiesExpression)){s=p.getTypeNode()?.getType();break}}}if(s)return A(s,e);{let i=e.getType().getCallSignatures();if(i.length>0){let a=i[0]?.getReturnType();return A(a,e)}}return"unknown"};var g=A,r=k;let t=F.addSourceFileAtPath(n);await t.refreshFromFileSystem(),F.resolveSourceFileDependencies();let T=t.getDescendantsOfKind(o.CallExpression),$=T.filter(e=>e.getExpression().getText().endsWith(".addRpcRoute")),U=T.filter(e=>e.getExpression().getText().endsWith(".addRenderRoute")),q=n.replace(/\.mts$/,".universal.d.ts");if($.length===0&&U.length===0){m.delete(P.resolve(n)),await H(q).catch(()=>{});return}let v=[],E=new Map;$.forEach(e=>{let[s,i]=e.getArguments();if(!s?.isKind(o.StringLiteral))return;let a=s.getLiteralValue(),p="",d="unknown",y="unknown",c="unknown",x="unknown",f=!1;if(i?.isKind(o.ObjectLiteralExpression)){let D=i,W=D.getProperty("prefix");if(W?.isKind(o.PropertyAssignment)){let h=W.getInitializer();h?.isKind(o.StringLiteral)&&(p=h.getLiteralValue())}let _=D.getProperty("schema");if(_?.isKind(o.PropertyAssignment)){let h=_.getInitializerIfKind(o.ObjectLiteralExpression);if(h){let Z=h.getProperty("consumes");if(Z?.isKind(o.PropertyAssignment)){let w=Z.getInitializer();I.isArrayLiteralExpression(w)&&(f=w.getElements().some(S=>S.isKind(o.StringLiteral)&&S.getLiteralValue()==="multipart/form-data"))}let z=w=>{let S=h.getProperty(w);if(S?.isKind(o.PropertyAssignment)){let M=S.getInitializer();if(M){let B=M.getType().getProperty("_output");if(B)return A(B.getTypeAtLocation(M).getApparentType(),M)}}return"unknown"};if(d=z("params"),y=z("querystring"),c=z("body"),f){let w="{ file: File }";c=c!=="unknown"&&c.trim().startsWith("{")?`(${c} & ${w})`:w}}}let G=D.getProperty("handler");if(G?.isKind(o.PropertyAssignment)){let h=G.getInitializer();h&&(x=k(h))}}let te=P.join(p,"rpc",a),re=X("rpc",p,a);v.push({type:"rpc",name:re,url:a,rpcUrl:te,paramsType:d,queryType:y,bodyType:c,returnType:x,isMultipart:f})}),U.forEach(e=>{let[s,i]=e.getArguments();if(!s?.isKind(o.StringLiteral))return;let a=s.getLiteralValue(),p="unknown",d="";if(i?.isKind(o.ObjectLiteralExpression)){let c=i.getProperty("prefix");if(c?.isKind(o.PropertyAssignment)){let f=c.getInitializer();f?.isKind(o.StringLiteral)&&(d=f.getLiteralValue())}let x=i.getProperty("handler");if(x?.isKind(o.PropertyAssignment)){let f=x.getInitializer();f&&(p=k(f))}}let y=X("loader",d,a);y!=="loader"&&v.push({type:"loader",name:y,returnType:p,url:a,loaderUrl:`${d}/loader${a}`})});let j=[];for(let[e,s]of E.entries())j.push(`import type { ${[...s].sort().join(", ")} } from "${e}";`);let K=[];v.forEach(e=>{e.type==="rpc"?K.push(J(e)):e.type==="loader"&&K.push(`export declare const ${e.name}: (ssrContext?: { req?: any, reply?: any, params?: any, query?: any, body?: any }) => ${e.returnType};`)});let Y=`// AUTO-GENERATED by @bobtail.software/b-ssr. DO NOT EDIT.
2
2
 
3
3
  `+(j.length>0?j.join(`
4
4
  `)+`
5
5
 
6
6
  `:"")+K.join(`
7
7
 
8
- `);await oe(O,Q);let z=[],D=[],U=[];E.forEach(e=>{if(U.push(`export const ${e.name} = exports.${e.name};`),e.type==="rpc"){let o=e.paramsType!=="unknown"||e.queryType!=="unknown"||e.bodyType!=="unknown"||e.isMultipart;z.push(`exports.${e.name} = createClientRpc({ url: '${e.rpcUrl}', method: 'POST', isMultipart: ${!!e.isMultipart} });`),D.push({name:e.name,url:e.url,type:e.type,requiresArgs:o})}else e.type==="loader"&&(z.push(`exports.${e.name} = createClientRpc({ url: '${e.loaderUrl}', method: 'GET' });`),D.push({name:e.name,url:e.url,type:e.type,requiresArgs:!1}))});let Y=z.join(`
9
- `),ee=`
8
+ `);await ie(q,Y);let L=[],N=[],V=[];v.forEach(e=>{if(V.push(`export const ${e.name} = exports.${e.name};`),e.type==="rpc"){let s=e.paramsType!=="unknown"||e.queryType!=="unknown"||e.bodyType!=="unknown"||e.isMultipart;L.push(`exports.${e.name} = createClientRpc({ url: '${e.rpcUrl}', method: 'POST', isMultipart: ${!!e.isMultipart} });`),N.push({name:e.name,url:e.url,type:e.type,requiresArgs:s})}else e.type==="loader"&&(L.push(`exports.${e.name} = createClientRpc({ url: '${e.loaderUrl}', method: 'GET' });`),N.push({name:e.name,url:e.url,type:e.type,requiresArgs:!1}))});let ee=`
10
9
  import { createClientRpc } from '@bobtail.software/b-ssr/client';
11
10
  const exports = {};
12
11
  if (import.meta.env.SSR) {
13
12
  try {
14
- ${J(D,r)}
13
+ ${Q(N,n)}
15
14
  } catch (e) {
16
15
  console.error('Error en el servidor SSR:', e);
17
16
  }
18
17
  } else {
19
- ${Y}
18
+ ${L.join(`
19
+ `)}
20
20
  }
21
- ${U.join(`
21
+ ${V.join(`
22
22
  `)}
23
- `;f.set(C.resolve(r),ee)}catch(t){console.error(`[rpc-generator] Error al procesar ${r}:`,{error:t})}}function X(r){let u=le(r),n="";u.length>0&&(n=`args: { ${u.join("; ")} }`);let P=[n,"ssrContext?: { req: any, reply: any }"].filter(Boolean).join(", ");return`export declare const ${r.name}: (${P}) => ${r.returnType};`}function J(r,u){return r.length===0?"":`
23
+ `;m.set(P.resolve(n),ee)}catch(t){console.error(`[rpc-generator] Error al procesar ${n}:`,{error:t})}}function J(n){let g=pe(n),r="";return g.length>0&&(r=`args: { ${g.join("; ")} }`),`export declare const ${n.name}: (${[r,"ssrContext?: { req: any, reply: any }"].filter(Boolean).join(", ")}) => ${n.returnType};`}function Q(n,g){return n.length===0?"":`
24
24
  let rpcOptionsMap, renderOptionsMap;
25
25
  async function getOptionsMaps() {
26
26
  if (rpcOptionsMap && renderOptionsMap) return;
27
27
  rpcOptionsMap = new Map();
28
28
  renderOptionsMap = new Map();
29
- const serverModulePath = '${u.replace(/\\/g,"/")}';
29
+ const serverModulePath = '${g.replace(/\\/g,"/")}';
30
30
  const routeModule = await import(/* @vite-ignore */ serverModulePath);
31
31
  const mockFastify = {
32
32
  addRpcRoute: (url, options) => rpcOptionsMap.set(url, options),
@@ -34,39 +34,22 @@ import se from"fast-glob";import{unlink as ie,writeFile as oe}from"fs/promises";
34
34
  };
35
35
  if (routeModule.default) await routeModule.default(mockFastify);
36
36
  }
37
-
38
- ${r.map(n=>{let t=[];return n.requiresArgs&&t.push("args"),t.push("ssrContext"),n.type==="rpc"?n.isMultipart?`
39
- exports.${n.name} = async () => {
40
- throw new Error('La funci\xF3n RPC "${n.name}" implica una subida de archivo y no puede ser llamada desde el servidor (SSR). Las subidas de archivos deben originarse desde el cliente.');
41
- };`:`
42
- exports.${n.name} = async (${t.join(", ")}) => {
43
- if (!ssrContext || !ssrContext.req || !ssrContext.reply) {
44
- throw new Error('ssrContext (con req y reply) es requerido para ejecutar RPC en el servidor.');
45
- }
37
+ ${n.map(r=>{let t=[];return r.requiresArgs&&t.push("args"),t.push("ssrContext"),r.type==="rpc"?r.isMultipart?`exports.${r.name} = async () => { throw new Error('RPC multipart no soportado en SSR.'); };`:`exports.${r.name} = async (${t.join(", ")}) => {
38
+ if (!ssrContext?.req || !ssrContext?.reply) throw new Error('ssrContext requerido');
46
39
  await getOptionsMaps();
47
- const options = rpcOptionsMap.get('${n.url}');
48
- if (!options?.handler) throw new Error('Handler para RPC "${n.name}" no encontrado.');
40
+ const options = rpcOptionsMap.get('${r.url}');
41
+ if (!options?.handler) throw new Error('Handler no encontrado');
49
42
  const augmentedReq = Object.assign(Object.create(ssrContext.req), args);
50
43
  return await options.handler.call(ssrContext.req.server, augmentedReq, ssrContext.reply);
51
- };`:`
52
- exports.${n.name} = async (ssrContext) => {
53
- if (!ssrContext || !ssrContext.req || !ssrContext.reply) {
54
- throw new Error('ssrContext (con req y reply) es requerido para ejecutar Loaders en el servidor.');
55
- }
44
+ };`:`exports.${r.name} = async (ssrContext) => {
45
+ if (!ssrContext?.req || !ssrContext?.reply) throw new Error('ssrContext requerido');
56
46
  await getOptionsMaps();
57
- const options = renderOptionsMap.get('${n.url}');
58
- if (!options) {
59
- throw new Error(\`Options for Loader "${n.name}" not found at runtime. Check the route file: ${u.replace(/\\/g,"/")}\`);
60
- }
47
+ const options = renderOptionsMap.get('${r.url}');
48
+ if (!options) throw new Error('Opciones loader no encontradas');
61
49
  let customData = {};
62
- let sessionData = {};
63
-
64
- if (options.handler) {
65
- customData = (await options.handler.call(ssrContext.req.server, ssrContext.req, ssrContext.reply)) || {};
66
- }
50
+ if (options.handler) customData = (await options.handler.call(ssrContext.req.server, ssrContext.req, ssrContext.reply)) || {};
67
51
  if (ssrContext.reply.sent) return;
68
-
69
- return { ...sessionData, ...customData };
52
+ return { ...customData };
70
53
  };`}).join(`
71
54
  `)}
72
- `}return{name:"b-ssr-vite-plugin-rpc-universal-generator",enforce:"pre",configureServer(r){async function u(){let t=await se(g,{absolute:!0});await Promise.all(t.map(P=>b(P)))}u();let n=t=>t.endsWith(".mts")||t.endsWith(".cts")||t.endsWith(".ts");r.watcher.on("add",t=>{n(t)&&b(t)}),r.watcher.on("change",t=>{n(t)&&b(t)}),r.watcher.on("unlink",t=>{n(t)&&f.delete(C.resolve(t))})},async resolveId(r,u){if(r.endsWith("?universal")){let n=r.slice(0,-10),t=await this.resolve(n,u,{skipSelf:!0});if(t)return I+t.id}return null},load(r){if(r.startsWith(I)){let u=r.slice(I.length);return f.get(u)}return null}}}function le(c){let g=[];return c.paramsType!=="unknown"&&g.push(`params: ${c.paramsType}`),c.queryType!=="unknown"&&g.push(`query: ${c.queryType}`),c.bodyType!=="unknown"&&g.push(`body: ${c.bodyType}`),g}export{xe as rpcGeneratorPlugin};
55
+ `}return{name:"b-ssr-vite-plugin-rpc-universal-generator",enforce:"pre",configureServer(n){async function g(){let t=await ne(u,{absolute:!0});await Promise.all(t.map(T=>C(T)))}g();let r=t=>t.endsWith(".mts");n.watcher.on("add",t=>r(t)&&C(t)),n.watcher.on("change",t=>r(t)&&C(t)),n.watcher.on("unlink",t=>{r(t)&&(m.delete(P.resolve(t)),H(t.replace(/\.mts$/,".universal.d.ts")).catch(()=>{}))})},async resolveId(n,g){if(n.includes(".universal")){let r=n.split("?")[0],t=r;if(r.endsWith(".universal"))t=r;else if(r.endsWith(".universal.ts"))t=r.slice(0,-3);else if(r.endsWith(".universal.mts"))t=r.slice(0,-4);else return null;let T=t.slice(0,-10)+".mts",$=await this.resolve(T,g,{skipSelf:!0});if($)return R+$.id;try{return await se(T),R+T}catch{}}return null},load(n){if(n.startsWith(R)){let g=n.slice(R.length);return m.get(g)}return null}}}function pe(l){let u=[];return l.paramsType!=="unknown"&&u.push(`params: ${l.paramsType}`),l.queryType!=="unknown"&&u.push(`query: ${l.queryType}`),l.bodyType!=="unknown"&&u.push(`body: ${l.bodyType}`),u}export{ye as rpcGeneratorPlugin};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobtail.software/b-ssr",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Fastify + Vite SSR Plugin wrapper with RPC",
5
5
  "author": "Victor Moreno <info@bobtail.software> (https://bobtail.software)",
6
6
  "license": "GPL-3.0",