vexapp-sdk 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Alex Richards
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,57 @@
1
+ # vexapp-sdk
2
+
3
+ React SDK for **Vex Flags**: load feature flag values from the Vex API (`POST /api/flags`) using your app's API key.
4
+
5
+ ## Requirements
6
+
7
+ - React 19 and React DOM 19 (peer dependencies)
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ bun add vexapp-sdk
13
+ ```
14
+
15
+ ```bash
16
+ npm install vexapp-sdk
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ Wrap your app (or a subtree) with `VexProvider`, passing your **API key** and, for local development, **`baseUrl`** pointing at the Vex API origin (not your Vite dev server).
22
+
23
+ ```tsx
24
+ import { VexFlag, VexProvider } from "vexapp-sdk";
25
+
26
+ export function App() {
27
+ return (
28
+ <VexProvider apiKey={import.meta.env.VITE_VEX_API_KEY} baseUrl={import.meta.env.VITE_VEX_API_URL}>
29
+ <Main />
30
+ </VexProvider>
31
+ );
32
+ }
33
+ ```
34
+
35
+ Use `VexFlag` with a name and default when the API is unavailable:
36
+
37
+ ```tsx
38
+ <VexFlag name="my-flag" defaultEnabled={false}>
39
+ {(enabled) => (enabled ? <NewFeature /> : <LegacyFeature />)}
40
+ </VexFlag>
41
+ ```
42
+
43
+ If you omit `baseUrl`, the SDK uses the production API host `https://vexapp.io`.
44
+
45
+ ## API surface
46
+
47
+ | Export | Role |
48
+ | ------------------ | ------------------------------------------ |
49
+ | `VexProvider` | Context provider; fetches and caches flags |
50
+ | `VexFlag` | Declares a flag and renders from remote/default |
51
+ | `useVexFlags` | Low-level context hook (nullable) |
52
+ | `fetchFlags` | Imperative `POST /api/flags` helper |
53
+ | `resolveFlagValue` | Pure merge of remote boolean vs default |
54
+
55
+ ## Docs
56
+
57
+ Product and dashboard docs: [vexapp.io](https://vexapp.io)
@@ -0,0 +1,10 @@
1
+ import type { ReactNode } from "react";
2
+ type VexFlagProps = {
3
+ children: ReactNode;
4
+ defaultEnabled: boolean;
5
+ fallback: ReactNode | undefined;
6
+ name: string;
7
+ };
8
+ export declare const VexFlag: (props: VexFlagProps) => ReactNode;
9
+ export {};
10
+ //# sourceMappingURL=VexFlag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VexFlag.d.ts","sourceRoot":"","sources":["../src/VexFlag.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,SAAS,GAAG,SAAS,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,OAAO,YAAY,KAAG,SAc7C,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { useEffect } from "react";
2
+ import { useVexFlags } from "./VexFlagsContext";
3
+ export const VexFlag = (props) => {
4
+ const { children, defaultEnabled, fallback = undefined, name } = props;
5
+ const ctx = useVexFlags();
6
+ useEffect(() => {
7
+ ctx?.registerFlag({ defaultEnabled, name });
8
+ }, [ctx, defaultEnabled, name]);
9
+ if (ctx == null) {
10
+ return defaultEnabled ? children : (fallback ?? null);
11
+ }
12
+ const enabled = ctx.resolve(name, defaultEnabled);
13
+ return enabled ? children : (fallback ?? null);
14
+ };
15
+ //# sourceMappingURL=VexFlag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VexFlag.js","sourceRoot":"","sources":["../src/VexFlag.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAShD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,KAAmB,EAAa,EAAE;IACxD,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,GAAG,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IACvE,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;IAE1B,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,EAAE,YAAY,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC;IAEhC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,OAAO,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;AACjD,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ type FlagEntry = {
3
+ defaultEnabled: boolean;
4
+ name: string;
5
+ };
6
+ type VexFlagsContextValue = {
7
+ cache: Record<string, boolean>;
8
+ registerFlag: (entry: FlagEntry) => void;
9
+ resolve: (name: string, defaultEnabled: boolean) => boolean;
10
+ };
11
+ type VexProviderProps = {
12
+ apiKey: string | undefined;
13
+ baseUrl: string | undefined;
14
+ children: ReactNode;
15
+ };
16
+ export declare const VexProvider: (props: VexProviderProps) => ReactNode;
17
+ export declare const useVexFlags: () => VexFlagsContextValue | null;
18
+ export {};
19
+ //# sourceMappingURL=VexFlagsContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VexFlagsContext.d.ts","sourceRoot":"","sources":["../src/VexFlagsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,KAAK,SAAS,GAAG;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,KAAK,oBAAoB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,KAAK,OAAO,CAAC;CAC7D,CAAC;AAMF,KAAK,gBAAgB,GAAG;IACtB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,gBAAgB,KAAG,SA0DrD,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,oBAAoB,GAAG,IAAmC,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
3
+ import { fetchFlags } from "./fetchFlags";
4
+ import { resolveFlagValue } from "./resolveFlagValue";
5
+ const VexFlagsContext = createContext(null);
6
+ const REFRESH_INTERVAL_MS = 5 * 60 * 1000;
7
+ export const VexProvider = (props) => {
8
+ const { apiKey, baseUrl, children } = props;
9
+ const [cache, setCache] = useState({});
10
+ const flagsRef = useRef(new Map());
11
+ const doFetch = useCallback(async () => {
12
+ if (apiKey == null || apiKey.length === 0) {
13
+ return;
14
+ }
15
+ const entries = Array.from(flagsRef.current.values());
16
+ if (entries.length === 0) {
17
+ return;
18
+ }
19
+ const flags = entries.map((e) => ({ defaultEnabled: e.defaultEnabled, name: e.name }));
20
+ try {
21
+ const result = await fetchFlags({ apiKey, baseUrl, flags });
22
+ setCache(result);
23
+ }
24
+ catch {
25
+ setCache({});
26
+ }
27
+ }, [apiKey, baseUrl]);
28
+ const [flagCount, setFlagCount] = useState(0);
29
+ const registerFlag = useCallback((entry) => {
30
+ flagsRef.current.set(entry.name, entry);
31
+ setFlagCount((n) => n + 1);
32
+ }, []);
33
+ useEffect(() => {
34
+ if (apiKey == null || apiKey.length === 0) {
35
+ return;
36
+ }
37
+ void doFetch();
38
+ const id = setInterval(() => void doFetch(), REFRESH_INTERVAL_MS);
39
+ return () => clearInterval(id);
40
+ }, [apiKey, doFetch, flagCount]);
41
+ useEffect(() => {
42
+ if (apiKey == null || apiKey.length === 0) {
43
+ return;
44
+ }
45
+ const onFocus = () => void doFetch();
46
+ window.addEventListener("focus", onFocus);
47
+ return () => window.removeEventListener("focus", onFocus);
48
+ }, [apiKey, doFetch]);
49
+ const resolve = useCallback((name, defaultEnabled) => {
50
+ const remote = cache[name];
51
+ return resolveFlagValue(remote, defaultEnabled);
52
+ }, [cache]);
53
+ const value = useMemo(() => ({ cache, registerFlag, resolve }), [cache, registerFlag, resolve]);
54
+ return _jsx(VexFlagsContext.Provider, { value: value, children: children });
55
+ };
56
+ export const useVexFlags = () => useContext(VexFlagsContext);
57
+ //# sourceMappingURL=VexFlagsContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VexFlagsContext.js","sourceRoot":"","sources":["../src/VexFlagsContext.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type FetchFlagsOptions = {
2
+ apiKey: string;
3
+ baseUrl: string | undefined;
4
+ flags: Array<{
5
+ defaultEnabled: boolean;
6
+ name: string;
7
+ }>;
8
+ };
9
+ export declare const fetchFlags: (opts: FetchFlagsOptions) => Promise<Record<string, boolean>>;
10
+ //# sourceMappingURL=fetchFlags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchFlags.d.ts","sourceRoot":"","sources":["../src/fetchFlags.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;QAAE,cAAc,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,MAAM,iBAAiB,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgCzF,CAAC"}
@@ -0,0 +1,35 @@
1
+ const DEFAULT_BASE_URL = "https://vexapp.io";
2
+ export const fetchFlags = async (opts) => {
3
+ const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
4
+ const url = `${baseUrl.replace(/\/$/, "")}/api/flags`;
5
+ const controller = new AbortController();
6
+ const timeout = setTimeout(() => controller.abort(), 10_000);
7
+ const response = await fetch(url, {
8
+ body: JSON.stringify({ flags: opts.flags }),
9
+ headers: {
10
+ "Content-Type": "application/json",
11
+ "X-Vex-Api-Key": opts.apiKey,
12
+ },
13
+ method: "POST",
14
+ signal: controller.signal,
15
+ });
16
+ clearTimeout(timeout);
17
+ if (response.status === 401 || response.status === 403) {
18
+ throw new Error("Unauthorized");
19
+ }
20
+ if (response.ok === false) {
21
+ throw new Error("Failed to fetch flags");
22
+ }
23
+ const data = await response.json();
24
+ if (data == null || typeof data !== "object") {
25
+ throw new Error("Invalid response");
26
+ }
27
+ const result = Object.entries(data).reduce((acc, [key, value]) => {
28
+ if (typeof key === "string" && typeof value === "boolean") {
29
+ return { ...acc, [key]: value };
30
+ }
31
+ return acc;
32
+ }, {});
33
+ return result;
34
+ };
35
+ //# sourceMappingURL=fetchFlags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchFlags.js","sourceRoot":"","sources":["../src/fetchFlags.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAQ7C,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,IAAuB,EAAoC,EAAE;IAC5F,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACjD,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC;IACtD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3C,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,IAAI,CAAC,MAAM;SAC7B;QACD,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,UAAU,CAAC,MAAM;KAC1B,CAAC,CAAC;IACH,YAAY,CAAC,OAAO,CAAC,CAAC;IACtB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC5C,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAA0B,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QACxF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1D,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;QAClC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { fetchFlags } from "./fetchFlags";
2
+ export type { FetchFlagsOptions } from "./fetchFlags";
3
+ export { resolveFlagValue } from "./resolveFlagValue";
4
+ export { VexFlag } from "./VexFlag";
5
+ export { VexProvider, useVexFlags } from "./VexFlagsContext";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { fetchFlags } from "./fetchFlags";
2
+ export { resolveFlagValue } from "./resolveFlagValue";
3
+ export { VexFlag } from "./VexFlag";
4
+ export { VexProvider, useVexFlags } from "./VexFlagsContext";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const resolveFlagValue: (remoteValue: boolean | null | undefined, defaultEnabled: boolean) => boolean;
2
+ //# sourceMappingURL=resolveFlagValue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveFlagValue.d.ts","sourceRoot":"","sources":["../src/resolveFlagValue.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAAI,aAAa,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,gBAAgB,OAAO,KAAG,OACnC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const resolveFlagValue = (remoteValue, defaultEnabled) => typeof remoteValue === "boolean" ? remoteValue : defaultEnabled;
2
+ //# sourceMappingURL=resolveFlagValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveFlagValue.js","sourceRoot":"","sources":["../src/resolveFlagValue.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,WAAuC,EAAE,cAAuB,EAAW,EAAE,CAC5G,OAAO,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC"}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "vexapp-sdk",
3
+ "version": "0.1.0",
4
+ "description": "React SDK for Vex Flags: feature toggles from the Vex dashboard via POST /api/flags",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "sideEffects": false,
18
+ "license": "MIT",
19
+ "author": "Alex Richards <alexchristopherrichards@gmail.com>",
20
+ "homepage": "https://vexapp.io",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/acrichards3/create-vex-app.git",
24
+ "directory": "vexapp-sdk"
25
+ },
26
+ "bugs": {
27
+ "url": "https://github.com/acrichards3/create-vex-app/issues"
28
+ },
29
+ "keywords": [
30
+ "vex",
31
+ "vexapp",
32
+ "feature-flags",
33
+ "flags",
34
+ "react",
35
+ "react-sdk"
36
+ ],
37
+ "scripts": {
38
+ "prepublishOnly": "npx tsc",
39
+ "build": "tsc",
40
+ "dev": "tsc --watch",
41
+ "lint": "eslint .",
42
+ "test": "bun test --passWithNoTests",
43
+ "typecheck": "tsc --noEmit"
44
+ },
45
+ "peerDependencies": {
46
+ "react": "^19.2.0",
47
+ "react-dom": "^19.2.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/react": "^19.0.6",
51
+ "@types/react-dom": "^19.0.3",
52
+ "@typescript-eslint/eslint-plugin": "^8",
53
+ "@typescript-eslint/parser": "^8",
54
+ "eslint": "^9",
55
+ "eslint-plugin-perfectionist": "^5",
56
+ "eslint-plugin-react": "^7.33.2",
57
+ "eslint-plugin-react-hooks": "^4.6.0",
58
+ "eslint-plugin-react-hooks-extra": "^2.13.0",
59
+ "eslint-plugin-sonarjs": "^4",
60
+ "eslint-plugin-unicorn": "^63",
61
+ "react": "^19.2.0",
62
+ "react-dom": "^19.2.0",
63
+ "typescript": "^5.9.0"
64
+ }
65
+ }