@flowselections/core 1.0.22 → 1.0.23
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 +61 -0
- package/dist/auth/redirect.d.ts +33 -4
- package/dist/auth/redirect.d.ts.map +1 -1
- package/dist/auth/redirect.js +58 -7
- package/dist/auth/useAuth.d.ts +1 -1
- package/dist/auth/useAuth.d.ts.map +1 -1
- package/dist/auth/useIsSuperadmin.d.ts +19 -0
- package/dist/auth/useIsSuperadmin.d.ts.map +1 -0
- package/dist/auth/useIsSuperadmin.js +16 -0
- package/dist/components/layout/AuthenticatedLayout.d.ts +18 -9
- package/dist/components/layout/AuthenticatedLayout.d.ts.map +1 -1
- package/dist/components/layout/AuthenticatedLayout.js +42 -8
- package/dist/components/layout/InstellingenPage.d.ts.map +1 -1
- package/dist/components/layout/InstellingenPage.js +9 -1
- package/dist/components/layout/ResetWachtwoordPage.d.ts +3 -1
- package/dist/components/layout/ResetWachtwoordPage.d.ts.map +1 -1
- package/dist/components/layout/ResetWachtwoordPage.js +5 -3
- package/dist/components/layout/Sidebar.d.ts +30 -6
- package/dist/components/layout/Sidebar.d.ts.map +1 -1
- package/dist/components/layout/Sidebar.js +31 -9
- package/dist/extensions/ShellExtensions.d.ts +14 -1
- package/dist/extensions/ShellExtensions.d.ts.map +1 -1
- package/dist/extensions/ShellExtensions.js +21 -2
- package/dist/hooks/useLogoSrc.d.ts +7 -0
- package/dist/hooks/useLogoSrc.d.ts.map +1 -0
- package/dist/hooks/useLogoSrc.js +29 -0
- package/dist/index.d.ts +17 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -4
- package/dist/permissions/resolve.d.ts +22 -0
- package/dist/permissions/resolve.d.ts.map +1 -0
- package/dist/permissions/resolve.js +76 -0
- package/dist/permissions/store.d.ts +38 -0
- package/dist/permissions/store.d.ts.map +1 -0
- package/dist/permissions/store.js +180 -0
- package/dist/permissions/useModulePermission.d.ts +52 -32
- package/dist/permissions/useModulePermission.d.ts.map +1 -1
- package/dist/permissions/useModulePermission.js +72 -104
- package/dist/routes/index.d.ts +48 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +63 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/permissions.server.d.ts +21 -8
- package/dist/server/permissions.server.d.ts.map +1 -1
- package/dist/server/permissions.server.js +54 -9
- package/dist/shell/ShellContext.d.ts +26 -0
- package/dist/shell/ShellContext.d.ts.map +1 -0
- package/dist/shell/ShellContext.js +14 -0
- package/dist/styles.css +127 -0
- package/dist/types/module.d.ts +39 -4
- package/dist/types/module.d.ts.map +1 -1
- package/dist/types/module.js +33 -5
- package/package.json +13 -5
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getRequest } from "@tanstack/react-start/server";
|
|
1
2
|
const RANK = { none: 0, view: 1, edit: 2 };
|
|
2
3
|
function isMissingRpc(error) {
|
|
3
4
|
const e = (error ?? {});
|
|
@@ -10,22 +11,44 @@ function isMissingRpc(error) {
|
|
|
10
11
|
message.includes("does not exist") ||
|
|
11
12
|
message.includes("could not find the function"));
|
|
12
13
|
}
|
|
14
|
+
/** Bearer-token van het huidige verzoek, of null. */
|
|
15
|
+
function requestToken() {
|
|
16
|
+
try {
|
|
17
|
+
const header = getRequest()?.headers?.get("authorization") ?? "";
|
|
18
|
+
return header.startsWith("Bearer ") ? header.slice(7) || null : null;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
13
24
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
* Geverifieerde user-id: uitsluitend uit het token van het verzoek, gevalideerd
|
|
26
|
+
* bij Supabase Auth (`getUser(token)`). Geen aanroeper-input.
|
|
27
|
+
*/
|
|
28
|
+
async function verifiedUserId(supabase) {
|
|
29
|
+
const token = requestToken();
|
|
30
|
+
const { data, error } = token ? await supabase.auth.getUser(token) : await supabase.auth.getUser();
|
|
31
|
+
if (error || !data?.user?.id)
|
|
32
|
+
throw new Response("Unauthorized", { status: 401 });
|
|
33
|
+
return data.user.id;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Server-side rechtencheck via RPC `effective_module_permission(_user_id,
|
|
37
|
+
* _module_id, _feature_id)` (3 argumenten).
|
|
18
38
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
39
|
+
* Sinds 1.0.23: `_user_id` komt uitsluitend uit de geverifieerde sessie van het
|
|
40
|
+
* verzoek; moduleniveau = `_feature_id ''`. **Vóór 1.0.23 liet deze functie
|
|
41
|
+
* alles door** (de RPC werd nooit gevonden → default-allow).
|
|
22
42
|
*
|
|
23
|
-
*
|
|
43
|
+
* - Ontbreekt de RPC (add-on niet geïnstalleerd) → toegestaan (default-allow).
|
|
44
|
+
* - Geen geldige sessie → 401. Onvoldoende rechten → 403.
|
|
24
45
|
*/
|
|
25
46
|
export async function requireModulePermission(supabase, moduleId, featureId = null, level = "view") {
|
|
47
|
+
const userId = await verifiedUserId(supabase);
|
|
26
48
|
const { data, error } = await supabase.rpc("effective_module_permission", {
|
|
49
|
+
_user_id: userId,
|
|
27
50
|
_module_id: moduleId,
|
|
28
|
-
_feature_id: featureId,
|
|
51
|
+
_feature_id: featureId ?? "",
|
|
29
52
|
});
|
|
30
53
|
if (error) {
|
|
31
54
|
if (isMissingRpc(error))
|
|
@@ -39,3 +62,25 @@ export async function requireModulePermission(supabase, moduleId, featureId = nu
|
|
|
39
62
|
}
|
|
40
63
|
return effective;
|
|
41
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Sinds 1.0.23. Rolvlaggen uit geverifieerde claims (bijv. `context.claims` uit
|
|
67
|
+
* requireSupabaseAuth). superadmin ⇒ admin. Zichtbaarheid, geen beveiliging.
|
|
68
|
+
*/
|
|
69
|
+
export function getRoleFlags(claims) {
|
|
70
|
+
const raw = claims?.["user_roles"];
|
|
71
|
+
const roles = Array.isArray(raw) ? raw.map(String) : [];
|
|
72
|
+
const isSuperadmin = roles.includes("superadmin");
|
|
73
|
+
return { roles, isSuperadmin, isAdmin: isSuperadmin || roles.includes("admin") };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Sinds 1.0.23. Superadmin? Claims eerst, terugval tabel `user_roles` (RLS:
|
|
77
|
+
* eigen rijen). Zichtbaarheid, geen beveiliging.
|
|
78
|
+
*/
|
|
79
|
+
export async function isSuperadminServer(supabase, userId, claims) {
|
|
80
|
+
if (getRoleFlags(claims).isSuperadmin)
|
|
81
|
+
return true;
|
|
82
|
+
const { data, error } = await supabase.from("user_roles").select("role").eq("user_id", userId);
|
|
83
|
+
if (error || !Array.isArray(data))
|
|
84
|
+
return false;
|
|
85
|
+
return data.some((r) => r.role === "superadmin");
|
|
86
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FlowModule } from "../types/module.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sinds 1.0.23. Context vanuit AuthenticatedLayout.
|
|
4
|
+
* `modules` = de ruwe lijst van de shell (vóór transforms);
|
|
5
|
+
* `visibleModules` = wat de zijbalk toont (na rechten + extensies).
|
|
6
|
+
* Zichtbaarheid, geen beveiliging.
|
|
7
|
+
*/
|
|
8
|
+
export interface ShellContextValue {
|
|
9
|
+
shellId?: string;
|
|
10
|
+
modules: FlowModule[];
|
|
11
|
+
visibleModules: FlowModule[];
|
|
12
|
+
/** True tijdens het eerste laden van de rechten. */
|
|
13
|
+
permissionsLoading: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const ShellContext: import("react").Context<ShellContextValue | null>;
|
|
16
|
+
/** Sinds 1.0.23. `null` buiten AuthenticatedLayout. Zichtbaarheid, geen beveiliging. */
|
|
17
|
+
export declare function useShell(): ShellContextValue | null;
|
|
18
|
+
/**
|
|
19
|
+
* Sinds 1.0.23. Vorm uit contract §6.1. `null` = geen provider; een lege of
|
|
20
|
+
* ontbrekende lijst mag nooit iets deactiveren. Zichtbaarheid, geen beveiliging.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useShellModules(): {
|
|
23
|
+
modules: FlowModule[];
|
|
24
|
+
shellId?: string;
|
|
25
|
+
} | null;
|
|
26
|
+
//# sourceMappingURL=ShellContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShellContext.d.ts","sourceRoot":"","sources":["../../src/core/shell/ShellContext.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,cAAc,EAAE,UAAU,EAAE,CAAC;IAC7B,oDAAoD;IACpD,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,YAAY,mDAAgD,CAAC;AAE1E,wFAAwF;AACxF,wBAAgB,QAAQ,IAAI,iBAAiB,GAAG,IAAI,CAEnD;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI;IAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGpF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
export const ShellContext = createContext(null);
|
|
3
|
+
/** Sinds 1.0.23. `null` buiten AuthenticatedLayout. Zichtbaarheid, geen beveiliging. */
|
|
4
|
+
export function useShell() {
|
|
5
|
+
return useContext(ShellContext);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Sinds 1.0.23. Vorm uit contract §6.1. `null` = geen provider; een lege of
|
|
9
|
+
* ontbrekende lijst mag nooit iets deactiveren. Zichtbaarheid, geen beveiliging.
|
|
10
|
+
*/
|
|
11
|
+
export function useShellModules() {
|
|
12
|
+
const ctx = useContext(ShellContext);
|
|
13
|
+
return ctx ? { modules: ctx.modules, shellId: ctx.shellId } : null;
|
|
14
|
+
}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@custom-variant dark (&:is(.dark *));
|
|
6
|
+
|
|
7
|
+
@layer base {
|
|
8
|
+
button, [role="button"], a, [type="button"], [type="submit"], [type="reset"] {
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@theme inline {
|
|
14
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
15
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
16
|
+
--radius-lg: var(--radius);
|
|
17
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
18
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
19
|
+
--radius-3xl: calc(var(--radius) + 12px);
|
|
20
|
+
--radius-4xl: calc(var(--radius) + 16px);
|
|
21
|
+
--color-background: var(--background);
|
|
22
|
+
--color-foreground: var(--foreground);
|
|
23
|
+
--color-card: var(--card);
|
|
24
|
+
--color-card-foreground: var(--card-foreground);
|
|
25
|
+
--color-popover: var(--popover);
|
|
26
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
27
|
+
--color-primary: var(--primary);
|
|
28
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
29
|
+
--color-secondary: var(--secondary);
|
|
30
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
31
|
+
--color-muted: var(--muted);
|
|
32
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
33
|
+
--color-accent: var(--accent);
|
|
34
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
35
|
+
--color-destructive: var(--destructive);
|
|
36
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
37
|
+
--color-success: var(--success);
|
|
38
|
+
--color-success-foreground: var(--success-foreground);
|
|
39
|
+
--color-warning: var(--warning);
|
|
40
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
41
|
+
--color-border: var(--border);
|
|
42
|
+
--color-input: var(--input);
|
|
43
|
+
--color-ring: var(--ring);
|
|
44
|
+
--color-chart-1: var(--chart-1);
|
|
45
|
+
--color-chart-2: var(--chart-2);
|
|
46
|
+
--color-chart-3: var(--chart-3);
|
|
47
|
+
--color-chart-4: var(--chart-4);
|
|
48
|
+
--color-chart-5: var(--chart-5);
|
|
49
|
+
--color-sidebar: var(--sidebar);
|
|
50
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
51
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
52
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
53
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
54
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
55
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
56
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
57
|
+
--color-sidebar-muted: var(--sidebar-muted);
|
|
58
|
+
--font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:root {
|
|
62
|
+
--radius: 0.5rem;
|
|
63
|
+
--background: hsl(210 20% 98%);
|
|
64
|
+
--foreground: hsl(214 79% 15%);
|
|
65
|
+
--card: hsl(0 0% 100%);
|
|
66
|
+
--card-foreground: hsl(214 79% 15%);
|
|
67
|
+
--popover: hsl(0 0% 100%);
|
|
68
|
+
--popover-foreground: hsl(214 79% 15%);
|
|
69
|
+
--primary: hsl(214 79% 33%);
|
|
70
|
+
--primary-foreground: hsl(0 0% 100%);
|
|
71
|
+
--secondary: hsl(214 30% 93%);
|
|
72
|
+
--secondary-foreground: hsl(214 79% 33%);
|
|
73
|
+
--muted: hsl(210 20% 96%);
|
|
74
|
+
--muted-foreground: hsl(214 20% 46%);
|
|
75
|
+
--accent: hsl(214 60% 90%);
|
|
76
|
+
--accent-foreground: hsl(214 79% 25%);
|
|
77
|
+
--destructive: hsl(0 72% 51%);
|
|
78
|
+
--destructive-foreground: hsl(0 0% 100%);
|
|
79
|
+
--success: hsl(142 71% 45%);
|
|
80
|
+
--success-foreground: hsl(0 0% 100%);
|
|
81
|
+
--warning: hsl(38 92% 50%);
|
|
82
|
+
--warning-foreground: hsl(0 0% 100%);
|
|
83
|
+
--border: hsl(214 20% 88%);
|
|
84
|
+
--input: hsl(214 20% 88%);
|
|
85
|
+
--ring: hsl(214 79% 33%);
|
|
86
|
+
--chart-1: hsl(214 79% 33%);
|
|
87
|
+
--chart-2: hsl(142 71% 45%);
|
|
88
|
+
--chart-3: hsl(38 92% 50%);
|
|
89
|
+
--chart-4: hsl(0 72% 51%);
|
|
90
|
+
--chart-5: hsl(280 60% 50%);
|
|
91
|
+
--sidebar: hsl(214 79% 33%);
|
|
92
|
+
--sidebar-foreground: hsl(0 0% 100%);
|
|
93
|
+
--sidebar-primary: hsl(0 0% 100%);
|
|
94
|
+
--sidebar-primary-foreground: hsl(214 79% 33%);
|
|
95
|
+
--sidebar-accent: hsl(214 79% 40%);
|
|
96
|
+
--sidebar-accent-foreground: hsl(0 0% 100%);
|
|
97
|
+
--sidebar-border: hsl(214 79% 45%);
|
|
98
|
+
--sidebar-ring: hsl(0 0% 100%);
|
|
99
|
+
--sidebar-muted: hsl(214 60% 70%);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@layer base {
|
|
103
|
+
* {
|
|
104
|
+
border-color: var(--color-border);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
body {
|
|
108
|
+
background-color: var(--color-background);
|
|
109
|
+
color: var(--color-foreground);
|
|
110
|
+
font-family: var(--font-sans);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.sidebar-scroll::-webkit-scrollbar {
|
|
114
|
+
width: 6px;
|
|
115
|
+
}
|
|
116
|
+
.sidebar-scroll::-webkit-scrollbar-track {
|
|
117
|
+
background: var(--color-sidebar);
|
|
118
|
+
}
|
|
119
|
+
.sidebar-scroll::-webkit-scrollbar-thumb {
|
|
120
|
+
background: var(--color-sidebar-accent);
|
|
121
|
+
border-radius: 3px;
|
|
122
|
+
}
|
|
123
|
+
.sidebar-scroll {
|
|
124
|
+
scrollbar-color: var(--color-sidebar-accent) var(--color-sidebar);
|
|
125
|
+
scrollbar-width: thin;
|
|
126
|
+
}
|
|
127
|
+
}
|
package/dist/types/module.d.ts
CHANGED
|
@@ -4,11 +4,35 @@ export interface NavItem {
|
|
|
4
4
|
label: string;
|
|
5
5
|
href: string;
|
|
6
6
|
icon: LucideIcon;
|
|
7
|
+
/**
|
|
8
|
+
* Optionele feature-id voor rechten (sinds 1.0.23). Zonder deze waarde leidt
|
|
9
|
+
* core hem af uit `href` via `featureKey()`.
|
|
10
|
+
* Zichtbaarheid, geen beveiliging.
|
|
11
|
+
*/
|
|
12
|
+
featureId?: string;
|
|
7
13
|
children?: Omit<NavItem, "children">[];
|
|
8
14
|
}
|
|
9
15
|
export interface SettingsCard {
|
|
10
16
|
component: ComponentType;
|
|
11
17
|
order: number;
|
|
18
|
+
/**
|
|
19
|
+
* Optioneel (sinds 1.0.23): module waar de kaart rechten van erft. Standaard
|
|
20
|
+
* de module waarin de kaart staat. Zichtbaarheid, geen beveiliging.
|
|
21
|
+
*/
|
|
22
|
+
moduleId?: string;
|
|
23
|
+
/** Optioneel (sinds 1.0.23): feature-id; zonder → moduleniveau. Zichtbaarheid, geen beveiliging. */
|
|
24
|
+
featureId?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Featureregistratie (sinds 1.0.23). Alleen typen; schrijven doet de adminmodule
|
|
28
|
+
* (die `label` naar `name` mapt). Zichtbaarheid, geen beveiliging.
|
|
29
|
+
*/
|
|
30
|
+
export interface FeatureDefinition {
|
|
31
|
+
/** Pad onder het modulesegment, `/`-gescheiden, bijv. `prijsgroepen/nieuw`. */
|
|
32
|
+
id: string;
|
|
33
|
+
label: string;
|
|
34
|
+
/** Alleen UI-groepering; de database kent geen hiërarchie. */
|
|
35
|
+
parent?: string;
|
|
12
36
|
}
|
|
13
37
|
export interface FlowModule {
|
|
14
38
|
id: string;
|
|
@@ -22,6 +46,8 @@ export interface FlowModule {
|
|
|
22
46
|
* gelijk is aan de registry-slug.
|
|
23
47
|
*/
|
|
24
48
|
registryKey?: string;
|
|
49
|
+
/** Optioneel (sinds 1.0.23). Zonder → afgeleid uit `nav.children` (`moduleFeatures`). */
|
|
50
|
+
features?: FeatureDefinition[];
|
|
25
51
|
}
|
|
26
52
|
/**
|
|
27
53
|
* De externe modulesleutel.
|
|
@@ -32,12 +58,21 @@ export interface FlowModule {
|
|
|
32
58
|
* 3. afsluitende underscores worden gestript.
|
|
33
59
|
*
|
|
34
60
|
* Waarom (3): een afsluitende underscore in een routepad is een TanStack
|
|
35
|
-
* un-nesting-conventie (`/voorraad_/detail`), geen betekenisvol segment.
|
|
36
|
-
* strippen levert dezelfde module twee sleutels op (`voorraad` en `voorraad_`)
|
|
37
|
-
* en verdwijnt hij half uit de zijbalk. Strippen is gekozen boven "registryKey
|
|
38
|
-
* verplicht maken", omdat dat laatste bestaande modules stil zou breken.
|
|
61
|
+
* un-nesting-conventie (`/voorraad_/detail`), geen betekenisvol segment.
|
|
39
62
|
*/
|
|
40
63
|
export declare function moduleKey(mod: FlowModule): string;
|
|
41
64
|
/** Zelfde afleidingsregel, maar voor een los pad (nav-children, URL-pathname). */
|
|
42
65
|
export declare function navKey(href: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Feature-id uit een pad (sinds 1.0.23): alles na het modulesegment,
|
|
68
|
+
* `/`-gescheiden; `index` en `$param`-segmenten vallen weg.
|
|
69
|
+
* `/klanten/prijsgroepen/nieuw` → `prijsgroepen/nieuw`; `/klanten` → `""`.
|
|
70
|
+
* Zichtbaarheid, geen beveiliging.
|
|
71
|
+
*/
|
|
72
|
+
export declare function featureKey(href: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Features van een module (sinds 1.0.23): `features` als opgegeven, anders
|
|
75
|
+
* afgeleid uit `nav.children`. Zichtbaarheid, geen beveiliging.
|
|
76
|
+
*/
|
|
77
|
+
export declare function moduleFeatures(mod: FlowModule): FeatureDefinition[];
|
|
43
78
|
//# sourceMappingURL=module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/core/types/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/core/types/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAGjD;AAMD,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG3C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,iBAAiB,EAAE,CAQnE"}
|
package/dist/types/module.js
CHANGED
|
@@ -7,18 +7,46 @@
|
|
|
7
7
|
* 3. afsluitende underscores worden gestript.
|
|
8
8
|
*
|
|
9
9
|
* Waarom (3): een afsluitende underscore in een routepad is een TanStack
|
|
10
|
-
* un-nesting-conventie (`/voorraad_/detail`), geen betekenisvol segment.
|
|
11
|
-
* strippen levert dezelfde module twee sleutels op (`voorraad` en `voorraad_`)
|
|
12
|
-
* en verdwijnt hij half uit de zijbalk. Strippen is gekozen boven "registryKey
|
|
13
|
-
* verplicht maken", omdat dat laatste bestaande modules stil zou breken.
|
|
10
|
+
* un-nesting-conventie (`/voorraad_/detail`), geen betekenisvol segment.
|
|
14
11
|
*/
|
|
15
12
|
export function moduleKey(mod) {
|
|
16
13
|
if (mod.registryKey)
|
|
17
14
|
return mod.registryKey;
|
|
18
15
|
return navKey(mod.nav.href);
|
|
19
16
|
}
|
|
17
|
+
function segments(href) {
|
|
18
|
+
return href.split("?")[0].split("#")[0].split("/").filter(Boolean);
|
|
19
|
+
}
|
|
20
20
|
/** Zelfde afleidingsregel, maar voor een los pad (nav-children, URL-pathname). */
|
|
21
21
|
export function navKey(href) {
|
|
22
|
-
const segment = href
|
|
22
|
+
const segment = segments(href)[0] ?? "";
|
|
23
23
|
return segment.replace(/_+$/, "");
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Feature-id uit een pad (sinds 1.0.23): alles na het modulesegment,
|
|
27
|
+
* `/`-gescheiden; `index` en `$param`-segmenten vallen weg.
|
|
28
|
+
* `/klanten/prijsgroepen/nieuw` → `prijsgroepen/nieuw`; `/klanten` → `""`.
|
|
29
|
+
* Zichtbaarheid, geen beveiliging.
|
|
30
|
+
*/
|
|
31
|
+
export function featureKey(href) {
|
|
32
|
+
return segments(href)
|
|
33
|
+
.slice(1)
|
|
34
|
+
.filter((s) => s !== "index" && !s.startsWith("$"))
|
|
35
|
+
.map((s) => s.replace(/_+$/, ""))
|
|
36
|
+
.join("/");
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Features van een module (sinds 1.0.23): `features` als opgegeven, anders
|
|
40
|
+
* afgeleid uit `nav.children`. Zichtbaarheid, geen beveiliging.
|
|
41
|
+
*/
|
|
42
|
+
export function moduleFeatures(mod) {
|
|
43
|
+
if (mod.features)
|
|
44
|
+
return mod.features;
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const child of mod.nav.children ?? []) {
|
|
47
|
+
const id = child.featureId ?? featureKey(child.href);
|
|
48
|
+
if (id && !out.some((f) => f.id === id))
|
|
49
|
+
out.push({ id, label: child.label });
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowselections/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.23",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,12 @@
|
|
|
14
14
|
"./server": {
|
|
15
15
|
"types": "./dist/server/index.d.ts",
|
|
16
16
|
"default": "./dist/server/index.js"
|
|
17
|
-
}
|
|
17
|
+
},
|
|
18
|
+
"./routes": {
|
|
19
|
+
"types": "./dist/routes/index.d.ts",
|
|
20
|
+
"default": "./dist/routes/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./styles.css": "./dist/styles.css"
|
|
18
23
|
},
|
|
19
24
|
"files": [
|
|
20
25
|
"dist"
|
|
@@ -23,9 +28,11 @@
|
|
|
23
28
|
"dev": "vite dev",
|
|
24
29
|
"build": "vite build",
|
|
25
30
|
"build:dev": "vite build --mode development",
|
|
26
|
-
"build:pkg": "tsc -p tsconfig.build.json",
|
|
31
|
+
"build:pkg": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json && node scripts/copy-styles.mjs && node scripts/check-pkg.mjs",
|
|
27
32
|
"preview": "vite preview",
|
|
28
|
-
"lint": "eslint ."
|
|
33
|
+
"lint": "eslint .",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"prepublishOnly": "npm run build:pkg"
|
|
29
36
|
},
|
|
30
37
|
"dependencies": {
|
|
31
38
|
"@cloudflare/vite-plugin": "^1.25.5",
|
|
@@ -102,6 +109,7 @@
|
|
|
102
109
|
"globals": "^15.15.0",
|
|
103
110
|
"typescript": "^5.8.3",
|
|
104
111
|
"typescript-eslint": "^8.56.1",
|
|
105
|
-
"vite": "^7.3.1"
|
|
112
|
+
"vite": "^7.3.1",
|
|
113
|
+
"vitest": "^3"
|
|
106
114
|
}
|
|
107
115
|
}
|