@lolyjs/core 0.1.0-alpha.9 → 0.2.0-alpha.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/README.md +467 -325
- package/dist/bootstrap-BiCQmSkx.d.mts +50 -0
- package/dist/bootstrap-BiCQmSkx.d.ts +50 -0
- package/dist/cli.cjs +98 -20
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +98 -20
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +165 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2 -35
- package/dist/index.d.ts +2 -35
- package/dist/index.js +165 -159
- package/dist/index.js.map +1 -1
- package/dist/react/hooks.cjs +5 -5
- package/dist/react/hooks.cjs.map +1 -1
- package/dist/react/hooks.d.mts +13 -3
- package/dist/react/hooks.d.ts +13 -3
- package/dist/react/hooks.js +5 -5
- package/dist/react/hooks.js.map +1 -1
- package/dist/react/sockets.cjs +4 -1
- package/dist/react/sockets.cjs.map +1 -1
- package/dist/react/sockets.js +4 -1
- package/dist/react/sockets.js.map +1 -1
- package/dist/runtime.cjs +87 -161
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.mts +3 -45
- package/dist/runtime.d.ts +3 -45
- package/dist/runtime.js +83 -161
- package/dist/runtime.js.map +1 -1
- package/package.json +2 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import { Request, Response } from 'express';
|
|
3
3
|
import { Socket, Server } from 'socket.io';
|
|
4
|
+
export { c as bootstrapClient } from './bootstrap-BiCQmSkx.mjs';
|
|
4
5
|
import { ZodSchema, z } from 'zod';
|
|
5
6
|
import * as express_rate_limit from 'express-rate-limit';
|
|
6
7
|
import pino, { Logger as Logger$1 } from 'pino';
|
|
@@ -215,40 +216,6 @@ interface BuildAppOptions {
|
|
|
215
216
|
}
|
|
216
217
|
declare function buildApp(options?: BuildAppOptions): Promise<void>;
|
|
217
218
|
|
|
218
|
-
declare const WINDOW_DATA_KEY = "__FW_DATA__";
|
|
219
|
-
|
|
220
|
-
type InitialData = {
|
|
221
|
-
pathname: string;
|
|
222
|
-
params: Record<string, string>;
|
|
223
|
-
props: Record<string, any>;
|
|
224
|
-
metadata?: {
|
|
225
|
-
title?: string;
|
|
226
|
-
description?: string;
|
|
227
|
-
} | null;
|
|
228
|
-
notFound?: boolean;
|
|
229
|
-
error?: boolean;
|
|
230
|
-
theme?: string;
|
|
231
|
-
};
|
|
232
|
-
declare global {
|
|
233
|
-
interface Window {
|
|
234
|
-
[WINDOW_DATA_KEY]?: InitialData;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
type ClientLoadedComponents = {
|
|
238
|
-
Page: React.ComponentType<any>;
|
|
239
|
-
layouts: React.ComponentType<any>[];
|
|
240
|
-
};
|
|
241
|
-
type ClientRouteLoaded = {
|
|
242
|
-
pattern: string;
|
|
243
|
-
paramNames: string[];
|
|
244
|
-
load: () => Promise<ClientLoadedComponents>;
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Bootstraps the client-side application.
|
|
249
|
-
*/
|
|
250
|
-
declare function bootstrapClient(routes: ClientRouteLoaded[], notFoundRoute: ClientRouteLoaded | null, errorRoute?: ClientRouteLoaded | null): void;
|
|
251
|
-
|
|
252
219
|
declare function withCache(fn: any, options: any): any;
|
|
253
220
|
|
|
254
221
|
/**
|
|
@@ -475,4 +442,4 @@ declare function requestLoggerMiddleware(options?: {
|
|
|
475
442
|
*/
|
|
476
443
|
declare function getRequestLogger(req: Request): Logger;
|
|
477
444
|
|
|
478
|
-
export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext,
|
|
445
|
+
export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext, buildApp, commonSchemas, createModuleLogger, createRateLimiter, defaultRateLimiter, generateRequestId, getAppDir, getBuildDir, getLogger, getRequestLogger, getStaticDir, lenientRateLimiter, loadConfig, logger, requestLoggerMiddleware, resetLogger, safeValidate, sanitizeObject, sanitizeParams, sanitizeQuery, sanitizeString, setLogger, startDevServer, startProdServer, strictRateLimiter, validate, withCache };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import { Request, Response } from 'express';
|
|
3
3
|
import { Socket, Server } from 'socket.io';
|
|
4
|
+
export { c as bootstrapClient } from './bootstrap-BiCQmSkx.js';
|
|
4
5
|
import { ZodSchema, z } from 'zod';
|
|
5
6
|
import * as express_rate_limit from 'express-rate-limit';
|
|
6
7
|
import pino, { Logger as Logger$1 } from 'pino';
|
|
@@ -215,40 +216,6 @@ interface BuildAppOptions {
|
|
|
215
216
|
}
|
|
216
217
|
declare function buildApp(options?: BuildAppOptions): Promise<void>;
|
|
217
218
|
|
|
218
|
-
declare const WINDOW_DATA_KEY = "__FW_DATA__";
|
|
219
|
-
|
|
220
|
-
type InitialData = {
|
|
221
|
-
pathname: string;
|
|
222
|
-
params: Record<string, string>;
|
|
223
|
-
props: Record<string, any>;
|
|
224
|
-
metadata?: {
|
|
225
|
-
title?: string;
|
|
226
|
-
description?: string;
|
|
227
|
-
} | null;
|
|
228
|
-
notFound?: boolean;
|
|
229
|
-
error?: boolean;
|
|
230
|
-
theme?: string;
|
|
231
|
-
};
|
|
232
|
-
declare global {
|
|
233
|
-
interface Window {
|
|
234
|
-
[WINDOW_DATA_KEY]?: InitialData;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
type ClientLoadedComponents = {
|
|
238
|
-
Page: React.ComponentType<any>;
|
|
239
|
-
layouts: React.ComponentType<any>[];
|
|
240
|
-
};
|
|
241
|
-
type ClientRouteLoaded = {
|
|
242
|
-
pattern: string;
|
|
243
|
-
paramNames: string[];
|
|
244
|
-
load: () => Promise<ClientLoadedComponents>;
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Bootstraps the client-side application.
|
|
249
|
-
*/
|
|
250
|
-
declare function bootstrapClient(routes: ClientRouteLoaded[], notFoundRoute: ClientRouteLoaded | null, errorRoute?: ClientRouteLoaded | null): void;
|
|
251
|
-
|
|
252
219
|
declare function withCache(fn: any, options: any): any;
|
|
253
220
|
|
|
254
221
|
/**
|
|
@@ -475,4 +442,4 @@ declare function requestLoggerMiddleware(options?: {
|
|
|
475
442
|
*/
|
|
476
443
|
declare function getRequestLogger(req: Request): Logger;
|
|
477
444
|
|
|
478
|
-
export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext,
|
|
445
|
+
export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext, buildApp, commonSchemas, createModuleLogger, createRateLimiter, defaultRateLimiter, generateRequestId, getAppDir, getBuildDir, getLogger, getRequestLogger, getStaticDir, lenientRateLimiter, loadConfig, logger, requestLoggerMiddleware, resetLogger, safeValidate, sanitizeObject, sanitizeParams, sanitizeQuery, sanitizeString, setLogger, startDevServer, startProdServer, strictRateLimiter, validate, withCache };
|
package/dist/index.js
CHANGED
|
@@ -1365,24 +1365,69 @@ function createClientConfig(projectRoot, mode) {
|
|
|
1365
1365
|
init_globals();
|
|
1366
1366
|
import path13 from "path";
|
|
1367
1367
|
import fs12 from "fs";
|
|
1368
|
-
function startClientBundler(projectRoot) {
|
|
1369
|
-
const { config, outDir } = createClientConfig(projectRoot,
|
|
1368
|
+
function startClientBundler(projectRoot, mode = "development") {
|
|
1369
|
+
const { config, outDir } = createClientConfig(projectRoot, mode);
|
|
1370
1370
|
copyStaticAssets(projectRoot, outDir);
|
|
1371
1371
|
const compiler = rspack2(config);
|
|
1372
|
+
let isBuilding = false;
|
|
1373
|
+
let buildResolve = null;
|
|
1374
|
+
let buildPromise = null;
|
|
1375
|
+
let lastBuildTime = Date.now();
|
|
1376
|
+
compiler.hooks.compile.tap("HotReload", () => {
|
|
1377
|
+
isBuilding = true;
|
|
1378
|
+
buildPromise = new Promise((resolve3) => {
|
|
1379
|
+
buildResolve = resolve3;
|
|
1380
|
+
});
|
|
1381
|
+
});
|
|
1372
1382
|
compiler.watch({}, (err, stats) => {
|
|
1373
1383
|
if (err) {
|
|
1374
1384
|
console.error("[framework][client] Rspack error:", err);
|
|
1385
|
+
isBuilding = false;
|
|
1386
|
+
lastBuildTime = Date.now();
|
|
1387
|
+
if (buildResolve) {
|
|
1388
|
+
buildResolve();
|
|
1389
|
+
buildResolve = null;
|
|
1390
|
+
buildPromise = null;
|
|
1391
|
+
}
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
if (!stats) {
|
|
1395
|
+
isBuilding = false;
|
|
1396
|
+
lastBuildTime = Date.now();
|
|
1375
1397
|
return;
|
|
1376
1398
|
}
|
|
1377
|
-
if (!stats) return;
|
|
1378
1399
|
if (stats.hasErrors()) {
|
|
1379
1400
|
console.error(
|
|
1380
1401
|
"[framework][client] Build with errors:\n",
|
|
1381
1402
|
stats.toString("errors-only")
|
|
1382
1403
|
);
|
|
1404
|
+
} else {
|
|
1405
|
+
console.log("[framework][client] \u2713 Client bundle rebuilt successfully");
|
|
1406
|
+
}
|
|
1407
|
+
isBuilding = false;
|
|
1408
|
+
lastBuildTime = Date.now();
|
|
1409
|
+
if (buildResolve) {
|
|
1410
|
+
buildResolve();
|
|
1411
|
+
buildResolve = null;
|
|
1412
|
+
buildPromise = null;
|
|
1383
1413
|
}
|
|
1384
1414
|
});
|
|
1385
|
-
return {
|
|
1415
|
+
return {
|
|
1416
|
+
outDir,
|
|
1417
|
+
waitForBuild: async () => {
|
|
1418
|
+
if (isBuilding && buildPromise) {
|
|
1419
|
+
await buildPromise;
|
|
1420
|
+
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
const timeSinceLastBuild = Date.now() - lastBuildTime;
|
|
1424
|
+
if (timeSinceLastBuild < 500) {
|
|
1425
|
+
await new Promise((resolve3) => setTimeout(resolve3, 200));
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
return Promise.resolve();
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1386
1431
|
}
|
|
1387
1432
|
function buildClientBundle(projectRoot) {
|
|
1388
1433
|
const { config, outDir } = createClientConfig(projectRoot, "production");
|
|
@@ -3113,7 +3158,9 @@ import path14 from "path";
|
|
|
3113
3158
|
function setupHotReload({
|
|
3114
3159
|
app,
|
|
3115
3160
|
appDir,
|
|
3116
|
-
route = "/__fw/hot"
|
|
3161
|
+
route = "/__fw/hot",
|
|
3162
|
+
waitForBuild,
|
|
3163
|
+
onFileChange
|
|
3117
3164
|
}) {
|
|
3118
3165
|
const clients = /* @__PURE__ */ new Set();
|
|
3119
3166
|
app.get(route, (req, res) => {
|
|
@@ -3134,9 +3181,25 @@ data: connected
|
|
|
3134
3181
|
ignoreInitial: true,
|
|
3135
3182
|
ignored: ["**/node_modules/**", `**/${BUILD_FOLDER_NAME}/**`, "**/.git/**"]
|
|
3136
3183
|
});
|
|
3137
|
-
function broadcastReload(reason, filePath) {
|
|
3184
|
+
async function broadcastReload(reason, filePath) {
|
|
3138
3185
|
const rel = path14.relative(appDir, filePath);
|
|
3139
3186
|
console.log(`[hot-reload] ${reason}: ${rel}`);
|
|
3187
|
+
if (onFileChange) {
|
|
3188
|
+
try {
|
|
3189
|
+
await onFileChange(filePath);
|
|
3190
|
+
} catch (error) {
|
|
3191
|
+
console.warn("[hot-reload] Error in onFileChange callback:", error);
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
if (waitForBuild) {
|
|
3195
|
+
try {
|
|
3196
|
+
console.log("[hot-reload] Waiting for client bundle to finish...");
|
|
3197
|
+
await waitForBuild();
|
|
3198
|
+
console.log("[hot-reload] Client bundle ready, sending reload event");
|
|
3199
|
+
} catch (error) {
|
|
3200
|
+
console.warn("[hot-reload] Error waiting for build:", error);
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3140
3203
|
for (const res of clients) {
|
|
3141
3204
|
res.write(`event: message
|
|
3142
3205
|
data: reload:${rel}
|
|
@@ -3275,14 +3338,29 @@ function setupServer(app, options) {
|
|
|
3275
3338
|
};
|
|
3276
3339
|
};
|
|
3277
3340
|
var getRoutes = getRoutes2;
|
|
3278
|
-
|
|
3341
|
+
const { outDir, waitForBuild } = startClientBundler(projectRoot, "development");
|
|
3342
|
+
const onFileChange = async (filePath) => {
|
|
3343
|
+
const rel = path17.relative(appDir, filePath);
|
|
3344
|
+
const isPageFile = filePath.includes("page.tsx") || filePath.includes("page.ts") || filePath.includes("layout.tsx") || filePath.includes("layout.ts") || filePath.includes("_not-found") || filePath.includes("_error");
|
|
3345
|
+
const isTsFile = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
|
|
3346
|
+
if (isTsFile) {
|
|
3347
|
+
clearAppRequireCache(appDir);
|
|
3348
|
+
console.log(`[hot-reload] Cleared require cache for: ${rel}`);
|
|
3349
|
+
}
|
|
3350
|
+
if (isPageFile) {
|
|
3351
|
+
const loader = new FilesystemRouteLoader(appDir);
|
|
3352
|
+
const newRoutes = loader.loadRoutes();
|
|
3353
|
+
writeClientRoutesManifest(newRoutes, projectRoot);
|
|
3354
|
+
console.log("[hot-reload] Client routes manifest reloaded");
|
|
3355
|
+
}
|
|
3356
|
+
};
|
|
3357
|
+
setupHotReload({ app, appDir, waitForBuild, onFileChange });
|
|
3358
|
+
app.use("/static", express.static(outDir));
|
|
3279
3359
|
const routes = routeLoader.loadRoutes();
|
|
3280
3360
|
const wssRoutes = routeLoader.loadWssRoutes();
|
|
3281
3361
|
const notFoundPage = routeLoader.loadNotFoundRoute();
|
|
3282
3362
|
const errorPage = routeLoader.loadErrorRoute();
|
|
3283
3363
|
writeClientRoutesManifest(routes, projectRoot);
|
|
3284
|
-
const { outDir } = startClientBundler(projectRoot);
|
|
3285
|
-
app.use("/static", express.static(outDir));
|
|
3286
3364
|
return {
|
|
3287
3365
|
routes,
|
|
3288
3366
|
wssRoutes,
|
|
@@ -3980,7 +4058,7 @@ async function handlePageRequest(options) {
|
|
|
3980
4058
|
const { errorPage, req, res, routeChunks, theme, projectRoot } = options;
|
|
3981
4059
|
const reqLogger = getRequestLogger(req);
|
|
3982
4060
|
if (errorPage) {
|
|
3983
|
-
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot);
|
|
4061
|
+
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env);
|
|
3984
4062
|
} else {
|
|
3985
4063
|
reqLogger.error("Unhandled error in page request", error, {
|
|
3986
4064
|
urlPath: options.urlPath,
|
|
@@ -4008,9 +4086,9 @@ async function handlePageRequestInternal(options) {
|
|
|
4008
4086
|
theme,
|
|
4009
4087
|
projectRoot
|
|
4010
4088
|
} = options;
|
|
4011
|
-
const clientJsPath = projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
|
|
4012
|
-
const clientCssPath = projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
|
|
4013
|
-
const assetManifest = projectRoot ? loadAssetManifest(projectRoot) : null;
|
|
4089
|
+
const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
|
|
4090
|
+
const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
|
|
4091
|
+
const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
|
|
4014
4092
|
const isDataReq = isDataRequest(req);
|
|
4015
4093
|
if (env === "prod" && ssgOutDir) {
|
|
4016
4094
|
if (isDataReq) {
|
|
@@ -4066,7 +4144,7 @@ async function handlePageRequestInternal(options) {
|
|
|
4066
4144
|
const reqLogger = getRequestLogger(req);
|
|
4067
4145
|
reqLogger.error("SSR shell error", err, { route: "not-found" });
|
|
4068
4146
|
if (!res.headersSent && errorPage) {
|
|
4069
|
-
renderErrorPageWithStream(errorPage, req, res, err, routeChunks);
|
|
4147
|
+
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
|
|
4070
4148
|
} else if (!res.headersSent) {
|
|
4071
4149
|
res.statusCode = 500;
|
|
4072
4150
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -4113,7 +4191,7 @@ async function handlePageRequestInternal(options) {
|
|
|
4113
4191
|
return;
|
|
4114
4192
|
} else {
|
|
4115
4193
|
if (errorPage) {
|
|
4116
|
-
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot);
|
|
4194
|
+
await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env);
|
|
4117
4195
|
return;
|
|
4118
4196
|
} else {
|
|
4119
4197
|
throw error;
|
|
@@ -4175,7 +4253,7 @@ async function handlePageRequestInternal(options) {
|
|
|
4175
4253
|
const reqLogger = getRequestLogger(req);
|
|
4176
4254
|
reqLogger.error("SSR shell error", err, { route: matched?.route?.pattern || "unknown" });
|
|
4177
4255
|
if (!res.headersSent && errorPage) {
|
|
4178
|
-
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot);
|
|
4256
|
+
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
|
|
4179
4257
|
} else if (!res.headersSent) {
|
|
4180
4258
|
res.statusCode = 500;
|
|
4181
4259
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -4193,7 +4271,7 @@ async function handlePageRequestInternal(options) {
|
|
|
4193
4271
|
abort();
|
|
4194
4272
|
});
|
|
4195
4273
|
}
|
|
4196
|
-
async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot) {
|
|
4274
|
+
async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev") {
|
|
4197
4275
|
try {
|
|
4198
4276
|
const isDataReq = isDataRequest(req);
|
|
4199
4277
|
const ctx = {
|
|
@@ -4222,9 +4300,9 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
4222
4300
|
return;
|
|
4223
4301
|
}
|
|
4224
4302
|
const appTree = buildAppTree(errorPage, { error: String(error) }, initialData.props);
|
|
4225
|
-
const clientJsPath = projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
|
|
4226
|
-
const clientCssPath = projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
|
|
4227
|
-
const assetManifest = projectRoot ? loadAssetManifest(projectRoot) : null;
|
|
4303
|
+
const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
|
|
4304
|
+
const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
|
|
4305
|
+
const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
|
|
4228
4306
|
const chunkName = routeChunks[ERROR_CHUNK_KEY];
|
|
4229
4307
|
let chunkHref = null;
|
|
4230
4308
|
if (chunkName != null) {
|
|
@@ -5099,11 +5177,6 @@ import { useEffect, useState, useRef } from "react";
|
|
|
5099
5177
|
// modules/runtime/client/RouterView.tsx
|
|
5100
5178
|
import { jsx } from "react/jsx-runtime";
|
|
5101
5179
|
function RouterView({ state }) {
|
|
5102
|
-
console.log("[loly:RouterView] Rendering", {
|
|
5103
|
-
url: state.url,
|
|
5104
|
-
hasRoute: !!state.route,
|
|
5105
|
-
hasComponents: !!state.components
|
|
5106
|
-
});
|
|
5107
5180
|
if (!state.route) {
|
|
5108
5181
|
if (state.components === null) {
|
|
5109
5182
|
return null;
|
|
@@ -5115,11 +5188,6 @@ function RouterView({ state }) {
|
|
|
5115
5188
|
}
|
|
5116
5189
|
const { Page, layouts } = state.components;
|
|
5117
5190
|
const { params, props } = state;
|
|
5118
|
-
console.log("[loly:RouterView] Creating page element", {
|
|
5119
|
-
hasPage: !!Page,
|
|
5120
|
-
layoutsCount: layouts.length,
|
|
5121
|
-
paramsKeys: Object.keys(params)
|
|
5122
|
-
});
|
|
5123
5191
|
let element = /* @__PURE__ */ jsx(Page, { params, ...props });
|
|
5124
5192
|
const layoutChain = layouts.slice().reverse();
|
|
5125
5193
|
for (const Layout of layoutChain) {
|
|
@@ -5425,7 +5493,6 @@ async function navigate(nextUrl, handlers, options) {
|
|
|
5425
5493
|
revalidate: options?.revalidate
|
|
5426
5494
|
});
|
|
5427
5495
|
if (json && json.error) {
|
|
5428
|
-
console.log("[client] Error detected in response:", json);
|
|
5429
5496
|
if (errorRoute) {
|
|
5430
5497
|
const handled = await handleErrorRoute(
|
|
5431
5498
|
nextUrl,
|
|
@@ -5467,50 +5534,23 @@ async function navigate(nextUrl, handlers, options) {
|
|
|
5467
5534
|
}
|
|
5468
5535
|
function createClickHandler(navigate2) {
|
|
5469
5536
|
return function handleClick(ev) {
|
|
5470
|
-
const target = ev.target;
|
|
5471
|
-
const tagName = target?.tagName.toLowerCase() || "unknown";
|
|
5472
|
-
console.log("[loly:click] Click event received", {
|
|
5473
|
-
type: ev.type,
|
|
5474
|
-
tagName,
|
|
5475
|
-
target: target?.tagName,
|
|
5476
|
-
defaultPrevented: ev.defaultPrevented,
|
|
5477
|
-
button: ev.button,
|
|
5478
|
-
clientX: ev.clientX,
|
|
5479
|
-
clientY: ev.clientY
|
|
5480
|
-
});
|
|
5481
5537
|
try {
|
|
5482
|
-
if (ev.defaultPrevented)
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
console.log("[loly:click] Not a click event, skipping", { type: ev.type });
|
|
5488
|
-
return;
|
|
5489
|
-
}
|
|
5490
|
-
if (ev.button !== 0) {
|
|
5491
|
-
console.log("[loly:click] Not left button, skipping", { button: ev.button });
|
|
5492
|
-
return;
|
|
5493
|
-
}
|
|
5494
|
-
if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) {
|
|
5495
|
-
console.log("[loly:click] Modifier keys pressed, skipping");
|
|
5496
|
-
return;
|
|
5497
|
-
}
|
|
5538
|
+
if (ev.defaultPrevented) return;
|
|
5539
|
+
if (ev.type !== "click") return;
|
|
5540
|
+
if (ev.button !== 0) return;
|
|
5541
|
+
if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;
|
|
5542
|
+
const target = ev.target;
|
|
5498
5543
|
if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {
|
|
5499
5544
|
if (target) {
|
|
5500
|
-
const
|
|
5501
|
-
if (
|
|
5502
|
-
console.log("[loly:click] Synthetic event on interactive element, skipping", { tagName: tagName3 });
|
|
5545
|
+
const tagName2 = target.tagName.toLowerCase();
|
|
5546
|
+
if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select") {
|
|
5503
5547
|
return;
|
|
5504
5548
|
}
|
|
5505
5549
|
}
|
|
5506
5550
|
}
|
|
5507
|
-
if (!target)
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
}
|
|
5511
|
-
const tagName2 = target.tagName.toLowerCase();
|
|
5512
|
-
if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
|
|
5513
|
-
console.log("[loly:click] Target is interactive element, skipping", { tagName: tagName2 });
|
|
5551
|
+
if (!target) return;
|
|
5552
|
+
const tagName = target.tagName.toLowerCase();
|
|
5553
|
+
if (tagName === "input" || tagName === "textarea" || tagName === "button" || tagName === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
|
|
5514
5554
|
return;
|
|
5515
5555
|
}
|
|
5516
5556
|
const interactiveParent = target.closest("input, textarea, button, select, [contenteditable], label");
|
|
@@ -5518,60 +5558,29 @@ function createClickHandler(navigate2) {
|
|
|
5518
5558
|
if (interactiveParent.tagName.toLowerCase() === "label") {
|
|
5519
5559
|
const label = interactiveParent;
|
|
5520
5560
|
if (label.control) {
|
|
5521
|
-
console.log("[loly:click] Inside label with control, skipping");
|
|
5522
5561
|
return;
|
|
5523
5562
|
}
|
|
5524
5563
|
} else {
|
|
5525
|
-
console.log("[loly:click] Inside interactive parent, skipping", {
|
|
5526
|
-
parentTag: interactiveParent.tagName.toLowerCase()
|
|
5527
|
-
});
|
|
5528
5564
|
return;
|
|
5529
5565
|
}
|
|
5530
5566
|
}
|
|
5531
5567
|
const anchor = target.closest("a[href]");
|
|
5532
|
-
if (!anchor)
|
|
5533
|
-
console.log("[loly:click] No anchor found, skipping");
|
|
5534
|
-
return;
|
|
5535
|
-
}
|
|
5536
|
-
console.log("[loly:click] Anchor found, processing navigation", {
|
|
5537
|
-
href: anchor.getAttribute("href")
|
|
5538
|
-
});
|
|
5568
|
+
if (!anchor) return;
|
|
5539
5569
|
const href = anchor.getAttribute("href");
|
|
5540
|
-
if (!href)
|
|
5541
|
-
|
|
5542
|
-
return;
|
|
5543
|
-
}
|
|
5544
|
-
if (href.startsWith("#")) {
|
|
5545
|
-
console.log("[loly:click] Hash link, skipping");
|
|
5546
|
-
return;
|
|
5547
|
-
}
|
|
5570
|
+
if (!href) return;
|
|
5571
|
+
if (href.startsWith("#")) return;
|
|
5548
5572
|
const url = new URL(href, window.location.href);
|
|
5549
|
-
if (url.origin !== window.location.origin)
|
|
5550
|
-
|
|
5551
|
-
return;
|
|
5552
|
-
}
|
|
5553
|
-
if (anchor.target && anchor.target !== "_self") {
|
|
5554
|
-
console.log("[loly:click] Link has target, skipping", { target: anchor.target });
|
|
5555
|
-
return;
|
|
5556
|
-
}
|
|
5573
|
+
if (url.origin !== window.location.origin) return;
|
|
5574
|
+
if (anchor.target && anchor.target !== "_self") return;
|
|
5557
5575
|
ev.preventDefault();
|
|
5558
|
-
console.log("[loly:click] Prevented default, navigating");
|
|
5559
5576
|
const nextUrl = url.pathname + url.search;
|
|
5560
5577
|
const currentUrl = window.location.pathname + window.location.search;
|
|
5561
|
-
if (nextUrl === currentUrl)
|
|
5562
|
-
console.log("[loly:click] Same URL, skipping", { nextUrl });
|
|
5563
|
-
return;
|
|
5564
|
-
}
|
|
5578
|
+
if (nextUrl === currentUrl) return;
|
|
5565
5579
|
const shouldRevalidate = anchor.hasAttribute("data-revalidate") && anchor.getAttribute("data-revalidate") !== "false";
|
|
5566
|
-
console.log("[loly:click] Pushing state and navigating", {
|
|
5567
|
-
nextUrl,
|
|
5568
|
-
currentUrl,
|
|
5569
|
-
shouldRevalidate
|
|
5570
|
-
});
|
|
5571
5580
|
window.history.pushState({}, "", nextUrl);
|
|
5572
5581
|
navigate2(nextUrl, shouldRevalidate ? { revalidate: true } : void 0);
|
|
5573
5582
|
} catch (error) {
|
|
5574
|
-
console.error("[
|
|
5583
|
+
console.error("[navigation] Error in click handler:", error);
|
|
5575
5584
|
}
|
|
5576
5585
|
};
|
|
5577
5586
|
}
|
|
@@ -5590,10 +5599,6 @@ function AppShell({
|
|
|
5590
5599
|
notFoundRoute,
|
|
5591
5600
|
errorRoute
|
|
5592
5601
|
}) {
|
|
5593
|
-
console.log("[loly:AppShell] Component rendering", {
|
|
5594
|
-
url: initialState.url,
|
|
5595
|
-
hasRoute: !!initialState.route
|
|
5596
|
-
});
|
|
5597
5602
|
const [state, setState] = useState(initialState);
|
|
5598
5603
|
const handlersRef = useRef({
|
|
5599
5604
|
setState,
|
|
@@ -5602,11 +5607,6 @@ function AppShell({
|
|
|
5602
5607
|
errorRoute
|
|
5603
5608
|
});
|
|
5604
5609
|
useEffect(() => {
|
|
5605
|
-
console.log("[loly:AppShell] Updating handlersRef", {
|
|
5606
|
-
routesCount: routes.length,
|
|
5607
|
-
hasNotFound: !!notFoundRoute,
|
|
5608
|
-
hasError: !!errorRoute
|
|
5609
|
-
});
|
|
5610
5610
|
handlersRef.current = {
|
|
5611
5611
|
setState,
|
|
5612
5612
|
routes,
|
|
@@ -5615,34 +5615,16 @@ function AppShell({
|
|
|
5615
5615
|
};
|
|
5616
5616
|
}, [routes, notFoundRoute, errorRoute]);
|
|
5617
5617
|
useEffect(() => {
|
|
5618
|
-
const effectId = Math.random().toString(36).substring(7);
|
|
5619
|
-
console.log("[loly:AppShell] Setting up event listeners", { effectId });
|
|
5620
5618
|
let isMounted = true;
|
|
5621
|
-
let listenerCount = 0;
|
|
5622
5619
|
async function handleNavigate(nextUrl, options) {
|
|
5623
|
-
if (!isMounted)
|
|
5624
|
-
console.warn("[loly:AppShell] navigate called but component is unmounted");
|
|
5625
|
-
return;
|
|
5626
|
-
}
|
|
5627
|
-
console.log("[loly:AppShell] Navigating to", nextUrl, options);
|
|
5620
|
+
if (!isMounted) return;
|
|
5628
5621
|
await navigate(nextUrl, handlersRef.current, options);
|
|
5629
5622
|
}
|
|
5630
5623
|
const handleClick = createClickHandler(handleNavigate);
|
|
5631
5624
|
const handlePopState = createPopStateHandler(handleNavigate);
|
|
5632
5625
|
window.addEventListener("click", handleClick, false);
|
|
5633
5626
|
window.addEventListener("popstate", handlePopState, false);
|
|
5634
|
-
listenerCount = 2;
|
|
5635
|
-
console.log("[loly:AppShell] Event listeners added", {
|
|
5636
|
-
clickListener: true,
|
|
5637
|
-
popStateListener: true,
|
|
5638
|
-
totalListeners: listenerCount
|
|
5639
|
-
});
|
|
5640
5627
|
return () => {
|
|
5641
|
-
console.log("[loly:AppShell] Cleaning up event listeners", {
|
|
5642
|
-
effectId,
|
|
5643
|
-
wasMounted: isMounted,
|
|
5644
|
-
listenersToRemove: listenerCount
|
|
5645
|
-
});
|
|
5646
5628
|
isMounted = false;
|
|
5647
5629
|
window.removeEventListener("click", handleClick, false);
|
|
5648
5630
|
window.removeEventListener("popstate", handlePopState, false);
|
|
@@ -5657,7 +5639,6 @@ function AppShell({
|
|
|
5657
5639
|
|
|
5658
5640
|
// modules/runtime/client/bootstrap.tsx
|
|
5659
5641
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
5660
|
-
var __loly_hydrated = false;
|
|
5661
5642
|
async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute, errorRoute) {
|
|
5662
5643
|
const isInitialNotFound = initialData?.notFound === true;
|
|
5663
5644
|
const isInitialError = initialData?.error === true;
|
|
@@ -5684,7 +5665,7 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
|
|
|
5684
5665
|
initialComponents = await notFoundRoute.load();
|
|
5685
5666
|
} else {
|
|
5686
5667
|
console.warn(
|
|
5687
|
-
`[client] No route match found for ${initialUrl}.
|
|
5668
|
+
`[client] No route match found for ${initialUrl}. Available routes:`,
|
|
5688
5669
|
routes.map((r) => r.pattern)
|
|
5689
5670
|
);
|
|
5690
5671
|
}
|
|
@@ -5697,29 +5678,57 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
|
|
|
5697
5678
|
props: initialData?.props ?? {}
|
|
5698
5679
|
};
|
|
5699
5680
|
}
|
|
5700
|
-
function
|
|
5701
|
-
|
|
5702
|
-
console.
|
|
5703
|
-
|
|
5681
|
+
function setupHotReload2() {
|
|
5682
|
+
try {
|
|
5683
|
+
console.log("[hot-reload] Attempting to connect to /__fw/hot...");
|
|
5684
|
+
const eventSource = new EventSource("/__fw/hot");
|
|
5685
|
+
let reloadTimeout = null;
|
|
5686
|
+
eventSource.addEventListener("message", (event) => {
|
|
5687
|
+
const data = event.data;
|
|
5688
|
+
if (data && data.startsWith("reload:")) {
|
|
5689
|
+
const filePath = data.slice(7);
|
|
5690
|
+
console.log(`[hot-reload] File changed: ${filePath}`);
|
|
5691
|
+
if (reloadTimeout) {
|
|
5692
|
+
clearTimeout(reloadTimeout);
|
|
5693
|
+
}
|
|
5694
|
+
reloadTimeout = setTimeout(() => {
|
|
5695
|
+
console.log("[hot-reload] Reloading page...");
|
|
5696
|
+
window.location.reload();
|
|
5697
|
+
}, 500);
|
|
5698
|
+
}
|
|
5699
|
+
});
|
|
5700
|
+
eventSource.addEventListener("ping", () => {
|
|
5701
|
+
console.log("[hot-reload] \u2713 Connected to hot reload server");
|
|
5702
|
+
});
|
|
5703
|
+
eventSource.onopen = () => {
|
|
5704
|
+
console.log("[hot-reload] \u2713 SSE connection opened");
|
|
5705
|
+
};
|
|
5706
|
+
eventSource.onerror = (error) => {
|
|
5707
|
+
const states = ["CONNECTING", "OPEN", "CLOSED"];
|
|
5708
|
+
const state = states[eventSource.readyState] || "UNKNOWN";
|
|
5709
|
+
if (eventSource.readyState === EventSource.CONNECTING) {
|
|
5710
|
+
console.log("[hot-reload] Connecting...");
|
|
5711
|
+
} else if (eventSource.readyState === EventSource.OPEN) {
|
|
5712
|
+
console.warn("[hot-reload] Connection error (but connection is open):", error);
|
|
5713
|
+
} else {
|
|
5714
|
+
console.log("[hot-reload] Connection closed (readyState:", state, ")");
|
|
5715
|
+
}
|
|
5716
|
+
};
|
|
5717
|
+
} catch (error) {
|
|
5718
|
+
console.log("[hot-reload] EventSource not supported or error:", error);
|
|
5704
5719
|
}
|
|
5705
|
-
|
|
5706
|
-
|
|
5720
|
+
}
|
|
5721
|
+
function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
|
|
5722
|
+
console.log("[client] Bootstrap starting, setting up hot reload...");
|
|
5723
|
+
setupHotReload2();
|
|
5707
5724
|
(async function bootstrap() {
|
|
5708
5725
|
const container = document.getElementById(APP_CONTAINER_ID2);
|
|
5709
5726
|
const initialData = getWindowData();
|
|
5710
|
-
console.log("[loly:runtime] bootstrap starting", {
|
|
5711
|
-
hasContainer: !!container,
|
|
5712
|
-
hasInitialData: !!initialData,
|
|
5713
|
-
containerId: APP_CONTAINER_ID2
|
|
5714
|
-
});
|
|
5715
5727
|
if (!container) {
|
|
5716
|
-
console.error(
|
|
5717
|
-
`[loly:runtime] Container #${APP_CONTAINER_ID2} not found.`
|
|
5718
|
-
);
|
|
5728
|
+
console.error(`Container #${APP_CONTAINER_ID2} not found for hydration`);
|
|
5719
5729
|
return;
|
|
5720
5730
|
}
|
|
5721
5731
|
const initialUrl = window.location.pathname + window.location.search;
|
|
5722
|
-
console.log("[loly:runtime] Loading initial route", { initialUrl });
|
|
5723
5732
|
try {
|
|
5724
5733
|
const initialState = await loadInitialRoute(
|
|
5725
5734
|
initialUrl,
|
|
@@ -5728,15 +5737,9 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
|
|
|
5728
5737
|
notFoundRoute,
|
|
5729
5738
|
errorRoute
|
|
5730
5739
|
);
|
|
5731
|
-
console.log("[loly:runtime] Initial route loaded", {
|
|
5732
|
-
url: initialState.url,
|
|
5733
|
-
hasRoute: !!initialState.route,
|
|
5734
|
-
hasComponents: !!initialState.components
|
|
5735
|
-
});
|
|
5736
5740
|
if (initialData?.metadata) {
|
|
5737
5741
|
applyMetadata(initialData.metadata);
|
|
5738
5742
|
}
|
|
5739
|
-
console.log("[loly:runtime] Hydrating React app");
|
|
5740
5743
|
hydrateRoot(
|
|
5741
5744
|
container,
|
|
5742
5745
|
/* @__PURE__ */ jsx3(
|
|
@@ -5749,9 +5752,12 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
|
|
|
5749
5752
|
}
|
|
5750
5753
|
)
|
|
5751
5754
|
);
|
|
5752
|
-
console.log("[loly:runtime] Hydrated successfully");
|
|
5753
5755
|
} catch (error) {
|
|
5754
|
-
console.error(
|
|
5756
|
+
console.error(
|
|
5757
|
+
"[client] Error loading initial route components for",
|
|
5758
|
+
initialUrl,
|
|
5759
|
+
error
|
|
5760
|
+
);
|
|
5755
5761
|
window.location.reload();
|
|
5756
5762
|
}
|
|
5757
5763
|
})();
|