@flowselections/admin-installatietechniek 1.0.3 → 1.0.5

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 (36) hide show
  1. package/dist-lib/components/AdminForInstallatieTechniek.d.ts +4 -0
  2. package/dist-lib/components/AdminForInstallatieTechniek.d.ts.map +1 -1
  3. package/dist-lib/components/AdminForInstallatieTechniek.js +223 -197
  4. package/dist-lib/components/ModuleAccessGuard.d.ts +15 -0
  5. package/dist-lib/components/ModuleAccessGuard.d.ts.map +1 -0
  6. package/dist-lib/components/ModuleAccessGuard.js +40 -0
  7. package/dist-lib/hooks/useModulePermission.d.ts +11 -4
  8. package/dist-lib/hooks/useModulePermission.d.ts.map +1 -1
  9. package/dist-lib/hooks/useModulePermission.js +33 -26
  10. package/dist-lib/index.d.ts +3 -3
  11. package/dist-lib/index.d.ts.map +1 -1
  12. package/dist-lib/index.js +2 -1
  13. package/dist-lib/integrations/supabase/auth-attacher.d.ts.map +1 -1
  14. package/dist-lib/integrations/supabase/auth-attacher.js +5 -1
  15. package/dist-lib/integrations/supabase/auth-middleware.d.ts +978 -133
  16. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  17. package/dist-lib/integrations/supabase/auth-middleware.js +21 -7
  18. package/dist-lib/integrations/supabase/client.d.ts +978 -133
  19. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  20. package/dist-lib/integrations/supabase/client.server.d.ts +978 -133
  21. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  22. package/dist-lib/integrations/supabase/types.d.ts +987 -137
  23. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  24. package/dist-lib/lib/admin.functions.d.ts +78644 -2655
  25. package/dist-lib/lib/admin.functions.d.ts.map +1 -1
  26. package/dist-lib/lib/admin.functions.js +351 -174
  27. package/dist-lib/lib/moduleDiscovery.d.ts +7 -2
  28. package/dist-lib/lib/moduleDiscovery.d.ts.map +1 -1
  29. package/dist-lib/lib/moduleDiscovery.js +26 -11
  30. package/dist-lib/lib/permissions.server.d.ts +14 -0
  31. package/dist-lib/lib/permissions.server.d.ts.map +1 -0
  32. package/dist-lib/lib/permissions.server.js +26 -0
  33. package/package.json +1 -1
  34. package/dist-lib/hooks/useModuleOrder.d.ts +0 -30
  35. package/dist-lib/hooks/useModuleOrder.d.ts.map +0 -1
  36. package/dist-lib/hooks/useModuleOrder.js +0 -99
@@ -1,10 +1,15 @@
1
+ export interface DiscoveredFeature {
2
+ id: string;
3
+ name: string;
4
+ }
1
5
  export interface DiscoveredModule {
2
6
  id: string;
3
7
  name: string;
8
+ features?: DiscoveredFeature[];
4
9
  }
5
10
  /**
6
- * Leidt de modulelijst af uit de routeboom van de draaiende shell.
7
- * Geen hardcoded modules: elke shell levert automatisch zijn eigen set.
11
+ * Leidt de modulelijst (inclusief onderdelen/subpagina's) af uit de routeboom
12
+ * van de draaiende shell. Geen hardcoded modules of onderdelen.
8
13
  */
9
14
  export declare function useDiscoveredModules(): DiscoveredModule[];
10
15
  //# sourceMappingURL=moduleDiscovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"moduleDiscovery.d.ts","sourceRoot":"","sources":["../../src/lib/moduleDiscovery.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAiBD;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,gBAAgB,EAAE,CAqCzD"}
