@lovrozagar/flare 0.3.1 → 0.4.1
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 +5 -4
- package/package.json +8 -2
- package/src/generators/index.ts +101 -43
- package/src/link/index.tsx +2 -1
- package/src/navigation/index.ts +32 -20
- package/src/plugins/index.ts +10 -10
- package/src/plugins/tw-compile.ts +4 -1
- package/src/route-builder/create-layout.ts +15 -7
- package/src/route-builder/create-page.ts +15 -7
- package/src/route-builder/create-root-layout.ts +10 -5
- package/src/route-builder/types.ts +18 -0
- package/src/router-primitives/types.ts +2 -1
- package/src/server/index.ts +24 -12
- package/src/server-handler/index.ts +3 -4
package/README.md
CHANGED
|
@@ -321,7 +321,7 @@ Chain order (typical): `intercept` → `cache` → `authenticate` → `input`
|
|
|
321
321
|
| Method | Role |
|
|
322
322
|
| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
323
323
|
| `.cache(config)` | Client / SSR / ISR / SSG / CDN |
|
|
324
|
-
| `.authenticate()` / `.authenticate("optional")`
|
|
324
|
+
| `.authenticate()` / `.authenticate("optional")` | Auth gate |
|
|
325
325
|
| `.authorize(fn)` | Role check; inherits parent unless overridden |
|
|
326
326
|
| `.input({ params, searchParams })` | Standard Schema or parse fn |
|
|
327
327
|
| `.effects({ loaderDeps, shouldRefetch })` | When to rerun the loader on search change |
|
|
@@ -462,9 +462,10 @@ export const route = createPage("_root_/dashboard")
|
|
|
462
462
|
```
|
|
463
463
|
|
|
464
464
|
- `.authenticate()` — required; null user → `UnauthenticatedError` (401).
|
|
465
|
-
- `.authenticate("optional")` — user may be null.
|
|
466
|
-
- `.authenticate(
|
|
467
|
-
-
|
|
465
|
+
- `.authenticate("optional")` — user may be null; `ctx.auth` is `null` for anonymous requests.
|
|
466
|
+
- Other arguments are callerData for `authenticateFn`: `.authenticate("admin")` is required, `.authenticate("optional", "viewer")` is optional.
|
|
467
|
+
- A required layout gates every route below it; a child cannot loosen it.
|
|
468
|
+
- `.authenticateOptional()` is a deprecated alias of `.authenticate("optional")`.
|
|
468
469
|
- `createServer(router).authenticateFn(fn)` is the app-wide hook (cookie, header, JWT).
|
|
469
470
|
|
|
470
471
|
Throw helpers: `ctx.notFound()`, `ctx.redirect({ to, params, search, status, replace })`, `ctx.unauthenticated()`, `ctx.unauthorized()`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovrozagar/flare",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Solid meta-framework. Server-driven, NDJSON streaming, renderToStream.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"flare",
|
|
@@ -102,6 +102,9 @@
|
|
|
102
102
|
"type:check": "tsc --noEmit -p tsconfig.src.json",
|
|
103
103
|
"type:check:tests": "NODE_OPTIONS='--max-old-space-size=4096' tsc --noEmit"
|
|
104
104
|
},
|
|
105
|
+
"dependencies": {
|
|
106
|
+
"@types/negotiator": "catalog:"
|
|
107
|
+
},
|
|
105
108
|
"devDependencies": {
|
|
106
109
|
"@babel/parser": "catalog:",
|
|
107
110
|
"@capsizecss/metrics": "catalog:",
|
|
@@ -111,7 +114,6 @@
|
|
|
111
114
|
"@solidjs/web": "catalog:",
|
|
112
115
|
"@tanstack/query-broadcast-client-experimental": "catalog:",
|
|
113
116
|
"@tanstack/solid-query": "catalog:",
|
|
114
|
-
"@types/negotiator": "catalog:",
|
|
115
117
|
"isbot": "catalog:",
|
|
116
118
|
"jsdom": "catalog:",
|
|
117
119
|
"magic-string": "catalog:",
|
|
@@ -140,6 +142,7 @@
|
|
|
140
142
|
"oxc-resolver": ">=11.23.0",
|
|
141
143
|
"sharp": ">=0.33.0",
|
|
142
144
|
"solid-js": ">=2.0.0-rc.0",
|
|
145
|
+
"tailwindcss": ">=4.0.0",
|
|
143
146
|
"vite": ">=8.0.0"
|
|
144
147
|
},
|
|
145
148
|
"peerDependenciesMeta": {
|
|
@@ -169,6 +172,9 @@
|
|
|
169
172
|
},
|
|
170
173
|
"sharp": {
|
|
171
174
|
"optional": true
|
|
175
|
+
},
|
|
176
|
+
"tailwindcss": {
|
|
177
|
+
"optional": true
|
|
172
178
|
}
|
|
173
179
|
}
|
|
174
180
|
}
|
package/src/generators/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { dirname, extname, join, posix } from "node:path";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, extname, join, posix, relative, resolve } from "node:path";
|
|
4
4
|
import { parse as babelParse } from "@babel/parser";
|
|
5
5
|
import { parseSeconds } from "../duration/index.ts";
|
|
6
6
|
import type { AuthenticateMode } from "../route-builder/types.ts";
|
|
@@ -494,9 +494,7 @@ export function extractRouteDefinitions(src: string, filePath: string): RouteDef
|
|
|
494
494
|
const nextExport = NEXT_EXPORT_RE.exec(rest);
|
|
495
495
|
const chainText = nextExport ? rest.slice(0, nextExport.index) : rest;
|
|
496
496
|
|
|
497
|
-
const
|
|
498
|
-
const hasAuthenticate = /\.authenticate\s*\(/.test(chainText);
|
|
499
|
-
const authenticateMode: AuthenticateMode = hasAuthenticateOptional ? "optional" : !!hasAuthenticate;
|
|
497
|
+
const authenticateMode = detectAuthenticateMode(chainText);
|
|
500
498
|
const hasAuthorize = /\.authorize\s*\(/.test(chainText);
|
|
501
499
|
const hasInput = /\.input\s*(?:<[^>]*>)?\s*\(/.test(chainText);
|
|
502
500
|
const responseRoute = /\.response\s*\(/.test(chainText);
|
|
@@ -640,6 +638,13 @@ function relativeImportPath(from: string, to: string): string {
|
|
|
640
638
|
return `${prefix}/${downs.join("/")}`;
|
|
641
639
|
}
|
|
642
640
|
|
|
641
|
+
/** Auth mode of a builder chain; mirrors `resolveAuthenticateArgs` in the route builder. */
|
|
642
|
+
export function detectAuthenticateMode(chainText: string): AuthenticateMode {
|
|
643
|
+
if (/\.authenticateOptional\s*\(/.test(chainText)) return "optional";
|
|
644
|
+
if (/\.authenticate\s*\(\s*(["'`])optional\1\s*[,)]/.test(chainText)) return "optional";
|
|
645
|
+
return /\.authenticate\s*\(/.test(chainText);
|
|
646
|
+
}
|
|
647
|
+
|
|
643
648
|
function formatRouteMeta(def: RouteDefinition): string {
|
|
644
649
|
const parts: string[] = [];
|
|
645
650
|
if (def.authenticateMode === true) parts.push("authenticate: true");
|
|
@@ -846,7 +851,11 @@ function serializeRouteMeta(def: RouteDefinition): string {
|
|
|
846
851
|
return `{${meta}}`;
|
|
847
852
|
}
|
|
848
853
|
|
|
849
|
-
export function generateRoutesFile(
|
|
854
|
+
export function generateRoutesFile(
|
|
855
|
+
defs: RouteDefinition[],
|
|
856
|
+
outputDir: string,
|
|
857
|
+
app: AppEntries = resolveAppEntries(".", outputDir),
|
|
858
|
+
): string {
|
|
850
859
|
const pages = defs.filter((d) => d.type === "page");
|
|
851
860
|
const layouts = generateLayoutsRecord(defs, outputDir);
|
|
852
861
|
|
|
@@ -858,22 +867,7 @@ export function generateRoutesFile(defs: RouteDefinition[], outputDir: string):
|
|
|
858
867
|
/* Detect whether any pages have .input() for search params typing */
|
|
859
868
|
const hasSearchParams = pages.some((d) => !d.responseRoute && d.hasInput);
|
|
860
869
|
|
|
861
|
-
|
|
862
|
-
const routerFilePath = posix.join(posix.dirname(outputDir), "router");
|
|
863
|
-
let hasQueryClient = false;
|
|
864
|
-
for (const ext of [".ts", ".tsx"]) {
|
|
865
|
-
try {
|
|
866
|
-
const routerSource = readFileSync(`${routerFilePath}${ext}`, "utf-8");
|
|
867
|
-
if (routerSource.includes("queryClientGetter")) {
|
|
868
|
-
hasQueryClient = true;
|
|
869
|
-
}
|
|
870
|
-
break;
|
|
871
|
-
} catch {
|
|
872
|
-
/* file doesn't exist with this extension */
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
const serverHandler = resolveCreateServerExport(outputDir);
|
|
870
|
+
const { hasQueryClient, serverHandler } = app;
|
|
877
871
|
const registry = generateRouteRegistry(defs, outputDir, hasAuth, hasQueryClient, serverHandler !== null);
|
|
878
872
|
|
|
879
873
|
/* Deduplicate meta objects */
|
|
@@ -1008,25 +1002,84 @@ export function generateVirtualModuleTypes(): string {
|
|
|
1008
1002
|
return `/// <reference types="vite/client" />\n/// <reference types="@lovrozagar/flare/virtual-types" />\n`;
|
|
1009
1003
|
}
|
|
1010
1004
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1005
|
+
export interface AppEntries {
|
|
1006
|
+
hasQueryClient: boolean;
|
|
1007
|
+
serverHandler: { exportName: string; importPath: string } | null;
|
|
1008
|
+
warnings: string[];
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
const ENTRY_EXTS = [".ts", ".tsx"];
|
|
1012
|
+
|
|
1013
|
+
/** Root-relative posix path of the first existing candidate (`base` as given, then with each extension). */
|
|
1014
|
+
function findSourceFile(rootDir: string, base: string): string | null {
|
|
1015
|
+
for (const candidate of [
|
|
1016
|
+
base,
|
|
1017
|
+
...ENTRY_EXTS.map((ext) => `${base}${ext}`),
|
|
1018
|
+
...ENTRY_EXTS.map((ext) => `${base}/index${ext}`),
|
|
1019
|
+
]) {
|
|
1020
|
+
const abs = resolve(rootDir, candidate);
|
|
1021
|
+
if (existsSync(abs) && statSync(abs).isFile()) return relative(resolve(rootDir), abs).replaceAll("\\", "/");
|
|
1026
1022
|
}
|
|
1027
1023
|
return null;
|
|
1028
1024
|
}
|
|
1029
1025
|
|
|
1026
|
+
function readSource(rootDir: string, rel: string | null): string | null {
|
|
1027
|
+
if (!rel) return null;
|
|
1028
|
+
try {
|
|
1029
|
+
return readFileSync(resolve(rootDir, rel), "utf-8");
|
|
1030
|
+
} catch {
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/** Relative module the server entry imports the router from: `createServer(x)` + `import { x } from "./..."`. */
|
|
1036
|
+
function routerImportOf(serverSource: string): string | null {
|
|
1037
|
+
const arg = serverSource.match(/createServer\s*(?:<[^>]*>)?\s*\(\s*(\w+)/)?.[1];
|
|
1038
|
+
if (!arg) return null;
|
|
1039
|
+
for (const m of serverSource.matchAll(/import\s*\{([^}]*)\}\s*from\s*["'](\.{1,2}\/[^"']+)["']/g)) {
|
|
1040
|
+
const names = (m[1] ?? "").split(",").map((n) =>
|
|
1041
|
+
n
|
|
1042
|
+
.trim()
|
|
1043
|
+
.split(/\s+as\s+/)
|
|
1044
|
+
.pop(),
|
|
1045
|
+
);
|
|
1046
|
+
if (names.includes(arg)) return m[2] ?? null;
|
|
1047
|
+
}
|
|
1048
|
+
return null;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* Server handler export and router facts for the registry. The server entry
|
|
1053
|
+
* defaults to `server.ts(x)` beside the output dir; the router is the module
|
|
1054
|
+
* the server passes to `createServer()`, else `router.ts(x)` beside it.
|
|
1055
|
+
*/
|
|
1056
|
+
export function resolveAppEntries(rootDir: string, outputDir: string, serverEntry?: string): AppEntries {
|
|
1057
|
+
const warnings: string[] = [];
|
|
1058
|
+
const srcDir = posix.dirname(outputDir);
|
|
1059
|
+
const serverFile = serverEntry ? findSourceFile(rootDir, serverEntry) : findSourceFile(rootDir, `${srcDir}/server`);
|
|
1060
|
+
const serverSource = readSource(rootDir, serverFile);
|
|
1061
|
+
|
|
1062
|
+
const routerSpec = serverSource && serverFile ? routerImportOf(serverSource) : null;
|
|
1063
|
+
const routerFile =
|
|
1064
|
+
(routerSpec && serverFile ? findSourceFile(rootDir, posix.join(posix.dirname(serverFile), routerSpec)) : null) ??
|
|
1065
|
+
findSourceFile(rootDir, `${srcDir}/router`);
|
|
1066
|
+
const hasQueryClient = readSource(rootDir, routerFile)?.includes("queryClientGetter") ?? false;
|
|
1067
|
+
|
|
1068
|
+
let serverHandler: AppEntries["serverHandler"] = null;
|
|
1069
|
+
if (serverSource && serverFile) {
|
|
1070
|
+
const exportName = serverSource.match(/export\s+const\s+(\w+)\s*=\s*createServer/)?.[1];
|
|
1071
|
+
if (exportName) {
|
|
1072
|
+
serverHandler = { exportName, importPath: relativeImportPath(`${outputDir}/routes.gen.ts`, serverFile) };
|
|
1073
|
+
} else if (/createServer\s*(?:<[^>]*>)?\s*\(/.test(serverSource)) {
|
|
1074
|
+
warnings.push(
|
|
1075
|
+
`${serverFile} calls createServer() without exporting it; export the chain (export const server = createServer(router)...) so routes.gen.ts can infer auth, env, and serverContext`,
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
return { hasQueryClient, serverHandler, warnings };
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1030
1083
|
/** Generate TypeScript declaration merging block for route type registry. */
|
|
1031
1084
|
export function generateRouteRegistry(
|
|
1032
1085
|
defs: RouteDefinition[],
|
|
@@ -1148,12 +1201,12 @@ export function generateRouteRegistry(
|
|
|
1148
1201
|
}
|
|
1149
1202
|
|
|
1150
1203
|
if (hasServer && hasAuth) {
|
|
1151
|
-
lines.push(`\t\tauth: NonNullable<
|
|
1204
|
+
lines.push(`\t\tauth: NonNullable<NonNullable<(typeof _FlareHandler)["~flare"]>["auth"]>`);
|
|
1152
1205
|
}
|
|
1153
1206
|
|
|
1154
1207
|
if (hasServer) {
|
|
1155
1208
|
lines.push(`\t\tenv: Parameters<typeof _FlareHandler["fetch"]>[1]`);
|
|
1156
|
-
lines.push(`\t\tserverContext:
|
|
1209
|
+
lines.push(`\t\tserverContext: NonNullable<(typeof _FlareHandler)["~flare"]>["serverContext"]`);
|
|
1157
1210
|
}
|
|
1158
1211
|
if (hasQueryClient) {
|
|
1159
1212
|
lines.push("\t\thasQueryClient: true");
|
|
@@ -1502,9 +1555,7 @@ export function scanSourceFilesFsCodegen(options: ScanOptions): RouteDefinition[
|
|
|
1502
1555
|
}
|
|
1503
1556
|
|
|
1504
1557
|
/* Extract chain metadata from file content */
|
|
1505
|
-
const
|
|
1506
|
-
const hasAuthenticate = /\.authenticate\s*\(/.test(content);
|
|
1507
|
-
const authenticateMode: AuthenticateMode = hasAuthenticateOptional ? "optional" : !!hasAuthenticate;
|
|
1558
|
+
const authenticateMode = detectAuthenticateMode(content);
|
|
1508
1559
|
const hasAuthorize = /\.authorize\s*\(/.test(content);
|
|
1509
1560
|
const hasInput = /\.input\s*(?:<[^>]*>)?\s*\(/.test(content);
|
|
1510
1561
|
const responseRoute = /\.response\s*\(/.test(content);
|
|
@@ -1533,6 +1584,8 @@ export interface RunGenerateOptions {
|
|
|
1533
1584
|
ignorePrefix?: string;
|
|
1534
1585
|
outputPath?: string;
|
|
1535
1586
|
rootDir: string;
|
|
1587
|
+
/** Server entry (root-relative or absolute); defaults to `server.ts(x)` beside the output dir. */
|
|
1588
|
+
serverEntry?: string;
|
|
1536
1589
|
srcDir?: string;
|
|
1537
1590
|
typesOutputPath?: string;
|
|
1538
1591
|
}
|
|
@@ -1617,7 +1670,12 @@ export function runGenerate(options: RunGenerateOptions): GenerateResult {
|
|
|
1617
1670
|
return { layouts: 0, routes: 0, warnings };
|
|
1618
1671
|
}
|
|
1619
1672
|
|
|
1620
|
-
const
|
|
1673
|
+
const app = resolveAppEntries(options.rootDir, outputDir, options.serverEntry);
|
|
1674
|
+
for (const warning of app.warnings) {
|
|
1675
|
+
warnings.push(warning);
|
|
1676
|
+
console.warn(`[flare:generate] ${warning}`);
|
|
1677
|
+
}
|
|
1678
|
+
const content = generateRoutesFile(defs, outputDir, app);
|
|
1621
1679
|
writeGenFile(fullOutputPath, content, "flare");
|
|
1622
1680
|
|
|
1623
1681
|
/* Write virtual module type declarations as a .d.ts file (must be ambient, not in a module) */
|
package/src/link/index.tsx
CHANGED
|
@@ -331,7 +331,7 @@ export function Link<TPath extends RoutePaths>(props: LinkProps<TPath>): JSX.Ele
|
|
|
331
331
|
};
|
|
332
332
|
},
|
|
333
333
|
({ disabled, el, external, hrefOnly, strategy }) => {
|
|
334
|
-
if (!el || disabled || hrefOnly || external) return;
|
|
334
|
+
if (!el || disabled || hrefOnly || external) return undefined;
|
|
335
335
|
|
|
336
336
|
if (strategy === "intent") {
|
|
337
337
|
el.addEventListener("focus", handleIntent);
|
|
@@ -368,6 +368,7 @@ export function Link<TPath extends RoutePaths>(props: LinkProps<TPath>): JSX.Ele
|
|
|
368
368
|
if (strategy === "render") {
|
|
369
369
|
return scheduleAfterLoad(() => triggerPrefetch());
|
|
370
370
|
}
|
|
371
|
+
return undefined;
|
|
371
372
|
},
|
|
372
373
|
);
|
|
373
374
|
|
package/src/navigation/index.ts
CHANGED
|
@@ -585,12 +585,12 @@ function hydrateCachedDeferred(cached: CachedMatch): boolean {
|
|
|
585
585
|
function commitCachedShell(
|
|
586
586
|
c: FlareProviderContext,
|
|
587
587
|
allModules: LoadedRouteModule[],
|
|
588
|
+
rootLayout: LoadedRouteModule | undefined,
|
|
588
589
|
search: SearchParams,
|
|
589
590
|
params: Record<string, string | string[]>,
|
|
590
591
|
): { hadShell: boolean; keepMatchIds: string[] } {
|
|
591
592
|
if (!ctx) return { hadShell: false, keepMatchIds: [] };
|
|
592
593
|
let found = false;
|
|
593
|
-
const heads: PerRouteHead[] = [];
|
|
594
594
|
const keepMatchIds: string[] = [];
|
|
595
595
|
for (const mod of allModules) {
|
|
596
596
|
const matchId = matchIdForModule(mod, search, params);
|
|
@@ -600,10 +600,23 @@ function commitCachedShell(
|
|
|
600
600
|
if (cached.hasDeferred && hydrateCachedDeferred(cached)) {
|
|
601
601
|
keepMatchIds.push(matchId);
|
|
602
602
|
}
|
|
603
|
-
if (cached.headConfig) heads.push({ head: cached.headConfig, matchId });
|
|
604
603
|
}
|
|
605
604
|
if (!found) return { hadShell: false, keepMatchIds: [] };
|
|
606
605
|
|
|
606
|
+
/* applyPerRouteHeads replaces the whole hierarchy, so a partial set would
|
|
607
|
+
* drop the root layout's CSS. Apply only when every route has a cached head;
|
|
608
|
+
* otherwise the post-fetch update applies the full set. */
|
|
609
|
+
const heads: PerRouteHead[] = [];
|
|
610
|
+
for (const mod of rootLayout ? [rootLayout, ...allModules] : allModules) {
|
|
611
|
+
const matchId = matchIdForModule(mod, search, params);
|
|
612
|
+
const head = ctx.matchCache.get(matchId)?.headConfig;
|
|
613
|
+
if (!head) {
|
|
614
|
+
heads.length = 0;
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
heads.push({ head, matchId });
|
|
618
|
+
}
|
|
619
|
+
|
|
607
620
|
c.setIntercepted(null);
|
|
608
621
|
c.setNotFound(false);
|
|
609
622
|
assignMatches(c, buildClientMatches(allModules, search, params));
|
|
@@ -1141,6 +1154,9 @@ export async function navigate(options: InternalNavigateOptions, redirectCount =
|
|
|
1141
1154
|
*/
|
|
1142
1155
|
const nonRootLayouts = modules.layouts.filter((m) => m._type !== "root-layout");
|
|
1143
1156
|
const allModules: LoadedRouteModule[] = [...nonRootLayouts, modules.page];
|
|
1157
|
+
/* The root layout still owns head state (title, CSS) on every navigation. */
|
|
1158
|
+
const rootLayout = modules.layouts.find((m) => m._type === "root-layout");
|
|
1159
|
+
const headModules = rootLayout ? [rootLayout, ...allModules] : allModules;
|
|
1144
1160
|
|
|
1145
1161
|
/* Instant navigation: reuse in-flight prefetch and paint a cached shell
|
|
1146
1162
|
* before the enter NDJSON hop. Skipped when this nav already fetched in
|
|
@@ -1160,7 +1176,7 @@ export async function navigate(options: InternalNavigateOptions, redirectCount =
|
|
|
1160
1176
|
}
|
|
1161
1177
|
}
|
|
1162
1178
|
if (controller.signal.aborted || myVersion !== navigationVersion) return;
|
|
1163
|
-
const shell = commitCachedShell(c, allModules, search, modules.params);
|
|
1179
|
+
const shell = commitCachedShell(c, allModules, rootLayout, search, modules.params);
|
|
1164
1180
|
hadShell = shell.hadShell;
|
|
1165
1181
|
paintedShell = shell.hadShell;
|
|
1166
1182
|
if (shell.hadShell) {
|
|
@@ -1387,25 +1403,21 @@ export async function navigate(options: InternalNavigateOptions, redirectCount =
|
|
|
1387
1403
|
const clientMatches = buildClientMatches(allModules, search, modules.params);
|
|
1388
1404
|
|
|
1389
1405
|
/* Step 11: Compute head data before update — used inside VT callback */
|
|
1390
|
-
const freshHeads =
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
if (!fetchedHeadIds.has(matchId)) {
|
|
1403
|
-
const cached = ctx.matchCache.get(matchId);
|
|
1404
|
-
if (cached?.headConfig) {
|
|
1405
|
-
perRouteHeads.push({ head: cached.headConfig, matchId });
|
|
1406
|
-
}
|
|
1406
|
+
const freshHeads = new Map<string, HeadConfig>();
|
|
1407
|
+
for (const h of fetchResult?.perRouteHeads ?? []) freshHeads.set(h.matchId, h.head);
|
|
1408
|
+
const fetchedIds = new Set(fetchResult?.matches.map((m) => m.matchId));
|
|
1409
|
+
/* Hierarchy order, root first. A fetched route uses its fresh head (none
|
|
1410
|
+
* under headReplace); an unfetched one falls back to the cache. */
|
|
1411
|
+
const perRouteHeads: PerRouteHead[] = [];
|
|
1412
|
+
for (const mod of headModules) {
|
|
1413
|
+
const matchId = matchIdForModule(mod, search, modules.params);
|
|
1414
|
+
const head = fetchedIds.has(matchId) ? freshHeads.get(matchId) : ctx.matchCache.get(matchId)?.headConfig;
|
|
1415
|
+
if (head) {
|
|
1416
|
+
perRouteHeads.push({ head, matchId });
|
|
1417
|
+
freshHeads.delete(matchId);
|
|
1407
1418
|
}
|
|
1408
1419
|
}
|
|
1420
|
+
for (const [matchId, head] of freshHeads) perRouteHeads.push({ head, matchId });
|
|
1409
1421
|
|
|
1410
1422
|
/* Step 12: Update state + scroll + head + cleanup.
|
|
1411
1423
|
* Everything inside update() so VT captures the complete state transition. */
|
package/src/plugins/index.ts
CHANGED
|
@@ -153,7 +153,7 @@ const ENTRY_EXTENSIONS = [".tsx", ".ts"];
|
|
|
153
153
|
|
|
154
154
|
function resolveEntry(root: string, base: string, override?: string): string {
|
|
155
155
|
if (override) {
|
|
156
|
-
if (!existsSync(
|
|
156
|
+
if (!existsSync(resolve(root, override))) {
|
|
157
157
|
throw new Error(`Flare: entry.${base} path "${override}" not found`);
|
|
158
158
|
}
|
|
159
159
|
return override;
|
|
@@ -189,7 +189,11 @@ function createResolverPlugin(): VitePlugin {
|
|
|
189
189
|
|
|
190
190
|
/* ── Generate ────────────────────────────────────────────────────────── */
|
|
191
191
|
|
|
192
|
-
function createGeneratePlugin(
|
|
192
|
+
function createGeneratePlugin(
|
|
193
|
+
config: FlarePluginConfig,
|
|
194
|
+
codegen: ReturnType<typeof resolveCodegenConfig>,
|
|
195
|
+
serverEntry: string,
|
|
196
|
+
): VitePlugin {
|
|
193
197
|
const ignorePrefix = config.ignorePrefix ?? "_";
|
|
194
198
|
|
|
195
199
|
const generateOpts = {
|
|
@@ -197,6 +201,7 @@ function createGeneratePlugin(config: FlarePluginConfig, codegen: ReturnType<typ
|
|
|
197
201
|
ignorePrefix,
|
|
198
202
|
outputPath: codegen.routesFilePath,
|
|
199
203
|
rootDir: "",
|
|
204
|
+
serverEntry,
|
|
200
205
|
typesOutputPath: codegen.typesFilePath,
|
|
201
206
|
};
|
|
202
207
|
|
|
@@ -235,12 +240,7 @@ function createGeneratePlugin(config: FlarePluginConfig, codegen: ReturnType<typ
|
|
|
235
240
|
|
|
236
241
|
/* ── SSR Build ───────────────────────────────────────────────────────── */
|
|
237
242
|
|
|
238
|
-
function createSsrBuildPlugin(
|
|
239
|
-
entries: ResolvedEntries,
|
|
240
|
-
config: FlarePluginConfig,
|
|
241
|
-
assetsBase: string,
|
|
242
|
-
assetsDir: string,
|
|
243
|
-
): VitePlugin {
|
|
243
|
+
function createSsrBuildPlugin(entries: ResolvedEntries, config: FlarePluginConfig, assetsDir: string): VitePlugin {
|
|
244
244
|
return {
|
|
245
245
|
config() {
|
|
246
246
|
return {
|
|
@@ -411,8 +411,8 @@ export function flare(config: FlarePluginConfig = EMPTY_OBJ): VitePlugin[] {
|
|
|
411
411
|
solid(solidConfig) as unknown as VitePlugin,
|
|
412
412
|
createImagePlugin(config, resolvedOptions.assetsBase, resolvedOptions.assetsDir),
|
|
413
413
|
createResolverPlugin(),
|
|
414
|
-
createGeneratePlugin(config, resolvedCodegen),
|
|
415
|
-
createSsrBuildPlugin(entries, config, resolvedOptions.
|
|
414
|
+
createGeneratePlugin(config, resolvedCodegen, resolve(root, entries.server)),
|
|
415
|
+
createSsrBuildPlugin(entries, config, resolvedOptions.assetsDir),
|
|
416
416
|
createDevServerPlugin(entries, resolvedOptions.assetsBase),
|
|
417
417
|
createPreviewServerPlugin(resolvedOptions.assetsBase),
|
|
418
418
|
createVirtualPlugin(config, entries, resolvedCodegen),
|
|
@@ -177,10 +177,13 @@ export function extractDeclarations(
|
|
|
177
177
|
return raw.replace(/\s+/g, " ").trim();
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
const TAILWIND_MODULE: string = "tailwindcss";
|
|
181
|
+
|
|
180
182
|
/** Initialize a Tailwind v4 compiler from an optional CSS entry file. */
|
|
181
183
|
export async function initTailwindCompiler(cssPath?: string): Promise<TailwindCompiler> {
|
|
182
184
|
try {
|
|
183
|
-
|
|
185
|
+
/* Optional peer: a non-literal specifier keeps consumers without tailwindcss typechecking. */
|
|
186
|
+
const tw = (await import(/* @vite-ignore */ TAILWIND_MODULE)) as { compile?: unknown; default?: unknown };
|
|
184
187
|
const compileFn = tw.compile ?? (tw.default as { compile?: unknown })?.compile;
|
|
185
188
|
if (typeof compileFn !== "function") {
|
|
186
189
|
throw new Error(
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from "./register.ts";
|
|
13
13
|
import {
|
|
14
14
|
type AuthenticateMode,
|
|
15
|
+
type AuthenticateModeFromArgs,
|
|
15
16
|
BUILDER_MARKER,
|
|
16
17
|
type CacheConfig,
|
|
17
18
|
type DeferFn,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
type SearchParamsValidator,
|
|
26
27
|
type ServerThrowHelpers,
|
|
27
28
|
type ServerUrlHelpers,
|
|
29
|
+
resolveAuthenticateArgs,
|
|
28
30
|
} from "./types.ts";
|
|
29
31
|
|
|
30
32
|
/* ── callback context types ─────────────────────────────────────── */
|
|
@@ -315,7 +317,11 @@ interface LayoutBuilderAfterInput<
|
|
|
315
317
|
TAuth extends AuthenticateMode,
|
|
316
318
|
TPreloaderContext,
|
|
317
319
|
> extends LayoutBuilderAfterAuthenticate<TPath, TParams, TSearch, TAuth, TPreloaderContext> {
|
|
318
|
-
authenticate(
|
|
320
|
+
/** Required by default; `.authenticate("optional")` lets anonymous requests through with `ctx.auth === null`. Other arguments are callerData for `authenticateFn`. */
|
|
321
|
+
authenticate<const TArgs extends readonly unknown[]>(
|
|
322
|
+
...args: TArgs
|
|
323
|
+
): LayoutBuilderAfterAuthenticate<TPath, TParams, TSearch, AuthenticateModeFromArgs<TArgs>, TPreloaderContext>;
|
|
324
|
+
/** @deprecated Use `.authenticate("optional", ...callerData)`. */
|
|
319
325
|
authenticateOptional(
|
|
320
326
|
...args: unknown[]
|
|
321
327
|
): LayoutBuilderAfterAuthenticate<TPath, TParams, TSearch, "optional", TPreloaderContext>;
|
|
@@ -601,12 +607,14 @@ function createBuilderAfterInput<
|
|
|
601
607
|
>(state: BuilderStateInternal): LayoutBuilderAfterInput<TPath, TParams, TSearch, TAuth, TPreloaderContext> {
|
|
602
608
|
return {
|
|
603
609
|
...createBuilderAfterAuthenticate<TPath, TParams, TSearch, TAuth, TPreloaderContext>(state),
|
|
604
|
-
authenticate(...args:
|
|
605
|
-
return createBuilderAfterAuthenticate<
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
+
authenticate<const TArgs extends readonly unknown[]>(...args: TArgs) {
|
|
611
|
+
return createBuilderAfterAuthenticate<
|
|
612
|
+
TPath,
|
|
613
|
+
TParams,
|
|
614
|
+
TSearch,
|
|
615
|
+
AuthenticateModeFromArgs<TArgs>,
|
|
616
|
+
TPreloaderContext
|
|
617
|
+
>({ ...state, ...resolveAuthenticateArgs(args) });
|
|
610
618
|
},
|
|
611
619
|
authenticateOptional(...args: unknown[]) {
|
|
612
620
|
return createBuilderAfterAuthenticate<TPath, TParams, TSearch, "optional", TPreloaderContext>({
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
} from "./register.ts";
|
|
12
12
|
import {
|
|
13
13
|
type AuthenticateMode,
|
|
14
|
+
type AuthenticateModeFromArgs,
|
|
14
15
|
BUILDER_MARKER,
|
|
15
16
|
type CacheConfig,
|
|
16
17
|
type DeferFn,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
type SearchParamsValidator,
|
|
25
26
|
type ServerThrowHelpers,
|
|
26
27
|
type ServerUrlHelpers,
|
|
28
|
+
resolveAuthenticateArgs,
|
|
27
29
|
} from "./types.ts";
|
|
28
30
|
|
|
29
31
|
/* ── callback context types ─────────────────────────────────────── */
|
|
@@ -385,7 +387,11 @@ interface PageBuilderAfterInput<
|
|
|
385
387
|
TAuth extends AuthenticateMode,
|
|
386
388
|
TPreloaderContext,
|
|
387
389
|
> extends PageBuilderAfterAuthenticate<TPath, TParams, TSearch, TAuth, TPreloaderContext> {
|
|
388
|
-
authenticate(
|
|
390
|
+
/** Required by default; `.authenticate("optional")` lets anonymous requests through with `ctx.auth === null`. Other arguments are callerData for `authenticateFn`. */
|
|
391
|
+
authenticate<const TArgs extends readonly unknown[]>(
|
|
392
|
+
...args: TArgs
|
|
393
|
+
): PageBuilderAfterAuthenticate<TPath, TParams, TSearch, AuthenticateModeFromArgs<TArgs>, TPreloaderContext>;
|
|
394
|
+
/** @deprecated Use `.authenticate("optional", ...callerData)`. */
|
|
389
395
|
authenticateOptional(
|
|
390
396
|
...args: unknown[]
|
|
391
397
|
): PageBuilderAfterAuthenticate<TPath, TParams, TSearch, "optional", TPreloaderContext>;
|
|
@@ -726,12 +732,14 @@ function createBuilderAfterInput<
|
|
|
726
732
|
>(state: BuilderStateInternal): PageBuilderAfterInput<TPath, TParams, TSearch, TAuth, TPreloaderContext> {
|
|
727
733
|
return {
|
|
728
734
|
...createBuilderAfterAuthenticate<TPath, TParams, TSearch, TAuth, TPreloaderContext>(state),
|
|
729
|
-
authenticate(...args:
|
|
730
|
-
return createBuilderAfterAuthenticate<
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
+
authenticate<const TArgs extends readonly unknown[]>(...args: TArgs) {
|
|
736
|
+
return createBuilderAfterAuthenticate<
|
|
737
|
+
TPath,
|
|
738
|
+
TParams,
|
|
739
|
+
TSearch,
|
|
740
|
+
AuthenticateModeFromArgs<TArgs>,
|
|
741
|
+
TPreloaderContext
|
|
742
|
+
>({ ...state, ...resolveAuthenticateArgs(args) });
|
|
735
743
|
},
|
|
736
744
|
authenticateOptional(...args: unknown[]) {
|
|
737
745
|
return createBuilderAfterAuthenticate<TPath, TParams, TSearch, "optional", TPreloaderContext>({
|
|
@@ -4,6 +4,7 @@ import type { Location } from "../router-primitives/index.ts";
|
|
|
4
4
|
import type { ResolvedAuth, ResolvedEnv, ResolvedQueryClient, ResolvedServerContext } from "./register.ts";
|
|
5
5
|
import {
|
|
6
6
|
type AuthenticateMode,
|
|
7
|
+
type AuthenticateModeFromArgs,
|
|
7
8
|
BUILDER_MARKER,
|
|
8
9
|
type CacheConfig,
|
|
9
10
|
type DeferFn,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
type SearchParamsValidator,
|
|
18
19
|
type ServerThrowHelpers,
|
|
19
20
|
type ServerUrlHelpers,
|
|
21
|
+
resolveAuthenticateArgs,
|
|
20
22
|
} from "./types.ts";
|
|
21
23
|
|
|
22
24
|
/* ── callback context types (root-specific) ─────────────────────── */
|
|
@@ -302,7 +304,11 @@ interface RootBuilderAfterInput<TPath extends string, TParams, TSearch> extends
|
|
|
302
304
|
TSearch,
|
|
303
305
|
false
|
|
304
306
|
> {
|
|
305
|
-
authenticate(
|
|
307
|
+
/** Required by default; `.authenticate("optional")` lets anonymous requests through with `ctx.auth === null`. Other arguments are callerData for `authenticateFn`. */
|
|
308
|
+
authenticate<const TArgs extends readonly unknown[]>(
|
|
309
|
+
...args: TArgs
|
|
310
|
+
): RootBuilderAfterAuthenticate<TPath, TParams, TSearch, AuthenticateModeFromArgs<TArgs>>;
|
|
311
|
+
/** @deprecated Use `.authenticate("optional", ...callerData)`. */
|
|
306
312
|
authenticateOptional(...args: unknown[]): RootBuilderAfterAuthenticate<TPath, TParams, TSearch, "optional">;
|
|
307
313
|
}
|
|
308
314
|
|
|
@@ -569,11 +575,10 @@ function createBuilderAfterInput<TPath extends string, TParams, TSearch>(
|
|
|
569
575
|
): RootBuilderAfterInput<TPath, TParams, TSearch> {
|
|
570
576
|
return {
|
|
571
577
|
...createBuilderAfterAuthenticate<TPath, TParams, TSearch, false>(state),
|
|
572
|
-
authenticate(...args:
|
|
573
|
-
return createBuilderAfterAuthenticate<TPath, TParams, TSearch,
|
|
578
|
+
authenticate<const TArgs extends readonly unknown[]>(...args: TArgs) {
|
|
579
|
+
return createBuilderAfterAuthenticate<TPath, TParams, TSearch, AuthenticateModeFromArgs<TArgs>>({
|
|
574
580
|
...state,
|
|
575
|
-
|
|
576
|
-
authenticateMode: true,
|
|
581
|
+
...resolveAuthenticateArgs(args),
|
|
577
582
|
});
|
|
578
583
|
},
|
|
579
584
|
authenticateOptional(...args: unknown[]) {
|
|
@@ -8,6 +8,24 @@ export type { FlareStore, FlareStoreEntry, StaticEntryData };
|
|
|
8
8
|
|
|
9
9
|
export type AuthenticateMode = false | "optional" | true;
|
|
10
10
|
|
|
11
|
+
/** `.authenticate("optional", ...callerData)` is optional; any other argument list is callerData for a required gate. */
|
|
12
|
+
export type AuthenticateModeFromArgs<TArgs extends readonly unknown[]> = TArgs extends readonly [
|
|
13
|
+
"optional",
|
|
14
|
+
...unknown[],
|
|
15
|
+
]
|
|
16
|
+
? "optional"
|
|
17
|
+
: true;
|
|
18
|
+
|
|
19
|
+
/** Runtime half of `AuthenticateModeFromArgs`: splits the mode from the callerData forwarded to `authenticateFn`. */
|
|
20
|
+
export function resolveAuthenticateArgs(args: readonly unknown[]): {
|
|
21
|
+
authenticate: unknown[];
|
|
22
|
+
authenticateMode: "optional" | true;
|
|
23
|
+
} {
|
|
24
|
+
return args[0] === "optional"
|
|
25
|
+
? { authenticate: args.slice(1), authenticateMode: "optional" }
|
|
26
|
+
: { authenticate: [...args], authenticateMode: true };
|
|
27
|
+
}
|
|
28
|
+
|
|
11
29
|
/**
|
|
12
30
|
* Symbol marker for route builder chain methods that look like render fns
|
|
13
31
|
* but return builder objects. Used to filter them out in SSR/hydration/navigation
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AuthenticateMode } from "../route-builder/types.ts";
|
|
1
2
|
import type { SearchParams } from "../url/index.ts";
|
|
2
3
|
|
|
3
4
|
export type PrefetchStrategy = false | "intent" | "render" | "viewport";
|
|
@@ -19,7 +20,7 @@ export type RouteMetaStatic = {
|
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export type RouteMeta = {
|
|
22
|
-
authenticate?:
|
|
23
|
+
authenticate?: AuthenticateMode;
|
|
23
24
|
authorize?: boolean;
|
|
24
25
|
client?: RouteMetaClient;
|
|
25
26
|
intercept?: { from: readonly string[]; render: string };
|
package/src/server/index.ts
CHANGED
|
@@ -39,25 +39,33 @@ export type MountTarget =
|
|
|
39
39
|
}
|
|
40
40
|
| ((request: Request, env: unknown, ctx: { waitUntil(p: Promise<unknown>): void }) => Response | Promise<Response>);
|
|
41
41
|
|
|
42
|
-
export interface ServerBuilder<
|
|
42
|
+
export interface ServerBuilder<
|
|
43
|
+
TExcluded extends string = never,
|
|
44
|
+
TAuth = unknown,
|
|
45
|
+
TServerContext = Record<string, unknown>,
|
|
46
|
+
> {
|
|
47
|
+
/** Type-only: what `.authenticateFn()` and `.serverContext()` resolve to. Generated route types read it. */
|
|
48
|
+
readonly "~flare"?: { auth: TAuth; serverContext: TServerContext };
|
|
43
49
|
authenticateFn: "authenticateFn" extends TExcluded
|
|
44
50
|
? never
|
|
45
|
-
: <
|
|
51
|
+
: <TNewAuth>(
|
|
46
52
|
fn: (ctx: {
|
|
47
53
|
callerData?: unknown[];
|
|
48
54
|
env: unknown;
|
|
49
55
|
request: Request;
|
|
50
56
|
serverContext: Record<string, unknown>;
|
|
51
57
|
url: URL;
|
|
52
|
-
}) =>
|
|
53
|
-
) => ServerBuilder<TExcluded | "authenticateFn">;
|
|
54
|
-
cache: "cache" extends TExcluded
|
|
58
|
+
}) => TNewAuth | null | Promise<TNewAuth | null>,
|
|
59
|
+
) => ServerBuilder<TExcluded | "authenticateFn", TNewAuth, TServerContext>;
|
|
60
|
+
cache: "cache" extends TExcluded
|
|
61
|
+
? never
|
|
62
|
+
: (config: HandlerCacheConfig) => ServerBuilder<TExcluded | "cache", TAuth, TServerContext>;
|
|
55
63
|
fetch(request: Request, env?: unknown, ctx?: { waitUntil?: (p: Promise<unknown>) => void }): Promise<Response>;
|
|
56
64
|
getStaticParams(): Promise<StaticParamsMap>;
|
|
57
65
|
keepalive: "keepalive" extends TExcluded
|
|
58
66
|
? never
|
|
59
|
-
: (config: KeepaliveConfig) => ServerBuilder<TExcluded | "keepalive">;
|
|
60
|
-
mount(prefix: string, target: MountTarget): ServerBuilder<TExcluded>;
|
|
67
|
+
: (config: KeepaliveConfig) => ServerBuilder<TExcluded | "keepalive", TAuth, TServerContext>;
|
|
68
|
+
mount(prefix: string, target: MountTarget): ServerBuilder<TExcluded, TAuth, TServerContext>;
|
|
61
69
|
security: "security" extends TExcluded
|
|
62
70
|
? never
|
|
63
71
|
: (
|
|
@@ -69,15 +77,19 @@ export interface ServerBuilder<TExcluded extends string = never> {
|
|
|
69
77
|
request: Request;
|
|
70
78
|
serverContext: Record<string, unknown>;
|
|
71
79
|
}) => SecurityConfig),
|
|
72
|
-
) => ServerBuilder<TExcluded | "security">;
|
|
80
|
+
) => ServerBuilder<TExcluded | "security", TAuth, TServerContext>;
|
|
73
81
|
serverContext: "serverContext" extends TExcluded
|
|
74
82
|
? never
|
|
75
83
|
: <T extends Record<string, unknown>>(
|
|
76
84
|
fn: (ctx: { env: unknown; request: Request }) => T | Promise<T>,
|
|
77
|
-
) => ServerBuilder<TExcluded | "serverContext">;
|
|
78
|
-
sitemap: "sitemap" extends TExcluded
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
) => ServerBuilder<TExcluded | "serverContext", TAuth, T>;
|
|
86
|
+
sitemap: "sitemap" extends TExcluded
|
|
87
|
+
? never
|
|
88
|
+
: (config: SitemapSubmitConfig) => ServerBuilder<TExcluded | "sitemap", TAuth, TServerContext>;
|
|
89
|
+
tracing: "tracing" extends TExcluded
|
|
90
|
+
? never
|
|
91
|
+
: (config: TracingConfig) => ServerBuilder<TExcluded | "tracing", TAuth, TServerContext>;
|
|
92
|
+
use(...args: (FlareMiddleware | PathMatcher | string)[]): ServerBuilder<TExcluded, TAuth, TServerContext>;
|
|
81
93
|
}
|
|
82
94
|
|
|
83
95
|
/* Internal implementation type — no exclusion tracking */
|
|
@@ -640,7 +640,6 @@ interface EngineResult {
|
|
|
640
640
|
|
|
641
641
|
async function handleSitemapSubmitRequest<TEnv>(
|
|
642
642
|
request: Request,
|
|
643
|
-
url: URL,
|
|
644
643
|
env: TEnv,
|
|
645
644
|
sitemapConfig: SitemapSubmitConfig<TEnv>,
|
|
646
645
|
): Promise<Response> {
|
|
@@ -1154,7 +1153,7 @@ export function createServerHandler<
|
|
|
1154
1153
|
|
|
1155
1154
|
if (url.pathname === "/_flare/sitemap/submit" && config.sitemap) {
|
|
1156
1155
|
/* Internal endpoints bypass middleware response handlers — only security headers */
|
|
1157
|
-
let sitemapResponse = await handleSitemapSubmitRequest(request,
|
|
1156
|
+
let sitemapResponse = await handleSitemapSubmitRequest(request, env, config.sitemap);
|
|
1158
1157
|
sitemapResponse = addSecurityHeaders(sitemapResponse, secHeaders);
|
|
1159
1158
|
return sitemapResponse;
|
|
1160
1159
|
}
|
|
@@ -1288,7 +1287,7 @@ export function createServerHandler<
|
|
|
1288
1287
|
client hashes into the new artifacts. */
|
|
1289
1288
|
if (
|
|
1290
1289
|
staticMeta &&
|
|
1291
|
-
match.route.o.authenticate
|
|
1290
|
+
!match.route.o.authenticate &&
|
|
1292
1291
|
match.route.o.authorize !== true &&
|
|
1293
1292
|
resolvedStore &&
|
|
1294
1293
|
!isISRBgRequest &&
|
|
@@ -1622,7 +1621,7 @@ export function createServerHandler<
|
|
|
1622
1621
|
*/
|
|
1623
1622
|
if (
|
|
1624
1623
|
staticMeta?.mode === "isr" &&
|
|
1625
|
-
match.route.o.authenticate
|
|
1624
|
+
!match.route.o.authenticate &&
|
|
1626
1625
|
match.route.o.authorize !== true &&
|
|
1627
1626
|
resolvedStore &&
|
|
1628
1627
|
!isDataRequest &&
|