apps-key-guard 0.0.1

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 ADDED
@@ -0,0 +1,191 @@
1
+ # @apps-admin/key-guard
2
+
3
+ 一个基于密钥验证的 React 访问控制组件,支持本地缓存和自动验证。
4
+
5
+ ## 功能特性
6
+
7
+ - 基于密钥的访问控制
8
+ - 本地存储密钥,自动验证
9
+ - 支持密钥等级检查(排除 none 等级)
10
+ - 支持密钥过期检查
11
+ - 完全可自定义样式
12
+ - TypeScript 支持
13
+
14
+ ## 安装
15
+
16
+ ```bash
17
+ npm install @apps-admin/key-guard
18
+ ```
19
+
20
+ 或者
21
+
22
+ ```bash
23
+ yarn add @apps-admin/key-guard
24
+ ```
25
+
26
+ ## 使用方法
27
+
28
+ ### 基础用法
29
+
30
+ ```tsx
31
+ import { KeyGuard } from '@apps-admin/key-guard';
32
+
33
+ function App() {
34
+ return (
35
+ <KeyGuard appName="my-app" apiBaseUrl="http://localhost:8080">
36
+ <div>
37
+ <h1>受保护的内容</h1>
38
+ <p>只有通过密钥验证的用户才能看到这里的内容</p>
39
+ </div>
40
+ </KeyGuard>
41
+ );
42
+ }
43
+ ```
44
+
45
+ ### 高级用法
46
+
47
+ ```tsx
48
+ import { KeyGuard } from '@apps-admin/key-guard';
49
+
50
+ function App() {
51
+ const handleValidated = (level: string) => {
52
+ console.log('用户验证成功,等级:', level);
53
+ // 可以根据等级做不同的处理
54
+ };
55
+
56
+ return (
57
+ <KeyGuard
58
+ appName="my-app"
59
+ apiBaseUrl="https://api.example.com"
60
+ title="请输入访问密钥"
61
+ placeholder="输入您的密钥"
62
+ buttonText="提交验证"
63
+ onValidated={handleValidated}
64
+ customStyle={{
65
+ backgroundColor: '#f0f0f0',
66
+ }}
67
+ >
68
+ <div>
69
+ <h1>受保护的内容</h1>
70
+ <p>只有通过密钥验证的用户才能看到这里的内容</p>
71
+ </div>
72
+ </KeyGuard>
73
+ );
74
+ }
75
+ ```
76
+
77
+ ## API 参数
78
+
79
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
80
+ |------|------|------|--------|------|
81
+ | `appName` | `string` | 是 | - | 应用名称,用于标识应用 |
82
+ | `apiBaseUrl` | `string` | 否 | `http://localhost:8080` | API 基础 URL |
83
+ | `children` | `ReactNode` | 是 | - | 验证成功后要渲染的子组件 |
84
+ | `onValidated` | `(level: string) => void` | 否 | - | 验证成功后的回调函数,返回密钥等级 |
85
+ | `customStyle` | `CSSProperties` | 否 | - | 自定义容器样式 |
86
+ | `title` | `string` | 否 | `访问验证` | 标题文本 |
87
+ | `placeholder` | `string` | 否 | `请输入访问密钥` | 输入框占位符 |
88
+ | `buttonText` | `string` | 否 | `验证` | 按钮文本 |
89
+
90
+ ## 工作原理
91
+
92
+ 1. 组件首次加载时,会检查 localStorage 中是否存在该应用的密钥
93
+ 2. 如果存在,自动使用该密钥进行验证
94
+ 3. 验证成功且密钥等级不为 `none` 时,渲染子组件
95
+ 4. 验证失败时,显示密钥输入表单
96
+ 5. 用户输入密钥后,调用后端 API 进行验证
97
+ 6. 验证成功后,将密钥存储到 localStorage,并渲染子组件
98
+
99
+ ## 后端 API 要求
100
+
101
+ 组件需要后端提供一个密钥验证接口:
102
+
103
+ **POST** `/api/public/keys/verify`
104
+
105
+ 请求体:
106
+ ```json
107
+ {
108
+ "app_name": "my-app",
109
+ "key_value": "user-input-key"
110
+ }
111
+ ```
112
+
113
+ 响应格式:
114
+ ```json
115
+ {
116
+ "code": 200,
117
+ "message": "验证成功",
118
+ "data": {
119
+ "valid": true,
120
+ "level": "vip",
121
+ "expires_at": "2024-12-31T23:59:59Z",
122
+ "message": "密钥有效"
123
+ }
124
+ }
125
+ ```
126
+
127
+ ## 密钥等级
128
+
129
+ - `none`: 无权限(验证会失败)
130
+ - `guest`: 游客
131
+ - `vip`: VIP 用户
132
+ - `super_vip`: 高级 VIP 用户
133
+
134
+ ## 开发
135
+
136
+ ### 本地开发和测试
137
+
138
+ 使用 Vite 开发服务器快速测试组件:
139
+
140
+ ```bash
141
+ # 安装依赖
142
+ npm install
143
+
144
+ # 启动开发服务器(自动打开浏览器)
145
+ npm run dev
146
+ ```
147
+
148
+ 开发服务器会在 `http://localhost:3000` 启动,并提供多个示例供测试:
149
+
150
+ - **基础示例**: 最简单的使用方式
151
+ - **自定义示例**: 展示自定义配置选项
152
+ - **多应用示例**: 展示如何处理多个应用
153
+
154
+ **测试前准备:**
155
+
156
+ 1. 确保后端服务已启动(默认 `http://localhost:8080`)
157
+ 2. 在数据库中创建测试应用:
158
+ ```bash
159
+ # 使用后端 API 创建应用
160
+ POST /api/apps
161
+ {
162
+ "name": "my-app",
163
+ "remark": "测试应用"
164
+ }
165
+ ```
166
+ 3. 为应用创建密钥(等级不能为 `none`):
167
+ ```bash
168
+ POST /api/keys
169
+ {
170
+ "app_id": 1,
171
+ "key_value": "test-key-123",
172
+ "level": "vip"
173
+ }
174
+ ```
175
+
176
+ ### 构建
177
+
178
+ ```bash
179
+ # 构建用于发布的包(监听模式)
180
+ npm run build:watch
181
+
182
+ # 构建用于发布的包
183
+ npm run build
184
+
185
+ # 预览构建结果
186
+ npm run preview
187
+ ```
188
+
189
+ ## License
190
+
191
+ MIT
@@ -0,0 +1,21 @@
1
+ import React, { ReactNode } from 'react';
2
+
3
+ declare enum Level {
4
+ None = "none",
5
+ Guest = "guest",
6
+ VIP = "vip",
7
+ SuperVIP = "super_vip"
8
+ }
9
+ interface KeyGuardProps {
10
+ appName: string;
11
+ apiBaseUrl?: string;
12
+ children: ReactNode;
13
+ onValidated?: (level: Level) => void;
14
+ customStyle?: React.CSSProperties;
15
+ title?: string;
16
+ placeholder?: string;
17
+ buttonText?: string;
18
+ }
19
+ declare const KeyGuard: React.FC<KeyGuardProps>;
20
+
21
+ export { KeyGuard, type KeyGuardProps, KeyGuard as default };
@@ -0,0 +1,21 @@
1
+ import React, { ReactNode } from 'react';
2
+
3
+ declare enum Level {
4
+ None = "none",
5
+ Guest = "guest",
6
+ VIP = "vip",
7
+ SuperVIP = "super_vip"
8
+ }
9
+ interface KeyGuardProps {
10
+ appName: string;
11
+ apiBaseUrl?: string;
12
+ children: ReactNode;
13
+ onValidated?: (level: Level) => void;
14
+ customStyle?: React.CSSProperties;
15
+ title?: string;
16
+ placeholder?: string;
17
+ buttonText?: string;
18
+ }
19
+ declare const KeyGuard: React.FC<KeyGuardProps>;
20
+
21
+ export { KeyGuard, type KeyGuardProps, KeyGuard as default };
package/dist/index.js ADDED
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ KeyGuard: () => KeyGuard,
34
+ default: () => index_default
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+ var import_react = require("react");
38
+ var import_axios = __toESM(require("axios"));
39
+ var import_jsx_runtime = require("react/jsx-runtime");
40
+ var STORAGE_KEY_PREFIX = "apps_admin_key_";
41
+ var KeyGuard = ({
42
+ appName,
43
+ apiBaseUrl = "http://localhost:8080",
44
+ children,
45
+ onValidated,
46
+ customStyle,
47
+ title = "\u8BBF\u95EE\u9A8C\u8BC1",
48
+ placeholder = "\u8BF7\u8F93\u5165\u8BBF\u95EE\u5BC6\u94A5",
49
+ buttonText = "\u9A8C\u8BC1"
50
+ }) => {
51
+ const [isValidated, setIsValidated] = (0, import_react.useState)(false);
52
+ const [keyValue, setKeyValue] = (0, import_react.useState)("");
53
+ const [error, setError] = (0, import_react.useState)("");
54
+ const [loading, setLoading] = (0, import_react.useState)(false);
55
+ const [initializing, setInitializing] = (0, import_react.useState)(true);
56
+ const storageKey = `${STORAGE_KEY_PREFIX}${appName}`;
57
+ const verifyKey = async (key) => {
58
+ try {
59
+ const response = await import_axios.default.post(
60
+ `${apiBaseUrl}/api/public/keys/verify`,
61
+ {
62
+ app_name: appName,
63
+ key_value: key
64
+ }
65
+ );
66
+ const { data } = response.data;
67
+ if (data.valid && data.level && data.level !== "none") {
68
+ localStorage.setItem(storageKey, key);
69
+ if (onValidated && data.level) {
70
+ onValidated(data.level);
71
+ }
72
+ return true;
73
+ } else {
74
+ setError(data.message || "\u5BC6\u94A5\u65E0\u6548\u6216\u6743\u9650\u4E0D\u8DB3");
75
+ return false;
76
+ }
77
+ } catch (err) {
78
+ if (import_axios.default.isAxiosError(err) && err.response) {
79
+ setError(err.response.data?.message || "\u9A8C\u8BC1\u5931\u8D25");
80
+ } else {
81
+ setError("\u7F51\u7EDC\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
82
+ }
83
+ return false;
84
+ }
85
+ };
86
+ (0, import_react.useEffect)(() => {
87
+ const checkStoredKey = async () => {
88
+ const storedKey = localStorage.getItem(storageKey);
89
+ if (storedKey) {
90
+ const isValid = await verifyKey(storedKey);
91
+ if (isValid) {
92
+ setIsValidated(true);
93
+ } else {
94
+ localStorage.removeItem(storageKey);
95
+ }
96
+ }
97
+ setInitializing(false);
98
+ };
99
+ checkStoredKey();
100
+ }, [appName]);
101
+ const handleSubmit = async (e) => {
102
+ e.preventDefault();
103
+ if (!keyValue.trim()) {
104
+ setError("\u8BF7\u8F93\u5165\u5BC6\u94A5");
105
+ return;
106
+ }
107
+ setError("");
108
+ setLoading(true);
109
+ const isValid = await verifyKey(keyValue);
110
+ if (isValid) {
111
+ setIsValidated(true);
112
+ }
113
+ setLoading(false);
114
+ };
115
+ if (initializing) {
116
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultCardStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: loadingStyle, children: "\u9A8C\u8BC1\u4E2D..." }) }) });
117
+ }
118
+ if (isValidated) {
119
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
120
+ }
121
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultCardStyle, children: [
122
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: titleStyle, children: title }),
123
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: handleSubmit, style: formStyle, children: [
124
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
125
+ "input",
126
+ {
127
+ type: "text",
128
+ value: keyValue,
129
+ onChange: (e) => setKeyValue(e.target.value),
130
+ placeholder,
131
+ style: inputStyle,
132
+ disabled: loading
133
+ }
134
+ ),
135
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: errorStyle, children: error }),
136
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", style: buttonStyle, disabled: loading, children: loading ? "\u9A8C\u8BC1\u4E2D..." : buttonText })
137
+ ] })
138
+ ] }) });
139
+ };
140
+ var defaultContainerStyle = {
141
+ display: "flex",
142
+ justifyContent: "center",
143
+ alignItems: "center",
144
+ minHeight: "100vh",
145
+ backgroundColor: "#f5f5f5"
146
+ };
147
+ var defaultCardStyle = {
148
+ backgroundColor: "white",
149
+ padding: "2rem",
150
+ borderRadius: "8px",
151
+ boxShadow: "0 2px 10px rgba(0, 0, 0, 0.1)",
152
+ width: "100%",
153
+ maxWidth: "400px"
154
+ };
155
+ var titleStyle = {
156
+ margin: "0 0 1.5rem 0",
157
+ fontSize: "1.5rem",
158
+ fontWeight: "600",
159
+ textAlign: "center",
160
+ color: "#333"
161
+ };
162
+ var formStyle = {
163
+ display: "flex",
164
+ flexDirection: "column",
165
+ gap: "1rem"
166
+ };
167
+ var inputStyle = {
168
+ padding: "0.75rem",
169
+ fontSize: "1rem",
170
+ border: "1px solid #ddd",
171
+ borderRadius: "4px",
172
+ outline: "none",
173
+ transition: "border-color 0.2s"
174
+ };
175
+ var buttonStyle = {
176
+ padding: "0.75rem",
177
+ fontSize: "1rem",
178
+ fontWeight: "500",
179
+ color: "white",
180
+ backgroundColor: "#007bff",
181
+ border: "none",
182
+ borderRadius: "4px",
183
+ cursor: "pointer",
184
+ transition: "background-color 0.2s"
185
+ };
186
+ var errorStyle = {
187
+ color: "#dc3545",
188
+ fontSize: "0.875rem",
189
+ marginTop: "-0.5rem"
190
+ };
191
+ var loadingStyle = {
192
+ textAlign: "center",
193
+ color: "#666",
194
+ fontSize: "1rem"
195
+ };
196
+ var index_default = KeyGuard;
197
+ // Annotate the CommonJS export names for ESM import in node:
198
+ 0 && (module.exports = {
199
+ KeyGuard
200
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,165 @@
1
+ // src/index.tsx
2
+ import { useState, useEffect } from "react";
3
+ import axios from "axios";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ var STORAGE_KEY_PREFIX = "apps_admin_key_";
6
+ var KeyGuard = ({
7
+ appName,
8
+ apiBaseUrl = "http://localhost:8080",
9
+ children,
10
+ onValidated,
11
+ customStyle,
12
+ title = "\u8BBF\u95EE\u9A8C\u8BC1",
13
+ placeholder = "\u8BF7\u8F93\u5165\u8BBF\u95EE\u5BC6\u94A5",
14
+ buttonText = "\u9A8C\u8BC1"
15
+ }) => {
16
+ const [isValidated, setIsValidated] = useState(false);
17
+ const [keyValue, setKeyValue] = useState("");
18
+ const [error, setError] = useState("");
19
+ const [loading, setLoading] = useState(false);
20
+ const [initializing, setInitializing] = useState(true);
21
+ const storageKey = `${STORAGE_KEY_PREFIX}${appName}`;
22
+ const verifyKey = async (key) => {
23
+ try {
24
+ const response = await axios.post(
25
+ `${apiBaseUrl}/api/public/keys/verify`,
26
+ {
27
+ app_name: appName,
28
+ key_value: key
29
+ }
30
+ );
31
+ const { data } = response.data;
32
+ if (data.valid && data.level && data.level !== "none") {
33
+ localStorage.setItem(storageKey, key);
34
+ if (onValidated && data.level) {
35
+ onValidated(data.level);
36
+ }
37
+ return true;
38
+ } else {
39
+ setError(data.message || "\u5BC6\u94A5\u65E0\u6548\u6216\u6743\u9650\u4E0D\u8DB3");
40
+ return false;
41
+ }
42
+ } catch (err) {
43
+ if (axios.isAxiosError(err) && err.response) {
44
+ setError(err.response.data?.message || "\u9A8C\u8BC1\u5931\u8D25");
45
+ } else {
46
+ setError("\u7F51\u7EDC\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
47
+ }
48
+ return false;
49
+ }
50
+ };
51
+ useEffect(() => {
52
+ const checkStoredKey = async () => {
53
+ const storedKey = localStorage.getItem(storageKey);
54
+ if (storedKey) {
55
+ const isValid = await verifyKey(storedKey);
56
+ if (isValid) {
57
+ setIsValidated(true);
58
+ } else {
59
+ localStorage.removeItem(storageKey);
60
+ }
61
+ }
62
+ setInitializing(false);
63
+ };
64
+ checkStoredKey();
65
+ }, [appName]);
66
+ const handleSubmit = async (e) => {
67
+ e.preventDefault();
68
+ if (!keyValue.trim()) {
69
+ setError("\u8BF7\u8F93\u5165\u5BC6\u94A5");
70
+ return;
71
+ }
72
+ setError("");
73
+ setLoading(true);
74
+ const isValid = await verifyKey(keyValue);
75
+ if (isValid) {
76
+ setIsValidated(true);
77
+ }
78
+ setLoading(false);
79
+ };
80
+ if (initializing) {
81
+ return /* @__PURE__ */ jsx("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ jsx("div", { style: defaultCardStyle, children: /* @__PURE__ */ jsx("div", { style: loadingStyle, children: "\u9A8C\u8BC1\u4E2D..." }) }) });
82
+ }
83
+ if (isValidated) {
84
+ return /* @__PURE__ */ jsx(Fragment, { children });
85
+ }
86
+ return /* @__PURE__ */ jsx("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ jsxs("div", { style: defaultCardStyle, children: [
87
+ /* @__PURE__ */ jsx("h2", { style: titleStyle, children: title }),
88
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: formStyle, children: [
89
+ /* @__PURE__ */ jsx(
90
+ "input",
91
+ {
92
+ type: "text",
93
+ value: keyValue,
94
+ onChange: (e) => setKeyValue(e.target.value),
95
+ placeholder,
96
+ style: inputStyle,
97
+ disabled: loading
98
+ }
99
+ ),
100
+ error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
101
+ /* @__PURE__ */ jsx("button", { type: "submit", style: buttonStyle, disabled: loading, children: loading ? "\u9A8C\u8BC1\u4E2D..." : buttonText })
102
+ ] })
103
+ ] }) });
104
+ };
105
+ var defaultContainerStyle = {
106
+ display: "flex",
107
+ justifyContent: "center",
108
+ alignItems: "center",
109
+ minHeight: "100vh",
110
+ backgroundColor: "#f5f5f5"
111
+ };
112
+ var defaultCardStyle = {
113
+ backgroundColor: "white",
114
+ padding: "2rem",
115
+ borderRadius: "8px",
116
+ boxShadow: "0 2px 10px rgba(0, 0, 0, 0.1)",
117
+ width: "100%",
118
+ maxWidth: "400px"
119
+ };
120
+ var titleStyle = {
121
+ margin: "0 0 1.5rem 0",
122
+ fontSize: "1.5rem",
123
+ fontWeight: "600",
124
+ textAlign: "center",
125
+ color: "#333"
126
+ };
127
+ var formStyle = {
128
+ display: "flex",
129
+ flexDirection: "column",
130
+ gap: "1rem"
131
+ };
132
+ var inputStyle = {
133
+ padding: "0.75rem",
134
+ fontSize: "1rem",
135
+ border: "1px solid #ddd",
136
+ borderRadius: "4px",
137
+ outline: "none",
138
+ transition: "border-color 0.2s"
139
+ };
140
+ var buttonStyle = {
141
+ padding: "0.75rem",
142
+ fontSize: "1rem",
143
+ fontWeight: "500",
144
+ color: "white",
145
+ backgroundColor: "#007bff",
146
+ border: "none",
147
+ borderRadius: "4px",
148
+ cursor: "pointer",
149
+ transition: "background-color 0.2s"
150
+ };
151
+ var errorStyle = {
152
+ color: "#dc3545",
153
+ fontSize: "0.875rem",
154
+ marginTop: "-0.5rem"
155
+ };
156
+ var loadingStyle = {
157
+ textAlign: "center",
158
+ color: "#666",
159
+ fontSize: "1rem"
160
+ };
161
+ var index_default = KeyGuard;
162
+ export {
163
+ KeyGuard,
164
+ index_default as default
165
+ };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "apps-key-guard",
3
+ "version": "0.0.1",
4
+ "description": "A React component for key-based access control with localStorage caching",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsup src/index.tsx --format cjs,esm --dts",
13
+ "build:watch": "tsup src/index.tsx --format cjs,esm --dts --watch",
14
+ "dev": "vite",
15
+ "preview": "vite preview",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "react",
20
+ "key",
21
+ "access-control",
22
+ "guard",
23
+ "authentication"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "peerDependencies": {
28
+ "react": "^18.0.0",
29
+ "react-dom": "^18.0.0"
30
+ },
31
+ "dependencies": {
32
+ "axios": "^1.7.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/react": "^18.3.0",
36
+ "@types/react-dom": "^18.3.0",
37
+ "@vitejs/plugin-react": "^4.2.0",
38
+ "react": "^18.3.0",
39
+ "react-dom": "^18.3.0",
40
+ "tsup": "^8.0.0",
41
+ "typescript": "^5.0.0",
42
+ "vite": "^5.0.0"
43
+ }
44
+ }