@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.
Files changed (45) hide show
  1. package/dist/auth/header-identity.d.ts +23 -0
  2. package/dist/auth/header-identity.d.ts.map +1 -0
  3. package/dist/auth/header-identity.js +53 -0
  4. package/dist/components/layout/AuthenticatedLayout.d.ts +2 -0
  5. package/dist/components/layout/AuthenticatedLayout.d.ts.map +1 -1
  6. package/dist/components/layout/AuthenticatedLayout.js +12 -3
  7. package/dist/components/layout/Header.d.ts +3 -1
  8. package/dist/components/layout/Header.d.ts.map +1 -1
  9. package/dist/components/layout/Header.js +5 -2
  10. package/dist/components/layout/HeaderIdentity.d.ts +5 -0
  11. package/dist/components/layout/HeaderIdentity.d.ts.map +1 -0
  12. package/dist/components/layout/HeaderIdentity.js +32 -0
  13. package/dist/components/layout/Sidebar.d.ts +26 -1
  14. package/dist/components/layout/Sidebar.d.ts.map +1 -1
  15. package/dist/components/layout/Sidebar.js +45 -7
  16. package/dist/components/layout/StartPage.d.ts +7 -0
  17. package/dist/components/layout/StartPage.d.ts.map +1 -0
  18. package/dist/components/layout/StartPage.js +51 -0
  19. package/dist/components/layout/useHeaderGreeting.d.ts +3 -0
  20. package/dist/components/layout/useHeaderGreeting.d.ts.map +1 -0
  21. package/dist/components/layout/useHeaderGreeting.js +40 -0
  22. package/dist/components/ui/command.d.ts +7 -7
  23. package/dist/extensions/ShellExtensions.d.ts +16 -1
  24. package/dist/extensions/ShellExtensions.d.ts.map +1 -1
  25. package/dist/extensions/ShellExtensions.js +27 -3
  26. package/dist/index.d.ts +5 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +3 -1
  29. package/dist/navigation/start.d.ts +60 -0
  30. package/dist/navigation/start.d.ts.map +1 -0
  31. package/dist/navigation/start.js +141 -0
  32. package/dist/routes/index.d.ts +40 -7
  33. package/dist/routes/index.d.ts.map +1 -1
  34. package/dist/routes/index.js +42 -8
  35. package/dist/server/shell-runtime.d.ts.map +1 -1
  36. package/dist/server/shell-runtime.js +59 -13
  37. package/dist/supabase/auth-middleware.d.ts +30 -0
  38. package/dist/supabase/auth-middleware.d.ts.map +1 -1
  39. package/dist/supabase/client.d.ts +30 -0
  40. package/dist/supabase/client.d.ts.map +1 -1
  41. package/dist/supabase/client.server.d.ts +30 -0
  42. package/dist/supabase/client.server.d.ts.map +1 -1
  43. package/dist/supabase/types.d.ts +30 -0
  44. package/dist/supabase/types.d.ts.map +1 -1
  45. 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 value = useMemo(() => ({ transforms, guard, useFooter }), [transforms, guard, useFooter]);
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 type { ModuleListTransform, ModuleListTransformContext, UseModuleListTransform, ShellExtensionsProviderProps, FooterItems, FooterTransform, UseFooterTransform, } from "./extensions/ShellExtensions.js";
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";
@@ -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":"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"}
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
+ }
@@ -1,19 +1,26 @@
1
1
  export interface SystemRouteOptions {
2
- /** Pad als er geen geldig `?redirect` is (na inloggen, handover, reset). */
3
- landing: string;
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
- /** `/login`: ingelogd → `?redirect` (alleen same-site) wint van `landing`. */
11
- export declare function loginRoute({ landing }: SystemRouteOptions): {
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 }: SystemRouteOptions): {
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 }: Pick<SystemRouteOptions, "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":"AA4BA,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,kBAAkB;6BAE7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,WAAW;sCAE5B;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;EAU9E;AAED,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,SAAoB,EAAE,EAAE,kBAAkB;;;;;;;;;;;;;;;;;;;;EAOvF;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC;;;;;;;;;;;;;;;;;;;sBAGzD,KAAK;;EAOxB;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAoB,EACpB,YAAY,GACb,EAAE,kBAAkB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;EAQhD"}
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"}
@@ -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 { safeRedirectPath } from "../auth/redirect.js";
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
- /** `/login`: ingelogd → `?redirect` (alleen same-site) wint van `landing`. */
32
- export function loginRoute({ landing }) {
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":"AAqEA,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,CAqB9D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYhE;AA+DD;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBvD;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"}
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
- return await fetch(url, { ...init, signal: ctrl.signal, redirect: "error" });
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;