@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.
- package/dist/vite-rpc-plugin.js +19 -36
- package/package.json +1 -1
package/dist/vite-rpc-plugin.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import
|
|
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
|
|
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
|
-
${
|
|
13
|
+
${Q(N,n)}
|
|
15
14
|
} catch (e) {
|
|
16
15
|
console.error('Error en el servidor SSR:', e);
|
|
17
16
|
}
|
|
18
17
|
} else {
|
|
19
|
-
${
|
|
18
|
+
${L.join(`
|
|
19
|
+
`)}
|
|
20
20
|
}
|
|
21
|
-
${
|
|
21
|
+
${V.join(`
|
|
22
22
|
`)}
|
|
23
|
-
`;
|
|
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 = '${
|
|
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
|
-
|
|
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('${
|
|
48
|
-
if (!options?.handler) throw new Error('Handler
|
|
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
|
-
|
|
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('${
|
|
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
|
-
|
|
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
|
-
|
|
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