@flowselections/core 1.0.25 → 1.0.26
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
CHANGED
|
@@ -4,9 +4,9 @@ Fundament-module: authenticatie, shell-layout (sidebar/header), instellingen en
|
|
|
4
4
|
gedeelde UI-componenten. Elke module heeft core als `peerDependency`; de shell
|
|
5
5
|
bepaalt welke core-versie draait.
|
|
6
6
|
|
|
7
|
-
## Gebruik 1.0.23 niet
|
|
7
|
+
## Gebruik 1.0.23 t/m 1.0.25 niet
|
|
8
8
|
|
|
9
|
-
**Core 1.0.23
|
|
9
|
+
**Core 1.0.23 tot en met 1.0.25 breken de clientbuild van shells** (`"Readable"/"AsyncLocalStorage" is not exported by "__vite-browser-external"`): servercode van `@tanstack/start-server-core` (`node:async_hooks`, `node:stream`) lekte naar de clientbundel. In 1.0.23 liep dat via de handoverpagina, in 1.0.24 en 1.0.25 via `./server`, dat `@tanstack/react-start/server` statisch importeerde — elke shell met een module die `./server` her-exporteert (zoals de admin-add-on) faalde. Gebruik **1.0.26 of hoger**.
|
|
10
10
|
|
|
11
11
|
Vanaf 1.0.24 wisselt `HandoverPage` de code in via een server-route in de shell. Het dashboard genereert daarvoor `src/routes/api/public/auth/handover.ts`:
|
|
12
12
|
|
|
@@ -21,7 +21,7 @@ export const Route = createFileRoute("/api/public/auth/handover")({
|
|
|
21
21
|
|
|
22
22
|
Ander pad? Geef `exchangePath` mee aan `HandoverPage` of `handoverRoute`. Zonder dit bestand mislukt alleen de handover (neutrale foutmelding); `/login` blijft werken.
|
|
23
23
|
|
|
24
|
-
`build:pkg` controleert met `scripts/check-client-graph.mjs` dat de hoofdbarrel
|
|
24
|
+
`build:pkg` controleert met `scripts/check-client-graph.mjs` dat de hoofdbarrel, `./routes` én `./server` geen letterlijke serverimport bevatten (statisch of `import("…")`). `npm run verify:consumer` bouwt twee minimale consumer-apps tegen het gepakte pakket: één zonder en één met `./server` in de clientgraaf (het geval van de admin-add-on).
|
|
25
25
|
|
|
26
26
|
## Modulecontract
|
|
27
27
|
|
|
@@ -11,8 +11,13 @@ export type PermissionLevel = "none" | "view" | "edit";
|
|
|
11
11
|
*
|
|
12
12
|
* - Ontbreekt de RPC (add-on niet geïnstalleerd) → toegestaan (default-allow).
|
|
13
13
|
* - Geen geldige sessie → 401. Onvoldoende rechten → 403.
|
|
14
|
+
*
|
|
15
|
+
* `request` is optioneel: geef `getRequest()` mee (uit de code van je eigen
|
|
16
|
+
* shell, die door de Start-compiler wél getransformeerd wordt) als jouw runtime
|
|
17
|
+
* het actuele verzoek niet zelf blootgeeft. Aan het antwoord verandert niets:
|
|
18
|
+
* het token wordt hoe dan ook bij Supabase Auth gevalideerd.
|
|
14
19
|
*/
|
|
15
|
-
export declare function requireModulePermission(supabase: SupabaseClient<any, any, any>, moduleId: string, featureId?: string | null, level?: PermissionLevel): Promise<PermissionLevel>;
|
|
20
|
+
export declare function requireModulePermission(supabase: SupabaseClient<any, any, any>, moduleId: string, featureId?: string | null, level?: PermissionLevel, request?: Request | null): Promise<PermissionLevel>;
|
|
16
21
|
export { getRoleFlags };
|
|
17
22
|
/**
|
|
18
23
|
* Sinds 1.0.23. Superadmin? Claims eerst, terugval tabel `user_roles` (RLS:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.server.d.ts","sourceRoot":"","sources":["../../src/core/server/permissions.server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"permissions.server.d.ts","sourceRoot":"","sources":["../../src/core/server/permissions.server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA8BhD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAuCvD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAM,GAAG,IAAW,EAC/B,KAAK,GAAE,eAAwB,EAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,GACvB,OAAO,CAAC,eAAe,CAAC,CAyB1B;AAED,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EACvC,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACtC,OAAO,CAAC,OAAO,CAAC,CAKlB"}
|
|
@@ -1,5 +1,28 @@
|
|
|
1
|
-
import { getRequest } from "@tanstack/react-start/server";
|
|
2
1
|
import { getRoleFlags } from "../auth/roles.js";
|
|
2
|
+
/**
|
|
3
|
+
* `@tanstack/react-start/server` mag hier **niet** statisch geïmporteerd worden
|
|
4
|
+
* (ook niet als letterlijke `import()`): het trekt `@tanstack/start-server-core`
|
|
5
|
+
* (node:async_hooks) in de bundel. Elke shell waarvan een module `./server` in
|
|
6
|
+
* zijn hoofdbarrel her-exporteert, breekt dan op de clientbuild.
|
|
7
|
+
*
|
|
8
|
+
* De specifier wordt pas ter plaatse in mekaar gezet, zodat geen enkele bundler
|
|
9
|
+
* hem statisch kan ontleden. De import draait dus uitsluitend op de server.
|
|
10
|
+
*/
|
|
11
|
+
const REACT_START_SERVER = ["@tanstack", "react-start", "server"].join("/");
|
|
12
|
+
/** Het actuele verzoek, voor zover de runtime dat prijsgeeft. */
|
|
13
|
+
async function ambientRequest() {
|
|
14
|
+
try {
|
|
15
|
+
const mod = (await import(/* @vite-ignore */ REACT_START_SERVER));
|
|
16
|
+
return mod.getRequest?.() ?? null;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function readRequestHeader(name, request) {
|
|
23
|
+
const req = request ?? (await ambientRequest());
|
|
24
|
+
return req?.headers?.get(name) ?? null;
|
|
25
|
+
}
|
|
3
26
|
const RANK = { none: 0, view: 1, edit: 2 };
|
|
4
27
|
function isMissingRpc(error) {
|
|
5
28
|
const e = (error ?? {});
|
|
@@ -13,21 +36,17 @@ function isMissingRpc(error) {
|
|
|
13
36
|
message.includes("could not find the function"));
|
|
14
37
|
}
|
|
15
38
|
/** Bearer-token van het huidige verzoek, of null. */
|
|
16
|
-
function requestToken() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return header.startsWith("Bearer ") ? header.slice(7) || null : null;
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
39
|
+
async function requestToken(request) {
|
|
40
|
+
const header = (await readRequestHeader("authorization", request)) ?? "";
|
|
41
|
+
return header.startsWith("Bearer ") ? header.slice(7) || null : null;
|
|
24
42
|
}
|
|
25
43
|
/**
|
|
26
44
|
* Geverifieerde user-id: uitsluitend uit het token van het verzoek, gevalideerd
|
|
27
|
-
* bij Supabase Auth (`getUser(token)`). Geen aanroeper-input
|
|
45
|
+
* bij Supabase Auth (`getUser(token)`). Geen aanroeper-input: een meegegeven
|
|
46
|
+
* `request` is het verzoek zelf, geen ingevulde user-id.
|
|
28
47
|
*/
|
|
29
|
-
async function verifiedUserId(supabase) {
|
|
30
|
-
const token = requestToken();
|
|
48
|
+
async function verifiedUserId(supabase, request) {
|
|
49
|
+
const token = await requestToken(request);
|
|
31
50
|
const { data, error } = token ? await supabase.auth.getUser(token) : await supabase.auth.getUser();
|
|
32
51
|
if (error || !data?.user?.id)
|
|
33
52
|
throw new Response("Unauthorized", { status: 401 });
|
|
@@ -43,9 +62,14 @@ async function verifiedUserId(supabase) {
|
|
|
43
62
|
*
|
|
44
63
|
* - Ontbreekt de RPC (add-on niet geïnstalleerd) → toegestaan (default-allow).
|
|
45
64
|
* - Geen geldige sessie → 401. Onvoldoende rechten → 403.
|
|
65
|
+
*
|
|
66
|
+
* `request` is optioneel: geef `getRequest()` mee (uit de code van je eigen
|
|
67
|
+
* shell, die door de Start-compiler wél getransformeerd wordt) als jouw runtime
|
|
68
|
+
* het actuele verzoek niet zelf blootgeeft. Aan het antwoord verandert niets:
|
|
69
|
+
* het token wordt hoe dan ook bij Supabase Auth gevalideerd.
|
|
46
70
|
*/
|
|
47
|
-
export async function requireModulePermission(supabase, moduleId, featureId = null, level = "view") {
|
|
48
|
-
const userId = await verifiedUserId(supabase);
|
|
71
|
+
export async function requireModulePermission(supabase, moduleId, featureId = null, level = "view", request) {
|
|
72
|
+
const userId = await verifiedUserId(supabase, request);
|
|
49
73
|
const { data, error } = await supabase.rpc("effective_module_permission", {
|
|
50
74
|
_user_id: userId,
|
|
51
75
|
_module_id: moduleId,
|
package/package.json
CHANGED
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@flowselections/core",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"private": false,
|
|
5
|
-
"sideEffects": false,
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"default": "./dist/index.js"
|
|
13
|
-
},
|
|
14
|
-
"./server": {
|
|
15
|
-
"types": "./dist/server/index.d.ts",
|
|
16
|
-
"default": "./dist/server/index.js"
|
|
17
|
-
},
|
|
18
|
-
"./routes": {
|
|
19
|
-
"types": "./dist/routes/index.d.ts",
|
|
20
|
-
"default": "./dist/routes/index.js"
|
|
21
|
-
},
|
|
22
|
-
"./styles.css": "./dist/styles.css"
|
|
23
|
-
},
|
|
24
|
-
"files": [
|
|
25
|
-
"dist"
|
|
26
|
-
],
|
|
27
|
-
"scripts": {
|
|
28
|
-
"dev": "vite dev",
|
|
29
|
-
"build": "vite build",
|
|
30
|
-
"build:dev": "vite build --mode development",
|
|
31
|
-
"build:pkg": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json && node scripts/copy-styles.mjs && node scripts/check-pkg.mjs && node scripts/check-client-graph.mjs",
|
|
32
|
-
"verify:consumer": "node scripts/verify-consumer.mjs",
|
|
33
|
-
"preview": "vite preview",
|
|
34
|
-
"lint": "eslint .",
|
|
35
|
-
"test": "vitest run",
|
|
36
|
-
"prepublishOnly": "npm run build:pkg"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@cloudflare/vite-plugin": "^1.25.5",
|
|
40
|
-
"@dnd-kit/core": "^6.3.1",
|
|
41
|
-
"@dnd-kit/sortable": "^10.0.0",
|
|
42
|
-
"@dnd-kit/utilities": "^3.2.2",
|
|
43
|
-
"@hookform/resolvers": "^5.2.2",
|
|
44
|
-
"@radix-ui/react-accordion": "^1.2.12",
|
|
45
|
-
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
46
|
-
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
|
47
|
-
"@radix-ui/react-avatar": "^1.1.11",
|
|
48
|
-
"@radix-ui/react-checkbox": "^1.3.3",
|
|
49
|
-
"@radix-ui/react-collapsible": "^1.1.12",
|
|
50
|
-
"@radix-ui/react-context-menu": "^2.2.16",
|
|
51
|
-
"@radix-ui/react-dialog": "^1.1.15",
|
|
52
|
-
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
53
|
-
"@radix-ui/react-hover-card": "^1.1.15",
|
|
54
|
-
"@radix-ui/react-label": "^2.1.8",
|
|
55
|
-
"@radix-ui/react-menubar": "^1.1.16",
|
|
56
|
-
"@radix-ui/react-navigation-menu": "^1.2.14",
|
|
57
|
-
"@radix-ui/react-popover": "^1.1.15",
|
|
58
|
-
"@radix-ui/react-progress": "^1.1.8",
|
|
59
|
-
"@radix-ui/react-radio-group": "^1.3.8",
|
|
60
|
-
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
61
|
-
"@radix-ui/react-select": "^2.2.6",
|
|
62
|
-
"@radix-ui/react-separator": "^1.1.8",
|
|
63
|
-
"@radix-ui/react-slider": "^1.3.6",
|
|
64
|
-
"@radix-ui/react-slot": "^1.2.4",
|
|
65
|
-
"@radix-ui/react-switch": "^1.2.6",
|
|
66
|
-
"@radix-ui/react-tabs": "^1.1.13",
|
|
67
|
-
"@radix-ui/react-toggle": "^1.1.10",
|
|
68
|
-
"@radix-ui/react-toggle-group": "^1.1.11",
|
|
69
|
-
"@radix-ui/react-tooltip": "^1.2.8",
|
|
70
|
-
"@supabase/supabase-js": "^2.103.2",
|
|
71
|
-
"@tailwindcss/vite": "^4.2.1",
|
|
72
|
-
"@tanstack/react-query": "^5.99.0",
|
|
73
|
-
"@tanstack/react-router": "^1.168.0",
|
|
74
|
-
"@tanstack/react-start": "^1.167.14",
|
|
75
|
-
"@tanstack/router-plugin": "^1.167.10",
|
|
76
|
-
"class-variance-authority": "^0.7.1",
|
|
77
|
-
"clsx": "^2.1.1",
|
|
78
|
-
"cmdk": "^1.1.1",
|
|
79
|
-
"date-fns": "^4.1.0",
|
|
80
|
-
"embla-carousel-react": "^8.6.0",
|
|
81
|
-
"input-otp": "^1.4.2",
|
|
82
|
-
"lucide-react": "^0.575.0",
|
|
83
|
-
"nitro": "3.0.260603-beta",
|
|
84
|
-
"react": "^19.2.0",
|
|
85
|
-
"react-barcode": "^1.6.1",
|
|
86
|
-
"react-day-picker": "^9.14.0",
|
|
87
|
-
"react-dom": "^19.2.0",
|
|
88
|
-
"react-hook-form": "^7.71.2",
|
|
89
|
-
"react-resizable-panels": "^4.6.5",
|
|
90
|
-
"recharts": "^2.15.4",
|
|
91
|
-
"sonner": "^2.0.7",
|
|
92
|
-
"tailwind-merge": "^3.5.0",
|
|
93
|
-
"tailwindcss": "^4.2.1",
|
|
94
|
-
"tw-animate-css": "^1.3.4",
|
|
95
|
-
"vaul": "^1.1.2",
|
|
96
|
-
"vite-tsconfig-paths": "^6.0.2",
|
|
97
|
-
"xlsx": "^0.18.5",
|
|
98
|
-
"zod": "^4.3.6"
|
|
99
|
-
},
|
|
100
|
-
"devDependencies": {
|
|
101
|
-
"@eslint/js": "^9.32.0",
|
|
102
|
-
"@lovable.dev/vite-tanstack-config": "2.23.1",
|
|
103
|
-
"@types/node": "^22.16.5",
|
|
104
|
-
"@types/react": "^19.2.0",
|
|
105
|
-
"@types/react-dom": "^19.2.0",
|
|
106
|
-
"@vitejs/plugin-react": "^5.0.4",
|
|
107
|
-
"eslint": "^9.32.0",
|
|
108
|
-
"eslint-plugin-react-hooks": "^5.2.0",
|
|
109
|
-
"eslint-plugin-react-refresh": "^0.4.20",
|
|
110
|
-
"globals": "^15.15.0",
|
|
111
|
-
"typescript": "^5.8.3",
|
|
112
|
-
"typescript-eslint": "^8.56.1",
|
|
113
|
-
"vite": "^7.3.1",
|
|
114
|
-
"vitest": "^3"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowselections/core",
|
|
3
|
+
"version": "1.0.26",
|
|
4
|
+
"private": false,
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./server": {
|
|
15
|
+
"types": "./dist/server/index.d.ts",
|
|
16
|
+
"default": "./dist/server/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./routes": {
|
|
19
|
+
"types": "./dist/routes/index.d.ts",
|
|
20
|
+
"default": "./dist/routes/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./styles.css": "./dist/styles.css"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "vite dev",
|
|
29
|
+
"build": "vite build",
|
|
30
|
+
"build:dev": "vite build --mode development",
|
|
31
|
+
"build:pkg": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json && node scripts/copy-styles.mjs && node scripts/check-pkg.mjs && node scripts/check-client-graph.mjs",
|
|
32
|
+
"verify:consumer": "node scripts/verify-consumer.mjs",
|
|
33
|
+
"preview": "vite preview",
|
|
34
|
+
"lint": "eslint .",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"prepublishOnly": "npm run build:pkg"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@cloudflare/vite-plugin": "^1.25.5",
|
|
40
|
+
"@dnd-kit/core": "^6.3.1",
|
|
41
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
42
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
43
|
+
"@hookform/resolvers": "^5.2.2",
|
|
44
|
+
"@radix-ui/react-accordion": "^1.2.12",
|
|
45
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
46
|
+
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
|
47
|
+
"@radix-ui/react-avatar": "^1.1.11",
|
|
48
|
+
"@radix-ui/react-checkbox": "^1.3.3",
|
|
49
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
50
|
+
"@radix-ui/react-context-menu": "^2.2.16",
|
|
51
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
52
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
53
|
+
"@radix-ui/react-hover-card": "^1.1.15",
|
|
54
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
55
|
+
"@radix-ui/react-menubar": "^1.1.16",
|
|
56
|
+
"@radix-ui/react-navigation-menu": "^1.2.14",
|
|
57
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
58
|
+
"@radix-ui/react-progress": "^1.1.8",
|
|
59
|
+
"@radix-ui/react-radio-group": "^1.3.8",
|
|
60
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
61
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
62
|
+
"@radix-ui/react-separator": "^1.1.8",
|
|
63
|
+
"@radix-ui/react-slider": "^1.3.6",
|
|
64
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
65
|
+
"@radix-ui/react-switch": "^1.2.6",
|
|
66
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
67
|
+
"@radix-ui/react-toggle": "^1.1.10",
|
|
68
|
+
"@radix-ui/react-toggle-group": "^1.1.11",
|
|
69
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
70
|
+
"@supabase/supabase-js": "^2.103.2",
|
|
71
|
+
"@tailwindcss/vite": "^4.2.1",
|
|
72
|
+
"@tanstack/react-query": "^5.99.0",
|
|
73
|
+
"@tanstack/react-router": "^1.168.0",
|
|
74
|
+
"@tanstack/react-start": "^1.167.14",
|
|
75
|
+
"@tanstack/router-plugin": "^1.167.10",
|
|
76
|
+
"class-variance-authority": "^0.7.1",
|
|
77
|
+
"clsx": "^2.1.1",
|
|
78
|
+
"cmdk": "^1.1.1",
|
|
79
|
+
"date-fns": "^4.1.0",
|
|
80
|
+
"embla-carousel-react": "^8.6.0",
|
|
81
|
+
"input-otp": "^1.4.2",
|
|
82
|
+
"lucide-react": "^0.575.0",
|
|
83
|
+
"nitro": "3.0.260603-beta",
|
|
84
|
+
"react": "^19.2.0",
|
|
85
|
+
"react-barcode": "^1.6.1",
|
|
86
|
+
"react-day-picker": "^9.14.0",
|
|
87
|
+
"react-dom": "^19.2.0",
|
|
88
|
+
"react-hook-form": "^7.71.2",
|
|
89
|
+
"react-resizable-panels": "^4.6.5",
|
|
90
|
+
"recharts": "^2.15.4",
|
|
91
|
+
"sonner": "^2.0.7",
|
|
92
|
+
"tailwind-merge": "^3.5.0",
|
|
93
|
+
"tailwindcss": "^4.2.1",
|
|
94
|
+
"tw-animate-css": "^1.3.4",
|
|
95
|
+
"vaul": "^1.1.2",
|
|
96
|
+
"vite-tsconfig-paths": "^6.0.2",
|
|
97
|
+
"xlsx": "^0.18.5",
|
|
98
|
+
"zod": "^4.3.6"
|
|
99
|
+
},
|
|
100
|
+
"devDependencies": {
|
|
101
|
+
"@eslint/js": "^9.32.0",
|
|
102
|
+
"@lovable.dev/vite-tanstack-config": "2.23.1",
|
|
103
|
+
"@types/node": "^22.16.5",
|
|
104
|
+
"@types/react": "^19.2.0",
|
|
105
|
+
"@types/react-dom": "^19.2.0",
|
|
106
|
+
"@vitejs/plugin-react": "^5.0.4",
|
|
107
|
+
"eslint": "^9.32.0",
|
|
108
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
109
|
+
"eslint-plugin-react-refresh": "^0.4.20",
|
|
110
|
+
"globals": "^15.15.0",
|
|
111
|
+
"typescript": "^5.8.3",
|
|
112
|
+
"typescript-eslint": "^8.56.1",
|
|
113
|
+
"vite": "^7.3.1",
|
|
114
|
+
"vitest": "^3"
|
|
115
|
+
}
|
|
116
|
+
}
|