@jay-framework/dev-server 0.25.4 → 0.26.0
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 +57 -1
- package/dist/index.js +286 -65
- package/package.json +17 -17
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,19 @@ interface DevServerOptions {
|
|
|
39
39
|
logLevel?: LogLevel;
|
|
40
40
|
/** HTTP server for HMR WebSocket attachment (avoids default port 24678 collision) */
|
|
41
41
|
httpServer?: Server;
|
|
42
|
+
/**
|
|
43
|
+
* Hosts the dev server's Vite host-check accepts, beyond localhost (DL#220). A list of hosts
|
|
44
|
+
* (Vite host-suffix syntax, e.g. `.example.dev`), or `true` to disable the check entirely — for
|
|
45
|
+
* cloud preview proxies. Merged with the `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` env var.
|
|
46
|
+
*/
|
|
47
|
+
allowedHosts?: string[] | true;
|
|
48
|
+
/**
|
|
49
|
+
* Enable source-editing dev markers (DL#219). When true, the pre-render pipeline injects
|
|
50
|
+
* `jay-dev-src` / `jay-dev-item` attributes so the source-editing inspector can map a rendered
|
|
51
|
+
* pixel back to its jay-html source. Off by default — the markers change rendered output, so
|
|
52
|
+
* they are only emitted for AIditor / source-editing sessions.
|
|
53
|
+
*/
|
|
54
|
+
sourceEditing?: boolean;
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
/**
|
|
@@ -173,6 +186,35 @@ declare class DevServerService {
|
|
|
173
186
|
loadRouteParams(routePath: string): AsyncGenerator<Record<string, string>[]>;
|
|
174
187
|
}
|
|
175
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Percent-encode `[`/`]` in the path of asset URLs (`href`/`src`) in served HTML.
|
|
191
|
+
*
|
|
192
|
+
* Dynamic routes produce asset paths with literal brackets (e.g.
|
|
193
|
+
* `.../pre-rendered/products/[slug]/page.css`), whether Vite serves them as
|
|
194
|
+
* `/@fs/…` or root-relative. Bare brackets in a URL are rejected by some
|
|
195
|
+
* dev-machine hosting proxies — the browser then sees an empty MIME type
|
|
196
|
+
* ("Refused to apply style … MIME type ('')"). This mirrors the production fix
|
|
197
|
+
* (DL#144/R7), which encodes brackets in *all* frontend asset paths; it is
|
|
198
|
+
* deliberately NOT `/@fs/`-specific (production has no `@fs`).
|
|
199
|
+
*
|
|
200
|
+
* Encoding only the emitted URL is sufficient and safe: the dev servers that
|
|
201
|
+
* handle these requests — Vite (`decodeURI`) and serve-static/express
|
|
202
|
+
* (`decodeURIComponent`) — decode `%5B` back to `[`, and CSS/module loading
|
|
203
|
+
* resolves via the plugin's `meta.originId` (not the id), so the encoded URL
|
|
204
|
+
* still maps to the literal on-disk file. Only the path (before `?`) is touched,
|
|
205
|
+
* so query strings (e.g. `?a[]=1`) are intact. In practice only asset URLs carry
|
|
206
|
+
* brackets — resolved navigation hrefs do not — so real links are unaffected.
|
|
207
|
+
* Exported so the dev-serving test guards the real behavior rather than a copy.
|
|
208
|
+
*/
|
|
209
|
+
declare function encodeBracketsInAssetUrls(html: string): string;
|
|
210
|
+
/**
|
|
211
|
+
* Filesystem-safe name for the per-route debug artifact, derived from the route
|
|
212
|
+
* path only (DL#229). The query string is dropped — otherwise a long query
|
|
213
|
+
* (e.g. an ~800-char auth token passed by a hosting proxy) pushes the filename
|
|
214
|
+
* past `NAME_MAX` (255) and `fs.writeFile` throws `ENAMETOOLONG`. Also strips
|
|
215
|
+
* non-fs-safe characters and length-caps as defense-in-depth. Pure → unit-tested.
|
|
216
|
+
*/
|
|
217
|
+
declare function debugPageName(url: string | undefined): string;
|
|
176
218
|
interface DevServerRoute {
|
|
177
219
|
path: string;
|
|
178
220
|
handler: RequestHandler;
|
|
@@ -277,7 +319,21 @@ interface CreateViteServerOptions {
|
|
|
277
319
|
clearScreen?: boolean;
|
|
278
320
|
/** HTTP server for HMR WebSocket (avoids default port 24678 collision) */
|
|
279
321
|
httpServer?: Server;
|
|
322
|
+
/**
|
|
323
|
+
* Hosts Vite's dev-server host-check accepts, beyond localhost (DL#220). A list of hosts (Vite
|
|
324
|
+
* host-suffix syntax, e.g. `.example.dev`), or `true` to disable the check entirely. Merged with
|
|
325
|
+
* the `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` env var. `undefined`/empty → Vite's default.
|
|
326
|
+
*/
|
|
327
|
+
allowedHosts?: string[] | true;
|
|
280
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* Resolves Vite's `server.allowedHosts` from the `.jay` config value and the
|
|
331
|
+
* `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` env var (Vite's own convention — honored natively only in
|
|
332
|
+
* Vite 6, so the nested Vite 5.4 needs us to read it). Returns `true` (disable check) if either source
|
|
333
|
+
* says so, a de-duplicated merged list otherwise, or `undefined` when neither is set (Vite keeps its
|
|
334
|
+
* localhost-only default). (DL#220)
|
|
335
|
+
*/
|
|
336
|
+
declare function resolveAllowedHosts(fromConfig: string[] | true | undefined, env: string | undefined): string[] | true | undefined;
|
|
281
337
|
/**
|
|
282
338
|
* Creates a Vite server configured for Jay Stack.
|
|
283
339
|
*
|
|
@@ -297,4 +353,4 @@ declare function createViteForCli(options: {
|
|
|
297
353
|
tsConfigFilePath?: string;
|
|
298
354
|
}): Promise<ViteDevServer>;
|
|
299
355
|
|
|
300
|
-
export { ACTION_ENDPOINT_BASE, type ActionBodyParserOptions, type ActionRouterOptions, type CreateViteServerOptions, DEV_SERVER_SERVICE, type DevServer, type DevServerOptions, type DevServerRoute, type DevServerRouteRegistrar, DevServerService, type FreezeEntry, FreezeStore, type RouteInfo, actionBodyParser, createActionRouter, createViteForCli, createViteServer, mkDevServer };
|
|
356
|
+
export { ACTION_ENDPOINT_BASE, type ActionBodyParserOptions, type ActionRouterOptions, type CreateViteServerOptions, DEV_SERVER_SERVICE, type DevServer, type DevServerOptions, type DevServerRoute, type DevServerRouteRegistrar, DevServerService, type FreezeEntry, FreezeStore, type RouteInfo, actionBodyParser, createActionRouter, createViteForCli, createViteServer, debugPageName, encodeBracketsInAssetUrls, mkDevServer, resolveAllowedHosts };
|
package/dist/index.js
CHANGED
|
@@ -7,15 +7,15 @@ import { createRequire } from "module";
|
|
|
7
7
|
import "@jay-framework/compiler-shared";
|
|
8
8
|
import * as path from "node:path";
|
|
9
9
|
import path__default from "node:path";
|
|
10
|
-
import { parseJayFile, JAY_IMPORT_RESOLVER, discoverHeadlessInstances, assignCoordinatesToJayHtml, parseAction, generateServerElementFile, parseContract, slowRenderTransform } from "@jay-framework/compiler-jay-html";
|
|
10
|
+
import { parseJayFile, JAY_IMPORT_RESOLVER, discoverHeadlessInstances, assignCoordinatesToJayHtml, parseAction, generateServerElementFile, noteExportedTypesFileChanged, injectDevMarkers, parseContract, slowRenderTransform } from "@jay-framework/compiler-jay-html";
|
|
11
11
|
import { getLogger, getDevLogger } from "@jay-framework/logger";
|
|
12
12
|
import { createRequire as createRequire$1 } from "node:module";
|
|
13
13
|
import * as fs from "node:fs";
|
|
14
|
-
import fs__default
|
|
14
|
+
import fs__default from "node:fs";
|
|
15
15
|
import { scanRoutes, createRoute, routeToExpressRoute } from "@jay-framework/stack-route-scanner";
|
|
16
|
-
import { makePassthroughInstanceComponent, actionRegistry, scanPlugins, serializeHeadTags, mergeHeadTags, serializeScripts, discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, runLoadParams, DevSlowlyChangingPhase, preparePluginClientInits, registerService, getServiceRegistry,
|
|
16
|
+
import { makePassthroughInstanceComponent, actionRegistry, scanPlugins, serializeHeadTags, mergeHeadTags, serializeScripts, discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, crossOriginErrorResponse, needsSameOriginCheck, isCrossOriginRequest, isSecureRequest, parseCookies, runLoadParams, DevSlowlyChangingPhase, preparePluginClientInits, registerService, getServiceRegistry, renderFastChangingData, getClientInitData, slowRenderInstances, normalizeInstancePropNames, resolveErrorPageToken, buildErrorViewState } from "@jay-framework/stack-server-runtime";
|
|
17
17
|
import * as fs$1 from "node:fs/promises";
|
|
18
|
-
import
|
|
18
|
+
import fs$1__default from "node:fs/promises";
|
|
19
19
|
import jsBeautify from "js-beautify";
|
|
20
20
|
import fs$2 from "fs";
|
|
21
21
|
import path$1 from "path";
|
|
@@ -1052,7 +1052,9 @@ function extractActionFromExpression(node) {
|
|
|
1052
1052
|
current = expr.expression;
|
|
1053
1053
|
continue;
|
|
1054
1054
|
}
|
|
1055
|
-
if (c$1.isPropertyAccessExpression(expr) && ["withServices", "withCaching", "withHandler", "withTimeout"].includes(
|
|
1055
|
+
if (c$1.isPropertyAccessExpression(expr) && ["withServices", "withCaching", "withHandler", "withTimeout", "withRequest"].includes(
|
|
1056
|
+
expr.name.text
|
|
1057
|
+
)) {
|
|
1056
1058
|
current = expr.expression;
|
|
1057
1059
|
continue;
|
|
1058
1060
|
}
|
|
@@ -1518,6 +1520,13 @@ function jayStackCompiler(options = {}) {
|
|
|
1518
1520
|
function stripInlineActionBuilders(code, builderNames) {
|
|
1519
1521
|
return transformJayStackBuilder(code, "action-strip.ts", "client", new Set(builderNames));
|
|
1520
1522
|
}
|
|
1523
|
+
function resolveAllowedHosts(fromConfig, env) {
|
|
1524
|
+
if (fromConfig === true) return true;
|
|
1525
|
+
const envHosts = (env ?? "").split(",").map((host) => host.trim()).filter(Boolean);
|
|
1526
|
+
if (envHosts.includes("true")) return true;
|
|
1527
|
+
const merged = [...fromConfig ?? [], ...envHosts];
|
|
1528
|
+
return merged.length ? Array.from(new Set(merged)) : void 0;
|
|
1529
|
+
}
|
|
1521
1530
|
async function createViteServer(options) {
|
|
1522
1531
|
const {
|
|
1523
1532
|
projectRoot,
|
|
@@ -1526,14 +1535,21 @@ async function createViteServer(options) {
|
|
|
1526
1535
|
jayRollupConfig = { tsConfigFilePath: path__default.join(projectRoot, "tsconfig.json") },
|
|
1527
1536
|
logLevel = "info",
|
|
1528
1537
|
clearScreen = true,
|
|
1529
|
-
httpServer
|
|
1538
|
+
httpServer,
|
|
1539
|
+
allowedHosts
|
|
1530
1540
|
} = options;
|
|
1541
|
+
const resolvedAllowedHosts = resolveAllowedHosts(
|
|
1542
|
+
allowedHosts,
|
|
1543
|
+
process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS
|
|
1544
|
+
);
|
|
1531
1545
|
const vite = await createServer({
|
|
1532
1546
|
// Don't start HTTP server - we use middleware mode
|
|
1533
1547
|
server: {
|
|
1534
1548
|
middlewareMode: true,
|
|
1535
1549
|
hmr: httpServer ? { server: httpServer } : void 0,
|
|
1536
|
-
watch: { ignored: ["**/build/**"] }
|
|
1550
|
+
watch: { ignored: ["**/build/**"] },
|
|
1551
|
+
// Omit the key entirely when unset so Vite keeps its localhost-only default (DL#220).
|
|
1552
|
+
...resolvedAllowedHosts !== void 0 && { allowedHosts: resolvedAllowedHosts }
|
|
1537
1553
|
},
|
|
1538
1554
|
// Use Jay Stack compiler for .jay-html and other custom transforms
|
|
1539
1555
|
plugins: [
|
|
@@ -1623,7 +1639,7 @@ function resolveClientImportPath(route) {
|
|
|
1623
1639
|
return route.compPath;
|
|
1624
1640
|
}
|
|
1625
1641
|
async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfig, options) {
|
|
1626
|
-
const exists = await
|
|
1642
|
+
const exists = await fs$1__default.access(route.compPath, fs$1__default.constants.F_OK).then(() => true).catch(() => false);
|
|
1627
1643
|
const parts = [];
|
|
1628
1644
|
const validations = [];
|
|
1629
1645
|
if (exists) {
|
|
@@ -1643,7 +1659,7 @@ async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfi
|
|
|
1643
1659
|
}
|
|
1644
1660
|
}
|
|
1645
1661
|
const jayHtmlFilePath = options?.preRenderedPath ?? route.jayHtmlPath;
|
|
1646
|
-
const jayHtmlSource = options?.preRenderedContent ?? (await
|
|
1662
|
+
const jayHtmlSource = options?.preRenderedContent ?? (await fs$1__default.readFile(jayHtmlFilePath)).toString();
|
|
1647
1663
|
const fileName = path__default.basename(route.jayHtmlPath);
|
|
1648
1664
|
const dirName = path__default.dirname(route.jayHtmlPath);
|
|
1649
1665
|
const jayHtmlWithValidations = await parseJayFile(
|
|
@@ -2018,8 +2034,9 @@ function buildPageReloadHmrScript() {
|
|
|
2018
2034
|
});
|
|
2019
2035
|
}`;
|
|
2020
2036
|
}
|
|
2021
|
-
function buildFreezeScript(routePattern) {
|
|
2037
|
+
function buildFreezeScript(routePattern, sourceFile) {
|
|
2022
2038
|
const routePatternLiteral = routePattern ? `'${routePattern}'` : "undefined";
|
|
2039
|
+
const sourceFileLiteral = sourceFile ? JSON.stringify(sourceFile) : "undefined";
|
|
2023
2040
|
return `
|
|
2024
2041
|
// Page Freeze (DL#127, DL#128 iframe addendum)
|
|
2025
2042
|
// Sticky embed mode: URL param sets a session cookie so in-iframe navigation preserves it
|
|
@@ -2074,13 +2091,152 @@ function buildFreezeScript(routePattern) {
|
|
|
2074
2091
|
}
|
|
2075
2092
|
}
|
|
2076
2093
|
|
|
2094
|
+
// Source-editing inspector (DL#219). Resolves a viewport point/rect to the jay-dev-* source
|
|
2095
|
+
// markers emitted when the dev server runs with sourceEditing on. Harmless without markers —
|
|
2096
|
+
// it simply finds no jay-dev-src and replies node:null. Reply carries source LOCATORS (line
|
|
2097
|
+
// ranges + route) plus runtime identities (forEach record id, region name + static props);
|
|
2098
|
+
// the agent reads bound expressions / collection / if-conditions from the jay-html itself.
|
|
2099
|
+
function __jayParseLines(s) {
|
|
2100
|
+
if (!s) return null;
|
|
2101
|
+
const parts = s.split(':');
|
|
2102
|
+
return { from: parseInt(parts[0], 10), to: parseInt(parts[1], 10) };
|
|
2103
|
+
}
|
|
2104
|
+
function __jayLines(el) {
|
|
2105
|
+
return __jayParseLines(el.getAttribute('jay-dev-src'));
|
|
2106
|
+
}
|
|
2107
|
+
// A significant enclosing frame: a forEach item root or a region boundary. Returns null for
|
|
2108
|
+
// plain wrapper elements (the agent reconstructs those from source via node.lines).
|
|
2109
|
+
function __jayFrame(el) {
|
|
2110
|
+
const item = el.getAttribute('jay-dev-item');
|
|
2111
|
+
if (item) return { kind: 'forEach', lines: __jayLines(el), itemId: item };
|
|
2112
|
+
const region = el.getAttribute('jay-dev-region');
|
|
2113
|
+
if (region) {
|
|
2114
|
+
// Region lines live in jay-dev-region-src (the <jay:…> tag's range), distinct from the
|
|
2115
|
+
// root element's own jay-dev-src.
|
|
2116
|
+
const frame = { kind: 'region', lines: __jayParseLines(el.getAttribute('jay-dev-region-src')), name: region };
|
|
2117
|
+
const rawProps = el.getAttribute('jay-dev-region-props');
|
|
2118
|
+
if (rawProps) { try { frame.props = JSON.parse(decodeURIComponent(rawProps)); } catch (e) {} }
|
|
2119
|
+
return frame;
|
|
2120
|
+
}
|
|
2121
|
+
return null;
|
|
2122
|
+
}
|
|
2123
|
+
// One-level HTML of an element: its open tag (authored attrs only, jay-* stripped), its direct
|
|
2124
|
+
// children shown as empty tags (grandchildren elided with …), and its text — so the agent sees
|
|
2125
|
+
// exactly what was clicked inside generated content without the whole subtree.
|
|
2126
|
+
function __jayOneLevelHtml(el) {
|
|
2127
|
+
if (!el || !el.tagName) return '';
|
|
2128
|
+
const tag = el.tagName.toLowerCase();
|
|
2129
|
+
let attrs = '';
|
|
2130
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
2131
|
+
const a = el.attributes[i];
|
|
2132
|
+
if (a.name.indexOf('jay-') === 0) continue; // strip jay-dev-* / jay-coordinate
|
|
2133
|
+
attrs += ' ' + a.name + '="' + a.value + '"';
|
|
2134
|
+
}
|
|
2135
|
+
let inner = '';
|
|
2136
|
+
const kids = el.childNodes || [];
|
|
2137
|
+
for (let i = 0; i < kids.length; i++) {
|
|
2138
|
+
const c = kids[i];
|
|
2139
|
+
if (c.nodeType === 3) inner += (c.textContent || '');
|
|
2140
|
+
else if (c.nodeType === 1) {
|
|
2141
|
+
const ct = c.tagName.toLowerCase();
|
|
2142
|
+
inner += '<' + ct + '>' + (c.childNodes && c.childNodes.length ? '…' : '') + '</' + ct + '>';
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
if (inner.length > 300) inner = inner.slice(0, 300) + '…';
|
|
2146
|
+
return '<' + tag + attrs + '>' + inner + '</' + tag + '>';
|
|
2147
|
+
}
|
|
2148
|
+
function __jayResolveElement(el) {
|
|
2149
|
+
if (!el) return null;
|
|
2150
|
+
// Walk el up to (but excluding) <body>.
|
|
2151
|
+
const entries = [];
|
|
2152
|
+
let cur = el;
|
|
2153
|
+
while (cur && cur.nodeType === 1 && cur.tagName && cur.tagName.toLowerCase() !== 'body') {
|
|
2154
|
+
entries.push(cur);
|
|
2155
|
+
cur = cur.parentElement;
|
|
2156
|
+
}
|
|
2157
|
+
// Source anchor = nearest element at/above el carrying a source marker (its line range).
|
|
2158
|
+
let sourceEl = null;
|
|
2159
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2160
|
+
if (entries[i].getAttribute('jay-dev-src')) { sourceEl = entries[i]; break; }
|
|
2161
|
+
}
|
|
2162
|
+
if (!sourceEl) return null;
|
|
2163
|
+
// Stack = only the significant enclosing frames (forEach + region), innermost → outermost.
|
|
2164
|
+
const stack = [];
|
|
2165
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2166
|
+
const f = __jayFrame(entries[i]);
|
|
2167
|
+
if (f) stack.push(f);
|
|
2168
|
+
}
|
|
2169
|
+
// node describes the ACTUAL element el (what the pointer hit / the rect chose). html — a
|
|
2170
|
+
// one-level rendering (open tag with authored attrs, direct children as empty tags, inline
|
|
2171
|
+
// text; grandchildren + long text elided) — is the single content field: it carries the tag,
|
|
2172
|
+
// attributes (src/href/value), and value, bounded in size. lines come from the source anchor;
|
|
2173
|
+
// for bound/generated content (an html-string value) el has no jay-dev-src of its own, so
|
|
2174
|
+
// lines point to the ENCLOSING binding (the editable source) and contentFromBinding flags it.
|
|
2175
|
+
const r = el.getBoundingClientRect();
|
|
2176
|
+
const node = {
|
|
2177
|
+
lines: __jayLines(sourceEl),
|
|
2178
|
+
tag: el.tagName ? el.tagName.toLowerCase() : '',
|
|
2179
|
+
html: __jayOneLevelHtml(el),
|
|
2180
|
+
rect: { x: r.x, y: r.y, width: r.width, height: r.height },
|
|
2181
|
+
};
|
|
2182
|
+
const childEls = Array.prototype.slice.call(el.children || []);
|
|
2183
|
+
const childrenGenerated =
|
|
2184
|
+
childEls.length > 0 && childEls.every((c) => !c.getAttribute('jay-dev-src'));
|
|
2185
|
+
if (!el.getAttribute('jay-dev-src') || childrenGenerated) {
|
|
2186
|
+
node.contentFromBinding = true;
|
|
2187
|
+
}
|
|
2188
|
+
return { node, stack };
|
|
2189
|
+
}
|
|
2190
|
+
function __jayInspectPoint(x, y) {
|
|
2191
|
+
return __jayResolveElement(document.elementFromPoint(x, y));
|
|
2192
|
+
}
|
|
2193
|
+
function __jayInspectRect(x, y, w, h) {
|
|
2194
|
+
const sel = { left: x, top: y, right: x + w, bottom: y + h };
|
|
2195
|
+
const marked = Array.prototype.slice.call(document.querySelectorAll('[jay-dev-src]'));
|
|
2196
|
+
let best = null, bestArea = -1;
|
|
2197
|
+
for (let i = 0; i < marked.length; i++) {
|
|
2198
|
+
const el = marked[i];
|
|
2199
|
+
const r = el.getBoundingClientRect();
|
|
2200
|
+
const elArea = r.width * r.height;
|
|
2201
|
+
if (elArea <= 0) continue;
|
|
2202
|
+
const ix = Math.max(0, Math.min(sel.right, r.right) - Math.max(sel.left, r.left));
|
|
2203
|
+
const iy = Math.max(0, Math.min(sel.bottom, r.bottom) - Math.max(sel.top, r.top));
|
|
2204
|
+
// Rect rule (DL#219): keep elements the box mostly encloses (overlap over the ELEMENT's
|
|
2205
|
+
// own area >= 0.8), then pick the LARGEST — the element the box was drawn around. A tight
|
|
2206
|
+
// box only clears the threshold for the small element; a big box clears it for the
|
|
2207
|
+
// container too, and largest-area returns the container (not its first child).
|
|
2208
|
+
if ((ix * iy) / elArea >= 0.8 && elArea > bestArea) {
|
|
2209
|
+
bestArea = elArea;
|
|
2210
|
+
best = el;
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
if (best) return __jayResolveElement(best);
|
|
2214
|
+
return __jayInspectPoint(x + w / 2, y + h / 2);
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2077
2217
|
if (__jayEmbedMode) {
|
|
2078
2218
|
// Notify parent of the current route on load (DL#128 route addendum)
|
|
2079
2219
|
window.parent.postMessage({ type: 'jay:route', route: window.location.pathname, routePattern: ${routePatternLiteral} }, '*');
|
|
2080
2220
|
|
|
2081
|
-
// Embed mode: parent triggers freeze via postMessage
|
|
2221
|
+
// Embed mode: parent triggers freeze / inspect via postMessage
|
|
2082
2222
|
window.addEventListener('message', (e) => {
|
|
2083
|
-
|
|
2223
|
+
const d = e.data;
|
|
2224
|
+
if (!d) return;
|
|
2225
|
+
if (d.type === 'jay:requestFreeze') { __jayDoFreeze(); return; }
|
|
2226
|
+
if (d.type === 'jay:inspectPoint' || d.type === 'jay:inspectRect') {
|
|
2227
|
+
const result = d.type === 'jay:inspectPoint'
|
|
2228
|
+
? __jayInspectPoint(d.x, d.y)
|
|
2229
|
+
: __jayInspectRect(d.x, d.y, d.width, d.height);
|
|
2230
|
+
window.parent.postMessage({
|
|
2231
|
+
type: 'jay:inspectResult',
|
|
2232
|
+
requestId: d.requestId,
|
|
2233
|
+
file: ${sourceFileLiteral},
|
|
2234
|
+
route: window.location.pathname,
|
|
2235
|
+
routePattern: ${routePatternLiteral},
|
|
2236
|
+
node: result ? result.node : null, // node.rect is the matched element's on-screen box
|
|
2237
|
+
stack: result ? result.stack : [],
|
|
2238
|
+
}, '*');
|
|
2239
|
+
}
|
|
2084
2240
|
});
|
|
2085
2241
|
} else {
|
|
2086
2242
|
// Standalone: Alt+S / Option+S keyboard shortcut
|
|
@@ -2105,7 +2261,7 @@ function buildAutomationWrap(options, mode) {
|
|
|
2105
2261
|
}
|
|
2106
2262
|
const appendLine = appendDom ? `
|
|
2107
2263
|
target.appendChild(wrapped.element.dom);` : "";
|
|
2108
|
-
const freezeScript = buildFreezeScript(options.routePattern);
|
|
2264
|
+
const freezeScript = buildFreezeScript(options.routePattern, options.sourceFile);
|
|
2109
2265
|
if (hasSlowViewState) {
|
|
2110
2266
|
return `
|
|
2111
2267
|
// Wrap with automation for dev tooling
|
|
@@ -2358,7 +2514,7 @@ async function generateFrozenPageHtml(vite, jayHtmlContent, jayHtmlFilename, jay
|
|
|
2358
2514
|
if (cached.cssHref) {
|
|
2359
2515
|
try {
|
|
2360
2516
|
const cssPath = cached.cssHref.replace(/^\/@fs/, "").replace(/\?.*$/, "");
|
|
2361
|
-
const cssContent = await
|
|
2517
|
+
const cssContent = await fs$1__default.readFile(cssPath, "utf-8");
|
|
2362
2518
|
inlineCss = `<style>${cssContent}</style>`;
|
|
2363
2519
|
} catch {
|
|
2364
2520
|
inlineCss = `<link rel="stylesheet" href="${cached.cssHref}" />`;
|
|
@@ -2437,11 +2593,11 @@ async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename
|
|
|
2437
2593
|
generateServerElementFile(parsedJayFile, serverElementOptions)
|
|
2438
2594
|
);
|
|
2439
2595
|
const serverElementDir = path__default.join(buildFolder, "pre-rendered", routeDir);
|
|
2440
|
-
await
|
|
2596
|
+
await fs$1__default.mkdir(serverElementDir, { recursive: true });
|
|
2441
2597
|
const adjustedCode = rebaseRelativeImports(serverElementCode, jayHtmlDir, serverElementDir);
|
|
2442
2598
|
const serverElementFilename = jayHtmlFilename.replace(".jay-html", ".server-element.ts");
|
|
2443
2599
|
const serverElementPath = path__default.join(serverElementDir, serverElementFilename);
|
|
2444
|
-
await
|
|
2600
|
+
await fs$1__default.writeFile(serverElementPath, adjustedCode, "utf-8");
|
|
2445
2601
|
const existingModule = vite.moduleGraph.getModuleById(serverElementPath);
|
|
2446
2602
|
if (existingModule) {
|
|
2447
2603
|
vite.moduleGraph.invalidateModule(existingModule);
|
|
@@ -2453,7 +2609,7 @@ async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename
|
|
|
2453
2609
|
if (parsedJayFile.css) {
|
|
2454
2610
|
const cssFilename = jayHtmlFilename.replace(".jay-html", ".css");
|
|
2455
2611
|
const cssPath = path__default.join(serverElementDir, cssFilename);
|
|
2456
|
-
await
|
|
2612
|
+
await fs$1__default.writeFile(cssPath, parsedJayFile.css, "utf-8");
|
|
2457
2613
|
const cssModules = vite.moduleGraph.getModulesByFile(cssPath);
|
|
2458
2614
|
if (cssModules) {
|
|
2459
2615
|
for (const mod of cssModules) {
|
|
@@ -3530,7 +3686,7 @@ class SlowRenderCache {
|
|
|
3530
3686
|
const preRenderedPath = this.computeCachePath(jayHtmlPath, params, routeDir);
|
|
3531
3687
|
let fileContent;
|
|
3532
3688
|
try {
|
|
3533
|
-
fileContent = await
|
|
3689
|
+
fileContent = await fs$1__default.readFile(preRenderedPath, "utf-8");
|
|
3534
3690
|
} catch {
|
|
3535
3691
|
return void 0;
|
|
3536
3692
|
}
|
|
@@ -3558,8 +3714,8 @@ class SlowRenderCache {
|
|
|
3558
3714
|
carryForward,
|
|
3559
3715
|
jayHtmlPath
|
|
3560
3716
|
);
|
|
3561
|
-
await
|
|
3562
|
-
await
|
|
3717
|
+
await fs$1__default.mkdir(path__default.dirname(preRenderedPath), { recursive: true });
|
|
3718
|
+
await fs$1__default.writeFile(preRenderedPath, fileContent, "utf-8");
|
|
3563
3719
|
this.trackFile(jayHtmlPath, preRenderedPath);
|
|
3564
3720
|
return {
|
|
3565
3721
|
preRenderedPath,
|
|
@@ -3575,7 +3731,7 @@ class SlowRenderCache {
|
|
|
3575
3731
|
async has(jayHtmlPath, params, routeDir) {
|
|
3576
3732
|
const preRenderedPath = this.computeCachePath(jayHtmlPath, params, routeDir);
|
|
3577
3733
|
try {
|
|
3578
|
-
await
|
|
3734
|
+
await fs$1__default.access(preRenderedPath);
|
|
3579
3735
|
return true;
|
|
3580
3736
|
} catch {
|
|
3581
3737
|
return false;
|
|
@@ -3590,7 +3746,7 @@ class SlowRenderCache {
|
|
|
3590
3746
|
if (files) {
|
|
3591
3747
|
for (const filePath of files) {
|
|
3592
3748
|
try {
|
|
3593
|
-
await
|
|
3749
|
+
await fs$1__default.unlink(filePath);
|
|
3594
3750
|
} catch {
|
|
3595
3751
|
}
|
|
3596
3752
|
}
|
|
@@ -3627,14 +3783,14 @@ class SlowRenderCache {
|
|
|
3627
3783
|
for (const files of this.pathToFiles.values()) {
|
|
3628
3784
|
for (const filePath of files) {
|
|
3629
3785
|
try {
|
|
3630
|
-
await
|
|
3786
|
+
await fs$1__default.unlink(filePath);
|
|
3631
3787
|
} catch {
|
|
3632
3788
|
}
|
|
3633
3789
|
}
|
|
3634
3790
|
}
|
|
3635
3791
|
this.pathToFiles.clear();
|
|
3636
3792
|
try {
|
|
3637
|
-
await
|
|
3793
|
+
await fs$1__default.rm(this.cacheDir, { recursive: true, force: true });
|
|
3638
3794
|
} catch {
|
|
3639
3795
|
}
|
|
3640
3796
|
}
|
|
@@ -3685,11 +3841,11 @@ class SlowRenderCache {
|
|
|
3685
3841
|
const basename = path__default.basename(jayHtmlPath, ".jay-html");
|
|
3686
3842
|
const cacheSubDir = path__default.join(this.cacheDir, dir);
|
|
3687
3843
|
try {
|
|
3688
|
-
const files = await
|
|
3844
|
+
const files = await fs$1__default.readdir(cacheSubDir);
|
|
3689
3845
|
for (const file of files) {
|
|
3690
3846
|
if (file.startsWith(basename)) {
|
|
3691
3847
|
try {
|
|
3692
|
-
await
|
|
3848
|
+
await fs$1__default.unlink(path__default.join(cacheSubDir, file));
|
|
3693
3849
|
} catch {
|
|
3694
3850
|
}
|
|
3695
3851
|
}
|
|
@@ -4005,6 +4161,10 @@ function createActionRouter(options) {
|
|
|
4005
4161
|
});
|
|
4006
4162
|
return;
|
|
4007
4163
|
}
|
|
4164
|
+
if (isRejectedCrossOrigin(action, req)) {
|
|
4165
|
+
res.status(403).json(crossOriginErrorResponse(actionName));
|
|
4166
|
+
return;
|
|
4167
|
+
}
|
|
4008
4168
|
let input;
|
|
4009
4169
|
try {
|
|
4010
4170
|
if (requestMethod === "GET") {
|
|
@@ -4036,11 +4196,15 @@ function createActionRouter(options) {
|
|
|
4036
4196
|
const cleanup = () => {
|
|
4037
4197
|
if (tempDir) cleanupTempDir(tempDir);
|
|
4038
4198
|
};
|
|
4199
|
+
const incoming = action.needsRequest ? readIncomingRequest(req) : void 0;
|
|
4200
|
+
if (action.needsRequest) {
|
|
4201
|
+
res.set("Cache-Control", registry.getCacheHeaders(actionName));
|
|
4202
|
+
}
|
|
4039
4203
|
if (registry.isStreaming(actionName)) {
|
|
4040
4204
|
res.setHeader("Content-Type", "application/x-ndjson");
|
|
4041
4205
|
res.setHeader("Transfer-Encoding", "chunked");
|
|
4042
4206
|
try {
|
|
4043
|
-
const generator = registry.executeStream(actionName, input);
|
|
4207
|
+
const generator = registry.executeStream(actionName, input, incoming);
|
|
4044
4208
|
for await (const chunk of generator) {
|
|
4045
4209
|
res.write(JSON.stringify({ chunk }) + "\n");
|
|
4046
4210
|
}
|
|
@@ -4053,7 +4217,7 @@ function createActionRouter(options) {
|
|
|
4053
4217
|
timing?.end();
|
|
4054
4218
|
return;
|
|
4055
4219
|
}
|
|
4056
|
-
const result = await registry.execute(actionName, input);
|
|
4220
|
+
const result = await registry.execute(actionName, input, incoming);
|
|
4057
4221
|
cleanup();
|
|
4058
4222
|
if (requestMethod === "GET" && result.success) {
|
|
4059
4223
|
const cacheHeaders = registry.getCacheHeaders(actionName);
|
|
@@ -4062,6 +4226,9 @@ function createActionRouter(options) {
|
|
|
4062
4226
|
}
|
|
4063
4227
|
}
|
|
4064
4228
|
if (result.success) {
|
|
4229
|
+
for (const setCookie of result.setCookies ?? []) {
|
|
4230
|
+
res.append("Set-Cookie", setCookie);
|
|
4231
|
+
}
|
|
4065
4232
|
res.status(200).json({
|
|
4066
4233
|
success: true,
|
|
4067
4234
|
data: result.data
|
|
@@ -4076,6 +4243,19 @@ function createActionRouter(options) {
|
|
|
4076
4243
|
timing?.end();
|
|
4077
4244
|
};
|
|
4078
4245
|
}
|
|
4246
|
+
function isRejectedCrossOrigin(action, req) {
|
|
4247
|
+
return needsSameOriginCheck(action) && isCrossOriginRequest({
|
|
4248
|
+
secFetchSite: req.headers["sec-fetch-site"],
|
|
4249
|
+
origin: req.headers.origin,
|
|
4250
|
+
requestOrigin: `${req.protocol}://${req.headers.host}`
|
|
4251
|
+
});
|
|
4252
|
+
}
|
|
4253
|
+
function readIncomingRequest(req) {
|
|
4254
|
+
return {
|
|
4255
|
+
cookies: parseCookies(req.headers.cookie),
|
|
4256
|
+
secure: isSecureRequest(req.protocol, req.headers["x-forwarded-proto"])
|
|
4257
|
+
};
|
|
4258
|
+
}
|
|
4079
4259
|
function getStatusCodeForError(code, isActionError) {
|
|
4080
4260
|
if (isActionError) {
|
|
4081
4261
|
return 422;
|
|
@@ -4206,6 +4386,11 @@ function actionBodyParser(options) {
|
|
|
4206
4386
|
next();
|
|
4207
4387
|
return;
|
|
4208
4388
|
}
|
|
4389
|
+
const routedAction = registryToUse.get(req.path.slice(ACTION_ENDPOINT_BASE.length + 1));
|
|
4390
|
+
if (routedAction && isRejectedCrossOrigin(routedAction, req)) {
|
|
4391
|
+
next();
|
|
4392
|
+
return;
|
|
4393
|
+
}
|
|
4209
4394
|
const contentType = req.headers["content-type"] || "";
|
|
4210
4395
|
if (contentType.startsWith("multipart/form-data")) {
|
|
4211
4396
|
const actionName = req.path.slice(ACTION_ENDPOINT_BASE.length + 1);
|
|
@@ -4402,6 +4587,30 @@ class DevServerService {
|
|
|
4402
4587
|
yield* runLoadParams(loaded.val.parts);
|
|
4403
4588
|
}
|
|
4404
4589
|
}
|
|
4590
|
+
function encodeBracketsInAssetUrls(html) {
|
|
4591
|
+
return html.replace(/\b(href|src)="([^"]*)"/g, (whole, attr, value) => {
|
|
4592
|
+
const q = value.indexOf("?");
|
|
4593
|
+
const pathPart = q === -1 ? value : value.slice(0, q);
|
|
4594
|
+
if (!pathPart.includes("[") && !pathPart.includes("]")) return whole;
|
|
4595
|
+
const encodedPath = pathPart.replace(/\[/g, "%5B").replace(/\]/g, "%5D");
|
|
4596
|
+
return `${attr}="${encodedPath}${q === -1 ? "" : value.slice(q)}"`;
|
|
4597
|
+
});
|
|
4598
|
+
}
|
|
4599
|
+
function debugPageName(url) {
|
|
4600
|
+
const routePath = (url || "/").split("?")[0];
|
|
4601
|
+
if (routePath === "/" || routePath === "") return "index";
|
|
4602
|
+
return routePath.replace(/^\//, "").replace(/\//g, "-").replace(/[^\w.-]/g, "_").slice(0, 200) || "index";
|
|
4603
|
+
}
|
|
4604
|
+
async function writeDebugPage(options, url, html) {
|
|
4605
|
+
if (options.logLevel !== "verbose" || !options.buildFolder) return;
|
|
4606
|
+
try {
|
|
4607
|
+
const clientScriptDir = path__default.join(options.buildFolder, "debug", "client-entry");
|
|
4608
|
+
await fs$1__default.mkdir(clientScriptDir, { recursive: true });
|
|
4609
|
+
await fs$1__default.writeFile(path__default.join(clientScriptDir, `${debugPageName(url)}.html`), html, "utf-8");
|
|
4610
|
+
} catch (e2) {
|
|
4611
|
+
getLogger().info(`[dev] debug page write skipped: ${e2.message}`);
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4405
4614
|
let _watchLinkedFiles = () => {
|
|
4406
4615
|
};
|
|
4407
4616
|
async function initRoutes(pagesBaseFolder) {
|
|
@@ -4469,7 +4678,7 @@ function resolvePluginExport(pluginPath, exportSubpath) {
|
|
|
4469
4678
|
const normalized = exportSubpath.replace(/^\.\//, "");
|
|
4470
4679
|
const packageJsonPath = path__default.join(pluginPath, "package.json");
|
|
4471
4680
|
try {
|
|
4472
|
-
const packageJson = JSON.parse(fs__default
|
|
4681
|
+
const packageJson = JSON.parse(fs__default.readFileSync(packageJsonPath, "utf-8"));
|
|
4473
4682
|
if (packageJson.exports) {
|
|
4474
4683
|
const exportKey = "./" + normalized;
|
|
4475
4684
|
const exportValue = packageJson.exports[exportKey];
|
|
@@ -4486,7 +4695,7 @@ function resolvePluginExport(pluginPath, exportSubpath) {
|
|
|
4486
4695
|
for (const dir of ["dist", "lib", ""]) {
|
|
4487
4696
|
const candidate = path__default.join(pluginPath, dir, normalized);
|
|
4488
4697
|
try {
|
|
4489
|
-
fs__default
|
|
4698
|
+
fs__default.accessSync(candidate);
|
|
4490
4699
|
return candidate;
|
|
4491
4700
|
} catch {
|
|
4492
4701
|
}
|
|
@@ -4495,14 +4704,14 @@ function resolvePluginExport(pluginPath, exportSubpath) {
|
|
|
4495
4704
|
}
|
|
4496
4705
|
function resolvePluginModule(plugin, exportKey = ".") {
|
|
4497
4706
|
const pkgJsonPath = path__default.join(plugin.pluginPath, "package.json");
|
|
4498
|
-
if (fs__default
|
|
4707
|
+
if (fs__default.existsSync(pkgJsonPath)) {
|
|
4499
4708
|
try {
|
|
4500
|
-
const pkg = JSON.parse(fs__default
|
|
4709
|
+
const pkg = JSON.parse(fs__default.readFileSync(pkgJsonPath, "utf-8"));
|
|
4501
4710
|
const mainExport = pkg.exports?.[exportKey];
|
|
4502
4711
|
const mainPath = typeof mainExport === "string" ? mainExport : mainExport?.default || mainExport?.import || pkg.main;
|
|
4503
4712
|
if (mainPath) {
|
|
4504
4713
|
const resolved = path__default.join(plugin.pluginPath, mainPath);
|
|
4505
|
-
if (fs__default
|
|
4714
|
+
if (fs__default.existsSync(resolved)) return resolved;
|
|
4506
4715
|
}
|
|
4507
4716
|
} catch {
|
|
4508
4717
|
}
|
|
@@ -4511,7 +4720,7 @@ function resolvePluginModule(plugin, exportKey = ".") {
|
|
|
4511
4720
|
for (const ext of [".ts", ".js", "/index.ts", "/index.js"]) {
|
|
4512
4721
|
const candidate = path__default.join(plugin.pluginPath, modulePath + ext);
|
|
4513
4722
|
try {
|
|
4514
|
-
fs__default
|
|
4723
|
+
fs__default.accessSync(candidate);
|
|
4515
4724
|
return candidate;
|
|
4516
4725
|
} catch {
|
|
4517
4726
|
}
|
|
@@ -4519,7 +4728,7 @@ function resolvePluginModule(plugin, exportKey = ".") {
|
|
|
4519
4728
|
for (const ext of [".ts", ".js"]) {
|
|
4520
4729
|
const candidate = path__default.join(plugin.pluginPath, "lib", path__default.basename(modulePath) + ext);
|
|
4521
4730
|
try {
|
|
4522
|
-
fs__default
|
|
4731
|
+
fs__default.accessSync(candidate);
|
|
4523
4732
|
return candidate;
|
|
4524
4733
|
} catch {
|
|
4525
4734
|
}
|
|
@@ -4547,7 +4756,9 @@ function defaults(options) {
|
|
|
4547
4756
|
pagesRoot: pagesRootFolder,
|
|
4548
4757
|
buildFolder
|
|
4549
4758
|
},
|
|
4550
|
-
httpServer: options.httpServer
|
|
4759
|
+
httpServer: options.httpServer,
|
|
4760
|
+
allowedHosts: options.allowedHosts,
|
|
4761
|
+
sourceEditing: options.sourceEditing
|
|
4551
4762
|
};
|
|
4552
4763
|
}
|
|
4553
4764
|
let _renderDevErrorPage = async (res, info) => {
|
|
@@ -4908,7 +5119,8 @@ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRen
|
|
|
4908
5119
|
initialPartsResult.val.headlessInstanceComponents,
|
|
4909
5120
|
partKeys,
|
|
4910
5121
|
pageParams,
|
|
4911
|
-
pageProps
|
|
5122
|
+
pageProps,
|
|
5123
|
+
options.sourceEditing
|
|
4912
5124
|
);
|
|
4913
5125
|
timing?.recordSlowRender(Date.now() - slowStart);
|
|
4914
5126
|
if (!preRenderResult) {
|
|
@@ -5056,26 +5268,26 @@ async function handleClientOnlyRequest(vite, route, options, slowlyPhase, pagePa
|
|
|
5056
5268
|
pluginsForPage,
|
|
5057
5269
|
{
|
|
5058
5270
|
enableAutomation: !options.disableAutomation,
|
|
5059
|
-
routePattern: routeToExpressRoute(route)
|
|
5271
|
+
routePattern: routeToExpressRoute(route),
|
|
5272
|
+
sourceFile: path__default.relative(options.projectRootFolder, route.jayHtmlPath)
|
|
5060
5273
|
}
|
|
5061
5274
|
);
|
|
5062
|
-
|
|
5063
|
-
const pageName = !url || url === "/" ? "index" : url.replace(/^\//, "").replace(/\//g, "-");
|
|
5064
|
-
const clientScriptDir = path__default.join(options.buildFolder, "debug", "client-entry");
|
|
5065
|
-
await fs__default.mkdir(clientScriptDir, { recursive: true });
|
|
5066
|
-
await fs__default.writeFile(path__default.join(clientScriptDir, `${pageName}.html`), pageHtml, "utf-8");
|
|
5067
|
-
}
|
|
5275
|
+
await writeDebugPage(options, url, pageHtml);
|
|
5068
5276
|
const viteStart = Date.now();
|
|
5069
|
-
const compiledPageHtml =
|
|
5277
|
+
const compiledPageHtml = encodeBracketsInAssetUrls(
|
|
5278
|
+
await vite.transformIndexHtml(url?.split("?")[0] || "/", pageHtml)
|
|
5279
|
+
);
|
|
5070
5280
|
timing?.recordViteClient(Date.now() - viteStart);
|
|
5071
5281
|
res.status(200).set({ "Content-Type": "text/html" }).send(compiledPageHtml);
|
|
5072
5282
|
timing?.end();
|
|
5073
5283
|
}
|
|
5074
5284
|
async function sendResponse(vite, res, url, jayHtmlPath, sourceJayHtmlPath, pageParts, viewState, carryForward, clientTrackByMap, projectInit, pluginsForPage, options, routePattern, routeDir, slowViewState, timing, preLoadedContent, headTags, scripts, statusCode = 200) {
|
|
5075
5285
|
let pageHtml;
|
|
5286
|
+
const sourceFile = path__default.relative(options.projectRootFolder, sourceJayHtmlPath);
|
|
5076
5287
|
try {
|
|
5077
5288
|
const jayHtmlDir = path__default.dirname(jayHtmlPath);
|
|
5078
|
-
const
|
|
5289
|
+
const rawContent = preLoadedContent ?? await fs$1__default.readFile(jayHtmlPath, "utf-8");
|
|
5290
|
+
const jayHtmlContent = options.sourceEditing ? injectDevMarkers(rawContent) : rawContent;
|
|
5079
5291
|
pageHtml = await generateSSRPageHtml(
|
|
5080
5292
|
vite,
|
|
5081
5293
|
jayHtmlContent,
|
|
@@ -5096,7 +5308,8 @@ async function sendResponse(vite, res, url, jayHtmlPath, sourceJayHtmlPath, page
|
|
|
5096
5308
|
{
|
|
5097
5309
|
enableAutomation: !options.disableAutomation,
|
|
5098
5310
|
slowViewState,
|
|
5099
|
-
routePattern
|
|
5311
|
+
routePattern,
|
|
5312
|
+
sourceFile
|
|
5100
5313
|
},
|
|
5101
5314
|
void 0,
|
|
5102
5315
|
headTags,
|
|
@@ -5116,23 +5329,21 @@ async function sendResponse(vite, res, url, jayHtmlPath, sourceJayHtmlPath, page
|
|
|
5116
5329
|
{
|
|
5117
5330
|
enableAutomation: !options.disableAutomation,
|
|
5118
5331
|
slowViewState,
|
|
5119
|
-
routePattern
|
|
5332
|
+
routePattern,
|
|
5333
|
+
sourceFile
|
|
5120
5334
|
}
|
|
5121
5335
|
);
|
|
5122
5336
|
}
|
|
5123
|
-
|
|
5124
|
-
const pageName = !url || url === "/" ? "index" : url.replace(/^\//, "").replace(/\//g, "-");
|
|
5125
|
-
const clientScriptDir = path__default.join(options.buildFolder, "debug", "client-entry");
|
|
5126
|
-
await fs__default.mkdir(clientScriptDir, { recursive: true });
|
|
5127
|
-
await fs__default.writeFile(path__default.join(clientScriptDir, `${pageName}.html`), pageHtml, "utf-8");
|
|
5128
|
-
}
|
|
5337
|
+
await writeDebugPage(options, url, pageHtml);
|
|
5129
5338
|
for (const [id, mod] of vite.moduleGraph.idToModuleMap) {
|
|
5130
5339
|
if (id.includes("html-proxy")) {
|
|
5131
5340
|
vite.moduleGraph.invalidateModule(mod);
|
|
5132
5341
|
}
|
|
5133
5342
|
}
|
|
5134
5343
|
const viteStart = Date.now();
|
|
5135
|
-
const compiledPageHtml =
|
|
5344
|
+
const compiledPageHtml = encodeBracketsInAssetUrls(
|
|
5345
|
+
await vite.transformIndexHtml(url?.split("?")[0] || "/", pageHtml)
|
|
5346
|
+
);
|
|
5136
5347
|
timing?.recordViteClient(Date.now() - viteStart);
|
|
5137
5348
|
res.status(statusCode).set({ "Content-Type": "text/html" }).send(compiledPageHtml);
|
|
5138
5349
|
timing?.end();
|
|
@@ -5151,7 +5362,7 @@ async function handleFrozenRequest(vite, route, options, freezeStore, slowRender
|
|
|
5151
5362
|
const routeDir = getRouteDir(route);
|
|
5152
5363
|
const cachedEntry = await slowRenderCache.get(route.jayHtmlPath, pageParams, routeDir);
|
|
5153
5364
|
const jayHtmlPath = cachedEntry?.preRenderedPath ?? route.jayHtmlPath;
|
|
5154
|
-
const jayHtmlContent = cachedEntry?.preRenderedContent ?? await
|
|
5365
|
+
const jayHtmlContent = cachedEntry?.preRenderedContent ?? await fs$1__default.readFile(jayHtmlPath, "utf-8");
|
|
5155
5366
|
const jayHtmlFilename = path__default.basename(jayHtmlPath);
|
|
5156
5367
|
const jayHtmlDir = path__default.dirname(jayHtmlPath);
|
|
5157
5368
|
const sourceDir = path__default.dirname(route.jayHtmlPath);
|
|
@@ -5176,7 +5387,9 @@ async function handleFrozenRequest(vite, route, options, freezeStore, slowRender
|
|
|
5176
5387
|
headers["Access-Control-Allow-Origin"] = "*";
|
|
5177
5388
|
}
|
|
5178
5389
|
if (injectDevHmr) {
|
|
5179
|
-
const compiledHtml =
|
|
5390
|
+
const compiledHtml = encodeBracketsInAssetUrls(
|
|
5391
|
+
await vite.transformIndexHtml(url?.split("?")[0] || "/", html)
|
|
5392
|
+
);
|
|
5180
5393
|
res.status(200).set(headers).send(compiledHtml);
|
|
5181
5394
|
} else {
|
|
5182
5395
|
res.status(200).set(headers).send(html);
|
|
@@ -5187,13 +5400,14 @@ async function handleFrozenRequest(vite, route, options, freezeStore, slowRender
|
|
|
5187
5400
|
}
|
|
5188
5401
|
timing?.end();
|
|
5189
5402
|
}
|
|
5190
|
-
async function preRenderJayHtml(route, slowViewState, headlessContracts, headlessInstanceComponents, partKeys = [], pageParams = {}, pageProps = { language: "en", url: "" }) {
|
|
5191
|
-
const
|
|
5403
|
+
async function preRenderJayHtml(route, slowViewState, headlessContracts, headlessInstanceComponents, partKeys = [], pageParams = {}, pageProps = { language: "en", url: "" }, sourceEditing = false) {
|
|
5404
|
+
const rawJayHtml = await fs$1__default.readFile(route.jayHtmlPath, "utf-8");
|
|
5405
|
+
const jayHtmlWithTemplates = sourceEditing ? injectDevMarkers(rawJayHtml) : rawJayHtml;
|
|
5192
5406
|
const sourceDir = path__default.dirname(route.jayHtmlPath);
|
|
5193
5407
|
let contract;
|
|
5194
5408
|
const contractPath = route.jayHtmlPath.replace(".jay-html", ".jay-contract");
|
|
5195
5409
|
try {
|
|
5196
|
-
const contractContent = await
|
|
5410
|
+
const contractContent = await fs$1__default.readFile(contractPath, "utf-8");
|
|
5197
5411
|
const parseResult = parseContract(contractContent, path__default.basename(contractPath));
|
|
5198
5412
|
if (parseResult.val) contract = parseResult.val;
|
|
5199
5413
|
} catch {
|
|
@@ -5290,10 +5504,10 @@ async function mkDevServer(rawOptions) {
|
|
|
5290
5504
|
const { publicBaseUrlPath, pagesRootFolder, projectRootFolder, buildFolder, jayRollupConfig } = options;
|
|
5291
5505
|
if (buildFolder) {
|
|
5292
5506
|
try {
|
|
5293
|
-
const entries = await
|
|
5507
|
+
const entries = await fs$1__default.readdir(buildFolder).catch(() => []);
|
|
5294
5508
|
for (const entry of entries) {
|
|
5295
5509
|
if (entry === "freezes") continue;
|
|
5296
|
-
await
|
|
5510
|
+
await fs$1__default.rm(path__default.join(buildFolder, entry), { recursive: true, force: true });
|
|
5297
5511
|
}
|
|
5298
5512
|
} catch {
|
|
5299
5513
|
}
|
|
@@ -5307,7 +5521,8 @@ async function mkDevServer(rawOptions) {
|
|
|
5307
5521
|
base: publicBaseUrlPath,
|
|
5308
5522
|
jayRollupConfig,
|
|
5309
5523
|
logLevel: viteLogLevel,
|
|
5310
|
-
httpServer: options.httpServer
|
|
5524
|
+
httpServer: options.httpServer,
|
|
5525
|
+
allowedHosts: options.allowedHosts
|
|
5311
5526
|
});
|
|
5312
5527
|
lifecycleManager.setViteServer(vite);
|
|
5313
5528
|
await lifecycleManager.initialize();
|
|
@@ -5369,7 +5584,7 @@ async function mkDevServer(rawOptions) {
|
|
|
5369
5584
|
for (let i = devServerRoutes.length - 1; i >= 0; i--) {
|
|
5370
5585
|
const route = devServerRoutes[i];
|
|
5371
5586
|
const fsPath = route.fsRoute.jayHtmlPath;
|
|
5372
|
-
const stillOnDisk = scannedRawRoutes.has(route.fsRoute.rawRoute) && fs__default
|
|
5587
|
+
const stillOnDisk = scannedRawRoutes.has(route.fsRoute.rawRoute) && fs__default.existsSync(fsPath);
|
|
5373
5588
|
if (!stillOnDisk) {
|
|
5374
5589
|
devServerRoutes.splice(i, 1);
|
|
5375
5590
|
}
|
|
@@ -5529,6 +5744,9 @@ function setupSlowRenderCacheInvalidation(vite, cache, pagesRootFolder, projectR
|
|
|
5529
5744
|
}
|
|
5530
5745
|
};
|
|
5531
5746
|
vite.watcher.on("change", (changedPath) => {
|
|
5747
|
+
if (/\.(ts|tsx|jay-contract)$/.test(changedPath)) {
|
|
5748
|
+
noteExportedTypesFileChanged(changedPath);
|
|
5749
|
+
}
|
|
5532
5750
|
if (watchedFiles.has(changedPath)) {
|
|
5533
5751
|
clearServerElementCache();
|
|
5534
5752
|
cache.clear().then(() => {
|
|
@@ -5596,5 +5814,8 @@ export {
|
|
|
5596
5814
|
createActionRouter,
|
|
5597
5815
|
createViteForCli,
|
|
5598
5816
|
createViteServer,
|
|
5599
|
-
|
|
5817
|
+
debugPageName,
|
|
5818
|
+
encodeBracketsInAssetUrls,
|
|
5819
|
+
mkDevServer,
|
|
5820
|
+
resolveAllowedHosts
|
|
5600
5821
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/dev-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,24 +23,24 @@
|
|
|
23
23
|
"test:watch": "vitest"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@jay-framework/compiler-jay-stack": "^0.
|
|
27
|
-
"@jay-framework/compiler-shared": "^0.
|
|
28
|
-
"@jay-framework/component": "^0.
|
|
29
|
-
"@jay-framework/fullstack-component": "^0.
|
|
30
|
-
"@jay-framework/logger": "^0.
|
|
31
|
-
"@jay-framework/runtime": "^0.
|
|
32
|
-
"@jay-framework/stack-client-runtime": "^0.
|
|
33
|
-
"@jay-framework/stack-route-scanner": "^0.
|
|
34
|
-
"@jay-framework/stack-server-build": "^0.
|
|
35
|
-
"@jay-framework/stack-server-runtime": "^0.
|
|
36
|
-
"@jay-framework/view-state-merge": "^0.
|
|
26
|
+
"@jay-framework/compiler-jay-stack": "^0.26.0",
|
|
27
|
+
"@jay-framework/compiler-shared": "^0.26.0",
|
|
28
|
+
"@jay-framework/component": "^0.26.0",
|
|
29
|
+
"@jay-framework/fullstack-component": "^0.26.0",
|
|
30
|
+
"@jay-framework/logger": "^0.26.0",
|
|
31
|
+
"@jay-framework/runtime": "^0.26.0",
|
|
32
|
+
"@jay-framework/stack-client-runtime": "^0.26.0",
|
|
33
|
+
"@jay-framework/stack-route-scanner": "^0.26.0",
|
|
34
|
+
"@jay-framework/stack-server-build": "^0.26.0",
|
|
35
|
+
"@jay-framework/stack-server-runtime": "^0.26.0",
|
|
36
|
+
"@jay-framework/view-state-merge": "^0.26.0",
|
|
37
37
|
"busboy": "^1.6.0",
|
|
38
|
-
"vite": "^
|
|
38
|
+
"vite": "^6.4.4"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@jay-framework/dev-environment": "^0.
|
|
42
|
-
"@jay-framework/jay-cli": "^0.
|
|
43
|
-
"@jay-framework/stack-client-runtime": "^0.
|
|
41
|
+
"@jay-framework/dev-environment": "^0.26.0",
|
|
42
|
+
"@jay-framework/jay-cli": "^0.26.0",
|
|
43
|
+
"@jay-framework/stack-client-runtime": "^0.26.0",
|
|
44
44
|
"@playwright/test": "^1.58.2",
|
|
45
45
|
"@types/busboy": "^1.5.4",
|
|
46
46
|
"@types/express": "^5.0.2",
|
|
@@ -52,6 +52,6 @@
|
|
|
52
52
|
"rimraf": "^5.0.5",
|
|
53
53
|
"tsup": "^8.0.1",
|
|
54
54
|
"typescript": "^5.3.3",
|
|
55
|
-
"vitest": "^1.
|
|
55
|
+
"vitest": "^4.1.11"
|
|
56
56
|
}
|
|
57
57
|
}
|