1
+ {"version":3,"file":"moduleDiscovery.d.ts","sourceRoot":"","sources":["../../src/lib/moduleDiscovery.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAiBD;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,gBAAgB,EAAE,CAqDzD"}
@@ -15,17 +15,17 @@ function prettify(segment) {
15
15
  return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
16
16
  }
17
17
  /**
18
- * Leidt de modulelijst af uit de routeboom van de draaiende shell.
19
- * Geen hardcoded modules: elke shell levert automatisch zijn eigen set.
18
+ * Leidt de modulelijst (inclusief onderdelen/subpagina's) af uit de routeboom
19
+ * van de draaiende shell. Geen hardcoded modules of onderdelen.
20
20
  */
21
21
  export function useDiscoveredModules() {
22
22
  const router = useRouter();
23
23
  const routesById = (router?.routesById ?? {});
24
24
  const ids = Object.keys(routesById).sort().join("|");
25
25
  return useMemo(() => {
26
- const found = new Map();
26
+ const names = new Map();
27
+ const features = new Map();
27
28
  for (const routeId of Object.keys(routesById)) {
28
- // Alleen routes binnen de beveiligde shell-omgeving.
29
29
  if (!routeId.startsWith("/_authenticated/"))
30
30
  continue;
31
31
  const path = routeId.slice("/_authenticated/".length);
@@ -39,16 +39,31 @@ export function useDiscoveredModules() {
39
39
  continue;
40
40
  const route = routesById[routeId];
41
41
  const title = route?.options?.staticData?.title;
42
- const isTopLevel = segments.length === 1 || (segments.length === 2 && segments[1] === "index");
43
- const existing = found.get(first);
44
- // Titel van de bovenliggende route wint van die van detailroutes.
42
+ const rest = segments.slice(1).filter((s) => s !== "index");
43
+ const isTopLevel = rest.length === 0;
44
+ const existing = names.get(first);
45
45
  if (!existing || (isTopLevel && typeof title === "string" && title.trim())) {
46
- found.set(first, (isTopLevel && title?.trim()) || existing || prettify(first));
46
+ names.set(first, (isTopLevel && title?.trim()) || existing || prettify(first));
47
+ }
48
+ if (!isTopLevel) {
49
+ // Dynamische segmenten ($id) zijn detailpagina's, geen los onderdeel.
50
+ if (rest.some((s) => s.startsWith("$")))
51
+ continue;
52
+ const featureId = rest.join("/");
53
+ const map = features.get(first) ?? new Map();
54
+ map.set(featureId, title?.trim() || rest.map(prettify).join(" › "));
55
+ features.set(first, map);
47
56
  }
48
57
  }
49
- // Geen alfabetische sortering: de volgorde van de routeboom is de
50
- // standaardvolgorde van de shell.
51
- return Array.from(found.entries()).map(([id, name]) => ({ id, name }));
58
+ return Array.from(names.entries())
59
+ .map(([id, name]) => ({
60
+ id,
61
+ name,
62
+ features: Array.from(features.get(id)?.entries() ?? [])
63
+ .map(([fid, fname]) => ({ id: fid, name: fname }))
64
+ .sort((a, b) => a.name.localeCompare(b.name, "nl")),
65
+ }))
66
+ .sort((a, b) => a.name.localeCompare(b.name, "nl"));
52
67
  // eslint-disable-next-line react-hooks/exhaustive-deps
53
68
  }, [ids]);
54
69
  }
@@ -0,0 +1,14 @@
1
+ import type { ModulePermission } from "../hooks/useModulePermission";
2
+ interface PermissionContext {
3
+ supabase: any;
4
+ userId: string;
5
+ }
6
+ /**
7
+ * Server-side controle voor moduletoegang. Moet in elke server function van
8
+ * een beveiligde module aangeroepen worden die gevoelige data leest of wijzigt.
9
+ * Deze functie draait dezelfde SQL-check als de frontendguard, dus de database
10
+ * is de enige bron van waarheid.
11
+ */
12
+ export declare function requireModulePermission(context: PermissionContext, moduleId: string, featureId?: string, level?: "view" | "edit"): Promise<ModulePermission>;
13
+ export {};
14
+ //# sourceMappingURL=permissions.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.server.d.ts","sourceRoot":"","sources":["../../src/lib/permissions.server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,UAAU,iBAAiB;IACzB,QAAQ,EAAE,GAAG,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAK,EACd,KAAK,GAAE,MAAM,GAAG,MAAe,6BA0BhC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Server-side controle voor moduletoegang. Moet in elke server function van
3
+ * een beveiligde module aangeroepen worden die gevoelige data leest of wijzigt.
4
+ * Deze functie draait dezelfde SQL-check als de frontendguard, dus de database
5
+ * is de enige bron van waarheid.
6
+ */
7
+ export async function requireModulePermission(context, moduleId, featureId = "", level = "view") {
8
+ const { supabase, userId } = context;
9
+ const { data, error } = await supabase.rpc("effective_module_permission", {
10
+ _user_id: userId,
11
+ _module_id: moduleId,
12
+ _feature_id: featureId,
13
+ });
14
+ if (error) {
15
+ console.error("[requireModulePermission] RPC error", error);
16
+ throw new Error("Kan moduletoegang niet controleren");
17
+ }
18
+ const permission = (data ?? "edit");
19
+ if (level === "edit" && permission !== "edit") {
20
+ throw new Error("Geen schrijfrechten voor deze module");
21
+ }
22
+ if (level === "view" && permission !== "view" && permission !== "edit") {
23
+ throw new Error("Geen leesrechten voor deze module");
24
+ }
25
+ return permission;
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/admin-installatietechniek",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "flowselections": {
5
5
  "moduleId": "admin-installatietechniek",
6
6
  "pages": [
@@ -1,30 +0,0 @@
1
- export interface ModuleOrderEntry {
2
- id: string;
3
- name: string;
4
- sortOrder: number | null;
5
- }
6
- interface OrderableModule {
7
- id: string;
8
- name?: string;
9
- }
10
- /** Laat elke actieve `useModuleOrder()` de volgorde direct opnieuw ophalen. */
11
- export declare function notifyModuleOrderChanged(): void;
12
- /**
13
- * Sorteert een modulelijst volgens de opgeslagen volgorde.
14
- * Modules zonder opgeslagen positie behouden hun oorspronkelijke plek
15
- * (de bronvolgorde van de shell) — geen alfabetische herschikking.
16
- */
17
- export declare function sortModulesByOrder<T extends OrderableModule>(modules: T[], order: ModuleOrderEntry[]): T[];
18
- /**
19
- * Haalt de opgeslagen zijbalk-volgorde op en levert een sorteerfunctie
20
- * die shells op hun modulelijst kunnen toepassen. Werkt realtime bij
21
- * zodra de adminpagina een nieuwe volgorde opslaat.
22
- */
23
- export declare function useModuleOrder(): {
24
- order: ModuleOrderEntry[];
25
- loading: boolean;
26
- sortModules: <T extends OrderableModule>(modules: T[]) => T[];
27
- reload: () => Promise<void>;
28
- };
29
- export {};
30
- //# sourceMappingURL=useModuleOrder.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useModuleOrder.d.ts","sourceRoot":"","sources":["../../src/hooks/useModuleOrder.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,+EAA+E;AAC/E,wBAAgB,wBAAwB,SAGvC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,eAAe,EAC1D,OAAO,EAAE,CAAC,EAAE,EACZ,KAAK,EAAE,gBAAgB,EAAE,GACxB,CAAC,EAAE,CAyBL;AAED;;;;GAIG;AACH,wBAAgB,cAAc;;;kBA6CzB,CAAC,SAAS,eAAe,WAAW,CAAC,EAAE;;EAK3C"}
@@ -1,99 +0,0 @@
1
- import { useCallback, useEffect, useState } from "react";
2
- import { getModuleOrder } from "../lib/admin.functions";
3
- const MODULE_ORDER_EVENT = "flowselections:module-order-changed";
4
- /** Laat elke actieve `useModuleOrder()` de volgorde direct opnieuw ophalen. */
5
- export function notifyModuleOrderChanged() {
6
- if (typeof window === "undefined")
7
- return;
8
- window.dispatchEvent(new CustomEvent(MODULE_ORDER_EVENT));
9
- }
10
- /**
11
- * Sorteert een modulelijst volgens de opgeslagen volgorde.
12
- * Modules zonder opgeslagen positie behouden hun oorspronkelijke plek
13
- * (de bronvolgorde van de shell) — geen alfabetische herschikking.
14
- */
15
- export function sortModulesByOrder(modules, order) {
16
- const safeModules = Array.isArray(modules) ? modules : [];
17
- const safeOrder = Array.isArray(order) ? order : [];
18
- if (safeOrder.length === 0)
19
- return safeModules;
20
- const positions = new Map();
21
- safeOrder.forEach((entry) => {
22
- if (entry?.id && typeof entry.sortOrder === "number") {
23
- positions.set(entry.id, entry.sortOrder);
24
- }
25
- });
26
- if (positions.size === 0)
27
- return safeModules;
28
- return safeModules
29
- .map((mod, index) => ({ mod, index }))
30
- .sort((a, b) => {
31
- const ao = positions.get(a.mod.id);
32
- const bo = positions.get(b.mod.id);
33
- if (ao !== undefined && bo !== undefined)
34
- return ao - bo;
35
- // Zonder positie: originele volgorde behouden, ná gepositioneerde modules.
36
- if (ao !== undefined)
37
- return -1;
38
- if (bo !== undefined)
39
- return 1;
40
- return a.index - b.index;
41
- })
42
- .map((entry) => entry.mod);
43
- }
44
- /**
45
- * Haalt de opgeslagen zijbalk-volgorde op en levert een sorteerfunctie
46
- * die shells op hun modulelijst kunnen toepassen. Werkt realtime bij
47
- * zodra de adminpagina een nieuwe volgorde opslaat.
48
- */
49
- export function useModuleOrder() {
50
- const [order, setOrder] = useState([]);
51
- const [loading, setLoading] = useState(true);
52
- const reload = useCallback(async () => {
53
- try {
54
- const result = await getModuleOrder();
55
- setOrder(Array.isArray(result?.modules) ? result.modules : []);
56
- }
57
- catch {
58
- setOrder([]);
59
- }
60
- finally {
61
- setLoading(false);
62
- }
63
- }, []);
64
- useEffect(() => {
65
- let cancelled = false;
66
- const load = async () => {
67
- try {
68
- const result = await getModuleOrder();
69
- if (cancelled)
70
- return;
71
- setOrder(Array.isArray(result?.modules) ? result.modules : []);
72
- }
73
- catch {
74
- if (!cancelled)
75
- setOrder([]);
76
- }
77
- finally {
78
- if (!cancelled)
79
- setLoading(false);
80
- }
81
- };
82
- load();
83
- const onChanged = () => {
84
- if (!cancelled)
85
- load();
86
- };
87
- if (typeof window !== "undefined") {
88
- window.addEventListener(MODULE_ORDER_EVENT, onChanged);
89
- }
90
- return () => {
91
- cancelled = true;
92
- if (typeof window !== "undefined") {
93
- window.removeEventListener(MODULE_ORDER_EVENT, onChanged);
94
- }
95
- };
96
- }, []);
97
- const sortModules = useCallback((modules) => sortModulesByOrder(modules, order), [order]);
98
- return { order, loading, sortModules, reload };
99
- }