@flowselections/core 1.0.31 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/header-identity.d.ts +23 -0
- package/dist/auth/header-identity.d.ts.map +1 -0
- package/dist/auth/header-identity.js +53 -0
- package/dist/components/layout/AuthenticatedLayout.d.ts +2 -0
- package/dist/components/layout/AuthenticatedLayout.d.ts.map +1 -1
- package/dist/components/layout/AuthenticatedLayout.js +12 -3
- package/dist/components/layout/Header.d.ts +3 -1
- package/dist/components/layout/Header.d.ts.map +1 -1
- package/dist/components/layout/Header.js +5 -2
- package/dist/components/layout/HeaderIdentity.d.ts +5 -0
- package/dist/components/layout/HeaderIdentity.d.ts.map +1 -0
- package/dist/components/layout/HeaderIdentity.js +32 -0
- package/dist/components/layout/Sidebar.d.ts +26 -1
- package/dist/components/layout/Sidebar.d.ts.map +1 -1
- package/dist/components/layout/Sidebar.js +45 -7
- package/dist/components/layout/StartPage.d.ts +7 -0
- package/dist/components/layout/StartPage.d.ts.map +1 -0
- package/dist/components/layout/StartPage.js +51 -0
- package/dist/components/layout/useHeaderGreeting.d.ts +3 -0
- package/dist/components/layout/useHeaderGreeting.d.ts.map +1 -0
- package/dist/components/layout/useHeaderGreeting.js +40 -0
- package/dist/components/ui/command.d.ts +7 -7
- package/dist/extensions/ShellExtensions.d.ts +16 -1
- package/dist/extensions/ShellExtensions.d.ts.map +1 -1
- package/dist/extensions/ShellExtensions.js +27 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/navigation/start.d.ts +60 -0
- package/dist/navigation/start.d.ts.map +1 -0
- package/dist/navigation/start.js +141 -0
- package/dist/routes/index.d.ts +40 -7
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +42 -8
- package/dist/server/shell-runtime.d.ts.map +1 -1
- package/dist/server/shell-runtime.js +59 -13
- package/dist/supabase/auth-middleware.d.ts +30 -0
- package/dist/supabase/auth-middleware.d.ts.map +1 -1
- package/dist/supabase/client.d.ts +30 -0
- package/dist/supabase/client.d.ts.map +1 -1
- package/dist/supabase/client.server.d.ts +30 -0
- package/dist/supabase/client.server.d.ts.map +1 -1
- package/dist/supabase/types.d.ts +30 -0
- package/dist/supabase/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useContext, useMemo } from "react";
|
|
3
|
-
const ShellExtensionsContext = createContext({ transforms: [] });
|
|
3
|
+
const ShellExtensionsContext = createContext({ transforms: [], startPaths: [] });
|
|
4
4
|
const identityFooter = () => (items) => items;
|
|
5
5
|
/** Sinds 1.0.23. Past de footer-transform toe; fout → ongewijzigd. Zichtbaarheid, geen beveiliging. */
|
|
6
6
|
export function useFooterItems(base) {
|
|
@@ -20,13 +20,16 @@ export function useFooterItems(base) {
|
|
|
20
20
|
return base;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
export function ShellExtensionsProvider({ useModuleList, guard, useFooter, children, }) {
|
|
23
|
+
export function ShellExtensionsProvider({ useModuleList, guard, useFooter, useStartPath, children, }) {
|
|
24
24
|
const transforms = useMemo(() => (Array.isArray(useModuleList) ? useModuleList : useModuleList ? [useModuleList] : []),
|
|
25
25
|
// Bewust op de referentie(s): de hooks moeten stabiel zijn, zodat de
|
|
26
26
|
// hook-volgorde tussen renders nooit verandert.
|
|
27
27
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
28
|
[useModuleList]);
|
|
29
|
-
const
|
|
29
|
+
const startPaths = useMemo(() => (Array.isArray(useStartPath) ? useStartPath : useStartPath ? [useStartPath] : []),
|
|
30
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
31
|
+
[useStartPath]);
|
|
32
|
+
const value = useMemo(() => ({ transforms, startPaths, guard, useFooter }), [transforms, startPaths, guard, useFooter]);
|
|
30
33
|
return _jsx(ShellExtensionsContext.Provider, { value: value, children: children });
|
|
31
34
|
}
|
|
32
35
|
export function useShellGuard() {
|
|
@@ -65,3 +68,24 @@ export function useModuleListTransform(modules, allModules = modules) {
|
|
|
65
68
|
}
|
|
66
69
|
return result;
|
|
67
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Sinds 1.0.32. Roept de startpagina-hooks aan (vaste volgorde) en geeft hun
|
|
73
|
+
* resultaten terug, rol vóór shell. Een fout of ongeldige vorm telt als
|
|
74
|
+
* "geen voorkeur" (fail-open).
|
|
75
|
+
*/
|
|
76
|
+
export function useStartPathPreferences() {
|
|
77
|
+
const { startPaths } = useContext(ShellExtensionsContext);
|
|
78
|
+
const out = [];
|
|
79
|
+
for (const useStart of startPaths) {
|
|
80
|
+
try {
|
|
81
|
+
const r = useStart();
|
|
82
|
+
if (r && (r.bron === "rol" || r.bron === "shell")) {
|
|
83
|
+
out.push({ bron: r.bron, pad: typeof r.pad === "string" ? r.pad : null, laden: r.laden === true });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
/* fail-open */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return [...out.filter((r) => r.bron === "rol"), ...out.filter((r) => r.bron === "shell")];
|
|
91
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -45,8 +45,11 @@ export { useIsMobile } from "./hooks/use-mobile.js";
|
|
|
45
45
|
export { useHuisstijl } from "./hooks/useHuisstijl.js";
|
|
46
46
|
export type { FlowModule, NavItem, SettingsCard, FeatureDefinition } from "./types/module.js";
|
|
47
47
|
export { moduleKey, navKey, featureKey, moduleFeatures } from "./types/module.js";
|
|
48
|
-
export { ShellExtensionsProvider, useModuleListTransform, useFooterItems } from "./extensions/ShellExtensions.js";
|
|
49
|
-
export
|
|
48
|
+
export { ShellExtensionsProvider, useModuleListTransform, useFooterItems, useStartPathPreferences, } from "./extensions/ShellExtensions.js";
|
|
49
|
+
export { StartPage } from "./components/layout/StartPage.js";
|
|
50
|
+
export { modulePagePath, isPathActive, routeExists, pickStartPath, orderStartPreferences, getFailedStartPaths, START_PATH, } from "./navigation/start.js";
|
|
51
|
+
export type { StartPathResult, StartPathSource, StartDecision, PickStartArgs } from "./navigation/start.js";
|
|
52
|
+
export type { ModuleListTransform, ModuleListTransformContext, UseModuleListTransform, ShellExtensionsProviderProps, FooterItems, FooterTransform, UseFooterTransform, UseStartPath, } from "./extensions/ShellExtensions.js";
|
|
50
53
|
export { ModuleGuardSlot } from "./extensions/ModuleGuardSlot.js";
|
|
51
54
|
export { useMyModulePermissions, useModulePermission, useModulePermissionTransform, useCan, Can, usePermissionFilteredModules, } from "./permissions/useModulePermission.js";
|
|
52
55
|
export type { PermissionLevel, ModulePermissionRow, CanProps } from "./permissions/useModulePermission.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/core/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGtF,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACnG,YAAY,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,YAAY,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAC3F,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGpD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAChH,OAAO,EACL,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EACnE,aAAa,EAAE,YAAY,EAAE,WAAW,GACzC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,kBAAkB,EACrE,sBAAsB,EAAE,iBAAiB,EAAE,iBAAiB,EAC5D,gBAAgB,EAAE,kBAAkB,GACrC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,GAC9D,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,GAC9D,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACnF,OAAO,EACL,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,gBAAgB,EACxE,wBAAwB,EAAE,qBAAqB,EAAE,iBAAiB,EAClE,qBAAqB,EAAE,oBAAoB,EAAE,iBAAiB,EAC9D,kBAAkB,EAAE,eAAe,EAAE,sBAAsB,EAC3D,sBAAsB,EAAE,sBAAsB,GAC/C,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAG/B,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGvD,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGlF,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,cAAc,EACd,uBAAuB,GACxB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EACL,cAAc,EACd,YAAY,EACZ,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,UAAU,GACX,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC5G,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,4BAA4B,EAC5B,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,YAAY,GACb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGlE,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,4BAA4B,EAC5B,MAAM,EACN,GAAG,EACH,4BAA4B,GAC7B,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,YAAY,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -43,7 +43,9 @@ export { useIsMobile } from "./hooks/use-mobile.js";
|
|
|
43
43
|
export { useHuisstijl } from "./hooks/useHuisstijl.js";
|
|
44
44
|
export { moduleKey, navKey, featureKey, moduleFeatures } from "./types/module.js";
|
|
45
45
|
// Shell-extensiepunten (allemaal optioneel; zonder provider ongewijzigd gedrag)
|
|
46
|
-
export { ShellExtensionsProvider, useModuleListTransform, useFooterItems } from "./extensions/ShellExtensions.js";
|
|
46
|
+
export { ShellExtensionsProvider, useModuleListTransform, useFooterItems, useStartPathPreferences, } from "./extensions/ShellExtensions.js";
|
|
47
|
+
export { StartPage } from "./components/layout/StartPage.js";
|
|
48
|
+
export { modulePagePath, isPathActive, routeExists, pickStartPath, orderStartPreferences, getFailedStartPaths, START_PATH, } from "./navigation/start.js";
|
|
47
49
|
export { ModuleGuardSlot } from "./extensions/ModuleGuardSlot.js";
|
|
48
50
|
// Rechten (leeskant; fail-open, zie README)
|
|
49
51
|
export { useMyModulePermissions, useModulePermission, useModulePermissionTransform, useCan, Can, usePermissionFilteredModules, } from "./permissions/useModulePermission.js";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { FlowModule } from "../types/module.js";
|
|
2
|
+
/** Standaardpad van de startpagina en de laatste terugval. */
|
|
3
|
+
export declare const START_PATH = "/start";
|
|
4
|
+
export declare const START_FALLBACK = "/instellingen";
|
|
5
|
+
/**
|
|
6
|
+
* Sinds 1.0.32. Bestemming van een module: bij een groep de href van het
|
|
7
|
+
* eerste (na het rechtenfilter zichtbare) kind, anders `nav.href`.
|
|
8
|
+
* Core gebruikt `nav.href` van een groep nooit als bestemming.
|
|
9
|
+
*/
|
|
10
|
+
export declare function modulePagePath(mod: FlowModule): string;
|
|
11
|
+
/** Actief als het pad gelijk is aan `href` of eronder valt. */
|
|
12
|
+
export declare function isPathActive(pathname: string, href: string): boolean;
|
|
13
|
+
type RouterLike = {
|
|
14
|
+
getMatchedRoutes?: (pathname: string, routePathname?: string) => unknown;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Sinds 1.0.32. Bestaat het pad als route (zonder te navigeren)? Een
|
|
18
|
+
* vangroute (root-splat) of alleen de root telt niet. Zonder router-API: `true`
|
|
19
|
+
* (fail-open).
|
|
20
|
+
*/
|
|
21
|
+
export declare function routeExists(router: RouterLike | null | undefined, path: string): boolean;
|
|
22
|
+
export type StartPathSource = "rol" | "shell";
|
|
23
|
+
export interface StartPathResult {
|
|
24
|
+
bron: StartPathSource;
|
|
25
|
+
pad: string | null;
|
|
26
|
+
laden: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Rol vóór shell; binnen dezelfde bron de registratievolgorde. */
|
|
29
|
+
export declare function orderStartPreferences(results: StartPathResult[]): StartPathResult[];
|
|
30
|
+
export interface PickStartArgs {
|
|
31
|
+
preferences: StartPathResult[];
|
|
32
|
+
/** Zichtbare modules in zijbalkvolgorde (na rechten en ordening). */
|
|
33
|
+
modules: FlowModule[];
|
|
34
|
+
failed?: string[];
|
|
35
|
+
canAccess: (path: string) => Promise<boolean> | boolean;
|
|
36
|
+
exists: (path: string) => boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface StartDecision {
|
|
39
|
+
pad: string;
|
|
40
|
+
stap: "rol" | "shell" | "module" | "instellingen";
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Sinds 1.0.32. Volgorde: rol → shell → eerste module → /instellingen.
|
|
44
|
+
* Een voorkeur telt alleen als hij bestaat, toegankelijk is en niet eerder in
|
|
45
|
+
* deze sessie mislukte.
|
|
46
|
+
*/
|
|
47
|
+
export declare function pickStartPath({ preferences, modules, failed, canAccess, exists }: PickStartArgs): Promise<StartDecision>;
|
|
48
|
+
/** Paden die vanuit /start eerder een 404 of "Geen toegang" gaven. */
|
|
49
|
+
export declare function getFailedStartPaths(): string[];
|
|
50
|
+
/** /start zet dit vlak vóór het navigeren. */
|
|
51
|
+
export declare function markStartNavigation(path: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Afronding van een navigatie: alleen als hij vanuit /start kwam en op dit
|
|
54
|
+
* pad landde, wordt een mislukking onthouden. Andere 404's tellen niet.
|
|
55
|
+
*/
|
|
56
|
+
export declare function settleStartNavigation(path: string, failed: boolean): void;
|
|
57
|
+
/** Alleen voor tests. */
|
|
58
|
+
export declare function __resetStartGuard(): void;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=start.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/core/navigation/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,8DAA8D;AAC9D,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAGtD;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKpE;AAED,KAAK,UAAU,GAAG;IAChB,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1E,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAexF;AAID,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,CAAC;AAC9C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,mEAAmE;AACnE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAEnF;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,qEAAqE;IACrE,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACxD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,cAAc,CAAC;CACnD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,MAAW,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAmBnI;AA8BD,sEAAsE;AACtE,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAED,8CAA8C;AAC9C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,QAE/C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,QAOlE;AAED,yBAAyB;AACzB,wBAAgB,iBAAiB,SAQhC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { safeRedirectPath } from "../auth/redirect.js";
|
|
2
|
+
/** Standaardpad van de startpagina en de laatste terugval. */
|
|
3
|
+
export const START_PATH = "/start";
|
|
4
|
+
export const START_FALLBACK = "/instellingen";
|
|
5
|
+
/**
|
|
6
|
+
* Sinds 1.0.32. Bestemming van een module: bij een groep de href van het
|
|
7
|
+
* eerste (na het rechtenfilter zichtbare) kind, anders `nav.href`.
|
|
8
|
+
* Core gebruikt `nav.href` van een groep nooit als bestemming.
|
|
9
|
+
*/
|
|
10
|
+
export function modulePagePath(mod) {
|
|
11
|
+
const first = mod.nav.children?.[0];
|
|
12
|
+
return first ? first.href : mod.nav.href;
|
|
13
|
+
}
|
|
14
|
+
/** Actief als het pad gelijk is aan `href` of eronder valt. */
|
|
15
|
+
export function isPathActive(pathname, href) {
|
|
16
|
+
if (!href)
|
|
17
|
+
return false;
|
|
18
|
+
if (pathname === href)
|
|
19
|
+
return true;
|
|
20
|
+
const base = href.endsWith("/") ? href.slice(0, -1) : href;
|
|
21
|
+
return base !== "" && pathname.startsWith(base + "/");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Sinds 1.0.32. Bestaat het pad als route (zonder te navigeren)? Een
|
|
25
|
+
* vangroute (root-splat) of alleen de root telt niet. Zonder router-API: `true`
|
|
26
|
+
* (fail-open).
|
|
27
|
+
*/
|
|
28
|
+
export function routeExists(router, path) {
|
|
29
|
+
if (!router || typeof router.getMatchedRoutes !== "function")
|
|
30
|
+
return true;
|
|
31
|
+
const pathname = path.split("?")[0].split("#")[0] || "/";
|
|
32
|
+
try {
|
|
33
|
+
// Oudere routerversies geven een object, nieuwere een tuple [routes, params, foundRoute].
|
|
34
|
+
const res = router.getMatchedRoutes(pathname, undefined);
|
|
35
|
+
const found = Array.isArray(res) ? res[2] : res?.foundRoute;
|
|
36
|
+
if (!found)
|
|
37
|
+
return false;
|
|
38
|
+
if (found.id === "__root__")
|
|
39
|
+
return false;
|
|
40
|
+
const full = found.fullPath ?? "";
|
|
41
|
+
if (full === "/$" || full === "$")
|
|
42
|
+
return false;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Rol vóór shell; binnen dezelfde bron de registratievolgorde. */
|
|
50
|
+
export function orderStartPreferences(results) {
|
|
51
|
+
return [...results.filter((r) => r.bron === "rol"), ...results.filter((r) => r.bron === "shell")];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sinds 1.0.32. Volgorde: rol → shell → eerste module → /instellingen.
|
|
55
|
+
* Een voorkeur telt alleen als hij bestaat, toegankelijk is en niet eerder in
|
|
56
|
+
* deze sessie mislukte.
|
|
57
|
+
*/
|
|
58
|
+
export async function pickStartPath({ preferences, modules, failed = [], canAccess, exists }) {
|
|
59
|
+
const skip = new Set(failed);
|
|
60
|
+
for (const pref of orderStartPreferences(preferences)) {
|
|
61
|
+
const pad = pref.pad ? safeRedirectPath(pref.pad, "") : "";
|
|
62
|
+
if (!pad || pad === START_PATH || skip.has(pad) || !exists(pad))
|
|
63
|
+
continue;
|
|
64
|
+
let ok = false;
|
|
65
|
+
try {
|
|
66
|
+
ok = await canAccess(pad);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
ok = true;
|
|
70
|
+
}
|
|
71
|
+
if (ok)
|
|
72
|
+
return { pad, stap: pref.bron };
|
|
73
|
+
}
|
|
74
|
+
for (const mod of modules) {
|
|
75
|
+
const pad = modulePagePath(mod);
|
|
76
|
+
if (!pad || pad === START_PATH || skip.has(pad) || !exists(pad))
|
|
77
|
+
continue;
|
|
78
|
+
return { pad, stap: "module" };
|
|
79
|
+
}
|
|
80
|
+
return { pad: START_FALLBACK, stap: "instellingen" };
|
|
81
|
+
}
|
|
82
|
+
// ─── Bescherming tegen rondjes ───────────────────────────────────────────────
|
|
83
|
+
const FAILED_KEY = "core:start:failed";
|
|
84
|
+
let memoryFailed = [];
|
|
85
|
+
let pending = null;
|
|
86
|
+
function readFailed() {
|
|
87
|
+
try {
|
|
88
|
+
const raw = globalThis.sessionStorage?.getItem(FAILED_KEY);
|
|
89
|
+
if (raw) {
|
|
90
|
+
const list = JSON.parse(raw);
|
|
91
|
+
if (Array.isArray(list))
|
|
92
|
+
return list.filter((p) => typeof p === "string");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
/* geen opslag */
|
|
97
|
+
}
|
|
98
|
+
return memoryFailed;
|
|
99
|
+
}
|
|
100
|
+
function writeFailed(list) {
|
|
101
|
+
memoryFailed = list;
|
|
102
|
+
try {
|
|
103
|
+
globalThis.sessionStorage?.setItem(FAILED_KEY, JSON.stringify(list));
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* geen opslag: alleen geheugen */
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** Paden die vanuit /start eerder een 404 of "Geen toegang" gaven. */
|
|
110
|
+
export function getFailedStartPaths() {
|
|
111
|
+
return [...new Set([...readFailed(), ...memoryFailed])];
|
|
112
|
+
}
|
|
113
|
+
/** /start zet dit vlak vóór het navigeren. */
|
|
114
|
+
export function markStartNavigation(path) {
|
|
115
|
+
pending = path;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Afronding van een navigatie: alleen als hij vanuit /start kwam en op dit
|
|
119
|
+
* pad landde, wordt een mislukking onthouden. Andere 404's tellen niet.
|
|
120
|
+
*/
|
|
121
|
+
export function settleStartNavigation(path, failed) {
|
|
122
|
+
if (pending === null || pending !== path)
|
|
123
|
+
return;
|
|
124
|
+
pending = null;
|
|
125
|
+
if (failed) {
|
|
126
|
+
const list = getFailedStartPaths();
|
|
127
|
+
if (!list.includes(path))
|
|
128
|
+
writeFailed([...list, path]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Alleen voor tests. */
|
|
132
|
+
export function __resetStartGuard() {
|
|
133
|
+
pending = null;
|
|
134
|
+
memoryFailed = [];
|
|
135
|
+
try {
|
|
136
|
+
globalThis.sessionStorage?.removeItem(FAILED_KEY);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
/* */
|
|
140
|
+
}
|
|
141
|
+
}
|
package/dist/routes/index.d.ts
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
export interface SystemRouteOptions {
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Pad als er geen geldig `?redirect` is (na inloggen, handover, reset).
|
|
4
|
+
* Sinds 1.0.32 optioneel: zonder → "/start" (startpagina per rol/shell).
|
|
5
|
+
*/
|
|
6
|
+
landing?: string;
|
|
4
7
|
/** Pad van de inlogpagina. Standaard "/login". */
|
|
5
8
|
loginPath?: string;
|
|
6
9
|
}
|
|
7
10
|
export interface LoginSearch {
|
|
8
11
|
redirect?: string;
|
|
9
12
|
}
|
|
10
|
-
/**
|
|
11
|
-
|
|
13
|
+
/**
|
|
14
|
+
* `/login`: ingelogd → `?redirect` (alleen same-site) wint van `landing`.
|
|
15
|
+
* Zonder `landing` (sinds 1.0.32): `?redirect` alleen als die toegankelijk is
|
|
16
|
+
* (`canAccessModule`), anders "/start".
|
|
17
|
+
*/
|
|
18
|
+
export declare function loginRoute({ landing }?: SystemRouteOptions): {
|
|
12
19
|
validateSearch: (search: Record<string, unknown>) => LoginSearch;
|
|
13
20
|
beforeLoad: ({ context, search }: {
|
|
14
21
|
context: unknown;
|
|
15
22
|
search: LoginSearch;
|
|
16
|
-
}) => void
|
|
23
|
+
}) => void | Promise<void>;
|
|
17
24
|
head: () => {
|
|
18
25
|
meta: ({
|
|
19
26
|
title: string;
|
|
@@ -35,7 +42,7 @@ export declare function loginRoute({ landing }: SystemRouteOptions): {
|
|
|
35
42
|
component: () => import("react/jsx-runtime").JSX.Element;
|
|
36
43
|
};
|
|
37
44
|
/** `/reset-wachtwoord`: de core-pagina, daarna naar `landing`. */
|
|
38
|
-
export declare function resetPasswordRoute({ landing, loginPath }
|
|
45
|
+
export declare function resetPasswordRoute({ landing, loginPath }?: SystemRouteOptions): {
|
|
39
46
|
head: () => {
|
|
40
47
|
meta: ({
|
|
41
48
|
title: string;
|
|
@@ -57,7 +64,7 @@ export declare function resetPasswordRoute({ landing, loginPath }: SystemRouteOp
|
|
|
57
64
|
component: () => import("react/jsx-runtime").JSX.Element;
|
|
58
65
|
};
|
|
59
66
|
/** `/`: redirect in beforeLoad, dus er wordt niets gerenderd (geen flits). */
|
|
60
|
-
export declare function landingRoute({ landing }
|
|
67
|
+
export declare function landingRoute({ landing }?: Pick<SystemRouteOptions, "landing">): {
|
|
61
68
|
head: () => {
|
|
62
69
|
meta: ({
|
|
63
70
|
title: string;
|
|
@@ -104,4 +111,30 @@ export declare function handoverRoute({ landing, loginPath, exchangePath, }: Sys
|
|
|
104
111
|
};
|
|
105
112
|
component: () => import("react/jsx-runtime").JSX.Element;
|
|
106
113
|
};
|
|
114
|
+
/**
|
|
115
|
+
* Sinds 1.0.32. `/start` onder `_authenticated` (door het dashboard
|
|
116
|
+
* gegenereerd): kiest rol → shell → eerste module → /instellingen.
|
|
117
|
+
*/
|
|
118
|
+
export declare function startRoute(): {
|
|
119
|
+
ssr: false;
|
|
120
|
+
head: () => {
|
|
121
|
+
meta: ({
|
|
122
|
+
title: string;
|
|
123
|
+
name?: undefined;
|
|
124
|
+
content?: undefined;
|
|
125
|
+
property?: undefined;
|
|
126
|
+
} | {
|
|
127
|
+
name: string;
|
|
128
|
+
content: string;
|
|
129
|
+
title?: undefined;
|
|
130
|
+
property?: undefined;
|
|
131
|
+
} | {
|
|
132
|
+
property: string;
|
|
133
|
+
content: string;
|
|
134
|
+
title?: undefined;
|
|
135
|
+
name?: undefined;
|
|
136
|
+
})[];
|
|
137
|
+
};
|
|
138
|
+
component: () => import("react/jsx-runtime").JSX.Element;
|
|
139
|
+
};
|
|
107
140
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/routes/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/routes/index.tsx"],"names":[],"mappings":"AA8BA,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,GAAE,kBAAuB;6BAElC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,WAAW;sCAE5B;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,KAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;EA0BrG;AAED,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,EAAE,OAAoB,EAAE,SAAoB,EAAE,GAAE,kBAAuB;;;;;;;;;;;;;;;;;;;;EAOzG;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,EAAE,OAAoB,EAAE,GAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAM;;;;;;;;;;;;;;;;;;;sBAG3E,KAAK;;EAOxB;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,EAC5B,OAAoB,EACpB,SAAoB,EACpB,YAAY,GACb,EAAE,kBAAkB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;EAQhD;AAED;;;GAGG;AACH,wBAAgB,UAAU;;;;;;;;;;;;;;;;;;;;;EAQzB"}
|
package/dist/routes/index.js
CHANGED
|
@@ -12,7 +12,9 @@ import { redirect } from "@tanstack/react-router";
|
|
|
12
12
|
import { LoginPage } from "../components/layout/LoginPage.js";
|
|
13
13
|
import { ResetWachtwoordPage } from "../components/layout/ResetWachtwoordPage.js";
|
|
14
14
|
import { HandoverPage } from "../components/layout/HandoverPage.js";
|
|
15
|
-
import {
|
|
15
|
+
import { StartPage } from "../components/layout/StartPage.js";
|
|
16
|
+
import { canAccessModule, safeRedirectPath } from "../auth/redirect.js";
|
|
17
|
+
import { START_PATH } from "../navigation/start.js";
|
|
16
18
|
function pageHead(title, description) {
|
|
17
19
|
return {
|
|
18
20
|
meta: [
|
|
@@ -28,23 +30,42 @@ function pageHead(title, description) {
|
|
|
28
30
|
function isAuthenticated(context) {
|
|
29
31
|
return Boolean(context?.auth?.isAuthenticated);
|
|
30
32
|
}
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
+
/**
|
|
34
|
+
* `/login`: ingelogd → `?redirect` (alleen same-site) wint van `landing`.
|
|
35
|
+
* Zonder `landing` (sinds 1.0.32): `?redirect` alleen als die toegankelijk is
|
|
36
|
+
* (`canAccessModule`), anders "/start".
|
|
37
|
+
*/
|
|
38
|
+
export function loginRoute({ landing } = {}) {
|
|
33
39
|
return {
|
|
34
40
|
validateSearch: (search) => typeof search.redirect === "string" ? { redirect: search.redirect } : {},
|
|
35
41
|
beforeLoad: ({ context, search }) => {
|
|
36
|
-
if (isAuthenticated(context))
|
|
42
|
+
if (!isAuthenticated(context))
|
|
43
|
+
return;
|
|
44
|
+
if (landing) {
|
|
37
45
|
throw redirect({ href: safeRedirectPath(search?.redirect, landing) });
|
|
38
46
|
}
|
|
47
|
+
const target = safeRedirectPath(search?.redirect, START_PATH);
|
|
48
|
+
if (target === START_PATH)
|
|
49
|
+
throw redirect({ href: START_PATH });
|
|
50
|
+
const auth = context.auth;
|
|
51
|
+
return canAccessModule(target, {
|
|
52
|
+
userId: auth?.user?.id ?? null,
|
|
53
|
+
accessToken: auth?.session?.access_token ?? null,
|
|
54
|
+
roles: Array.isArray(auth?.roles) ? auth.roles : [],
|
|
55
|
+
}).then((ok) => {
|
|
56
|
+
throw redirect({ href: ok ? target : START_PATH });
|
|
57
|
+
}, () => {
|
|
58
|
+
throw redirect({ href: target });
|
|
59
|
+
});
|
|
39
60
|
},
|
|
40
61
|
head: () => pageHead("Inloggen | Flora Select", "Log veilig in bij Flora Select."),
|
|
41
62
|
component: function LoginRouteComponent() {
|
|
42
|
-
return _jsx(LoginPage, { redirectTo: landing, routeHandlesRedirect: true });
|
|
63
|
+
return _jsx(LoginPage, { redirectTo: landing ?? START_PATH, routeHandlesRedirect: true });
|
|
43
64
|
},
|
|
44
65
|
};
|
|
45
66
|
}
|
|
46
67
|
/** `/reset-wachtwoord`: de core-pagina, daarna naar `landing`. */
|
|
47
|
-
export function resetPasswordRoute({ landing, loginPath = "/login" }) {
|
|
68
|
+
export function resetPasswordRoute({ landing = START_PATH, loginPath = "/login" } = {}) {
|
|
48
69
|
return {
|
|
49
70
|
head: () => pageHead("Nieuw wachtwoord | Flora Select", "Stel een nieuw wachtwoord in voor Flora Select."),
|
|
50
71
|
component: function ResetPasswordRouteComponent() {
|
|
@@ -53,7 +74,7 @@ export function resetPasswordRoute({ landing, loginPath = "/login" }) {
|
|
|
53
74
|
};
|
|
54
75
|
}
|
|
55
76
|
/** `/`: redirect in beforeLoad, dus er wordt niets gerenderd (geen flits). */
|
|
56
|
-
export function landingRoute({ landing }) {
|
|
77
|
+
export function landingRoute({ landing = START_PATH } = {}) {
|
|
57
78
|
return {
|
|
58
79
|
head: () => pageHead("Flora Select", "Open de Flora Select-omgeving."),
|
|
59
80
|
beforeLoad: () => {
|
|
@@ -65,7 +86,7 @@ export function landingRoute({ landing }) {
|
|
|
65
86
|
};
|
|
66
87
|
}
|
|
67
88
|
/** `/auth/handover`: client-only, want de sessie staat alleen in localStorage. */
|
|
68
|
-
export function handoverRoute({ landing, loginPath = "/login", exchangePath, }) {
|
|
89
|
+
export function handoverRoute({ landing = START_PATH, loginPath = "/login", exchangePath, }) {
|
|
69
90
|
return {
|
|
70
91
|
ssr: false,
|
|
71
92
|
head: () => pageHead("Aanmelden | Flora Select", "Rond de veilige aanmelding bij Flora Select af."),
|
|
@@ -74,3 +95,16 @@ export function handoverRoute({ landing, loginPath = "/login", exchangePath, })
|
|
|
74
95
|
},
|
|
75
96
|
};
|
|
76
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Sinds 1.0.32. `/start` onder `_authenticated` (door het dashboard
|
|
100
|
+
* gegenereerd): kiest rol → shell → eerste module → /instellingen.
|
|
101
|
+
*/
|
|
102
|
+
export function startRoute() {
|
|
103
|
+
return {
|
|
104
|
+
ssr: false,
|
|
105
|
+
head: () => pageHead("Start | Flora Select", "Je startpagina in Flora Select wordt geopend."),
|
|
106
|
+
component: function StartRouteComponent() {
|
|
107
|
+
return _jsx(StartPage, {});
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-runtime.d.ts","sourceRoot":"","sources":["../../src/core/server/shell-runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shell-runtime.d.ts","sourceRoot":"","sources":["../../src/core/server/shell-runtime.ts"],"names":[],"mappings":"AAmHA,iDAAiD;AACjD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CASjE;AAmBD;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmB9D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYhE;AA+DD;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAcvD;AA4BD,oFAAoF;AACpF,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAWpD;AAyFD,4EAA4E;AAC5E,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAuBjF;AAED,4FAA4F;AAC5F,wBAAsB,eAAe,CAAC,GAAG,CAAC,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAU5G;AAED,yBAAyB;AACzB,wBAAgB,2BAA2B,SAW1C"}
|
|
@@ -56,12 +56,62 @@ async function timedFetch(url, init) {
|
|
|
56
56
|
const ctrl = new AbortController();
|
|
57
57
|
const t = setTimeout(() => ctrl.abort(), TIMEOUT_MS);
|
|
58
58
|
try {
|
|
59
|
-
|
|
59
|
+
const response = await fetch(url, { ...init, signal: ctrl.signal, redirect: "manual" });
|
|
60
|
+
if ((response.status >= 300 && response.status <= 399) || response.type === "opaqueredirect") {
|
|
61
|
+
throw new Error(`onverwachte doorverwijzing (status ${response.status})`);
|
|
62
|
+
}
|
|
63
|
+
return response;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Transport errors can echo a URL or credential. Scrub outgoing values
|
|
67
|
+
// before propagating the error; never attach the request or response body.
|
|
68
|
+
const sensitive = [];
|
|
69
|
+
new Headers(init.headers).forEach((value) => sensitive.push(value));
|
|
70
|
+
if (typeof init.body === "string") {
|
|
71
|
+
sensitive.push(init.body);
|
|
72
|
+
try {
|
|
73
|
+
const collect = (value) => {
|
|
74
|
+
if (typeof value === "string")
|
|
75
|
+
sensitive.push(value);
|
|
76
|
+
else if (Array.isArray(value))
|
|
77
|
+
value.forEach(collect);
|
|
78
|
+
else if (value && typeof value === "object")
|
|
79
|
+
Object.values(value).forEach(collect);
|
|
80
|
+
};
|
|
81
|
+
collect(JSON.parse(init.body));
|
|
82
|
+
}
|
|
83
|
+
catch { /* No body content is logged. */ }
|
|
84
|
+
}
|
|
85
|
+
const detail = errorDetail(error, sensitive);
|
|
86
|
+
const sanitized = new Error(detail.message);
|
|
87
|
+
sanitized.name = detail.error;
|
|
88
|
+
throw sanitized;
|
|
60
89
|
}
|
|
61
90
|
finally {
|
|
62
91
|
clearTimeout(t);
|
|
63
92
|
}
|
|
64
93
|
}
|
|
94
|
+
/** Only bounded error name/message; never serialize an error's extra fields. */
|
|
95
|
+
function errorDetail(error, sensitive = []) {
|
|
96
|
+
const redact = (text) => {
|
|
97
|
+
const values = [...sensitive,
|
|
98
|
+
process.env.SB_SERVICE_ROLE_KEY, process.env.CENTRAL_AUTH_SECRET,
|
|
99
|
+
process.env.SUPABASE_PUBLISHABLE_KEY, process.env.SUPABASE_ANON_KEY,
|
|
100
|
+
cronCache?.value?.secret,
|
|
101
|
+
].filter((value) => typeof value === "string" && value.length > 0);
|
|
102
|
+
let result = text;
|
|
103
|
+
for (const value of values.sort((a, b) => b.length - a.length)) {
|
|
104
|
+
result = result.split(value).join("[redacted]");
|
|
105
|
+
}
|
|
106
|
+
return result.replace(/https?:\/\/[^\s"'<>]+/gi, "[url]")
|
|
107
|
+
.replace(/\b(?:sb_secret_|sb_publishable_)[\w-]+|\beyJ[\w-]*\.[\w-]+\.[\w-]+/g, "[redacted]")
|
|
108
|
+
.replace(/[\r\n\t]/g, " ").slice(0, 200);
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
error: redact(error instanceof Error ? error.name : "UnknownError"),
|
|
112
|
+
message: redact(error instanceof Error ? error.message : "onbekende fout"),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
65
115
|
/** Absolute https-origin zonder pad, of null. */
|
|
66
116
|
export function normalizeShellBaseUrl(raw) {
|
|
67
117
|
if (typeof raw !== "string" || !raw.trim())
|
|
@@ -109,9 +159,7 @@ export async function getShellBaseUrl() {
|
|
|
109
159
|
return value;
|
|
110
160
|
}
|
|
111
161
|
catch (e) {
|
|
112
|
-
warn("read", "shell-adres lezen mislukt; laatst bekende waarde gebruikt",
|
|
113
|
-
error: e instanceof Error ? e.message : "onbekend",
|
|
114
|
-
});
|
|
162
|
+
warn("read", "shell-adres lezen mislukt; laatst bekende waarde gebruikt", errorDetail(e));
|
|
115
163
|
const last = baseUrlCache?.value ?? null;
|
|
116
164
|
baseUrlCache = { value: last, at: Date.now() };
|
|
117
165
|
return last;
|
|
@@ -213,9 +261,7 @@ export async function ensureCentralLink() {
|
|
|
213
261
|
.then((ok) => { nextLinkCheck = Date.now() + (ok ? LINK_INTERVAL_MS : CRON_TTL_MS); })
|
|
214
262
|
.catch((e) => {
|
|
215
263
|
nextLinkCheck = Date.now() + CRON_TTL_MS;
|
|
216
|
-
warn("link-error", "Central-koppeling controleren mislukt",
|
|
217
|
-
error: e instanceof Error ? e.name : "onbekend",
|
|
218
|
-
});
|
|
264
|
+
warn("link-error", "Central-koppeling controleren mislukt", errorDetail(e));
|
|
219
265
|
})
|
|
220
266
|
.finally(() => {
|
|
221
267
|
linkInflight = null;
|
|
@@ -256,9 +302,9 @@ export async function ensureCronKeys() {
|
|
|
256
302
|
return;
|
|
257
303
|
cronKeyInflight = cronKeysOnce()
|
|
258
304
|
.then((ok) => { nextCronKeyCheck = Date.now() + (ok ? LINK_INTERVAL_MS : CRON_TTL_MS); })
|
|
259
|
-
.catch(() => {
|
|
305
|
+
.catch((e) => {
|
|
260
306
|
nextCronKeyCheck = Date.now() + CRON_TTL_MS;
|
|
261
|
-
warn("cron-key-error", "cronsleutel synchroniseren mislukt");
|
|
307
|
+
warn("cron-key-error", "cronsleutel synchroniseren mislukt", errorDetail(e));
|
|
262
308
|
})
|
|
263
309
|
.finally(() => { cronKeyInflight = null; });
|
|
264
310
|
return cronKeyInflight;
|
|
@@ -327,8 +373,8 @@ async function getCronConfig(force = false, previous) {
|
|
|
327
373
|
return cronCache.value;
|
|
328
374
|
cronCache = null;
|
|
329
375
|
cronInflight = readCronConfig()
|
|
330
|
-
.catch(() => {
|
|
331
|
-
warn("cron-error", "croncontrole lezen mislukt");
|
|
376
|
+
.catch((e) => {
|
|
377
|
+
warn("cron-error", "croncontrole lezen mislukt", errorDetail(e));
|
|
332
378
|
return null;
|
|
333
379
|
})
|
|
334
380
|
.then((value) => {
|
|
@@ -376,8 +422,8 @@ export async function checkCronRequest(request) {
|
|
|
376
422
|
});
|
|
377
423
|
return null;
|
|
378
424
|
}
|
|
379
|
-
catch {
|
|
380
|
-
warn("cron-check", "croncontrole mislukt; verzoek doorgelaten");
|
|
425
|
+
catch (e) {
|
|
426
|
+
warn("cron-check", "croncontrole mislukt; verzoek doorgelaten", errorDetail(e));
|
|
381
427
|
return null;
|
|
382
428
|
}
|
|
383
429
|
}
|
|
@@ -2,6 +2,36 @@ import type { Database } from './types.js';
|
|
|
2
2
|
export declare const requireSupabaseAuth: import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
3
3
|
supabase: import("@supabase/supabase-js").SupabaseClient<Database, "public", "public", {
|
|
4
4
|
Tables: {
|
|
5
|
+
roles: {
|
|
6
|
+
Row: {
|
|
7
|
+
id: string;
|
|
8
|
+
key: string;
|
|
9
|
+
name: string;
|
|
10
|
+
is_protected: boolean;
|
|
11
|
+
created_at: string;
|
|
12
|
+
updated_at: string;
|
|
13
|
+
permissions_initialized: boolean;
|
|
14
|
+
};
|
|
15
|
+
Insert: {
|
|
16
|
+
id?: string;
|
|
17
|
+
key: string;
|
|
18
|
+
name: string;
|
|
19
|
+
is_protected?: boolean;
|
|
20
|
+
created_at?: string;
|
|
21
|
+
updated_at?: string;
|
|
22
|
+
permissions_initialized?: boolean;
|
|
23
|
+
};
|
|
24
|
+
Update: {
|
|
25
|
+
id?: string;
|
|
26
|
+
key?: string;
|
|
27
|
+
name?: string;
|
|
28
|
+
is_protected?: boolean;
|
|
29
|
+
created_at?: string;
|
|
30
|
+
updated_at?: string;
|
|
31
|
+
permissions_initialized?: boolean;
|
|
32
|
+
};
|
|
33
|
+
Relationships: [];
|
|
34
|
+
};
|
|
5
35
|
bugs: {
|
|
6
36
|
Row: {
|
|
7
37
|
attachment_url: string | null;
|