@finesoft/front 0.1.37 → 0.1.39
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 +70 -0
- package/dist/app-XEMPAI6H.js +10 -0
- package/dist/browser.cjs +265 -33
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +152 -15
- package/dist/browser.d.ts +152 -15
- package/dist/browser.js +18 -2
- package/dist/{chunk-AX7PXYXU.js → chunk-4PPCVAKZ.js} +144 -31
- package/dist/chunk-4PPCVAKZ.js.map +1 -0
- package/dist/{chunk-SFGR32K6.js → chunk-OYTIGVEG.js} +13 -8
- package/dist/chunk-OYTIGVEG.js.map +1 -0
- package/dist/{chunk-OXKFPW4U.js → chunk-SDPWQT2T.js} +118 -6
- package/dist/chunk-SDPWQT2T.js.map +1 -0
- package/dist/{chunk-AYO3UUQC.js → chunk-XQ3UWZOS.js} +72 -3
- package/dist/chunk-XQ3UWZOS.js.map +1 -0
- package/dist/index.cjs +365 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +24 -8
- package/dist/index.js.map +1 -1
- package/dist/{src-MVACJWBF.js → src-XNC7QNVI.js} +3 -3
- package/package.json +1 -1
- package/dist/app-D4K35MX3.js +0 -10
- package/dist/chunk-AX7PXYXU.js.map +0 -1
- package/dist/chunk-AYO3UUQC.js.map +0 -1
- package/dist/chunk-OXKFPW4U.js.map +0 -1
- package/dist/chunk-SFGR32K6.js.map +0 -1
- /package/dist/{app-D4K35MX3.js.map → app-XEMPAI6H.js.map} +0 -0
- /package/dist/{src-MVACJWBF.js.map → src-XNC7QNVI.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -395,7 +395,8 @@ var init_router = __esm({
|
|
|
395
395
|
Router = class {
|
|
396
396
|
routes = [];
|
|
397
397
|
/** 添加路由规则 */
|
|
398
|
-
add(pattern, intentId,
|
|
398
|
+
add(pattern, intentId, renderModeOrOptions) {
|
|
399
|
+
const opts = typeof renderModeOrOptions === "string" ? { renderMode: renderModeOrOptions } : renderModeOrOptions ?? {};
|
|
399
400
|
const paramNames = [];
|
|
400
401
|
const regexStr = pattern.split(/(\/:[\w]+\??)/).map((segment) => {
|
|
401
402
|
const paramMatch = segment.match(/^\/:(\w+)(\?)?$/);
|
|
@@ -410,7 +411,9 @@ var init_router = __esm({
|
|
|
410
411
|
intentId,
|
|
411
412
|
regex: new RegExp(`^${regexStr}/?$`),
|
|
412
413
|
paramNames,
|
|
413
|
-
renderMode
|
|
414
|
+
renderMode: opts.renderMode,
|
|
415
|
+
beforeGuards: opts.beforeGuards,
|
|
416
|
+
afterGuards: opts.afterGuards
|
|
414
417
|
});
|
|
415
418
|
return this;
|
|
416
419
|
}
|
|
@@ -432,7 +435,9 @@ var init_router = __esm({
|
|
|
432
435
|
return {
|
|
433
436
|
intent: { id: route.intentId, params },
|
|
434
437
|
action: makeFlowAction(urlOrPath),
|
|
435
|
-
renderMode: route.renderMode
|
|
438
|
+
renderMode: route.renderMode,
|
|
439
|
+
beforeGuards: route.beforeGuards,
|
|
440
|
+
afterGuards: route.afterGuards
|
|
436
441
|
};
|
|
437
442
|
}
|
|
438
443
|
}
|
|
@@ -507,6 +512,27 @@ var init_composite = __esm({
|
|
|
507
512
|
}
|
|
508
513
|
});
|
|
509
514
|
|
|
515
|
+
// ../core/src/middleware/pipeline.ts
|
|
516
|
+
async function runBeforeLoadGuards(guards, ctx) {
|
|
517
|
+
for (const guard of guards) {
|
|
518
|
+
const result = await guard(ctx);
|
|
519
|
+
if (result.kind !== "next") return result;
|
|
520
|
+
}
|
|
521
|
+
return { kind: "next" };
|
|
522
|
+
}
|
|
523
|
+
async function runAfterLoadGuards(guards, ctx) {
|
|
524
|
+
for (const guard of guards) {
|
|
525
|
+
const result = await guard(ctx);
|
|
526
|
+
if (result.kind !== "next") return result;
|
|
527
|
+
}
|
|
528
|
+
return { kind: "next" };
|
|
529
|
+
}
|
|
530
|
+
var init_pipeline = __esm({
|
|
531
|
+
"../core/src/middleware/pipeline.ts"() {
|
|
532
|
+
"use strict";
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
|
|
510
536
|
// ../core/src/prefetched-intents/stable-stringify.ts
|
|
511
537
|
function stableStringify(obj, _seen) {
|
|
512
538
|
if (obj === null || obj === void 0) return String(obj);
|
|
@@ -589,6 +615,7 @@ var init_framework = __esm({
|
|
|
589
615
|
init_container();
|
|
590
616
|
init_make_dependencies();
|
|
591
617
|
init_dispatcher2();
|
|
618
|
+
init_pipeline();
|
|
592
619
|
init_prefetched_intents();
|
|
593
620
|
init_router();
|
|
594
621
|
Framework = class _Framework {
|
|
@@ -597,6 +624,8 @@ var init_framework = __esm({
|
|
|
597
624
|
actionDispatcher;
|
|
598
625
|
router;
|
|
599
626
|
prefetchedIntents;
|
|
627
|
+
beforeGuards = [];
|
|
628
|
+
afterGuards = [];
|
|
600
629
|
constructor(container, prefetchedIntents) {
|
|
601
630
|
this.container = container;
|
|
602
631
|
this.intentDispatcher = new IntentDispatcher();
|
|
@@ -660,6 +689,25 @@ var init_framework = __esm({
|
|
|
660
689
|
registerIntent(controller) {
|
|
661
690
|
this.intentDispatcher.register(controller);
|
|
662
691
|
}
|
|
692
|
+
// ===== Navigation Middleware =====
|
|
693
|
+
/** 注册 beforeLoad 守卫(路由匹配后、数据加载前) */
|
|
694
|
+
beforeLoad(guard) {
|
|
695
|
+
this.beforeGuards.push(guard);
|
|
696
|
+
}
|
|
697
|
+
/** 注册 afterLoad 守卫(数据加载后、渲染前) */
|
|
698
|
+
afterLoad(guard) {
|
|
699
|
+
this.afterGuards.push(guard);
|
|
700
|
+
}
|
|
701
|
+
/** 执行所有 beforeLoad 守卫(全局 → 路由级) */
|
|
702
|
+
runBeforeLoad(ctx, routeGuards) {
|
|
703
|
+
const guards = routeGuards?.length ? [...this.beforeGuards, ...routeGuards] : this.beforeGuards;
|
|
704
|
+
return runBeforeLoadGuards(guards, ctx);
|
|
705
|
+
}
|
|
706
|
+
/** 执行所有 afterLoad 守卫(全局 → 路由级) */
|
|
707
|
+
runAfterLoad(ctx, routeGuards) {
|
|
708
|
+
const guards = routeGuards?.length ? [...this.afterGuards, ...routeGuards] : this.afterGuards;
|
|
709
|
+
return runAfterLoadGuards(guards, ctx);
|
|
710
|
+
}
|
|
663
711
|
/** 销毁 Framework 实例 */
|
|
664
712
|
dispose() {
|
|
665
713
|
this.container.dispose();
|
|
@@ -823,7 +871,11 @@ function defineRoutes(framework, definitions) {
|
|
|
823
871
|
framework.registerIntent(def.controller);
|
|
824
872
|
registeredIntents.add(def.intentId);
|
|
825
873
|
}
|
|
826
|
-
framework.router.add(def.path, def.intentId,
|
|
874
|
+
framework.router.add(def.path, def.intentId, {
|
|
875
|
+
renderMode: def.renderMode,
|
|
876
|
+
beforeGuards: def.beforeLoad,
|
|
877
|
+
afterGuards: def.afterLoad
|
|
878
|
+
});
|
|
827
879
|
}
|
|
828
880
|
}
|
|
829
881
|
var init_define_routes = __esm({
|
|
@@ -943,6 +995,74 @@ var init_uuid = __esm({
|
|
|
943
995
|
}
|
|
944
996
|
});
|
|
945
997
|
|
|
998
|
+
// ../core/src/middleware/context.ts
|
|
999
|
+
function parseCookieString(str) {
|
|
1000
|
+
const map = /* @__PURE__ */ new Map();
|
|
1001
|
+
if (!str) return map;
|
|
1002
|
+
for (const pair of str.split(";")) {
|
|
1003
|
+
const idx = pair.indexOf("=");
|
|
1004
|
+
if (idx === -1) continue;
|
|
1005
|
+
const key = pair.slice(0, idx).trim();
|
|
1006
|
+
const val = pair.slice(idx + 1).trim();
|
|
1007
|
+
if (key) map.set(key, val);
|
|
1008
|
+
}
|
|
1009
|
+
return map;
|
|
1010
|
+
}
|
|
1011
|
+
function createServerContext(options) {
|
|
1012
|
+
const { url, intent, container, request } = options;
|
|
1013
|
+
const parsed = new URL(url, "http://localhost");
|
|
1014
|
+
const cookieHeader = request?.headers.get("cookie") ?? "";
|
|
1015
|
+
const cookies = parseCookieString(cookieHeader);
|
|
1016
|
+
return {
|
|
1017
|
+
url,
|
|
1018
|
+
path: parsed.pathname,
|
|
1019
|
+
params: intent.params ?? {},
|
|
1020
|
+
intent,
|
|
1021
|
+
isServer: true,
|
|
1022
|
+
container,
|
|
1023
|
+
getCookie: (name) => cookies.get(name),
|
|
1024
|
+
getHeader: (name) => request?.headers.get(name) ?? void 0
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
function createBrowserContext(options) {
|
|
1028
|
+
const { url, intent, container } = options;
|
|
1029
|
+
const parsed = new URL(url, window.location.origin);
|
|
1030
|
+
return {
|
|
1031
|
+
url,
|
|
1032
|
+
path: parsed.pathname,
|
|
1033
|
+
params: intent.params ?? {},
|
|
1034
|
+
intent,
|
|
1035
|
+
isServer: false,
|
|
1036
|
+
container,
|
|
1037
|
+
getCookie: (name) => parseCookieString(document.cookie).get(name),
|
|
1038
|
+
getHeader: () => void 0
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
var init_context = __esm({
|
|
1042
|
+
"../core/src/middleware/context.ts"() {
|
|
1043
|
+
"use strict";
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
// ../core/src/middleware/types.ts
|
|
1048
|
+
function next() {
|
|
1049
|
+
return { kind: "next" };
|
|
1050
|
+
}
|
|
1051
|
+
function redirect(url, status = 302) {
|
|
1052
|
+
return { kind: "redirect", url, status };
|
|
1053
|
+
}
|
|
1054
|
+
function rewrite(url) {
|
|
1055
|
+
return { kind: "rewrite", url };
|
|
1056
|
+
}
|
|
1057
|
+
function deny(status = 403, message = "Forbidden") {
|
|
1058
|
+
return { kind: "deny", status, message };
|
|
1059
|
+
}
|
|
1060
|
+
var init_types2 = __esm({
|
|
1061
|
+
"../core/src/middleware/types.ts"() {
|
|
1062
|
+
"use strict";
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
|
|
946
1066
|
// ../core/src/index.ts
|
|
947
1067
|
var init_src = __esm({
|
|
948
1068
|
"../core/src/index.ts"() {
|
|
@@ -968,6 +1088,9 @@ var init_src = __esm({
|
|
|
968
1088
|
init_optional();
|
|
969
1089
|
init_url();
|
|
970
1090
|
init_uuid();
|
|
1091
|
+
init_context();
|
|
1092
|
+
init_pipeline();
|
|
1093
|
+
init_types2();
|
|
971
1094
|
}
|
|
972
1095
|
});
|
|
973
1096
|
|
|
@@ -1000,6 +1123,25 @@ async function ssrRender(options) {
|
|
|
1000
1123
|
let page;
|
|
1001
1124
|
let serverData = [];
|
|
1002
1125
|
if (match) {
|
|
1126
|
+
const navCtx = createServerContext({
|
|
1127
|
+
url: fullPath,
|
|
1128
|
+
intent: match.intent,
|
|
1129
|
+
container: framework.container,
|
|
1130
|
+
request: ssrContext?.request
|
|
1131
|
+
});
|
|
1132
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
1133
|
+
navCtx,
|
|
1134
|
+
match.beforeGuards
|
|
1135
|
+
);
|
|
1136
|
+
if (beforeResult.kind !== "next") {
|
|
1137
|
+
const earlyReturn = handleMiddlewareResult(
|
|
1138
|
+
beforeResult,
|
|
1139
|
+
getErrorPage,
|
|
1140
|
+
renderApp,
|
|
1141
|
+
framework
|
|
1142
|
+
);
|
|
1143
|
+
if (earlyReturn) return earlyReturn;
|
|
1144
|
+
}
|
|
1003
1145
|
try {
|
|
1004
1146
|
page = await framework.dispatch(match.intent);
|
|
1005
1147
|
serverData = [{ intent: match.intent, data: page }];
|
|
@@ -1010,6 +1152,23 @@ async function ssrRender(options) {
|
|
|
1010
1152
|
);
|
|
1011
1153
|
page = getErrorPage(500, "Internal error");
|
|
1012
1154
|
}
|
|
1155
|
+
const postCtx = {
|
|
1156
|
+
...navCtx,
|
|
1157
|
+
page
|
|
1158
|
+
};
|
|
1159
|
+
const afterResult = await framework.runAfterLoad(
|
|
1160
|
+
postCtx,
|
|
1161
|
+
match.afterGuards
|
|
1162
|
+
);
|
|
1163
|
+
if (afterResult.kind !== "next") {
|
|
1164
|
+
const lateReturn = handleMiddlewareResult(
|
|
1165
|
+
afterResult,
|
|
1166
|
+
getErrorPage,
|
|
1167
|
+
renderApp,
|
|
1168
|
+
framework
|
|
1169
|
+
);
|
|
1170
|
+
if (lateReturn) return lateReturn;
|
|
1171
|
+
}
|
|
1013
1172
|
} else {
|
|
1014
1173
|
page = getErrorPage(404, "Page not found");
|
|
1015
1174
|
}
|
|
@@ -1025,6 +1184,38 @@ async function ssrRender(options) {
|
|
|
1025
1184
|
framework.dispose();
|
|
1026
1185
|
}
|
|
1027
1186
|
}
|
|
1187
|
+
function handleMiddlewareResult(result, getErrorPage, renderApp, framework) {
|
|
1188
|
+
switch (result.kind) {
|
|
1189
|
+
case "next":
|
|
1190
|
+
return null;
|
|
1191
|
+
case "redirect":
|
|
1192
|
+
return {
|
|
1193
|
+
html: "",
|
|
1194
|
+
head: "",
|
|
1195
|
+
css: "",
|
|
1196
|
+
serverData: [],
|
|
1197
|
+
redirect: { url: result.url, status: result.status }
|
|
1198
|
+
};
|
|
1199
|
+
case "rewrite":
|
|
1200
|
+
return {
|
|
1201
|
+
html: "",
|
|
1202
|
+
head: "",
|
|
1203
|
+
css: "",
|
|
1204
|
+
serverData: [],
|
|
1205
|
+
redirect: { url: result.url, status: 301 }
|
|
1206
|
+
};
|
|
1207
|
+
case "deny": {
|
|
1208
|
+
const errorPage = getErrorPage(result.status, result.message);
|
|
1209
|
+
const rendered = renderApp(errorPage, framework);
|
|
1210
|
+
return {
|
|
1211
|
+
html: rendered.html,
|
|
1212
|
+
head: rendered.head,
|
|
1213
|
+
css: rendered.css,
|
|
1214
|
+
serverData: []
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1028
1219
|
var init_render = __esm({
|
|
1029
1220
|
"../ssr/src/render.ts"() {
|
|
1030
1221
|
"use strict";
|
|
@@ -1294,17 +1485,22 @@ function createSSRApp(options) {
|
|
|
1294
1485
|
const cached = isrCache.get(cacheKey);
|
|
1295
1486
|
if (cached) return c.html(cached);
|
|
1296
1487
|
const requestFetch = parentFetch ? createInternalFetch(parentFetch, ssrDepth + 1) : void 0;
|
|
1488
|
+
const ssrContext = { request: c.req.raw };
|
|
1489
|
+
if (requestFetch) ssrContext.fetch = requestFetch;
|
|
1297
1490
|
const {
|
|
1298
1491
|
html: appHtml,
|
|
1299
1492
|
head,
|
|
1300
1493
|
css,
|
|
1301
1494
|
serverData,
|
|
1302
|
-
renderMode
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1495
|
+
renderMode,
|
|
1496
|
+
redirect: middlewareRedirect
|
|
1497
|
+
} = await render(url, locale, ssrContext);
|
|
1498
|
+
if (middlewareRedirect) {
|
|
1499
|
+
return c.redirect(
|
|
1500
|
+
middlewareRedirect.url,
|
|
1501
|
+
middlewareRedirect.status
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1308
1504
|
if (renderMode === "csr") {
|
|
1309
1505
|
return c.html(injectCSRShell(template, locale));
|
|
1310
1506
|
}
|
|
@@ -1368,11 +1564,14 @@ __export(index_exports, {
|
|
|
1368
1564
|
autoAdapter: () => autoAdapter,
|
|
1369
1565
|
buildUrl: () => buildUrl,
|
|
1370
1566
|
cloudflareAdapter: () => cloudflareAdapter,
|
|
1567
|
+
createBrowserContext: () => createBrowserContext,
|
|
1371
1568
|
createPrefetchedIntentsFromDom: () => createPrefetchedIntentsFromDom,
|
|
1372
1569
|
createSSRApp: () => createSSRApp,
|
|
1373
1570
|
createSSRRender: () => createSSRRender,
|
|
1374
1571
|
createServer: () => createServer,
|
|
1572
|
+
createServerContext: () => createServerContext,
|
|
1375
1573
|
defineRoutes: () => defineRoutes,
|
|
1574
|
+
deny: () => deny,
|
|
1376
1575
|
deserializeServerData: () => deserializeServerData,
|
|
1377
1576
|
detectRuntime: () => detectRuntime,
|
|
1378
1577
|
finesoftFrontViteConfig: () => finesoftFrontViteConfig,
|
|
@@ -1391,10 +1590,12 @@ __export(index_exports, {
|
|
|
1391
1590
|
makeFlowAction: () => makeFlowAction,
|
|
1392
1591
|
mapEach: () => mapEach,
|
|
1393
1592
|
netlifyAdapter: () => netlifyAdapter,
|
|
1593
|
+
next: () => next,
|
|
1394
1594
|
nodeAdapter: () => nodeAdapter,
|
|
1395
1595
|
parseAcceptLanguage: () => parseAcceptLanguage,
|
|
1396
1596
|
pipe: () => pipe,
|
|
1397
1597
|
pipeAsync: () => pipeAsync,
|
|
1598
|
+
redirect: () => redirect,
|
|
1398
1599
|
registerActionHandlers: () => registerActionHandlers,
|
|
1399
1600
|
registerExternalUrlHandler: () => registerExternalUrlHandler,
|
|
1400
1601
|
registerFlowActionHandler: () => registerFlowActionHandler,
|
|
@@ -1405,6 +1606,9 @@ __export(index_exports, {
|
|
|
1405
1606
|
resetFilterCache: () => resetFilterCache,
|
|
1406
1607
|
resolveAdapter: () => resolveAdapter,
|
|
1407
1608
|
resolveRoot: () => resolveRoot,
|
|
1609
|
+
rewrite: () => rewrite,
|
|
1610
|
+
runAfterLoadGuards: () => runAfterLoadGuards,
|
|
1611
|
+
runBeforeLoadGuards: () => runBeforeLoadGuards,
|
|
1408
1612
|
serializeServerData: () => serializeServerData,
|
|
1409
1613
|
shouldLog: () => shouldLog,
|
|
1410
1614
|
ssrRender: () => ssrRender,
|
|
@@ -1540,6 +1744,22 @@ var History = class {
|
|
|
1540
1744
|
tryScroll(this.log, () => this.getScrollablePageElement(), scrollY);
|
|
1541
1745
|
});
|
|
1542
1746
|
}
|
|
1747
|
+
/** 仅推入 URL,不缓存页面状态(用于页面加载失败场景) */
|
|
1748
|
+
pushUrl(url) {
|
|
1749
|
+
const id = generateUuid();
|
|
1750
|
+
window.history.pushState({ id }, "", url);
|
|
1751
|
+
this.currentStateId = id;
|
|
1752
|
+
this.scrollTop = 0;
|
|
1753
|
+
this.log.info("pushUrl (no state)", url, id);
|
|
1754
|
+
}
|
|
1755
|
+
/** 仅替换 URL,不缓存页面状态(用于页面加载失败场景) */
|
|
1756
|
+
replaceUrl(url) {
|
|
1757
|
+
const id = generateUuid();
|
|
1758
|
+
window.history.replaceState({ id }, "", url);
|
|
1759
|
+
this.currentStateId = id;
|
|
1760
|
+
this.scrollTop = 0;
|
|
1761
|
+
this.log.info("replaceUrl (no state)", url, id);
|
|
1762
|
+
}
|
|
1543
1763
|
updateState(update) {
|
|
1544
1764
|
if (!this.currentStateId) {
|
|
1545
1765
|
this.log.warn(
|
|
@@ -1571,31 +1791,49 @@ function registerFlowActionHandler(deps) {
|
|
|
1571
1791
|
const { framework, log, callbacks, updateApp } = deps;
|
|
1572
1792
|
let isFirstPage = true;
|
|
1573
1793
|
let navigationId = 0;
|
|
1794
|
+
const MAX_REDIRECTS = 5;
|
|
1574
1795
|
const defaultGetScrollable = () => document.getElementById("scrollable-page-override") || document.getElementById("scrollable-page") || document.documentElement;
|
|
1575
1796
|
const history = new History(log, {
|
|
1576
1797
|
getScrollablePageElement: deps.getScrollablePageElement ?? defaultGetScrollable
|
|
1577
1798
|
});
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
const match2 = framework.routeUrl(url);
|
|
1584
|
-
if (match2) {
|
|
1585
|
-
const page = await framework.dispatch(
|
|
1586
|
-
match2.intent
|
|
1587
|
-
);
|
|
1588
|
-
callbacks.onModal(page);
|
|
1589
|
-
}
|
|
1799
|
+
async function navigateTo(url, redirectCount, thisNav) {
|
|
1800
|
+
if (redirectCount >= MAX_REDIRECTS) {
|
|
1801
|
+
log.error(
|
|
1802
|
+
`Navigation redirect loop detected (${MAX_REDIRECTS} redirects), stopping at: ${url}`
|
|
1803
|
+
);
|
|
1590
1804
|
return;
|
|
1591
1805
|
}
|
|
1592
|
-
const
|
|
1593
|
-
const shouldReplace = isFirstPage;
|
|
1806
|
+
const shouldReplace = isFirstPage || url === window.location.pathname + window.location.search;
|
|
1594
1807
|
const match = framework.routeUrl(url);
|
|
1595
1808
|
if (!match) {
|
|
1596
1809
|
log.warn(`FlowAction: no route for ${url}`);
|
|
1597
1810
|
return;
|
|
1598
1811
|
}
|
|
1812
|
+
const navCtx = createBrowserContext({
|
|
1813
|
+
url,
|
|
1814
|
+
intent: match.intent,
|
|
1815
|
+
container: framework.container
|
|
1816
|
+
});
|
|
1817
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
1818
|
+
navCtx,
|
|
1819
|
+
match.beforeGuards
|
|
1820
|
+
);
|
|
1821
|
+
if (beforeResult.kind === "redirect") {
|
|
1822
|
+
log.debug(`beforeLoad \u2192 redirect to ${beforeResult.url}`);
|
|
1823
|
+
await navigateTo(beforeResult.url, redirectCount + 1, thisNav);
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1826
|
+
if (beforeResult.kind === "deny") {
|
|
1827
|
+
log.warn(
|
|
1828
|
+
`beforeLoad \u2192 denied (${beforeResult.status}): ${beforeResult.message}`
|
|
1829
|
+
);
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
if (beforeResult.kind === "rewrite") {
|
|
1833
|
+
log.debug(`beforeLoad \u2192 rewrite to ${beforeResult.url}`);
|
|
1834
|
+
await navigateTo(beforeResult.url, redirectCount + 1, thisNav);
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1599
1837
|
const pagePromise = framework.dispatch(
|
|
1600
1838
|
match.intent
|
|
1601
1839
|
);
|
|
@@ -1610,26 +1848,80 @@ function registerFlowActionHandler(deps) {
|
|
|
1610
1848
|
}
|
|
1611
1849
|
history.beforeTransition();
|
|
1612
1850
|
updateApp({
|
|
1613
|
-
page: pagePromise.then(
|
|
1614
|
-
|
|
1615
|
-
|
|
1851
|
+
page: pagePromise.then(
|
|
1852
|
+
async (page) => {
|
|
1853
|
+
if (thisNav !== navigationId) {
|
|
1854
|
+
log.info("FlowAction commit superseded", url);
|
|
1855
|
+
return page;
|
|
1856
|
+
}
|
|
1857
|
+
const postCtx = {
|
|
1858
|
+
...navCtx,
|
|
1859
|
+
page
|
|
1860
|
+
};
|
|
1861
|
+
const afterResult = await framework.runAfterLoad(
|
|
1862
|
+
postCtx,
|
|
1863
|
+
match.afterGuards
|
|
1864
|
+
);
|
|
1865
|
+
if (afterResult.kind === "redirect") {
|
|
1866
|
+
log.debug(`afterLoad \u2192 redirect to ${afterResult.url}`);
|
|
1867
|
+
navigateTo(afterResult.url, redirectCount + 1, thisNav);
|
|
1868
|
+
return page;
|
|
1869
|
+
}
|
|
1870
|
+
let canonicalURL = url;
|
|
1871
|
+
if (afterResult.kind === "rewrite") {
|
|
1872
|
+
canonicalURL = afterResult.url;
|
|
1873
|
+
log.debug(`afterLoad \u2192 rewrite URL to ${canonicalURL}`);
|
|
1874
|
+
}
|
|
1875
|
+
if (afterResult.kind === "deny") {
|
|
1876
|
+
log.warn(`afterLoad \u2192 denied (${afterResult.status})`);
|
|
1877
|
+
return page;
|
|
1878
|
+
}
|
|
1879
|
+
if (shouldReplace) {
|
|
1880
|
+
history.replaceState({ page }, canonicalURL);
|
|
1881
|
+
} else {
|
|
1882
|
+
history.pushState({ page }, canonicalURL);
|
|
1883
|
+
}
|
|
1884
|
+
callbacks.onNavigate(
|
|
1885
|
+
new URL(canonicalURL, window.location.origin).pathname
|
|
1886
|
+
);
|
|
1887
|
+
didEnterPage(page);
|
|
1616
1888
|
return page;
|
|
1889
|
+
},
|
|
1890
|
+
(error) => {
|
|
1891
|
+
if (thisNav === navigationId) {
|
|
1892
|
+
const canonicalURL = url;
|
|
1893
|
+
if (shouldReplace) {
|
|
1894
|
+
history.replaceUrl(canonicalURL);
|
|
1895
|
+
} else {
|
|
1896
|
+
history.pushUrl(canonicalURL);
|
|
1897
|
+
}
|
|
1898
|
+
callbacks.onNavigate(
|
|
1899
|
+
new URL(canonicalURL, window.location.origin).pathname
|
|
1900
|
+
);
|
|
1901
|
+
}
|
|
1902
|
+
throw error;
|
|
1617
1903
|
}
|
|
1618
|
-
|
|
1619
|
-
if (shouldReplace) {
|
|
1620
|
-
history.replaceState({ page }, canonicalURL);
|
|
1621
|
-
} else {
|
|
1622
|
-
history.pushState({ page }, canonicalURL);
|
|
1623
|
-
}
|
|
1624
|
-
callbacks.onNavigate(
|
|
1625
|
-
new URL(canonicalURL, window.location.origin).pathname
|
|
1626
|
-
);
|
|
1627
|
-
didEnterPage(page);
|
|
1628
|
-
return page;
|
|
1629
|
-
}),
|
|
1904
|
+
),
|
|
1630
1905
|
isFirstPage
|
|
1631
1906
|
});
|
|
1632
1907
|
isFirstPage = false;
|
|
1908
|
+
}
|
|
1909
|
+
framework.onAction(ACTION_KINDS.FLOW, async (action) => {
|
|
1910
|
+
const flowAction = action;
|
|
1911
|
+
const url = flowAction.url;
|
|
1912
|
+
log.debug(`FlowAction \u2192 ${url}`);
|
|
1913
|
+
if (flowAction.presentationContext === "modal") {
|
|
1914
|
+
const match = framework.routeUrl(url);
|
|
1915
|
+
if (match) {
|
|
1916
|
+
const page = await framework.dispatch(
|
|
1917
|
+
match.intent
|
|
1918
|
+
);
|
|
1919
|
+
callbacks.onModal(page);
|
|
1920
|
+
}
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const thisNav = ++navigationId;
|
|
1924
|
+
await navigateTo(url, 0, thisNav);
|
|
1633
1925
|
});
|
|
1634
1926
|
history.onPopState(async (url, cachedState) => {
|
|
1635
1927
|
log.debug(`popstate \u2192 ${url}, cached=${!!cachedState}`);
|
|
@@ -1654,6 +1946,30 @@ function registerFlowActionHandler(deps) {
|
|
|
1654
1946
|
});
|
|
1655
1947
|
return;
|
|
1656
1948
|
}
|
|
1949
|
+
const navCtx = createBrowserContext({
|
|
1950
|
+
url: parsed.pathname + parsed.search,
|
|
1951
|
+
intent: routeMatch.intent,
|
|
1952
|
+
container: framework.container
|
|
1953
|
+
});
|
|
1954
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
1955
|
+
navCtx,
|
|
1956
|
+
routeMatch.beforeGuards
|
|
1957
|
+
);
|
|
1958
|
+
if (beforeResult.kind === "redirect") {
|
|
1959
|
+
log.debug(`popstate beforeLoad \u2192 redirect to ${beforeResult.url}`);
|
|
1960
|
+
const thisNav = ++navigationId;
|
|
1961
|
+
await navigateTo(beforeResult.url, 0, thisNav);
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
if (beforeResult.kind === "deny" || beforeResult.kind === "rewrite") {
|
|
1965
|
+
if (beforeResult.kind === "deny") {
|
|
1966
|
+
log.warn(`popstate beforeLoad \u2192 denied`);
|
|
1967
|
+
} else {
|
|
1968
|
+
const thisNav = ++navigationId;
|
|
1969
|
+
await navigateTo(beforeResult.url, 0, thisNav);
|
|
1970
|
+
}
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1657
1973
|
const pagePromise = framework.dispatch(
|
|
1658
1974
|
routeMatch.intent
|
|
1659
1975
|
);
|
|
@@ -1843,7 +2159,7 @@ function _sanitizeProxyPath(raw) {
|
|
|
1843
2159
|
const pattern = `"${config.prefix}/*"`;
|
|
1844
2160
|
const headersJson = JSON.stringify(config.headers ?? {});
|
|
1845
2161
|
const cacheStr = config.cache ? JSON.stringify(config.cache) : "null";
|
|
1846
|
-
const
|
|
2162
|
+
const redirect2 = config.followRedirects ? '"follow"' : '"manual"';
|
|
1847
2163
|
let authCode = "";
|
|
1848
2164
|
if (config.auth) {
|
|
1849
2165
|
const envKey = JSON.stringify(config.auth.envKey);
|
|
@@ -1862,7 +2178,7 @@ function _sanitizeProxyPath(raw) {
|
|
|
1862
2178
|
_reqUrl.searchParams.forEach((v, k) => _target.searchParams.set(k, v));
|
|
1863
2179
|
const _headers = ${headersJson};${authCode}
|
|
1864
2180
|
try {
|
|
1865
|
-
const _resp = await fetch(_target.toString(), { headers: _headers, redirect: ${
|
|
2181
|
+
const _resp = await fetch(_target.toString(), { headers: _headers, redirect: ${redirect2} });
|
|
1866
2182
|
const _body = await _resp.text();
|
|
1867
2183
|
const _rh = { "Content-Type": _resp.headers.get("Content-Type") || "application/json" };
|
|
1868
2184
|
if (${cacheStr}) _rh["Cache-Control"] = ${cacheStr};
|
|
@@ -3287,11 +3603,14 @@ function finesoftFrontViteConfig(options = {}) {
|
|
|
3287
3603
|
autoAdapter,
|
|
3288
3604
|
buildUrl,
|
|
3289
3605
|
cloudflareAdapter,
|
|
3606
|
+
createBrowserContext,
|
|
3290
3607
|
createPrefetchedIntentsFromDom,
|
|
3291
3608
|
createSSRApp,
|
|
3292
3609
|
createSSRRender,
|
|
3293
3610
|
createServer,
|
|
3611
|
+
createServerContext,
|
|
3294
3612
|
defineRoutes,
|
|
3613
|
+
deny,
|
|
3295
3614
|
deserializeServerData,
|
|
3296
3615
|
detectRuntime,
|
|
3297
3616
|
finesoftFrontViteConfig,
|
|
@@ -3310,10 +3629,12 @@ function finesoftFrontViteConfig(options = {}) {
|
|
|
3310
3629
|
makeFlowAction,
|
|
3311
3630
|
mapEach,
|
|
3312
3631
|
netlifyAdapter,
|
|
3632
|
+
next,
|
|
3313
3633
|
nodeAdapter,
|
|
3314
3634
|
parseAcceptLanguage,
|
|
3315
3635
|
pipe,
|
|
3316
3636
|
pipeAsync,
|
|
3637
|
+
redirect,
|
|
3317
3638
|
registerActionHandlers,
|
|
3318
3639
|
registerExternalUrlHandler,
|
|
3319
3640
|
registerFlowActionHandler,
|
|
@@ -3324,6 +3645,9 @@ function finesoftFrontViteConfig(options = {}) {
|
|
|
3324
3645
|
resetFilterCache,
|
|
3325
3646
|
resolveAdapter,
|
|
3326
3647
|
resolveRoot,
|
|
3648
|
+
rewrite,
|
|
3649
|
+
runAfterLoadGuards,
|
|
3650
|
+
runBeforeLoadGuards,
|
|
3327
3651
|
serializeServerData,
|
|
3328
3652
|
shouldLog,
|
|
3329
3653
|
ssrRender,
|