lovable-ssr 0.1.22 → 0.1.24
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/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/registry.d.ts +3 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +7 -0
- package/dist/ssr/buildHeadHtml.d.ts.map +1 -1
- package/dist/ssr/buildHeadHtml.js +1 -8
- package/dist/ssr/server.d.ts +3 -0
- package/dist/ssr/server.d.ts.map +1 -1
- package/dist/ssr/server.js +47 -77
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +25 -1
- package/dist/utils/escapeHtml.d.ts +2 -0
- package/dist/utils/escapeHtml.d.ts.map +1 -0
- package/dist/utils/escapeHtml.js +8 -0
- package/package.json +72 -66
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './globals.js';
|
|
2
|
-
export type { RouteConfig, ComponentWithGetData, RouteDataParams, SitemapEntry, SitemapRouteConfig, SitemapChangefreq, } from './types.js';
|
|
3
|
-
export { registerRoutes, getRoutes } from './registry.js';
|
|
2
|
+
export type { RouteConfig, ComponentWithGetData, RouteDataParams, SitemapEntry, SitemapRouteConfig, SitemapChangefreq, MiddlewareContext, MiddlewareFn, MiddlewareResponse, } from './types.js';
|
|
3
|
+
export { registerRoutes, getRoutes, registerMiddleware } from './registry.js';
|
|
4
4
|
export { BrowserRouteDataProvider } from './components/BrowserRouteDataProvider.js';
|
|
5
5
|
export { SEO, type SEOProps } from './components/SEO.js';
|
|
6
6
|
export { default as RouterService } from './router/RouterService.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,YAAY,EACV,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,YAAY,EACV,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EACL,MAAM,EACN,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import './globals.js';
|
|
2
|
-
export { registerRoutes, getRoutes } from './registry.js';
|
|
2
|
+
export { registerRoutes, getRoutes, registerMiddleware } from './registry.js';
|
|
3
3
|
export { BrowserRouteDataProvider } from './components/BrowserRouteDataProvider.js';
|
|
4
4
|
export { SEO } from './components/SEO.js';
|
|
5
5
|
export { default as RouterService } from './router/RouterService.js';
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { RouteConfig } from './types.js';
|
|
1
|
+
import type { MiddlewareFn, RouteConfig } from './types.js';
|
|
2
2
|
export declare function registerRoutes(r: RouteConfig[]): void;
|
|
3
3
|
export declare function getRoutes(): RouteConfig[];
|
|
4
|
+
export declare function registerMiddleware(m: MiddlewareFn): void;
|
|
5
|
+
export declare function getMiddleware(): MiddlewareFn | null;
|
|
4
6
|
//# sourceMappingURL=registry.d.ts.map
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK5D,wBAAgB,cAAc,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,IAAI,CAErD;AAED,wBAAgB,SAAS,IAAI,WAAW,EAAE,CAEzC;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAExD;AAED,wBAAgB,aAAa,IAAI,YAAY,GAAG,IAAI,CAEnD"}
|
package/dist/registry.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
let routes = [];
|
|
2
|
+
let middleware = null;
|
|
2
3
|
export function registerRoutes(r) {
|
|
3
4
|
routes = r;
|
|
4
5
|
}
|
|
5
6
|
export function getRoutes() {
|
|
6
7
|
return routes;
|
|
7
8
|
}
|
|
9
|
+
export function registerMiddleware(m) {
|
|
10
|
+
middleware = m;
|
|
11
|
+
}
|
|
12
|
+
export function getMiddleware() {
|
|
13
|
+
return middleware;
|
|
14
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildHeadHtml.d.ts","sourceRoot":"","sources":["../../src/ssr/buildHeadHtml.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"buildHeadHtml.d.ts","sourceRoot":"","sources":["../../src/ssr/buildHeadHtml.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAG5D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,GAAG;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAwBA"}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
return s
|
|
3
|
-
.replace(/&/g, '&')
|
|
4
|
-
.replace(/</g, '<')
|
|
5
|
-
.replace(/>/g, '>')
|
|
6
|
-
.replace(/"/g, '"')
|
|
7
|
-
.replace(/'/g, ''');
|
|
8
|
-
}
|
|
1
|
+
import { escapeHtml } from '../utils/escapeHtml.js';
|
|
9
2
|
export function buildHeadHtmlFromSEO(props) {
|
|
10
3
|
const title = `<title>${escapeHtml(props.title)}</title>`;
|
|
11
4
|
const metaTags = [
|
package/dist/ssr/server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Express } from 'express';
|
|
2
|
+
import type { MiddlewareFn } from '../types.js';
|
|
2
3
|
export interface RenderResult {
|
|
3
4
|
html: string;
|
|
4
5
|
preloadedData: Record<string, unknown>;
|
|
@@ -22,6 +23,8 @@ export interface CreateServerConfig {
|
|
|
22
23
|
sitemap?: {
|
|
23
24
|
siteUrl: string;
|
|
24
25
|
};
|
|
26
|
+
/** Middleware executed before rendering each route. If it returns a response, the route is not rendered. */
|
|
27
|
+
middleware?: MiddlewareFn;
|
|
25
28
|
}
|
|
26
29
|
export declare function createServer(config: CreateServerConfig): Promise<{
|
|
27
30
|
getApp: () => Express;
|
package/dist/ssr/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/ssr/server.ts"],"names":[],"mappings":"AAGA,OAAgB,EAAE,KAAK,OAAO,EAAkD,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/ssr/server.ts"],"names":[],"mappings":"AAGA,OAAgB,EAAE,KAAK,OAAO,EAAkD,MAAM,SAAS,CAAC;AAKhG,OAAO,KAAK,EAAqB,YAAY,EAAoD,MAAM,aAAa,CAAC;AAGrH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wGAAwG;IACxG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,uGAAuG;IACvG,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,4GAA4G;IAC5G,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B;AA2TD,wBAAsB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC;IACtE,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CACxD,CAAC,CAOD;AAED;qDACqD;AACrD,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,QAO7D"}
|
package/dist/ssr/server.js
CHANGED
|
@@ -3,8 +3,10 @@ import path from 'node:path';
|
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import express from 'express';
|
|
5
5
|
import { createServer as createViteServer } from 'vite';
|
|
6
|
-
import { getRoutes } from '../registry.js';
|
|
6
|
+
import { getMiddleware, getRoutes } from '../registry.js';
|
|
7
7
|
import RouterService from '../router/RouterService.js';
|
|
8
|
+
import { buildRequestContext } from '../types.js';
|
|
9
|
+
import { escapeHtml } from '../utils/escapeHtml.js';
|
|
8
10
|
function defaultDistEntryPath(entryPath) {
|
|
9
11
|
return entryPath
|
|
10
12
|
.replace(/^src\//, 'dist/')
|
|
@@ -16,15 +18,6 @@ class SsrServer {
|
|
|
16
18
|
config;
|
|
17
19
|
isProd;
|
|
18
20
|
_rendererCache;
|
|
19
|
-
/** On-demand SSR cache: key = pathname + normalized search params, value = render result. Only used in production. */
|
|
20
|
-
_ssrCache = new Map();
|
|
21
|
-
normalizeCacheKey(url) {
|
|
22
|
-
const u = new URL(url, 'http://localhost');
|
|
23
|
-
const search = new URLSearchParams(u.search);
|
|
24
|
-
const sorted = new URLSearchParams([...search.entries()].sort((a, b) => a[0].localeCompare(b[0])));
|
|
25
|
-
const q = sorted.toString();
|
|
26
|
-
return (u.pathname || '/') + (q ? `?${q}` : '');
|
|
27
|
-
}
|
|
28
21
|
constructor(config) {
|
|
29
22
|
this.config = {
|
|
30
23
|
root: path.resolve(config.root),
|
|
@@ -32,6 +25,7 @@ class SsrServer {
|
|
|
32
25
|
port: config.port ?? 5173,
|
|
33
26
|
cssLinkInDev: config.cssLinkInDev ?? '<link rel="stylesheet" href="/src/index.css"></head>',
|
|
34
27
|
extraRoutes: config.extraRoutes ?? (() => { }),
|
|
28
|
+
middleware: config.middleware ?? null,
|
|
35
29
|
sitemap: config.sitemap ?? undefined,
|
|
36
30
|
};
|
|
37
31
|
this.isProd = process.env.NODE_ENV === 'production';
|
|
@@ -122,28 +116,52 @@ Sitemap: ${baseUrl}/sitemap.xml`);
|
|
|
122
116
|
});
|
|
123
117
|
}
|
|
124
118
|
buildSitemapXml(entries) {
|
|
125
|
-
const lines = entries.map((e) => ` <url><loc>${
|
|
119
|
+
const lines = entries.map((e) => ` <url><loc>${escapeHtml(e.loc)}</loc><lastmod>${e.lastmod ?? ''}</lastmod><changefreq>${e.changefreq ?? 'weekly'}</changefreq><priority>${e.priority ?? 0.5}</priority></url>`);
|
|
126
120
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
127
121
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
128
122
|
${lines.join('\n')}
|
|
129
123
|
</urlset>`;
|
|
130
124
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
125
|
+
async runMiddleware(ctx) {
|
|
126
|
+
const mw = this.config.middleware ?? getMiddleware();
|
|
127
|
+
if (!mw)
|
|
128
|
+
return;
|
|
129
|
+
return await mw(ctx);
|
|
130
|
+
}
|
|
131
|
+
sendMiddlewareResponse(res, mwRes) {
|
|
132
|
+
if (mwRes.headers) {
|
|
133
|
+
for (const [key, value] of Object.entries(mwRes.headers)) {
|
|
134
|
+
res.setHeader(key, value);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (mwRes.redirect) {
|
|
138
|
+
res.redirect(mwRes.status ?? 302, mwRes.redirect);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
res.status(mwRes.status ?? 200).send(mwRes.body ?? '');
|
|
138
142
|
}
|
|
139
143
|
async handleRequest(req, res, next) {
|
|
140
144
|
const url = req.originalUrl;
|
|
141
145
|
const pathname = url.replace(/\?.*$/, '').replace(/#.*$/, '') || '/';
|
|
142
146
|
try {
|
|
147
|
+
const matchedRoute = RouterService.matchRoute(pathname);
|
|
148
|
+
const params = matchedRoute
|
|
149
|
+
? RouterService.routeParams(matchedRoute.path, pathname)
|
|
150
|
+
: { routeParams: {}, searchParams: {} };
|
|
151
|
+
const requestContext = buildRequestContext(req);
|
|
152
|
+
const mwResult = await this.runMiddleware({
|
|
153
|
+
request: requestContext,
|
|
154
|
+
route: matchedRoute,
|
|
155
|
+
pathname,
|
|
156
|
+
params,
|
|
157
|
+
});
|
|
158
|
+
if (mwResult) {
|
|
159
|
+
return this.sendMiddlewareResponse(res, mwResult);
|
|
160
|
+
}
|
|
143
161
|
if (!RouterService.isSsrRoute(pathname)) {
|
|
144
162
|
return await this.renderSpa(url, res);
|
|
145
163
|
}
|
|
146
|
-
return await this.renderSsr(url, res,
|
|
164
|
+
return await this.renderSsr(url, res, requestContext);
|
|
147
165
|
}
|
|
148
166
|
catch (e) {
|
|
149
167
|
if (this.vite) {
|
|
@@ -162,68 +180,20 @@ ${lines.join('\n')}
|
|
|
162
180
|
const template = this.readTemplate(path.join(this.config.root, 'dist', 'index.html'));
|
|
163
181
|
return res.status(200).set({ 'Content-Type': 'text/html' }).send(template);
|
|
164
182
|
}
|
|
165
|
-
async
|
|
183
|
+
async resolveRenderResult(url, render, requestContext) {
|
|
184
|
+
const result = await render(url, { requestContext });
|
|
185
|
+
return {
|
|
186
|
+
appHtml: typeof result.html === 'string' ? result.html : '',
|
|
187
|
+
preloadedData: result.preloadedData ?? {},
|
|
188
|
+
helmet: result.helmet,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async renderSsr(url, res, requestContext) {
|
|
166
192
|
const { template, render } = await this.getSsrRenderer();
|
|
167
193
|
if (process.env.NODE_ENV !== 'production' && process.env.LOVABLE_SSR_DEBUG) {
|
|
168
194
|
console.log('[lovable-ssr] render(url)', url);
|
|
169
195
|
}
|
|
170
|
-
|
|
171
|
-
let preloadedData;
|
|
172
|
-
let helmet;
|
|
173
|
-
// Constrói um contexto simples de request (cookies raw + headers) para o getData.
|
|
174
|
-
const cookiesRaw = req.headers.cookie ?? '';
|
|
175
|
-
const cookies = {};
|
|
176
|
-
if (cookiesRaw) {
|
|
177
|
-
cookiesRaw.split(';').forEach((part) => {
|
|
178
|
-
const [k, ...rest] = part.split('=');
|
|
179
|
-
if (!k)
|
|
180
|
-
return;
|
|
181
|
-
const key = k.trim();
|
|
182
|
-
if (!key)
|
|
183
|
-
return;
|
|
184
|
-
const value = rest.join('=').trim();
|
|
185
|
-
cookies[key] = decodeURIComponent(value);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
const requestContext = {
|
|
189
|
-
cookiesRaw,
|
|
190
|
-
cookies,
|
|
191
|
-
headers: req.headers,
|
|
192
|
-
method: req.method,
|
|
193
|
-
url: req.originalUrl,
|
|
194
|
-
};
|
|
195
|
-
if (this.isProd) {
|
|
196
|
-
const cacheKey = this.normalizeCacheKey(url);
|
|
197
|
-
const hasCookies = !!cookiesRaw;
|
|
198
|
-
// Evita cachear respostas personalizadas por cookies (ex.: auth).
|
|
199
|
-
if (!hasCookies) {
|
|
200
|
-
const cached = this._ssrCache.get(cacheKey);
|
|
201
|
-
if (cached) {
|
|
202
|
-
appHtml = cached.html;
|
|
203
|
-
preloadedData = cached.preloadedData;
|
|
204
|
-
helmet = cached.helmet;
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
const result = await render(url, { requestContext });
|
|
208
|
-
appHtml = typeof result.html === 'string' ? result.html : '';
|
|
209
|
-
preloadedData = result.preloadedData ?? {};
|
|
210
|
-
helmet = result.helmet;
|
|
211
|
-
this._ssrCache.set(cacheKey, { html: appHtml, preloadedData, helmet });
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
const result = await render(url, { requestContext });
|
|
216
|
-
appHtml = typeof result.html === 'string' ? result.html : '';
|
|
217
|
-
preloadedData = result.preloadedData ?? {};
|
|
218
|
-
helmet = result.helmet;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
const result = await render(url, { requestContext });
|
|
223
|
-
appHtml = typeof result.html === 'string' ? result.html : '';
|
|
224
|
-
preloadedData = result.preloadedData ?? {};
|
|
225
|
-
helmet = result.helmet;
|
|
226
|
-
}
|
|
196
|
+
const { appHtml, preloadedData, helmet } = await this.resolveRenderResult(url, render, requestContext);
|
|
227
197
|
let html = template.replace('<div id="root"></div>', `<div id="root">${appHtml}</div>`);
|
|
228
198
|
html = this.injectHelmet(html, helmet);
|
|
229
199
|
html = this.injectPreloadedData(html, preloadedData);
|
package/dist/types.d.ts
CHANGED
|
@@ -32,9 +32,28 @@ export type RequestContext = {
|
|
|
32
32
|
method: string;
|
|
33
33
|
url: string;
|
|
34
34
|
};
|
|
35
|
+
export declare function parseCookies(raw: string): Record<string, string>;
|
|
36
|
+
export declare function buildRequestContext(req: {
|
|
37
|
+
headers: IncomingHttpHeaders;
|
|
38
|
+
method: string;
|
|
39
|
+
originalUrl: string;
|
|
40
|
+
}): RequestContext;
|
|
35
41
|
export type RouteDataParams = {
|
|
36
42
|
routeParams: Record<string, string>;
|
|
37
43
|
searchParams: Record<string, string>;
|
|
38
44
|
request?: RequestContext;
|
|
39
45
|
};
|
|
46
|
+
export type MiddlewareContext = {
|
|
47
|
+
request: RequestContext;
|
|
48
|
+
route: RouteConfig | undefined;
|
|
49
|
+
pathname: string;
|
|
50
|
+
params: Omit<RouteDataParams, 'request'>;
|
|
51
|
+
};
|
|
52
|
+
export type MiddlewareResponse = {
|
|
53
|
+
redirect?: string;
|
|
54
|
+
status?: number;
|
|
55
|
+
headers?: Record<string, string>;
|
|
56
|
+
body?: string;
|
|
57
|
+
};
|
|
58
|
+
export type MiddlewareFn = (ctx: MiddlewareContext) => Promise<MiddlewareResponse | void> | MiddlewareResponse | void;
|
|
40
59
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,oBAAoB,GAAG,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG;IAC5D,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1E,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACpE,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,oBAAoB,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,oBAAoB,GAAG,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG;IAC5D,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1E,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACpE,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,oBAAoB,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWhE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE;IACvC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,cAAc,CASjB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CACzB,GAAG,EAAE,iBAAiB,KACnB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,kBAAkB,GAAG,IAAI,CAAC"}
|
package/dist/types.js
CHANGED
|
@@ -1 +1,25 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export function parseCookies(raw) {
|
|
2
|
+
const cookies = {};
|
|
3
|
+
if (!raw)
|
|
4
|
+
return cookies;
|
|
5
|
+
raw.split(';').forEach((part) => {
|
|
6
|
+
const [k, ...rest] = part.split('=');
|
|
7
|
+
if (!k)
|
|
8
|
+
return;
|
|
9
|
+
const key = k.trim();
|
|
10
|
+
if (!key)
|
|
11
|
+
return;
|
|
12
|
+
cookies[key] = decodeURIComponent(rest.join('=').trim());
|
|
13
|
+
});
|
|
14
|
+
return cookies;
|
|
15
|
+
}
|
|
16
|
+
export function buildRequestContext(req) {
|
|
17
|
+
const cookiesRaw = req.headers.cookie ?? '';
|
|
18
|
+
return {
|
|
19
|
+
cookiesRaw,
|
|
20
|
+
cookies: parseCookies(cookiesRaw),
|
|
21
|
+
headers: req.headers,
|
|
22
|
+
method: req.method,
|
|
23
|
+
url: req.originalUrl,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escapeHtml.d.ts","sourceRoot":"","sources":["../../src/utils/escapeHtml.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAO5C"}
|
package/package.json
CHANGED
|
@@ -1,66 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "lovable-ssr",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "SSR and route data engine for Lovable projects",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"ssr",
|
|
8
|
-
"react",
|
|
9
|
-
"vite",
|
|
10
|
-
"express",
|
|
11
|
-
"lovable",
|
|
12
|
-
"getData",
|
|
13
|
-
"route-registry",
|
|
14
|
-
"server-side-rendering"
|
|
15
|
-
],
|
|
16
|
-
"type": "module",
|
|
17
|
-
"main": "./dist/index.js",
|
|
18
|
-
"module": "./dist/index.js",
|
|
19
|
-
"types": "./dist/index.d.ts",
|
|
20
|
-
"exports": {
|
|
21
|
-
".": {
|
|
22
|
-
"import": "./dist/index.js",
|
|
23
|
-
"types": "./dist/index.d.ts"
|
|
24
|
-
},
|
|
25
|
-
"./server": {
|
|
26
|
-
"import": "./dist/ssr/server.js",
|
|
27
|
-
"types": "./dist/ssr/server.d.ts"
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"files": [
|
|
31
|
-
"dist"
|
|
32
|
-
],
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "tsc && npm run build:docs",
|
|
35
|
-
"dev": "tsc --watch",
|
|
36
|
-
"changelog": "standard-version --message \"[skip ci]\"",
|
|
37
|
-
"changelog:rc": "npm run changelog -- --prerelease rc --skip.changelog --skip.tag",
|
|
38
|
-
"changelog:patch": "npm run changelog -- --release-as patch --prerelease rc",
|
|
39
|
-
"changelog:minor": "npm run changelog -- --release-as minor --prerelease rc",
|
|
40
|
-
"changelog:major": "npm run changelog -- --release-as major --prerelease rc",
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
},
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"@
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"react
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "lovable-ssr",
|
|
3
|
+
"version": "0.1.24",
|
|
4
|
+
"description": "SSR and route data engine for Lovable projects",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"ssr",
|
|
8
|
+
"react",
|
|
9
|
+
"vite",
|
|
10
|
+
"express",
|
|
11
|
+
"lovable",
|
|
12
|
+
"getData",
|
|
13
|
+
"route-registry",
|
|
14
|
+
"server-side-rendering"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./server": {
|
|
26
|
+
"import": "./dist/ssr/server.js",
|
|
27
|
+
"types": "./dist/ssr/server.d.ts"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc && npm run build:docs",
|
|
35
|
+
"dev": "tsc --watch",
|
|
36
|
+
"changelog": "standard-version --message \"[skip ci]\"",
|
|
37
|
+
"changelog:rc": "npm run changelog -- --prerelease rc --skip.changelog --skip.tag",
|
|
38
|
+
"changelog:patch": "npm run changelog -- --release-as patch --prerelease rc",
|
|
39
|
+
"changelog:minor": "npm run changelog -- --release-as minor --prerelease rc",
|
|
40
|
+
"changelog:major": "npm run changelog -- --release-as major --prerelease rc",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:watch": "vitest",
|
|
43
|
+
"test:e2e": "playwright test",
|
|
44
|
+
"build:docs": "cd doc && npm run docs:build"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"react": "^18.0.0",
|
|
48
|
+
"react-dom": "^18.0.0",
|
|
49
|
+
"react-router-dom": "^6.0.0"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"express": "^4.21.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@playwright/test": "^1.59.1",
|
|
56
|
+
"@types/express": "^4.17.21",
|
|
57
|
+
"@types/node": "^22.16.5",
|
|
58
|
+
"@types/react": "^18.3.23",
|
|
59
|
+
"@types/react-dom": "^18.3.7",
|
|
60
|
+
"happy-dom": "^20.8.9",
|
|
61
|
+
"react": "^18.3.1",
|
|
62
|
+
"react-dom": "^18.3.1",
|
|
63
|
+
"react-router-dom": "^6.30.1",
|
|
64
|
+
"standard-version": "^9.5.0",
|
|
65
|
+
"typescript": "^5.8.3",
|
|
66
|
+
"vite": "^5.4.19",
|
|
67
|
+
"vitest": "^4.1.4"
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=18"
|
|
71
|
+
}
|
|
72
|
+
}
|