@bobtail.software/b-ssr 1.0.60 → 1.0.64
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.cjs +80 -31
- package/dist/vite-rpc-plugin.js +81 -32
- package/package.json +1 -1
package/dist/vite-rpc-plugin.cjs
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var de=Object.create;var I=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var ye=Object.getPrototypeOf,he=Object.prototype.hasOwnProperty;var be=(o,l)=>{for(var x in l)I(o,x,{get:l[x],enumerable:!0})},te=(o,l,x,C)=>{if(l&&typeof l=="object"||typeof l=="function")for(let w of fe(l))!he.call(o,w)&&w!==x&&I(o,w,{get:()=>l[w],enumerable:!(C=me(l,w))||C.enumerable});return o};var re=(o,l,x)=>(x=o!=null?de(ye(o)):{},te(l||!o||!o.__esModule?I(x,"default",{value:o,enumerable:!0}):x,o)),Te=o=>te(I({},"__esModule",{value:!0}),o);var Se={};be(Se,{rpcGeneratorPlugin:()=>Pe});module.exports=Te(Se);var se=re(require("fast-glob"),1),q=require("fs/promises"),a=re(require("path"),1),K=require("prettier"),s=require("ts-morph"),L="virtual:b-ssr-rpc-universal:";function xe(o){let l=o.replace(/[^a-zA-Z0-9]+(.)?/g,(x,C)=>C?C.toUpperCase():"");return l.charAt(0).toLowerCase()+l.slice(1)}function Z(o,l,x){let C=a.default.basename(x,a.default.extname(x))||"Index",w=l.replace(/:[a-zA-Z0-9_]+/g,"").replace(/\//g," "),j=`${o} ${w} ${C}`;return xe(j)}function Pe(o={}){let{routerPattern:l="src-ts/routers/**/*.mts",tsConfigFilePath:x="tsconfig.json",routerBaseDir:C="src-ts/routers"}=o,w=new Map,j=new Set,B=new s.Project({tsConfigFilePath:x,skipAddingFilesFromTsConfig:!1}),ne=a.default.resolve(process.cwd(),C||".");async function W(t){try{let D=function(e){return e.replace(/import\(['"](.*?)['"]\)/g,(p,i)=>{if(!a.default.isAbsolute(i))return p;let n=i;if(!a.default.extname(n)){let T=B.getSourceFile(y=>y.getFilePath().replace(/\.(mts|ts|tsx)$/,"")===i);T&&(n=T.getFilePath())}let u=a.default.relative(a.default.dirname(M),n).replace(/\\/g,"/");return u.startsWith(".")||(u="./"+u),`import("${u}")`})},O=function(e,p){if(e.getSymbol()?.getName()==="Promise"){let d=e.getAwaitedType();if(d)return`Promise<${O(d,p)}>`}let i=e.getAliasSymbol()??e.getSymbol();if(i?.getName()==="__object")return D(e.getText(p,s.ts.TypeFormatFlags.NoTruncation|s.ts.TypeFormatFlags.UseFullyQualifiedType));if(e.isObject()&&!i){let d=(f,h=0)=>{if(!(h>5)){if(f.isArray()){let P=f.getArrayElementType();P&&d(P,h);return}if(f.isObject()&&!f.getSymbol()&&!f.getAliasSymbol()){for(let P of f.getApparentProperties()){let $=P.getValueDeclaration();$&&d(P.getTypeAtLocation($),h+1)}return}O(f,p)}};return d(e),D(e.getText(p,s.ts.TypeFormatFlags.NoTruncation|s.ts.TypeFormatFlags.UseFullyQualifiedType))}if(!i)return D(e.getText(p,s.ts.TypeFormatFlags.NoTruncation));let n=i.getDeclarations()[0];if(!n)return i.getName();if(s.Node.isImportSpecifier(n)||s.Node.isImportClause(n)){let d=n.getFirstAncestorByKind(s.SyntaxKind.ImportDeclaration);if(d){let f=d.getModuleSpecifierValue(),h=i.getName();return v.has(f)||v.set(f,new Set),v.get(f)?.add(h),h}}let u=n.getSourceFile();if(u.getFilePath()===b.getFilePath())return i.getName();if(u.isInNodeModules())return D(e.getText(p,s.ts.TypeFormatFlags.NoTruncation));let T=a.default.relative(a.default.dirname(M),u.getFilePath()).replace(/\\/g,"/"),E=T.startsWith(".")?T:`./${T}`,S=i.getName();return v.has(E)||v.set(E,new Set),v.get(E)?.add(S),S},Q=function(e){let p;if(s.Node.isFunctionLikeDeclaration(e)||s.Node.isArrowFunction(e)){let i=e.getDescendantsOfKind(s.SyntaxKind.ReturnStatement);for(let n of i){let u=n.getExpression();if(u?.isKind(s.SyntaxKind.SatisfiesExpression)){p=u.getTypeNode()?.getType();break}}}if(p)return O(p,e);{let i=e.getType().getCallSignatures();if(i.length>0){let n=i[0]?.getReturnType();return O(n,e)}}return"unknown"};var m=D,r=O,g=Q;let b=B.addSourceFileAtPath(t);await b.refreshFromFileSystem(),B.resolveSourceFileDependencies();let c=b.getDescendantsOfKind(s.SyntaxKind.CallExpression),A=c.filter(e=>e.getExpression().getText().endsWith(".addRpcRoute")),F=c.filter(e=>e.getExpression().getText().endsWith(".addRenderRoute")),R=c.filter(e=>e.getExpression().getText().endsWith(".addLoaderRoute")),k=a.default.extname(t),M=t.substring(0,t.length-k.length)+".universal.d.ts",V=a.default.resolve(t);if(A.length===0&&F.length===0&&R.length===0){w.delete(V),j.delete(V),M!==t&&await(0,q.unlink)(M).catch(()=>{});return}j.add(V);let _=[],v=new Map;v.has("fastify")||v.set("fastify",new Set),v.get("fastify")?.add("FastifyRequest"),v.get("fastify")?.add("FastifyReply");let ce=e=>{let p="unknown",i="unknown",n="unknown",u=!1;if(!e||!s.Node.isObjectLiteralExpression(e))return{paramsType:p,queryType:i,bodyType:n,isMultipart:u};let T=e.getProperty("schema");if(T?.isKind(s.SyntaxKind.PropertyAssignment)){let y=T.getInitializer();if(y?.isKind(s.SyntaxKind.Identifier)){let S=y.getSymbol()?.getValueDeclaration();if(S){let d=S.getFirstDescendantByKind(s.SyntaxKind.ObjectLiteralExpression);d&&(y=d)}}if(y&&s.Node.isObjectLiteralExpression(y)){let E=y.getProperty("consumes");if(E?.isKind(s.SyntaxKind.PropertyAssignment)){let d=E.getInitializer();s.Node.isArrayLiteralExpression(d)&&(u=d.getElements().some(f=>f.isKind(s.SyntaxKind.StringLiteral)&&f.getLiteralValue()==="multipart/form-data"))}let S=d=>{let f=y.getProperty(d);if(f?.isKind(s.SyntaxKind.PropertyAssignment)){let h=f.getInitializer();if(h){let P=h.getType(),$=P.getProperty("_output");return O($?$.getTypeAtLocation(h).getApparentType():P,h)}}return"unknown"};if(p=S("params"),i=S("querystring"),n=S("body"),u){let d="{ file: File }";n=n!=="unknown"&&n.trim().startsWith("{")?`(${n} & ${d})`:d}}}return{paramsType:p,queryType:i,bodyType:n,isMultipart:u}},N=a.default.relative(ne,a.default.dirname(t)).split(a.default.sep).join("/"),pe=N==="."||!N?"":N.startsWith("/")?N:"/"+N,z=(e,p)=>{let[i,n]=e.getArguments();if(!i?.isKind(s.SyntaxKind.StringLiteral))return;let u=i.getLiteralValue(),T="unknown",y=pe,{paramsType:E,queryType:S,bodyType:d,isMultipart:f}=ce(n);if(n?.isKind(s.SyntaxKind.ObjectLiteralExpression)){let $=n.getProperty("prefix");if($?.isKind(s.SyntaxKind.PropertyAssignment)){let U=$.getInitializer();U?.isKind(s.SyntaxKind.StringLiteral)&&(y=U.getLiteralValue())}let ee=n.getProperty("handler");if(ee?.isKind(s.SyntaxKind.PropertyAssignment)){let U=ee.getInitializer();U&&(T=Q(U),T.startsWith("Promise<")||(T=`Promise<${T}>`))}}let h="",P="";p==="rpc"?(h=a.default.join(y,"rpc",u).replace(/\\/g,"/"),P=Z("action",y,u)):p==="loader"?(h=a.default.join(y,"loader",u).replace(/\\/g,"/"),P=Z("loader",y,u)):p==="api"&&(h=a.default.join(y,"api",u).replace(/\\/g,"/"),P=Z("get",y,u)),P&&_.push({type:p,name:P,returnType:T,url:u,rpcUrl:h,loaderUrl:h,paramsType:E,queryType:S,bodyType:d,isMultipart:f})};A.forEach(e=>z(e,"rpc")),F.forEach(e=>z(e,"loader")),R.forEach(e=>z(e,"api"));let H=[];for(let[e,p]of v.entries())H.push(`import type { ${[...p].sort().join(", ")} } from "${e}";`);let X=[];_.forEach(e=>{X.push(ie(e))});let G=`// AUTO-GENERATED by @bobtail.software/b-ssr. DO NOT EDIT.
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
|
|
4
4
|
`+(H.length>0?H.join(`
|
|
5
5
|
`)+`
|
|
6
6
|
|
|
7
|
-
`:"")+
|
|
7
|
+
`:"")+X.join(`
|
|
8
8
|
|
|
9
|
-
`);try{let e=await(0,
|
|
9
|
+
`);try{let e=await(0,K.resolveConfig)(M)||{};G=await(0,K.format)(G,{...e,parser:"typescript",filepath:M})}catch{}await(0,q.writeFile)(M,G);let Y=[],J=[];_.forEach(e=>{let i=e.type==="rpc"?"POST":"GET",n=e.type==="loader"?e.loaderUrl:e.rpcUrl;J.push({name:e.name,rpcUrl:n,method:i,isMultipart:!!e.isMultipart}),Y.push({name:e.name,url:e.url,type:e.type,requiresArgs:!0})});let ue=`
|
|
10
10
|
import { createClientRpc } from '@bobtail.software/b-ssr/client';
|
|
11
|
+
|
|
11
12
|
if (import.meta.env.DEV) {
|
|
12
|
-
console.debug('\u{1F6E1}\uFE0F [B-SSR Security] Loaded SAFE Client-Stub for: ${
|
|
13
|
+
console.debug('\u{1F6E1}\uFE0F [B-SSR Security] Loaded SAFE Client-Stub for: ${a.default.basename(t)}');
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
${J.map(e=>`
|
|
17
|
+
export const ${e.name} = createClientRpc({
|
|
18
|
+
url: '${e.rpcUrl}',
|
|
19
|
+
method: '${e.method}',
|
|
20
|
+
isMultipart: ${e.isMultipart}
|
|
21
|
+
});
|
|
22
|
+
`).join(`
|
|
15
23
|
`)}
|
|
16
|
-
`,
|
|
24
|
+
`,ge=ae(Y,t);w.set(a.default.resolve(t),{client:ue,server:ge})}catch(b){console.error(`[rpc-generator] Error al procesar ${t}:`,{error:b})}}let oe=(t,m,r)=>{if(m.includes("node_modules")||m.startsWith(L))return null;if(r?.ssr===!0&&/\.[cm]?[jt]sx?$/.test(m)){let g=/\brequire\s*\(/.test(t),b=/\bmodule\.exports\b/.test(t),c=/\bexports\./.test(t);if(g||b||c)return"import { createRequire } from 'module';"+`
|
|
17
25
|
const require = createRequire(import.meta.url);
|
|
18
26
|
const module = { exports: {} };
|
|
19
27
|
const exports = module.exports;
|
|
20
|
-
|
|
21
|
-
export default module.exports;`}return null};function
|
|
28
|
+
`+t+`
|
|
29
|
+
export default module.exports;`}return null};function ie(t){let m=we(t),r="";return m.length>0&&(r=`args: { ${m.join("; ")} }`),r||(r="args: { signal?: AbortSignal }"),`export declare const ${t.name}: (${r}, ssrContext?: { req?: FastifyRequest, reply?: FastifyReply }) => ${t.returnType};`}function ae(t,m){if(t.length===0)return"";let r=a.default.relative(process.cwd(),m).replace(/\\/g,"/");return`
|
|
22
30
|
import path from 'path';
|
|
23
31
|
import { pathToFileURL } from 'url';
|
|
24
32
|
|
|
25
33
|
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
26
|
-
throw new Error('\u{1F6A8} [B-SSR SECURITY ALERT] Server-side code leaked to browser: ${
|
|
34
|
+
throw new Error('\u{1F6A8} [B-SSR SECURITY ALERT] Server-side code leaked to browser: ${`./${a.default.relative(process.cwd(),m).replace(/\\/g,"/")}`}');
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
let initPromise;
|
|
@@ -31,59 +39,100 @@ export default module.exports;`}return null};function le(s){let o=Fe(s),t=o.leng
|
|
|
31
39
|
|
|
32
40
|
function getOptionsMaps() {
|
|
33
41
|
if (initPromise) return initPromise;
|
|
42
|
+
|
|
34
43
|
initPromise = (async () => {
|
|
35
|
-
rpcOptionsMap = new Map();
|
|
44
|
+
rpcOptionsMap = new Map();
|
|
45
|
+
renderOptionsMap = new Map();
|
|
46
|
+
loaderApiOptionsMap = new Map();
|
|
36
47
|
const projectRoot = process.cwd();
|
|
37
|
-
const absolutePath = path.resolve(projectRoot, '${
|
|
48
|
+
const absolutePath = path.resolve(projectRoot, '${r}');
|
|
38
49
|
const serverModuleUrl = pathToFileURL(absolutePath).href;
|
|
39
50
|
|
|
40
51
|
if (typeof globalThis.require === 'undefined') {
|
|
41
|
-
try {
|
|
52
|
+
try {
|
|
53
|
+
const { createRequire } = await import('module');
|
|
54
|
+
globalThis.require = createRequire(serverModulePath);
|
|
55
|
+
} catch (e) {}
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
const routeModule = await import(/* @vite-ignore */ serverModuleUrl);
|
|
59
|
+
|
|
45
60
|
const mockMethods = {
|
|
46
61
|
addRpcRoute: (url, options) => rpcOptionsMap.set(url, options),
|
|
47
62
|
addRenderRoute: (url, options) => renderOptionsMap.set(url, options),
|
|
48
63
|
addLoaderRoute: (url, options) => loaderApiOptionsMap.set(url, options),
|
|
49
|
-
register: async (plugin, opts) => {
|
|
64
|
+
register: async (plugin, opts) => {
|
|
65
|
+
const fn = plugin.default || plugin;
|
|
66
|
+
if (typeof fn === 'function') await fn(mockFastify, opts);
|
|
67
|
+
},
|
|
50
68
|
after: (cb) => { if(cb) cb(); return Promise.resolve(); },
|
|
51
69
|
ready: (cb) => { if(cb) cb(); return Promise.resolve(); },
|
|
52
|
-
decorate: () => {},
|
|
70
|
+
decorate: () => {},
|
|
71
|
+
addHook: () => {},
|
|
72
|
+
withTypeProvider: () => mockFastify
|
|
53
73
|
};
|
|
54
|
-
|
|
74
|
+
|
|
75
|
+
const mockFastify = new Proxy(mockMethods, {
|
|
76
|
+
get: (target, prop) => {
|
|
77
|
+
if (prop in target) return target[prop];
|
|
78
|
+
return () => {};
|
|
79
|
+
}
|
|
80
|
+
});
|
|
55
81
|
|
|
56
82
|
let entryPoint = routeModule.default || routeModule;
|
|
83
|
+
|
|
57
84
|
if (typeof entryPoint === 'function') {
|
|
58
|
-
try {
|
|
85
|
+
try {
|
|
86
|
+
await entryPoint(mockFastify);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.error('\u274C [B-SSR CRITICAL] Error inicializando rutas backend:', serverModulePath, err);
|
|
89
|
+
}
|
|
59
90
|
}
|
|
60
91
|
})();
|
|
92
|
+
|
|
61
93
|
return initPromise;
|
|
62
94
|
}
|
|
63
95
|
|
|
64
|
-
${
|
|
96
|
+
${t.map(c=>{let A=[];c.requiresArgs&&A.push("args"),A.push("ssrContext");let F=c.requiresArgs?"args":"{}",R="";return c.type==="rpc"?R=`
|
|
65
97
|
if (fn.isMultipart) throw new Error('RPC multipart no soportado en SSR.');
|
|
66
98
|
await getOptionsMaps();
|
|
67
|
-
const options = rpcOptionsMap.get('${
|
|
68
|
-
if (!options?.handler) throw new Error('Handler no encontrado para RPC: ${
|
|
69
|
-
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${
|
|
99
|
+
const options = rpcOptionsMap.get('${c.url}');
|
|
100
|
+
if (!options?.handler) throw new Error('Handler no encontrado para RPC: ${c.name}');
|
|
101
|
+
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${F});
|
|
70
102
|
return await options.handler.call(ssrContext.req.server, augmentedReq, ssrContext.reply);
|
|
71
|
-
`:
|
|
103
|
+
`:c.type==="api"?R=`
|
|
72
104
|
await getOptionsMaps();
|
|
73
|
-
const options = loaderApiOptionsMap.get('${
|
|
74
|
-
if (!options?.handler) {
|
|
75
|
-
|
|
105
|
+
const options = loaderApiOptionsMap.get('${c.url}');
|
|
106
|
+
if (!options?.handler) {
|
|
107
|
+
console.error('\u26A0\uFE0F [B-SSR Warning] Handler API no encontrado:', '${c.name}', 'URL:', '${c.url}');
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${F});
|
|
76
111
|
return await options.handler.call(ssrContext.req.server, augmentedReq, ssrContext.reply);
|
|
77
|
-
`:
|
|
112
|
+
`:R=`
|
|
78
113
|
await getOptionsMaps();
|
|
79
|
-
const options = renderOptionsMap.get('${
|
|
114
|
+
const options = renderOptionsMap.get('${c.url}');
|
|
80
115
|
if (!options) return {};
|
|
81
|
-
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${
|
|
116
|
+
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${F});
|
|
82
117
|
let customData = {};
|
|
83
|
-
try {
|
|
84
|
-
|
|
118
|
+
try {
|
|
119
|
+
if (options.handler) {
|
|
120
|
+
customData = (await options.handler.call(ssrContext.req.server, augmentedReq, ssrContext.reply)) || {};
|
|
121
|
+
}
|
|
122
|
+
} catch (handlerErr) {
|
|
123
|
+
console.error('\u274C [B-SSR Handler Error] ${c.name}:', handlerErr);
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
85
126
|
if (ssrContext.reply.sent) return;
|
|
86
127
|
return { ...customData };
|
|
87
|
-
`,`export const ${
|
|
128
|
+
`,`export const ${c.name} = async (${A.join(", ")}) => {
|
|
129
|
+
try {
|
|
130
|
+
if (!ssrContext?.req) throw new Error('ssrContext requerido en ${c.name} (SSR)');
|
|
131
|
+
${R}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('\u274C [B-SSR Error] ${c.name}:', error);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
};`}).join(`
|
|
88
137
|
`)}
|
|
89
|
-
`}async function
|
|
138
|
+
`}async function le(){let t=await(0,se.default)(l,{absolute:!0});await Promise.all(t.map(m=>W(m)))}return{name:"b-ssr-vite-plugin-rpc-universal-generator",enforce:"pre",async buildStart(){await le()},configureServer(t){let m=r=>r.endsWith(".mts")||r.endsWith(".ts");t.watcher.on("add",r=>m(r)&&W(r)),t.watcher.on("change",r=>m(r)&&W(r)),t.watcher.on("unlink",r=>{if(m(r)){let g=a.default.resolve(r);w.delete(g),j.delete(g);let b=a.default.extname(r),c=r.substring(0,r.length-b.length)+".universal.d.ts";(0,q.unlink)(c).catch(()=>{})}})},async resolveId(t,m,r){if(t.startsWith(L))return null;if(t.includes(".universal")){let g=t.split("?")[0],b=g;if(g.endsWith(".universal"))b=g;else if(g.endsWith(".universal.ts"))b=g.slice(0,-3);else if(g.endsWith(".universal.mts"))b=g.slice(0,-4);else if(g.endsWith(".universal.js"))b=g.slice(0,-3);else return null;let c=[".mts",".ts"];for(let A of c){let F=b.slice(0,-10)+A,R=await this.resolve(F,m,{skipSelf:!0});if(R){let k=r?.ssr?"?mode=ssr":"?mode=client";return L+R.id+k}try{await(0,q.access)(F);let k=r?.ssr?"?mode=ssr":"?mode=client";return L+F+k}catch{}}}return null},async load(t,m){if(t.startsWith(L)){let r=t.slice(L.length).split("?")[0],g=w.get(r);return g||(await W(r),g=w.get(r)),g?m?.ssr===!0?g.server:g.client:null}if(m?.ssr!==!0){let r=a.default.resolve(t);if(j.has(r))return`throw new Error("\u{1F6A8} [B-SSR FIREWALL] BLOCKED: Backend File imported in Client: ${a.default.basename(t)}");`}return null},transform:oe}}function we(o){let l=[];return o.paramsType!=="unknown"&&l.push(`params: ${o.paramsType}`),o.queryType!=="unknown"&&l.push(`query: ${o.queryType}`),o.bodyType!=="unknown"&&l.push(`body: ${o.bodyType}`),l.push("signal?: AbortSignal"),l}0&&(module.exports={rpcGeneratorPlugin});
|
package/dist/vite-rpc-plugin.js
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pe from"fast-glob";import{access as ue,unlink as ee,writeFile as ge}from"fs/promises";import o from"path";import{format as de,resolveConfig as me}from"prettier";import{Node as M,Project as fe,SyntaxKind as h,ts as j}from"ts-morph";var L="virtual:b-ssr-rpc-universal:";function ye(T){let x=T.replace(/[^a-zA-Z0-9]+(.)?/g,(k,O)=>O?O.toUpperCase():"");return x.charAt(0).toLowerCase()+x.slice(1)}function G(T,x,k){let O=o.basename(k,o.extname(k))||"Index",C=x.replace(/:[a-zA-Z0-9_]+/g,"").replace(/\//g," "),q=`${T} ${C} ${O}`;return ye(q)}function Re(T={}){let{routerPattern:x="src-ts/routers/**/*.mts",tsConfigFilePath:k="tsconfig.json",routerBaseDir:O="src-ts/routers"}=T,C=new Map,q=new Set,K=new fe({tsConfigFilePath:k,skipAddingFilesFromTsConfig:!1}),te=o.resolve(process.cwd(),O||".");async function I(t){try{let N=function(e){return e.replace(/import\(['"](.*?)['"]\)/g,(a,n)=>{if(!o.isAbsolute(n))return a;let s=n;if(!o.extname(s)){let y=K.getSourceFile(d=>d.getFilePath().replace(/\.(mts|ts|tsx)$/,"")===n);y&&(s=y.getFilePath())}let l=o.relative(o.dirname(A),s).replace(/\\/g,"/");return l.startsWith(".")||(l="./"+l),`import("${l}")`})},$=function(e,a){if(e.getSymbol()?.getName()==="Promise"){let p=e.getAwaitedType();if(p)return`Promise<${$(p,a)}>`}let n=e.getAliasSymbol()??e.getSymbol();if(n?.getName()==="__object")return N(e.getText(a,j.TypeFormatFlags.NoTruncation|j.TypeFormatFlags.UseFullyQualifiedType));if(e.isObject()&&!n){let p=(g,m=0)=>{if(!(m>5)){if(g.isArray()){let b=g.getArrayElementType();b&&p(b,m);return}if(g.isObject()&&!g.getSymbol()&&!g.getAliasSymbol()){for(let b of g.getApparentProperties()){let E=b.getValueDeclaration();E&&p(b.getTypeAtLocation(E),m+1)}return}$(g,a)}};return p(e),N(e.getText(a,j.TypeFormatFlags.NoTruncation|j.TypeFormatFlags.UseFullyQualifiedType))}if(!n)return N(e.getText(a,j.TypeFormatFlags.NoTruncation));let s=n.getDeclarations()[0];if(!s)return n.getName();if(M.isImportSpecifier(s)||M.isImportClause(s)){let p=s.getFirstAncestorByKind(h.ImportDeclaration);if(p){let g=p.getModuleSpecifierValue(),m=n.getName();return F.has(g)||F.set(g,new Set),F.get(g)?.add(m),m}}let l=s.getSourceFile();if(l.getFilePath()===f.getFilePath())return n.getName();if(l.isInNodeModules())return N(e.getText(a,j.TypeFormatFlags.NoTruncation));let y=o.relative(o.dirname(A),l.getFilePath()).replace(/\\/g,"/"),R=y.startsWith(".")?y:`./${y}`,P=n.getName();return F.has(R)||F.set(R,new Set),F.get(R)?.add(P),P},Z=function(e){let a;if(M.isFunctionLikeDeclaration(e)||M.isArrowFunction(e)){let n=e.getDescendantsOfKind(h.ReturnStatement);for(let s of n){let l=s.getExpression();if(l?.isKind(h.SatisfiesExpression)){a=l.getTypeNode()?.getType();break}}}if(a)return $(a,e);{let n=e.getType().getCallSignatures();if(n.length>0){let s=n[0]?.getReturnType();return $(s,e)}}return"unknown"};var u=N,r=$,c=Z;let f=K.addSourceFileAtPath(t);await f.refreshFromFileSystem(),K.resolveSourceFileDependencies();let i=f.getDescendantsOfKind(h.CallExpression),v=i.filter(e=>e.getExpression().getText().endsWith(".addRpcRoute")),w=i.filter(e=>e.getExpression().getText().endsWith(".addRenderRoute")),S=i.filter(e=>e.getExpression().getText().endsWith(".addLoaderRoute")),D=o.extname(t),A=t.substring(0,t.length-D.length)+".universal.d.ts",B=o.resolve(t);if(v.length===0&&w.length===0&&S.length===0){C.delete(B),q.delete(B),A!==t&&await ee(A).catch(()=>{});return}q.add(B);let V=[],F=new Map;F.has("fastify")||F.set("fastify",new Set),F.get("fastify")?.add("FastifyRequest"),F.get("fastify")?.add("FastifyReply");let ie=e=>{let a="unknown",n="unknown",s="unknown",l=!1;if(!e||!M.isObjectLiteralExpression(e))return{paramsType:a,queryType:n,bodyType:s,isMultipart:l};let y=e.getProperty("schema");if(y?.isKind(h.PropertyAssignment)){let d=y.getInitializer();if(d?.isKind(h.Identifier)){let P=d.getSymbol()?.getValueDeclaration();if(P){let p=P.getFirstDescendantByKind(h.ObjectLiteralExpression);p&&(d=p)}}if(d&&M.isObjectLiteralExpression(d)){let R=d.getProperty("consumes");if(R?.isKind(h.PropertyAssignment)){let p=R.getInitializer();M.isArrayLiteralExpression(p)&&(l=p.getElements().some(g=>g.isKind(h.StringLiteral)&&g.getLiteralValue()==="multipart/form-data"))}let P=p=>{let g=d.getProperty(p);if(g?.isKind(h.PropertyAssignment)){let m=g.getInitializer();if(m){let b=m.getType(),E=b.getProperty("_output");return $(E?E.getTypeAtLocation(m).getApparentType():b,m)}}return"unknown"};if(a=P("params"),n=P("querystring"),s=P("body"),l){let p="{ file: File }";s=s!=="unknown"&&s.trim().startsWith("{")?`(${s} & ${p})`:p}}}return{paramsType:a,queryType:n,bodyType:s,isMultipart:l}},U=o.relative(te,o.dirname(t)).split(o.sep).join("/"),ae=U==="."||!U?"":U.startsWith("/")?U:"/"+U,_=(e,a)=>{let[n,s]=e.getArguments();if(!n?.isKind(h.StringLiteral))return;let l=n.getLiteralValue(),y="unknown",d=ae,{paramsType:R,queryType:P,bodyType:p,isMultipart:g}=ie(s);if(s?.isKind(h.ObjectLiteralExpression)){let E=s.getProperty("prefix");if(E?.isKind(h.PropertyAssignment)){let W=E.getInitializer();W?.isKind(h.StringLiteral)&&(d=W.getLiteralValue())}let J=s.getProperty("handler");if(J?.isKind(h.PropertyAssignment)){let W=J.getInitializer();W&&(y=Z(W),y.startsWith("Promise<")||(y=`Promise<${y}>`))}}let m="",b="";a==="rpc"?(m=o.join(d,"rpc",l).replace(/\\/g,"/"),b=G("action",d,l)):a==="loader"?(m=o.join(d,"loader",l).replace(/\\/g,"/"),b=G("loader",d,l)):a==="api"&&(m=o.join(d,"api",l).replace(/\\/g,"/"),b=G("get",d,l)),b&&V.push({type:a,name:b,returnType:y,url:l,rpcUrl:m,loaderUrl:m,paramsType:R,queryType:P,bodyType:p,isMultipart:g})};v.forEach(e=>_(e,"rpc")),w.forEach(e=>_(e,"loader")),S.forEach(e=>_(e,"api"));let z=[];for(let[e,a]of F.entries())z.push(`import type { ${[...a].sort().join(", ")} } from "${e}";`);let Q=[];V.forEach(e=>{Q.push(se(e))});let H=`// AUTO-GENERATED by @bobtail.software/b-ssr. DO NOT EDIT.
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
|
|
4
|
-
`+(
|
|
4
|
+
`+(z.length>0?z.join(`
|
|
5
5
|
`)+`
|
|
6
6
|
|
|
7
|
-
`:"")+
|
|
7
|
+
`:"")+Q.join(`
|
|
8
8
|
|
|
9
|
-
`);try{let e=await
|
|
9
|
+
`);try{let e=await me(A)||{};H=await de(H,{...e,parser:"typescript",filepath:A})}catch{}await ge(A,H);let X=[],Y=[];V.forEach(e=>{let n=e.type==="rpc"?"POST":"GET",s=e.type==="loader"?e.loaderUrl:e.rpcUrl;Y.push({name:e.name,rpcUrl:s,method:n,isMultipart:!!e.isMultipart}),X.push({name:e.name,url:e.url,type:e.type,requiresArgs:!0})});let le=`
|
|
10
10
|
import { createClientRpc } from '@bobtail.software/b-ssr/client';
|
|
11
|
+
|
|
11
12
|
if (import.meta.env.DEV) {
|
|
12
|
-
console.debug('\u{1F6E1}\uFE0F [B-SSR Security] Loaded SAFE Client-Stub for: ${
|
|
13
|
+
console.debug('\u{1F6E1}\uFE0F [B-SSR Security] Loaded SAFE Client-Stub for: ${o.basename(t)}');
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
${Y.map(e=>`
|
|
17
|
+
export const ${e.name} = createClientRpc({
|
|
18
|
+
url: '${e.rpcUrl}',
|
|
19
|
+
method: '${e.method}',
|
|
20
|
+
isMultipart: ${e.isMultipart}
|
|
21
|
+
});
|
|
22
|
+
`).join(`
|
|
15
23
|
`)}
|
|
16
|
-
`,
|
|
24
|
+
`,ce=ne(X,t);C.set(o.resolve(t),{client:le,server:ce})}catch(f){console.error(`[rpc-generator] Error al procesar ${t}:`,{error:f})}}let re=(t,u,r)=>{if(u.includes("node_modules")||u.startsWith(L))return null;if(r?.ssr===!0&&/\.[cm]?[jt]sx?$/.test(u)){let c=/\brequire\s*\(/.test(t),f=/\bmodule\.exports\b/.test(t),i=/\bexports\./.test(t);if(c||f||i)return"import { createRequire } from 'module';"+`
|
|
17
25
|
const require = createRequire(import.meta.url);
|
|
18
26
|
const module = { exports: {} };
|
|
19
27
|
const exports = module.exports;
|
|
20
|
-
|
|
21
|
-
export default module.exports;`}return null};function
|
|
28
|
+
`+t+`
|
|
29
|
+
export default module.exports;`}return null};function se(t){let u=he(t),r="";return u.length>0&&(r=`args: { ${u.join("; ")} }`),r||(r="args: { signal?: AbortSignal }"),`export declare const ${t.name}: (${r}, ssrContext?: { req?: FastifyRequest, reply?: FastifyReply }) => ${t.returnType};`}function ne(t,u){if(t.length===0)return"";let r=o.relative(process.cwd(),u).replace(/\\/g,"/");return`
|
|
22
30
|
import path from 'path';
|
|
23
31
|
import { pathToFileURL } from 'url';
|
|
24
32
|
|
|
25
33
|
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
26
|
-
throw new Error('\u{1F6A8} [B-SSR SECURITY ALERT] Server-side code leaked to browser: ${
|
|
34
|
+
throw new Error('\u{1F6A8} [B-SSR SECURITY ALERT] Server-side code leaked to browser: ${`./${o.relative(process.cwd(),u).replace(/\\/g,"/")}`}');
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
let initPromise;
|
|
@@ -31,59 +39,100 @@ export default module.exports;`}return null};function oe(n){let s=Te(n),t=s.leng
|
|
|
31
39
|
|
|
32
40
|
function getOptionsMaps() {
|
|
33
41
|
if (initPromise) return initPromise;
|
|
42
|
+
|
|
34
43
|
initPromise = (async () => {
|
|
35
|
-
rpcOptionsMap = new Map();
|
|
44
|
+
rpcOptionsMap = new Map();
|
|
45
|
+
renderOptionsMap = new Map();
|
|
46
|
+
loaderApiOptionsMap = new Map();
|
|
36
47
|
const projectRoot = process.cwd();
|
|
37
|
-
const absolutePath = path.resolve(projectRoot, '${
|
|
48
|
+
const absolutePath = path.resolve(projectRoot, '${r}');
|
|
38
49
|
const serverModuleUrl = pathToFileURL(absolutePath).href;
|
|
39
50
|
|
|
40
51
|
if (typeof globalThis.require === 'undefined') {
|
|
41
|
-
try {
|
|
52
|
+
try {
|
|
53
|
+
const { createRequire } = await import('module');
|
|
54
|
+
globalThis.require = createRequire(serverModulePath);
|
|
55
|
+
} catch (e) {}
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
const routeModule = await import(/* @vite-ignore */ serverModuleUrl);
|
|
59
|
+
|
|
45
60
|
const mockMethods = {
|
|
46
61
|
addRpcRoute: (url, options) => rpcOptionsMap.set(url, options),
|
|
47
62
|
addRenderRoute: (url, options) => renderOptionsMap.set(url, options),
|
|
48
63
|
addLoaderRoute: (url, options) => loaderApiOptionsMap.set(url, options),
|
|
49
|
-
register: async (plugin, opts) => {
|
|
64
|
+
register: async (plugin, opts) => {
|
|
65
|
+
const fn = plugin.default || plugin;
|
|
66
|
+
if (typeof fn === 'function') await fn(mockFastify, opts);
|
|
67
|
+
},
|
|
50
68
|
after: (cb) => { if(cb) cb(); return Promise.resolve(); },
|
|
51
69
|
ready: (cb) => { if(cb) cb(); return Promise.resolve(); },
|
|
52
|
-
decorate: () => {},
|
|
70
|
+
decorate: () => {},
|
|
71
|
+
addHook: () => {},
|
|
72
|
+
withTypeProvider: () => mockFastify
|
|
53
73
|
};
|
|
54
|
-
|
|
74
|
+
|
|
75
|
+
const mockFastify = new Proxy(mockMethods, {
|
|
76
|
+
get: (target, prop) => {
|
|
77
|
+
if (prop in target) return target[prop];
|
|
78
|
+
return () => {};
|
|
79
|
+
}
|
|
80
|
+
});
|
|
55
81
|
|
|
56
82
|
let entryPoint = routeModule.default || routeModule;
|
|
83
|
+
|
|
57
84
|
if (typeof entryPoint === 'function') {
|
|
58
|
-
try {
|
|
85
|
+
try {
|
|
86
|
+
await entryPoint(mockFastify);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.error('\u274C [B-SSR CRITICAL] Error inicializando rutas backend:', serverModulePath, err);
|
|
89
|
+
}
|
|
59
90
|
}
|
|
60
91
|
})();
|
|
92
|
+
|
|
61
93
|
return initPromise;
|
|
62
94
|
}
|
|
63
95
|
|
|
64
|
-
${
|
|
96
|
+
${t.map(i=>{let v=[];i.requiresArgs&&v.push("args"),v.push("ssrContext");let w=i.requiresArgs?"args":"{}",S="";return i.type==="rpc"?S=`
|
|
65
97
|
if (fn.isMultipart) throw new Error('RPC multipart no soportado en SSR.');
|
|
66
98
|
await getOptionsMaps();
|
|
67
|
-
const options = rpcOptionsMap.get('${
|
|
68
|
-
if (!options?.handler) throw new Error('Handler no encontrado para RPC: ${
|
|
69
|
-
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${
|
|
99
|
+
const options = rpcOptionsMap.get('${i.url}');
|
|
100
|
+
if (!options?.handler) throw new Error('Handler no encontrado para RPC: ${i.name}');
|
|
101
|
+
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${w});
|
|
70
102
|
return await options.handler.call(ssrContext.req.server, augmentedReq, ssrContext.reply);
|
|
71
|
-
`:
|
|
103
|
+
`:i.type==="api"?S=`
|
|
72
104
|
await getOptionsMaps();
|
|
73
|
-
const options = loaderApiOptionsMap.get('${
|
|
74
|
-
if (!options?.handler) {
|
|
75
|
-
|
|
105
|
+
const options = loaderApiOptionsMap.get('${i.url}');
|
|
106
|
+
if (!options?.handler) {
|
|
107
|
+
console.error('\u26A0\uFE0F [B-SSR Warning] Handler API no encontrado:', '${i.name}', 'URL:', '${i.url}');
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${w});
|
|
76
111
|
return await options.handler.call(ssrContext.req.server, augmentedReq, ssrContext.reply);
|
|
77
|
-
`:
|
|
112
|
+
`:S=`
|
|
78
113
|
await getOptionsMaps();
|
|
79
|
-
const options = renderOptionsMap.get('${
|
|
114
|
+
const options = renderOptionsMap.get('${i.url}');
|
|
80
115
|
if (!options) return {};
|
|
81
|
-
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${
|
|
116
|
+
const augmentedReq = Object.assign(Object.create(ssrContext.req), ${w});
|
|
82
117
|
let customData = {};
|
|
83
|
-
try {
|
|
84
|
-
|
|
118
|
+
try {
|
|
119
|
+
if (options.handler) {
|
|
120
|
+
customData = (await options.handler.call(ssrContext.req.server, augmentedReq, ssrContext.reply)) || {};
|
|
121
|
+
}
|
|
122
|
+
} catch (handlerErr) {
|
|
123
|
+
console.error('\u274C [B-SSR Handler Error] ${i.name}:', handlerErr);
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
85
126
|
if (ssrContext.reply.sent) return;
|
|
86
127
|
return { ...customData };
|
|
87
|
-
`,`export const ${
|
|
128
|
+
`,`export const ${i.name} = async (${v.join(", ")}) => {
|
|
129
|
+
try {
|
|
130
|
+
if (!ssrContext?.req) throw new Error('ssrContext requerido en ${i.name} (SSR)');
|
|
131
|
+
${S}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('\u274C [B-SSR Error] ${i.name}:', error);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
};`}).join(`
|
|
88
137
|
`)}
|
|
89
|
-
`}async function
|
|
138
|
+
`}async function oe(){let t=await pe(x,{absolute:!0});await Promise.all(t.map(u=>I(u)))}return{name:"b-ssr-vite-plugin-rpc-universal-generator",enforce:"pre",async buildStart(){await oe()},configureServer(t){let u=r=>r.endsWith(".mts")||r.endsWith(".ts");t.watcher.on("add",r=>u(r)&&I(r)),t.watcher.on("change",r=>u(r)&&I(r)),t.watcher.on("unlink",r=>{if(u(r)){let c=o.resolve(r);C.delete(c),q.delete(c);let f=o.extname(r),i=r.substring(0,r.length-f.length)+".universal.d.ts";ee(i).catch(()=>{})}})},async resolveId(t,u,r){if(t.startsWith(L))return null;if(t.includes(".universal")){let c=t.split("?")[0],f=c;if(c.endsWith(".universal"))f=c;else if(c.endsWith(".universal.ts"))f=c.slice(0,-3);else if(c.endsWith(".universal.mts"))f=c.slice(0,-4);else if(c.endsWith(".universal.js"))f=c.slice(0,-3);else return null;let i=[".mts",".ts"];for(let v of i){let w=f.slice(0,-10)+v,S=await this.resolve(w,u,{skipSelf:!0});if(S){let D=r?.ssr?"?mode=ssr":"?mode=client";return L+S.id+D}try{await ue(w);let D=r?.ssr?"?mode=ssr":"?mode=client";return L+w+D}catch{}}}return null},async load(t,u){if(t.startsWith(L)){let r=t.slice(L.length).split("?")[0],c=C.get(r);return c||(await I(r),c=C.get(r)),c?u?.ssr===!0?c.server:c.client:null}if(u?.ssr!==!0){let r=o.resolve(t);if(q.has(r))return`throw new Error("\u{1F6A8} [B-SSR FIREWALL] BLOCKED: Backend File imported in Client: ${o.basename(t)}");`}return null},transform:re}}function he(T){let x=[];return T.paramsType!=="unknown"&&x.push(`params: ${T.paramsType}`),T.queryType!=="unknown"&&x.push(`query: ${T.queryType}`),T.bodyType!=="unknown"&&x.push(`body: ${T.bodyType}`),x.push("signal?: AbortSignal"),x}export{Re as rpcGeneratorPlugin};
|
package/package.json
CHANGED