@lolyjs/core 0.1.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 +607 -0
- package/bin/loly.cjs +6 -0
- package/dist/bootstrap-BiCQmSkx.d.mts +50 -0
- package/dist/bootstrap-BiCQmSkx.d.ts +50 -0
- package/dist/cli.cjs +5186 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +5181 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +5774 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +445 -0
- package/dist/index.d.ts +445 -0
- package/dist/index.js +5731 -0
- package/dist/index.js.map +1 -0
- package/dist/react/cache.cjs +251 -0
- package/dist/react/cache.cjs.map +1 -0
- package/dist/react/cache.d.mts +59 -0
- package/dist/react/cache.d.ts +59 -0
- package/dist/react/cache.js +220 -0
- package/dist/react/cache.js.map +1 -0
- package/dist/react/components.cjs +218 -0
- package/dist/react/components.cjs.map +1 -0
- package/dist/react/components.d.mts +26 -0
- package/dist/react/components.d.ts +26 -0
- package/dist/react/components.js +190 -0
- package/dist/react/components.js.map +1 -0
- package/dist/react/hooks.cjs +86 -0
- package/dist/react/hooks.cjs.map +1 -0
- package/dist/react/hooks.d.mts +19 -0
- package/dist/react/hooks.d.ts +19 -0
- package/dist/react/hooks.js +58 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react/sockets.cjs +43 -0
- package/dist/react/sockets.cjs.map +1 -0
- package/dist/react/sockets.d.mts +29 -0
- package/dist/react/sockets.d.ts +29 -0
- package/dist/react/sockets.js +18 -0
- package/dist/react/sockets.js.map +1 -0
- package/dist/react/themes.cjs +145 -0
- package/dist/react/themes.cjs.map +1 -0
- package/dist/react/themes.d.mts +13 -0
- package/dist/react/themes.d.ts +13 -0
- package/dist/react/themes.js +117 -0
- package/dist/react/themes.js.map +1 -0
- package/dist/runtime.cjs +626 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.mts +11 -0
- package/dist/runtime.d.ts +11 -0
- package/dist/runtime.js +599 -0
- package/dist/runtime.js.map +1 -0
- package/package.json +101 -0
package/dist/runtime.cjs
ADDED
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// modules/runtime/client/index.tsx
|
|
21
|
+
var client_exports = {};
|
|
22
|
+
__export(client_exports, {
|
|
23
|
+
bootstrapClient: () => bootstrapClient
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(client_exports);
|
|
26
|
+
|
|
27
|
+
// modules/runtime/client/bootstrap.tsx
|
|
28
|
+
var import_client = require("react-dom/client");
|
|
29
|
+
|
|
30
|
+
// modules/runtime/client/constants.ts
|
|
31
|
+
var WINDOW_DATA_KEY = "__FW_DATA__";
|
|
32
|
+
var APP_CONTAINER_ID = "__app";
|
|
33
|
+
|
|
34
|
+
// modules/runtime/client/window-data.ts
|
|
35
|
+
function getWindowData() {
|
|
36
|
+
return window[WINDOW_DATA_KEY] ?? null;
|
|
37
|
+
}
|
|
38
|
+
function setWindowData(data) {
|
|
39
|
+
window[WINDOW_DATA_KEY] = data;
|
|
40
|
+
if (typeof window !== "undefined") {
|
|
41
|
+
window.dispatchEvent(
|
|
42
|
+
new CustomEvent("fw-data-refresh", {
|
|
43
|
+
detail: { data }
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function getCurrentTheme() {
|
|
49
|
+
return getWindowData()?.theme ?? null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// modules/runtime/client/route-matcher.ts
|
|
53
|
+
function buildClientRegexFromPattern(pattern) {
|
|
54
|
+
const segments = pattern.split("/").filter(Boolean);
|
|
55
|
+
const regexParts = [];
|
|
56
|
+
for (let i = 0; i < segments.length; i++) {
|
|
57
|
+
const seg = segments[i];
|
|
58
|
+
if (seg.startsWith("[...") && seg.endsWith("]")) {
|
|
59
|
+
if (i !== segments.length - 1) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Catch-all segment "${seg}" in "${pattern}" must be the last segment.`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
regexParts.push("(.+)");
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (seg.startsWith("[") && seg.endsWith("]")) {
|
|
68
|
+
regexParts.push("([^/]+)");
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const escaped = seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
72
|
+
regexParts.push(escaped);
|
|
73
|
+
}
|
|
74
|
+
const regexSource = "^/" + regexParts.join("/") + "/?$";
|
|
75
|
+
return new RegExp(regexSource);
|
|
76
|
+
}
|
|
77
|
+
function matchRouteClient(pathWithSearch, routes) {
|
|
78
|
+
const [pathname] = pathWithSearch.split("?");
|
|
79
|
+
for (const r of routes) {
|
|
80
|
+
const regex = buildClientRegexFromPattern(r.pattern);
|
|
81
|
+
const match = regex.exec(pathname);
|
|
82
|
+
if (!match) continue;
|
|
83
|
+
const params = {};
|
|
84
|
+
r.paramNames.forEach((name, idx) => {
|
|
85
|
+
params[name] = decodeURIComponent(match[idx + 1] || "");
|
|
86
|
+
});
|
|
87
|
+
return { route: r, params };
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// modules/runtime/client/metadata.ts
|
|
93
|
+
function applyMetadata(md) {
|
|
94
|
+
if (!md) return;
|
|
95
|
+
if (md.title) {
|
|
96
|
+
document.title = md.title;
|
|
97
|
+
}
|
|
98
|
+
if (md.description) {
|
|
99
|
+
let meta = document.querySelector(
|
|
100
|
+
'meta[name="description"]'
|
|
101
|
+
);
|
|
102
|
+
if (!meta) {
|
|
103
|
+
meta = document.createElement("meta");
|
|
104
|
+
meta.name = "description";
|
|
105
|
+
document.head.appendChild(meta);
|
|
106
|
+
}
|
|
107
|
+
meta.content = md.description;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// modules/runtime/client/AppShell.tsx
|
|
112
|
+
var import_react = require("react");
|
|
113
|
+
|
|
114
|
+
// modules/runtime/client/RouterView.tsx
|
|
115
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
116
|
+
function RouterView({ state }) {
|
|
117
|
+
if (!state.route) {
|
|
118
|
+
if (state.components === null) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: "404 - Route not found" });
|
|
122
|
+
}
|
|
123
|
+
if (!state.components) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const { Page, layouts } = state.components;
|
|
127
|
+
const { params, props } = state;
|
|
128
|
+
let element = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Page, { params, ...props });
|
|
129
|
+
const layoutChain = layouts.slice().reverse();
|
|
130
|
+
for (const Layout of layoutChain) {
|
|
131
|
+
element = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Layout, { params, ...props, children: element });
|
|
132
|
+
}
|
|
133
|
+
return element;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// modules/react/cache/client-data-cache/index.ts
|
|
137
|
+
var CACHE_KEY = "__FW_DATA_CACHE__";
|
|
138
|
+
var MAX_CACHE_SIZE = 100;
|
|
139
|
+
function getCacheStore() {
|
|
140
|
+
if (typeof window !== "undefined") {
|
|
141
|
+
if (!window[CACHE_KEY]) {
|
|
142
|
+
window[CACHE_KEY] = {
|
|
143
|
+
data: /* @__PURE__ */ new Map(),
|
|
144
|
+
index: /* @__PURE__ */ new Map(),
|
|
145
|
+
lru: []
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return window[CACHE_KEY];
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
data: /* @__PURE__ */ new Map(),
|
|
152
|
+
index: /* @__PURE__ */ new Map(),
|
|
153
|
+
lru: []
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
var cacheStore = getCacheStore();
|
|
157
|
+
var dataCache = cacheStore.data;
|
|
158
|
+
var pathIndex = cacheStore.index;
|
|
159
|
+
var lru = cacheStore.lru;
|
|
160
|
+
function extractPathBase(key) {
|
|
161
|
+
return key.split("?")[0];
|
|
162
|
+
}
|
|
163
|
+
function addToIndex(key) {
|
|
164
|
+
const pathBase = extractPathBase(key);
|
|
165
|
+
if (!pathIndex.has(pathBase)) {
|
|
166
|
+
pathIndex.set(pathBase, /* @__PURE__ */ new Set());
|
|
167
|
+
}
|
|
168
|
+
pathIndex.get(pathBase).add(key);
|
|
169
|
+
}
|
|
170
|
+
function removeFromIndex(key) {
|
|
171
|
+
const pathBase = extractPathBase(key);
|
|
172
|
+
const keys = pathIndex.get(pathBase);
|
|
173
|
+
if (keys) {
|
|
174
|
+
keys.delete(key);
|
|
175
|
+
if (keys.size === 0) {
|
|
176
|
+
pathIndex.delete(pathBase);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function updateLRU(key) {
|
|
181
|
+
const index = lru.indexOf(key);
|
|
182
|
+
if (index !== -1) {
|
|
183
|
+
lru.splice(index, 1);
|
|
184
|
+
}
|
|
185
|
+
lru.push(key);
|
|
186
|
+
}
|
|
187
|
+
function evictOldest() {
|
|
188
|
+
while (lru.length >= MAX_CACHE_SIZE && lru.length > 0) {
|
|
189
|
+
const oldestKey = lru.shift();
|
|
190
|
+
dataCache.delete(oldestKey);
|
|
191
|
+
removeFromIndex(oldestKey);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function setCacheEntry(key, entry) {
|
|
195
|
+
const existingEntry = dataCache.get(key);
|
|
196
|
+
const wasFulfilled = existingEntry?.status === "fulfilled";
|
|
197
|
+
dataCache.set(key, entry);
|
|
198
|
+
if (entry.status === "fulfilled") {
|
|
199
|
+
if (!wasFulfilled) {
|
|
200
|
+
addToIndex(key);
|
|
201
|
+
}
|
|
202
|
+
updateLRU(key);
|
|
203
|
+
evictOldest();
|
|
204
|
+
} else if (wasFulfilled) {
|
|
205
|
+
removeFromIndex(key);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function deleteCacheEntry(key) {
|
|
209
|
+
if (dataCache.has(key)) {
|
|
210
|
+
dataCache.delete(key);
|
|
211
|
+
removeFromIndex(key);
|
|
212
|
+
const lruIndex = lru.indexOf(key);
|
|
213
|
+
if (lruIndex !== -1) {
|
|
214
|
+
lru.splice(lruIndex, 1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function buildDataUrl(url) {
|
|
219
|
+
return url + (url.includes("?") ? "&" : "?") + "__fw_data=1";
|
|
220
|
+
}
|
|
221
|
+
async function fetchRouteDataOnce(url) {
|
|
222
|
+
const dataUrl = buildDataUrl(url);
|
|
223
|
+
const res = await fetch(dataUrl, {
|
|
224
|
+
headers: {
|
|
225
|
+
"x-fw-data": "1",
|
|
226
|
+
Accept: "application/json"
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
let json = {};
|
|
230
|
+
try {
|
|
231
|
+
const text = await res.text();
|
|
232
|
+
if (text) {
|
|
233
|
+
json = JSON.parse(text);
|
|
234
|
+
}
|
|
235
|
+
} catch (parseError) {
|
|
236
|
+
console.error(
|
|
237
|
+
"[client][cache] Failed to parse response as JSON:",
|
|
238
|
+
parseError
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
const result = {
|
|
242
|
+
ok: res.ok,
|
|
243
|
+
status: res.status,
|
|
244
|
+
json
|
|
245
|
+
};
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
async function getRouteData(url, options) {
|
|
249
|
+
const key = buildDataUrl(url);
|
|
250
|
+
if (options?.revalidate) {
|
|
251
|
+
deleteCacheEntry(key);
|
|
252
|
+
}
|
|
253
|
+
const entry = dataCache.get(key);
|
|
254
|
+
if (entry) {
|
|
255
|
+
if (entry.status === "fulfilled") {
|
|
256
|
+
updateLRU(key);
|
|
257
|
+
return entry.value;
|
|
258
|
+
}
|
|
259
|
+
if (entry.status === "pending") {
|
|
260
|
+
return entry.promise;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const promise = fetchRouteDataOnce(url).then((value) => {
|
|
264
|
+
setCacheEntry(key, { status: "fulfilled", value });
|
|
265
|
+
return value;
|
|
266
|
+
}).catch((error) => {
|
|
267
|
+
console.error("[client][cache] Error fetching route data:", error);
|
|
268
|
+
dataCache.set(key, { status: "rejected", error });
|
|
269
|
+
throw error;
|
|
270
|
+
});
|
|
271
|
+
dataCache.set(key, { status: "pending", promise });
|
|
272
|
+
return promise;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// modules/runtime/client/navigation.ts
|
|
276
|
+
async function handleErrorRoute(nextUrl, json, errorRoute, setState) {
|
|
277
|
+
try {
|
|
278
|
+
const components = await errorRoute.load();
|
|
279
|
+
let theme = "light";
|
|
280
|
+
if (typeof document !== "undefined") {
|
|
281
|
+
const cookieMatch = document.cookie.match(/theme=([^;]+)/);
|
|
282
|
+
if (cookieMatch) {
|
|
283
|
+
theme = cookieMatch[1];
|
|
284
|
+
} else if (json.theme) {
|
|
285
|
+
theme = json.theme;
|
|
286
|
+
} else {
|
|
287
|
+
const currentTheme = getCurrentTheme();
|
|
288
|
+
if (currentTheme) theme = currentTheme;
|
|
289
|
+
}
|
|
290
|
+
} else if (json.theme) {
|
|
291
|
+
theme = json.theme;
|
|
292
|
+
}
|
|
293
|
+
const errorProps = {
|
|
294
|
+
...json.props || {
|
|
295
|
+
error: json.message || "An error occurred"
|
|
296
|
+
},
|
|
297
|
+
theme
|
|
298
|
+
};
|
|
299
|
+
const windowData = {
|
|
300
|
+
pathname: nextUrl,
|
|
301
|
+
params: json.params || {},
|
|
302
|
+
props: errorProps,
|
|
303
|
+
metadata: json.metadata ?? null,
|
|
304
|
+
theme,
|
|
305
|
+
notFound: false,
|
|
306
|
+
error: true
|
|
307
|
+
};
|
|
308
|
+
setWindowData(windowData);
|
|
309
|
+
setState({
|
|
310
|
+
url: nextUrl,
|
|
311
|
+
route: errorRoute,
|
|
312
|
+
params: json.params || {},
|
|
313
|
+
components,
|
|
314
|
+
props: errorProps
|
|
315
|
+
});
|
|
316
|
+
return true;
|
|
317
|
+
} catch (loadError) {
|
|
318
|
+
console.error(
|
|
319
|
+
"[client] Error loading error route components:",
|
|
320
|
+
loadError
|
|
321
|
+
);
|
|
322
|
+
window.location.href = nextUrl;
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async function handleNotFoundRoute(nextUrl, json, notFoundRoute, setState) {
|
|
327
|
+
let theme = "light";
|
|
328
|
+
if (typeof document !== "undefined") {
|
|
329
|
+
const cookieMatch = document.cookie.match(/theme=([^;]+)/);
|
|
330
|
+
if (cookieMatch) {
|
|
331
|
+
theme = cookieMatch[1];
|
|
332
|
+
} else if (json.theme) {
|
|
333
|
+
theme = json.theme;
|
|
334
|
+
} else {
|
|
335
|
+
const currentTheme = getCurrentTheme();
|
|
336
|
+
if (currentTheme) theme = currentTheme;
|
|
337
|
+
}
|
|
338
|
+
} else if (json.theme) {
|
|
339
|
+
theme = json.theme;
|
|
340
|
+
}
|
|
341
|
+
const notFoundProps = {
|
|
342
|
+
...json.props ?? {},
|
|
343
|
+
theme
|
|
344
|
+
};
|
|
345
|
+
const windowData = {
|
|
346
|
+
pathname: nextUrl,
|
|
347
|
+
params: {},
|
|
348
|
+
props: notFoundProps,
|
|
349
|
+
metadata: json.metadata ?? null,
|
|
350
|
+
theme,
|
|
351
|
+
notFound: true,
|
|
352
|
+
error: false
|
|
353
|
+
};
|
|
354
|
+
setWindowData(windowData);
|
|
355
|
+
if (notFoundRoute) {
|
|
356
|
+
const components = await notFoundRoute.load();
|
|
357
|
+
setState({
|
|
358
|
+
url: nextUrl,
|
|
359
|
+
route: notFoundRoute,
|
|
360
|
+
params: {},
|
|
361
|
+
components,
|
|
362
|
+
props: notFoundProps
|
|
363
|
+
});
|
|
364
|
+
} else {
|
|
365
|
+
setState({
|
|
366
|
+
url: nextUrl,
|
|
367
|
+
route: null,
|
|
368
|
+
params: {},
|
|
369
|
+
components: null,
|
|
370
|
+
props: {}
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async function handleNormalRoute(nextUrl, json, routes, setState) {
|
|
375
|
+
applyMetadata(json.metadata ?? null);
|
|
376
|
+
let theme = "light";
|
|
377
|
+
if (typeof document !== "undefined") {
|
|
378
|
+
const cookieMatch = document.cookie.match(/theme=([^;]+)/);
|
|
379
|
+
if (cookieMatch) {
|
|
380
|
+
theme = cookieMatch[1];
|
|
381
|
+
} else if (json.theme) {
|
|
382
|
+
theme = json.theme;
|
|
383
|
+
} else {
|
|
384
|
+
const currentTheme = getCurrentTheme();
|
|
385
|
+
if (currentTheme) {
|
|
386
|
+
theme = currentTheme;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
} else if (json.theme) {
|
|
390
|
+
theme = json.theme;
|
|
391
|
+
}
|
|
392
|
+
const newProps = {
|
|
393
|
+
...json.props ?? {},
|
|
394
|
+
theme
|
|
395
|
+
// Always include theme
|
|
396
|
+
};
|
|
397
|
+
const matched = matchRouteClient(nextUrl, routes);
|
|
398
|
+
if (!matched) {
|
|
399
|
+
window.location.href = nextUrl;
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
const windowData = {
|
|
403
|
+
pathname: nextUrl,
|
|
404
|
+
params: matched.params,
|
|
405
|
+
props: newProps,
|
|
406
|
+
metadata: json.metadata ?? null,
|
|
407
|
+
theme,
|
|
408
|
+
notFound: false,
|
|
409
|
+
error: false
|
|
410
|
+
};
|
|
411
|
+
setWindowData(windowData);
|
|
412
|
+
const components = await matched.route.load();
|
|
413
|
+
window.scrollTo({
|
|
414
|
+
top: 0,
|
|
415
|
+
behavior: "smooth"
|
|
416
|
+
});
|
|
417
|
+
setState({
|
|
418
|
+
url: nextUrl,
|
|
419
|
+
route: matched.route,
|
|
420
|
+
params: matched.params,
|
|
421
|
+
components,
|
|
422
|
+
props: newProps
|
|
423
|
+
});
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
async function navigate(nextUrl, handlers, options) {
|
|
427
|
+
const { setState, routes, notFoundRoute, errorRoute } = handlers;
|
|
428
|
+
try {
|
|
429
|
+
const { ok, json } = await getRouteData(nextUrl, {
|
|
430
|
+
revalidate: options?.revalidate
|
|
431
|
+
});
|
|
432
|
+
if (json && json.error) {
|
|
433
|
+
console.log("[client] Error detected in response:", json);
|
|
434
|
+
if (errorRoute) {
|
|
435
|
+
const handled = await handleErrorRoute(
|
|
436
|
+
nextUrl,
|
|
437
|
+
json,
|
|
438
|
+
errorRoute,
|
|
439
|
+
setState
|
|
440
|
+
);
|
|
441
|
+
if (handled) return;
|
|
442
|
+
} else {
|
|
443
|
+
console.warn(
|
|
444
|
+
"[client] Error route not available, reloading page.",
|
|
445
|
+
errorRoute
|
|
446
|
+
);
|
|
447
|
+
window.location.href = nextUrl;
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (!ok) {
|
|
452
|
+
if (json && json.redirect) {
|
|
453
|
+
window.location.href = json.redirect.destination;
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
window.location.href = nextUrl;
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (json.redirect) {
|
|
460
|
+
window.location.href = json.redirect.destination;
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (json.notFound) {
|
|
464
|
+
await handleNotFoundRoute(nextUrl, json, notFoundRoute, setState);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
await handleNormalRoute(nextUrl, json, routes, setState);
|
|
468
|
+
} catch (err) {
|
|
469
|
+
console.error("[client] Error fetching FW data:", err);
|
|
470
|
+
window.location.href = nextUrl;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
function createClickHandler(navigate2) {
|
|
474
|
+
return function handleClick(ev) {
|
|
475
|
+
if (ev.defaultPrevented) return;
|
|
476
|
+
if (ev.button !== 0) return;
|
|
477
|
+
if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;
|
|
478
|
+
const target = ev.target;
|
|
479
|
+
if (!target) return;
|
|
480
|
+
const anchor = target.closest("a[href]");
|
|
481
|
+
if (!anchor) return;
|
|
482
|
+
const href = anchor.getAttribute("href");
|
|
483
|
+
if (!href) return;
|
|
484
|
+
if (href.startsWith("#")) return;
|
|
485
|
+
const url = new URL(href, window.location.href);
|
|
486
|
+
if (url.origin !== window.location.origin) return;
|
|
487
|
+
if (anchor.target && anchor.target !== "_self") return;
|
|
488
|
+
ev.preventDefault();
|
|
489
|
+
const nextUrl = url.pathname + url.search;
|
|
490
|
+
const currentUrl = window.location.pathname + window.location.search;
|
|
491
|
+
if (nextUrl === currentUrl) return;
|
|
492
|
+
const shouldRevalidate = anchor.hasAttribute("data-revalidate") && anchor.getAttribute("data-revalidate") !== "false";
|
|
493
|
+
window.history.pushState({}, "", nextUrl);
|
|
494
|
+
navigate2(nextUrl, shouldRevalidate ? { revalidate: true } : void 0);
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function createPopStateHandler(navigate2) {
|
|
498
|
+
return function handlePopState() {
|
|
499
|
+
const nextUrl = window.location.pathname + window.location.search;
|
|
500
|
+
navigate2(nextUrl);
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// modules/runtime/client/AppShell.tsx
|
|
505
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
506
|
+
function AppShell({
|
|
507
|
+
initialState,
|
|
508
|
+
routes,
|
|
509
|
+
notFoundRoute,
|
|
510
|
+
errorRoute
|
|
511
|
+
}) {
|
|
512
|
+
const [state, setState] = (0, import_react.useState)(initialState);
|
|
513
|
+
(0, import_react.useEffect)(() => {
|
|
514
|
+
const handlers = {
|
|
515
|
+
setState,
|
|
516
|
+
routes,
|
|
517
|
+
notFoundRoute,
|
|
518
|
+
errorRoute
|
|
519
|
+
};
|
|
520
|
+
async function handleNavigate(nextUrl, options) {
|
|
521
|
+
await navigate(nextUrl, handlers, options);
|
|
522
|
+
}
|
|
523
|
+
const handleClick = createClickHandler(handleNavigate);
|
|
524
|
+
const handlePopState = createPopStateHandler(handleNavigate);
|
|
525
|
+
window.addEventListener("click", handleClick);
|
|
526
|
+
window.addEventListener("popstate", handlePopState);
|
|
527
|
+
return () => {
|
|
528
|
+
window.removeEventListener("click", handleClick);
|
|
529
|
+
window.removeEventListener("popstate", handlePopState);
|
|
530
|
+
};
|
|
531
|
+
}, [routes, notFoundRoute, errorRoute]);
|
|
532
|
+
const isError = state.route === errorRoute;
|
|
533
|
+
const isNotFound = state.route === notFoundRoute;
|
|
534
|
+
const routeType = isError ? "error" : isNotFound ? "notfound" : "normal";
|
|
535
|
+
const routeKey = `${state.url}:${routeType}`;
|
|
536
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RouterView, { state }, routeKey);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// modules/runtime/client/bootstrap.tsx
|
|
540
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
541
|
+
async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute, errorRoute) {
|
|
542
|
+
const isInitialNotFound = initialData?.notFound === true;
|
|
543
|
+
const isInitialError = initialData?.error === true;
|
|
544
|
+
let initialRoute = null;
|
|
545
|
+
let initialParams = {};
|
|
546
|
+
let initialComponents = null;
|
|
547
|
+
if (isInitialError && errorRoute) {
|
|
548
|
+
initialRoute = errorRoute;
|
|
549
|
+
initialParams = initialData?.params ?? {};
|
|
550
|
+
initialComponents = await errorRoute.load();
|
|
551
|
+
} else if (isInitialNotFound && notFoundRoute) {
|
|
552
|
+
initialRoute = notFoundRoute;
|
|
553
|
+
initialParams = {};
|
|
554
|
+
initialComponents = await notFoundRoute.load();
|
|
555
|
+
} else {
|
|
556
|
+
const match = matchRouteClient(initialUrl, routes);
|
|
557
|
+
if (match) {
|
|
558
|
+
initialRoute = match.route;
|
|
559
|
+
initialParams = match.params;
|
|
560
|
+
initialComponents = await match.route.load();
|
|
561
|
+
} else if (notFoundRoute) {
|
|
562
|
+
initialRoute = notFoundRoute;
|
|
563
|
+
initialParams = {};
|
|
564
|
+
initialComponents = await notFoundRoute.load();
|
|
565
|
+
} else {
|
|
566
|
+
console.warn(
|
|
567
|
+
`[client] No route match found for ${initialUrl}. Available routes:`,
|
|
568
|
+
routes.map((r) => r.pattern)
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
url: initialUrl,
|
|
574
|
+
route: initialRoute,
|
|
575
|
+
params: initialParams,
|
|
576
|
+
components: initialComponents,
|
|
577
|
+
props: initialData?.props ?? {}
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
|
|
581
|
+
(async function bootstrap() {
|
|
582
|
+
const container = document.getElementById(APP_CONTAINER_ID);
|
|
583
|
+
const initialData = getWindowData();
|
|
584
|
+
if (!container) {
|
|
585
|
+
console.error(`Container #${APP_CONTAINER_ID} not found for hydration`);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const initialUrl = window.location.pathname + window.location.search;
|
|
589
|
+
try {
|
|
590
|
+
const initialState = await loadInitialRoute(
|
|
591
|
+
initialUrl,
|
|
592
|
+
initialData,
|
|
593
|
+
routes,
|
|
594
|
+
notFoundRoute,
|
|
595
|
+
errorRoute
|
|
596
|
+
);
|
|
597
|
+
if (initialData?.metadata) {
|
|
598
|
+
applyMetadata(initialData.metadata);
|
|
599
|
+
}
|
|
600
|
+
(0, import_client.hydrateRoot)(
|
|
601
|
+
container,
|
|
602
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
603
|
+
AppShell,
|
|
604
|
+
{
|
|
605
|
+
initialState,
|
|
606
|
+
routes,
|
|
607
|
+
notFoundRoute,
|
|
608
|
+
errorRoute
|
|
609
|
+
}
|
|
610
|
+
)
|
|
611
|
+
);
|
|
612
|
+
} catch (error) {
|
|
613
|
+
console.error(
|
|
614
|
+
"[client] Error loading initial route components for",
|
|
615
|
+
initialUrl,
|
|
616
|
+
error
|
|
617
|
+
);
|
|
618
|
+
window.location.reload();
|
|
619
|
+
}
|
|
620
|
+
})();
|
|
621
|
+
}
|
|
622
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
623
|
+
0 && (module.exports = {
|
|
624
|
+
bootstrapClient
|
|
625
|
+
});
|
|
626
|
+
//# sourceMappingURL=runtime.cjs.map
|