lovable-ssr 0.1.23 → 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/ssr/buildHeadHtml.d.ts.map +1 -1
- package/dist/ssr/buildHeadHtml.js +1 -8
- package/dist/ssr/server.d.ts.map +1 -1
- package/dist/ssr/server.js +13 -75
- package/dist/types.d.ts +6 -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 +8 -2
|
@@ -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.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
|
@@ -5,6 +5,8 @@ import express from 'express';
|
|
|
5
5
|
import { createServer as createViteServer } from 'vite';
|
|
6
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),
|
|
@@ -123,20 +116,12 @@ Sitemap: ${baseUrl}/sitemap.xml`);
|
|
|
123
116
|
});
|
|
124
117
|
}
|
|
125
118
|
buildSitemapXml(entries) {
|
|
126
|
-
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>`);
|
|
127
120
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
128
121
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
129
122
|
${lines.join('\n')}
|
|
130
123
|
</urlset>`;
|
|
131
124
|
}
|
|
132
|
-
escapeXml(str) {
|
|
133
|
-
return str
|
|
134
|
-
.replace(/&/g, '&')
|
|
135
|
-
.replace(/</g, '<')
|
|
136
|
-
.replace(/>/g, '>')
|
|
137
|
-
.replace(/"/g, '"')
|
|
138
|
-
.replace(/'/g, ''');
|
|
139
|
-
}
|
|
140
125
|
async runMiddleware(ctx) {
|
|
141
126
|
const mw = this.config.middleware ?? getMiddleware();
|
|
142
127
|
if (!mw)
|
|
@@ -163,27 +148,7 @@ ${lines.join('\n')}
|
|
|
163
148
|
const params = matchedRoute
|
|
164
149
|
? RouterService.routeParams(matchedRoute.path, pathname)
|
|
165
150
|
: { routeParams: {}, searchParams: {} };
|
|
166
|
-
const
|
|
167
|
-
const cookies = {};
|
|
168
|
-
if (cookiesRaw) {
|
|
169
|
-
cookiesRaw.split(';').forEach((part) => {
|
|
170
|
-
const [k, ...rest] = part.split('=');
|
|
171
|
-
if (!k)
|
|
172
|
-
return;
|
|
173
|
-
const key = k.trim();
|
|
174
|
-
if (!key)
|
|
175
|
-
return;
|
|
176
|
-
const value = rest.join('=').trim();
|
|
177
|
-
cookies[key] = decodeURIComponent(value);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
const requestContext = {
|
|
181
|
-
cookiesRaw,
|
|
182
|
-
cookies,
|
|
183
|
-
headers: req.headers,
|
|
184
|
-
method: req.method,
|
|
185
|
-
url: req.originalUrl,
|
|
186
|
-
};
|
|
151
|
+
const requestContext = buildRequestContext(req);
|
|
187
152
|
const mwResult = await this.runMiddleware({
|
|
188
153
|
request: requestContext,
|
|
189
154
|
route: matchedRoute,
|
|
@@ -215,47 +180,20 @@ ${lines.join('\n')}
|
|
|
215
180
|
const template = this.readTemplate(path.join(this.config.root, 'dist', 'index.html'));
|
|
216
181
|
return res.status(200).set({ 'Content-Type': 'text/html' }).send(template);
|
|
217
182
|
}
|
|
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
|
+
}
|
|
218
191
|
async renderSsr(url, res, requestContext) {
|
|
219
192
|
const { template, render } = await this.getSsrRenderer();
|
|
220
193
|
if (process.env.NODE_ENV !== 'production' && process.env.LOVABLE_SSR_DEBUG) {
|
|
221
194
|
console.log('[lovable-ssr] render(url)', url);
|
|
222
195
|
}
|
|
223
|
-
|
|
224
|
-
let preloadedData;
|
|
225
|
-
let helmet;
|
|
226
|
-
const cookiesRaw = requestContext.cookiesRaw;
|
|
227
|
-
if (this.isProd) {
|
|
228
|
-
const cacheKey = this.normalizeCacheKey(url);
|
|
229
|
-
const hasCookies = !!cookiesRaw;
|
|
230
|
-
// Evita cachear respostas personalizadas por cookies (ex.: auth).
|
|
231
|
-
if (!hasCookies) {
|
|
232
|
-
const cached = this._ssrCache.get(cacheKey);
|
|
233
|
-
if (cached) {
|
|
234
|
-
appHtml = cached.html;
|
|
235
|
-
preloadedData = cached.preloadedData;
|
|
236
|
-
helmet = cached.helmet;
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
const result = await render(url, { requestContext });
|
|
240
|
-
appHtml = typeof result.html === 'string' ? result.html : '';
|
|
241
|
-
preloadedData = result.preloadedData ?? {};
|
|
242
|
-
helmet = result.helmet;
|
|
243
|
-
this._ssrCache.set(cacheKey, { html: appHtml, preloadedData, helmet });
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
const result = await render(url, { requestContext });
|
|
248
|
-
appHtml = typeof result.html === 'string' ? result.html : '';
|
|
249
|
-
preloadedData = result.preloadedData ?? {};
|
|
250
|
-
helmet = result.helmet;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
const result = await render(url, { requestContext });
|
|
255
|
-
appHtml = typeof result.html === 'string' ? result.html : '';
|
|
256
|
-
preloadedData = result.preloadedData ?? {};
|
|
257
|
-
helmet = result.helmet;
|
|
258
|
-
}
|
|
196
|
+
const { appHtml, preloadedData, helmet } = await this.resolveRenderResult(url, render, requestContext);
|
|
259
197
|
let html = template.replace('<div id="root"></div>', `<div id="root">${appHtml}</div>`);
|
|
260
198
|
html = this.injectHelmet(html, helmet);
|
|
261
199
|
html = this.injectPreloadedData(html, preloadedData);
|
package/dist/types.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ 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>;
|
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;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"}
|
|
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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lovable-ssr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "SSR and route data engine for Lovable projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"changelog:patch": "npm run changelog -- --release-as patch --prerelease rc",
|
|
39
39
|
"changelog:minor": "npm run changelog -- --release-as minor --prerelease rc",
|
|
40
40
|
"changelog:major": "npm run changelog -- --release-as major --prerelease rc",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:watch": "vitest",
|
|
43
|
+
"test:e2e": "playwright test",
|
|
41
44
|
"build:docs": "cd doc && npm run docs:build"
|
|
42
45
|
},
|
|
43
46
|
"peerDependencies": {
|
|
@@ -49,16 +52,19 @@
|
|
|
49
52
|
"express": "^4.21.0"
|
|
50
53
|
},
|
|
51
54
|
"devDependencies": {
|
|
55
|
+
"@playwright/test": "^1.59.1",
|
|
52
56
|
"@types/express": "^4.17.21",
|
|
53
57
|
"@types/node": "^22.16.5",
|
|
54
58
|
"@types/react": "^18.3.23",
|
|
55
59
|
"@types/react-dom": "^18.3.7",
|
|
60
|
+
"happy-dom": "^20.8.9",
|
|
56
61
|
"react": "^18.3.1",
|
|
57
62
|
"react-dom": "^18.3.1",
|
|
58
63
|
"react-router-dom": "^6.30.1",
|
|
59
64
|
"standard-version": "^9.5.0",
|
|
60
65
|
"typescript": "^5.8.3",
|
|
61
|
-
"vite": "^5.4.19"
|
|
66
|
+
"vite": "^5.4.19",
|
|
67
|
+
"vitest": "^4.1.4"
|
|
62
68
|
},
|
|
63
69
|
"engines": {
|
|
64
70
|
"node": ">=18"
|