@niid/sdk 1.0.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/README.md +257 -0
- package/dist/components/LoginButton.d.ts +5 -0
- package/dist/components/LoginButton.d.ts.map +1 -0
- package/dist/components/LoginButton.vanilla.d.ts +4 -0
- package/dist/components/LoginButton.vanilla.d.ts.map +1 -0
- package/dist/core/NIIDClient.d.ts +18 -0
- package/dist/core/NIIDClient.d.ts.map +1 -0
- package/dist/core/OAuthFlow.d.ts +15 -0
- package/dist/core/OAuthFlow.d.ts.map +1 -0
- package/dist/core/TokenManager.d.ts +19 -0
- package/dist/core/TokenManager.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2955 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +4 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +192 -0
- package/dist/react.js.map +1 -0
- package/dist/styles/button.css +1 -0
- package/dist/types/index.d.ts +64 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/storage.d.ts +9 -0
- package/dist/utils/storage.d.ts.map +1 -0
- package/dist/utils/validation.d.ts +6 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/vanilla.d.ts +4 -0
- package/dist/vanilla.d.ts.map +1 -0
- package/dist/vanilla.js +163 -0
- package/dist/vanilla.js.map +1 -0
- package/package.json +72 -0
package/dist/react.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, createElement, useState, useEffect, useCallback } from "react";
|
|
3
|
+
import { NIIDClient } from "./index.js";
|
|
4
|
+
/* empty css */
|
|
5
|
+
/**
|
|
6
|
+
* @license lucide-react v0.562.0 - ISC
|
|
7
|
+
*
|
|
8
|
+
* This source code is licensed under the ISC license.
|
|
9
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
10
|
+
*/
|
|
11
|
+
const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
12
|
+
const toCamelCase = (string) => string.replace(
|
|
13
|
+
/^([A-Z])|[\s-_]+(\w)/g,
|
|
14
|
+
(match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
|
|
15
|
+
);
|
|
16
|
+
const toPascalCase = (string) => {
|
|
17
|
+
const camelCase = toCamelCase(string);
|
|
18
|
+
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
|
19
|
+
};
|
|
20
|
+
const mergeClasses = (...classes) => classes.filter((className, index, array) => {
|
|
21
|
+
return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
|
|
22
|
+
}).join(" ").trim();
|
|
23
|
+
const hasA11yProp = (props) => {
|
|
24
|
+
for (const prop in props) {
|
|
25
|
+
if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* @license lucide-react v0.562.0 - ISC
|
|
32
|
+
*
|
|
33
|
+
* This source code is licensed under the ISC license.
|
|
34
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
35
|
+
*/
|
|
36
|
+
var defaultAttributes = {
|
|
37
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
38
|
+
width: 24,
|
|
39
|
+
height: 24,
|
|
40
|
+
viewBox: "0 0 24 24",
|
|
41
|
+
fill: "none",
|
|
42
|
+
stroke: "currentColor",
|
|
43
|
+
strokeWidth: 2,
|
|
44
|
+
strokeLinecap: "round",
|
|
45
|
+
strokeLinejoin: "round"
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* @license lucide-react v0.562.0 - ISC
|
|
49
|
+
*
|
|
50
|
+
* This source code is licensed under the ISC license.
|
|
51
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
52
|
+
*/
|
|
53
|
+
const Icon = forwardRef(
|
|
54
|
+
({
|
|
55
|
+
color = "currentColor",
|
|
56
|
+
size = 24,
|
|
57
|
+
strokeWidth = 2,
|
|
58
|
+
absoluteStrokeWidth,
|
|
59
|
+
className = "",
|
|
60
|
+
children,
|
|
61
|
+
iconNode,
|
|
62
|
+
...rest
|
|
63
|
+
}, ref) => createElement(
|
|
64
|
+
"svg",
|
|
65
|
+
{
|
|
66
|
+
ref,
|
|
67
|
+
...defaultAttributes,
|
|
68
|
+
width: size,
|
|
69
|
+
height: size,
|
|
70
|
+
stroke: color,
|
|
71
|
+
strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
|
72
|
+
className: mergeClasses("lucide", className),
|
|
73
|
+
...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
|
|
74
|
+
...rest
|
|
75
|
+
},
|
|
76
|
+
[
|
|
77
|
+
...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),
|
|
78
|
+
...Array.isArray(children) ? children : [children]
|
|
79
|
+
]
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
/**
|
|
83
|
+
* @license lucide-react v0.562.0 - ISC
|
|
84
|
+
*
|
|
85
|
+
* This source code is licensed under the ISC license.
|
|
86
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
87
|
+
*/
|
|
88
|
+
const createLucideIcon = (iconName, iconNode) => {
|
|
89
|
+
const Component = forwardRef(
|
|
90
|
+
({ className, ...props }, ref) => createElement(Icon, {
|
|
91
|
+
ref,
|
|
92
|
+
iconNode,
|
|
93
|
+
className: mergeClasses(
|
|
94
|
+
`lucide-${toKebabCase(toPascalCase(iconName))}`,
|
|
95
|
+
`lucide-${iconName}`,
|
|
96
|
+
className
|
|
97
|
+
),
|
|
98
|
+
...props
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
Component.displayName = toPascalCase(iconName);
|
|
102
|
+
return Component;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* @license lucide-react v0.562.0 - ISC
|
|
106
|
+
*
|
|
107
|
+
* This source code is licensed under the ISC license.
|
|
108
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
109
|
+
*/
|
|
110
|
+
const __iconNode = [
|
|
111
|
+
[
|
|
112
|
+
"path",
|
|
113
|
+
{
|
|
114
|
+
d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
|
|
115
|
+
key: "oel41y"
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
];
|
|
119
|
+
const Shield = createLucideIcon("shield", __iconNode);
|
|
120
|
+
const LoginButton = ({
|
|
121
|
+
clientId,
|
|
122
|
+
clientSecret,
|
|
123
|
+
apiUrl,
|
|
124
|
+
ssoUrl,
|
|
125
|
+
redirectUri,
|
|
126
|
+
scope,
|
|
127
|
+
onSuccess,
|
|
128
|
+
onError,
|
|
129
|
+
className = "",
|
|
130
|
+
children,
|
|
131
|
+
variant = "primary"
|
|
132
|
+
}) => {
|
|
133
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
134
|
+
const [error, setError] = useState(null);
|
|
135
|
+
const [client, setClient] = useState(null);
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
const niidClient = new NIIDClient({
|
|
138
|
+
clientId,
|
|
139
|
+
clientSecret,
|
|
140
|
+
apiUrl,
|
|
141
|
+
ssoUrl,
|
|
142
|
+
redirectUri,
|
|
143
|
+
scope
|
|
144
|
+
});
|
|
145
|
+
setClient(niidClient);
|
|
146
|
+
}, [clientId, clientSecret, apiUrl, ssoUrl, redirectUri, scope]);
|
|
147
|
+
const handleClick = useCallback(() => {
|
|
148
|
+
if (!client || isLoading) return;
|
|
149
|
+
setError(null);
|
|
150
|
+
setIsLoading(true);
|
|
151
|
+
try {
|
|
152
|
+
client.login(redirectUri, scope);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
setError(err.message);
|
|
155
|
+
setIsLoading(false);
|
|
156
|
+
if (onError) {
|
|
157
|
+
onError(err);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}, [client, redirectUri, scope, isLoading, onError]);
|
|
161
|
+
const buttonClasses = [
|
|
162
|
+
"niid-login-button",
|
|
163
|
+
`niid-login-button-${variant}`,
|
|
164
|
+
isLoading ? "niid-login-button-loading" : "",
|
|
165
|
+
className
|
|
166
|
+
].filter(Boolean).join(" ");
|
|
167
|
+
return /* @__PURE__ */ jsxs(
|
|
168
|
+
"button",
|
|
169
|
+
{
|
|
170
|
+
type: "button",
|
|
171
|
+
className: buttonClasses,
|
|
172
|
+
onClick: handleClick,
|
|
173
|
+
disabled: isLoading,
|
|
174
|
+
"aria-label": "Sign in with NIID",
|
|
175
|
+
children: [
|
|
176
|
+
isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "niid-login-button-spinner" }),
|
|
178
|
+
/* @__PURE__ */ jsx("span", { className: "niid-login-button-text", children: "Loading..." })
|
|
179
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
180
|
+
/* @__PURE__ */ jsx(Shield, { className: "niid-login-button-icon", size: 16 }),
|
|
181
|
+
/* @__PURE__ */ jsx("span", { className: "niid-login-button-text", children: children || "Sign in with NIID" })
|
|
182
|
+
] }),
|
|
183
|
+
error && /* @__PURE__ */ jsx("span", { style: { display: "none" }, "aria-live": "polite", children: error })
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
export {
|
|
189
|
+
LoginButton,
|
|
190
|
+
NIIDClient
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sources":["../node_modules/lucide-react/dist/esm/shared/src/utils.js","../node_modules/lucide-react/dist/esm/defaultAttributes.js","../node_modules/lucide-react/dist/esm/Icon.js","../node_modules/lucide-react/dist/esm/createLucideIcon.js","../node_modules/lucide-react/dist/esm/icons/shield.js","../src/components/LoginButton.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.562.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\nconst hasA11yProp = (props) => {\n for (const prop in props) {\n if (prop.startsWith(\"aria-\") || prop === \"role\" || prop === \"title\") {\n return true;\n }\n }\n};\n\nexport { hasA11yProp, mergeClasses, toCamelCase, toKebabCase, toPascalCase };\n//# sourceMappingURL=utils.js.map\n","/**\n * @license lucide-react v0.562.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-react v0.562.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.js';\nimport { mergeClasses, hasA11yProp } from './shared/src/utils.js';\n\nconst Icon = forwardRef(\n ({\n color = \"currentColor\",\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = \"\",\n children,\n iconNode,\n ...rest\n }, ref) => createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n className: mergeClasses(\"lucide\", className),\n ...!children && !hasA11yProp(rest) && { \"aria-hidden\": \"true\" },\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n )\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-react v0.562.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses, toKebabCase, toPascalCase } from './shared/src/utils.js';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(\n `lucide-${toKebabCase(toPascalCase(iconName))}`,\n `lucide-${iconName}`,\n className\n ),\n ...props\n })\n );\n Component.displayName = toPascalCase(iconName);\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n","/**\n * @license lucide-react v0.562.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\",\n key: \"oel41y\"\n }\n ]\n];\nconst Shield = createLucideIcon(\"shield\", __iconNode);\n\nexport { __iconNode, Shield as default };\n//# sourceMappingURL=shield.js.map\n","import React, { useState, useEffect, useCallback } from 'react';\r\nimport { Shield } from 'lucide-react';\r\nimport { NIIDClient } from '../core/NIIDClient';\r\nimport { LoginButtonProps, UserInfo } from '../types';\r\nimport '../styles/button.css';\r\n\r\nexport const LoginButton: React.FC<LoginButtonProps> = ({\r\n clientId,\r\n clientSecret,\r\n apiUrl,\r\n ssoUrl,\r\n redirectUri,\r\n scope,\r\n onSuccess,\r\n onError,\r\n className = '',\r\n children,\r\n variant = 'primary'\r\n}) => {\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [client, setClient] = useState<NIIDClient | null>(null);\r\n\r\n useEffect(() => {\r\n const niidClient = new NIIDClient({\r\n clientId,\r\n clientSecret,\r\n apiUrl,\r\n ssoUrl,\r\n redirectUri,\r\n scope\r\n });\r\n setClient(niidClient);\r\n }, [clientId, clientSecret, apiUrl, ssoUrl, redirectUri, scope]);\r\n\r\n const handleClick = useCallback(() => {\r\n if (!client || isLoading) return;\r\n\r\n setError(null);\r\n setIsLoading(true);\r\n\r\n try {\r\n client.login(redirectUri, scope);\r\n } catch (err: any) {\r\n setError(err.message);\r\n setIsLoading(false);\r\n if (onError) {\r\n onError(err);\r\n }\r\n }\r\n }, [client, redirectUri, scope, isLoading, onError]);\r\n\r\n const buttonClasses = [\r\n 'niid-login-button',\r\n `niid-login-button-${variant}`,\r\n isLoading ? 'niid-login-button-loading' : '',\r\n className\r\n ].filter(Boolean).join(' ');\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n className={buttonClasses}\r\n onClick={handleClick}\r\n disabled={isLoading}\r\n aria-label=\"Sign in with NIID\"\r\n >\r\n {isLoading ? (\r\n <>\r\n <span className=\"niid-login-button-spinner\" />\r\n <span className=\"niid-login-button-text\">Loading...</span>\r\n </>\r\n ) : (\r\n <>\r\n <Shield className=\"niid-login-button-icon\" size={16} />\r\n <span className=\"niid-login-button-text\">\r\n {children || 'Sign in with NIID'}\r\n </span>\r\n </>\r\n )}\r\n {error && (\r\n <span style={{ display: 'none' }} aria-live=\"polite\">\r\n {error}\r\n </span>\r\n )}\r\n </button>\r\n );\r\n};\r\n\r\n"],"names":[],"mappings":"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","x_google_ignoreList":[0,1,2,3,4]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap";.niid-login-button{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;position:relative;display:inline-flex;align-items:center;justify-content:center;padding:12px 24px;font-size:14px;font-weight:500;line-height:1.5;text-align:center;text-decoration:none;border:none;border-radius:12px;cursor:pointer;transition:all .2s ease;outline:none;-webkit-user-select:none;user-select:none;-webkit-font-smoothing:antialiased}.niid-login-button:focus-visible{outline:2px solid #52525b;outline-offset:2px}.niid-login-button:disabled{opacity:.5;cursor:not-allowed}.niid-login-button-primary{background-color:#fff;color:#000}.niid-login-button-primary:hover:not(:disabled){background-color:#e4e4e7}.niid-login-button-primary:active:not(:disabled){background-color:#d4d4d8}.niid-login-button-secondary{background-color:#27272a;color:#fff}.niid-login-button-secondary:hover:not(:disabled){background-color:#3f3f46}.niid-login-button-secondary:active:not(:disabled){background-color:#52525b}.niid-login-button-loading{pointer-events:none}.niid-login-button-icon{display:inline-flex;align-items:center;margin-right:8px;width:16px;height:16px}.niid-login-button-spinner{display:inline-block;width:16px;height:16px;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:niid-spin .6s linear infinite;margin-right:8px}@keyframes niid-spin{to{transform:rotate(360deg)}}.niid-login-button-text{display:inline-flex;align-items:center}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface UserInfo {
|
|
3
|
+
id: number;
|
|
4
|
+
email: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
phone?: string;
|
|
7
|
+
is_active?: boolean;
|
|
8
|
+
created_at?: string;
|
|
9
|
+
updated_at?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TokenResponse {
|
|
12
|
+
access_token: string;
|
|
13
|
+
refresh_token?: string;
|
|
14
|
+
token_type: string;
|
|
15
|
+
expires_in: number;
|
|
16
|
+
scope?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface NIIDConfig {
|
|
19
|
+
clientId: string;
|
|
20
|
+
clientSecret?: string;
|
|
21
|
+
apiUrl?: string;
|
|
22
|
+
ssoUrl?: string;
|
|
23
|
+
redirectUri?: string;
|
|
24
|
+
scope?: string;
|
|
25
|
+
storageKey?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface JWTPayload {
|
|
28
|
+
sub: string;
|
|
29
|
+
exp: number;
|
|
30
|
+
iat: number;
|
|
31
|
+
client_id?: string;
|
|
32
|
+
scope?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface LoginButtonProps {
|
|
35
|
+
clientId: string;
|
|
36
|
+
clientSecret?: string;
|
|
37
|
+
apiUrl?: string;
|
|
38
|
+
ssoUrl?: string;
|
|
39
|
+
redirectUri?: string;
|
|
40
|
+
scope?: string;
|
|
41
|
+
onSuccess?: (user: UserInfo) => void;
|
|
42
|
+
onError?: (error: Error) => void;
|
|
43
|
+
className?: string;
|
|
44
|
+
children?: ReactNode;
|
|
45
|
+
variant?: 'primary' | 'secondary';
|
|
46
|
+
}
|
|
47
|
+
export interface LoginButtonConfig {
|
|
48
|
+
clientId: string;
|
|
49
|
+
clientSecret?: string;
|
|
50
|
+
apiUrl?: string;
|
|
51
|
+
ssoUrl?: string;
|
|
52
|
+
redirectUri?: string;
|
|
53
|
+
scope?: string;
|
|
54
|
+
onSuccess?: (user: UserInfo) => void;
|
|
55
|
+
onError?: (error: Error) => void;
|
|
56
|
+
className?: string;
|
|
57
|
+
text?: string;
|
|
58
|
+
variant?: 'primary' | 'secondary';
|
|
59
|
+
}
|
|
60
|
+
export interface LoginButtonInstance {
|
|
61
|
+
destroy: () => void;
|
|
62
|
+
update: (config: Partial<LoginButtonConfig>) => void;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;CACtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,GAAE,MAAe;IAInC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IASrC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAU/B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IASzB,KAAK,IAAI,IAAI;CAad"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { NIIDConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
export declare function validateConfig(config: NIIDConfig): void;
|
|
4
|
+
export declare function generateState(): string;
|
|
5
|
+
export declare function buildAuthorizationUrl(ssoUrl: string, clientId: string, redirectUri: string, scope?: string, state?: string): string;
|
|
6
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAwBvD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,MAAwB,EAC/B,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAaR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vanilla.d.ts","sourceRoot":"","sources":["../src/vanilla.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,cAAc,SAAS,CAAC"}
|
package/dist/vanilla.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { NIIDClient } from "./index.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
function createLoginButton(config, container) {
|
|
4
|
+
let client = null;
|
|
5
|
+
let buttonElement = null;
|
|
6
|
+
let isLoading = false;
|
|
7
|
+
let currentConfig = { ...config };
|
|
8
|
+
const init = () => {
|
|
9
|
+
client = new NIIDClient({
|
|
10
|
+
clientId: config.clientId,
|
|
11
|
+
clientSecret: config.clientSecret,
|
|
12
|
+
apiUrl: config.apiUrl,
|
|
13
|
+
ssoUrl: config.ssoUrl,
|
|
14
|
+
redirectUri: config.redirectUri,
|
|
15
|
+
scope: config.scope
|
|
16
|
+
});
|
|
17
|
+
const button = document.createElement("button");
|
|
18
|
+
button.type = "button";
|
|
19
|
+
button.className = [
|
|
20
|
+
"niid-login-button",
|
|
21
|
+
`niid-login-button-${config.variant || "primary"}`,
|
|
22
|
+
config.className || ""
|
|
23
|
+
].filter(Boolean).join(" ");
|
|
24
|
+
button.setAttribute("aria-label", "Sign in with NIID");
|
|
25
|
+
const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
26
|
+
icon.setAttribute("class", "niid-login-button-icon");
|
|
27
|
+
icon.setAttribute("width", "16");
|
|
28
|
+
icon.setAttribute("height", "16");
|
|
29
|
+
icon.setAttribute("viewBox", "0 0 24 24");
|
|
30
|
+
icon.setAttribute("fill", "none");
|
|
31
|
+
icon.setAttribute("stroke", "currentColor");
|
|
32
|
+
icon.setAttribute("stroke-width", "2");
|
|
33
|
+
icon.setAttribute("stroke-linecap", "round");
|
|
34
|
+
icon.setAttribute("stroke-linejoin", "round");
|
|
35
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
36
|
+
path.setAttribute("d", "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z");
|
|
37
|
+
path.setAttribute("fill", "currentColor");
|
|
38
|
+
icon.appendChild(path);
|
|
39
|
+
const text = document.createElement("span");
|
|
40
|
+
text.className = "niid-login-button-text";
|
|
41
|
+
text.textContent = config.text || "Sign in with NIID";
|
|
42
|
+
button.appendChild(icon);
|
|
43
|
+
button.appendChild(text);
|
|
44
|
+
button.addEventListener("click", handleClick);
|
|
45
|
+
container.appendChild(button);
|
|
46
|
+
buttonElement = button;
|
|
47
|
+
handleCallback();
|
|
48
|
+
};
|
|
49
|
+
const handleClick = async () => {
|
|
50
|
+
if (!client || isLoading) return;
|
|
51
|
+
isLoading = true;
|
|
52
|
+
updateButtonState(true);
|
|
53
|
+
try {
|
|
54
|
+
client.login(currentConfig.redirectUri, currentConfig.scope);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
isLoading = false;
|
|
57
|
+
updateButtonState(false);
|
|
58
|
+
if (currentConfig.onError) {
|
|
59
|
+
currentConfig.onError(error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const handleCallback = async () => {
|
|
64
|
+
if (!client) return;
|
|
65
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
66
|
+
if (urlParams.get("code")) {
|
|
67
|
+
isLoading = true;
|
|
68
|
+
updateButtonState(true);
|
|
69
|
+
try {
|
|
70
|
+
const user = await client.handleCallback();
|
|
71
|
+
if (user && currentConfig.onSuccess) {
|
|
72
|
+
currentConfig.onSuccess(user);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (currentConfig.onError) {
|
|
76
|
+
currentConfig.onError(error);
|
|
77
|
+
}
|
|
78
|
+
} finally {
|
|
79
|
+
isLoading = false;
|
|
80
|
+
updateButtonState(false);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const updateButtonState = (loading) => {
|
|
85
|
+
if (!buttonElement) return;
|
|
86
|
+
if (loading) {
|
|
87
|
+
buttonElement.classList.add("niid-login-button-loading");
|
|
88
|
+
buttonElement.disabled = true;
|
|
89
|
+
const spinner = document.createElement("span");
|
|
90
|
+
spinner.className = "niid-login-button-spinner";
|
|
91
|
+
const text = document.createElement("span");
|
|
92
|
+
text.className = "niid-login-button-text";
|
|
93
|
+
text.textContent = "Loading...";
|
|
94
|
+
buttonElement.innerHTML = "";
|
|
95
|
+
buttonElement.appendChild(spinner);
|
|
96
|
+
buttonElement.appendChild(text);
|
|
97
|
+
} else {
|
|
98
|
+
buttonElement.classList.remove("niid-login-button-loading");
|
|
99
|
+
buttonElement.disabled = false;
|
|
100
|
+
const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
101
|
+
icon.setAttribute("class", "niid-login-button-icon");
|
|
102
|
+
icon.setAttribute("width", "16");
|
|
103
|
+
icon.setAttribute("height", "16");
|
|
104
|
+
icon.setAttribute("viewBox", "0 0 24 24");
|
|
105
|
+
icon.setAttribute("fill", "none");
|
|
106
|
+
icon.setAttribute("stroke", "currentColor");
|
|
107
|
+
icon.setAttribute("stroke-width", "2");
|
|
108
|
+
icon.setAttribute("stroke-linecap", "round");
|
|
109
|
+
icon.setAttribute("stroke-linejoin", "round");
|
|
110
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
111
|
+
path.setAttribute("d", "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z");
|
|
112
|
+
path.setAttribute("fill", "currentColor");
|
|
113
|
+
icon.appendChild(path);
|
|
114
|
+
const text = document.createElement("span");
|
|
115
|
+
text.className = "niid-login-button-text";
|
|
116
|
+
text.textContent = currentConfig.text || "Sign in with NIID";
|
|
117
|
+
buttonElement.innerHTML = "";
|
|
118
|
+
buttonElement.appendChild(icon);
|
|
119
|
+
buttonElement.appendChild(text);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const destroy = () => {
|
|
123
|
+
if (buttonElement) {
|
|
124
|
+
buttonElement.removeEventListener("click", handleClick);
|
|
125
|
+
buttonElement.remove();
|
|
126
|
+
buttonElement = null;
|
|
127
|
+
}
|
|
128
|
+
client = null;
|
|
129
|
+
};
|
|
130
|
+
const update = (newConfig) => {
|
|
131
|
+
currentConfig = { ...currentConfig, ...newConfig };
|
|
132
|
+
if (newConfig.text && buttonElement) {
|
|
133
|
+
const textElement = buttonElement.querySelector(".niid-login-button-text");
|
|
134
|
+
if (textElement) {
|
|
135
|
+
textElement.textContent = newConfig.text;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (newConfig.variant && buttonElement) {
|
|
139
|
+
buttonElement.className = buttonElement.className.replace(/niid-login-button-(primary|secondary)/g, "").trim();
|
|
140
|
+
buttonElement.classList.add(`niid-login-button-${newConfig.variant}`);
|
|
141
|
+
}
|
|
142
|
+
if (newConfig.clientId || newConfig.clientSecret || newConfig.apiUrl || newConfig.ssoUrl) {
|
|
143
|
+
client = new NIIDClient({
|
|
144
|
+
clientId: currentConfig.clientId,
|
|
145
|
+
clientSecret: currentConfig.clientSecret,
|
|
146
|
+
apiUrl: currentConfig.apiUrl,
|
|
147
|
+
ssoUrl: currentConfig.ssoUrl,
|
|
148
|
+
redirectUri: currentConfig.redirectUri,
|
|
149
|
+
scope: currentConfig.scope
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
init();
|
|
154
|
+
return {
|
|
155
|
+
destroy,
|
|
156
|
+
update
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export {
|
|
160
|
+
NIIDClient,
|
|
161
|
+
createLoginButton
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=vanilla.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vanilla.js","sources":["../src/components/LoginButton.vanilla.ts"],"sourcesContent":["import { NIIDClient } from '../core/NIIDClient';\r\nimport { LoginButtonConfig, LoginButtonInstance, UserInfo } from '../types';\r\nimport '../styles/button.css';\r\n\r\nexport function createLoginButton(\r\n config: LoginButtonConfig,\r\n container: HTMLElement\r\n): LoginButtonInstance {\r\n let client: NIIDClient | null = null;\r\n let buttonElement: HTMLButtonElement | null = null;\r\n let isLoading = false;\r\n let currentConfig = { ...config };\r\n\r\n const init = () => {\r\n client = new NIIDClient({\r\n clientId: config.clientId,\r\n clientSecret: config.clientSecret,\r\n apiUrl: config.apiUrl,\r\n ssoUrl: config.ssoUrl,\r\n redirectUri: config.redirectUri,\r\n scope: config.scope\r\n });\r\n\r\n const button = document.createElement('button');\r\n button.type = 'button';\r\n button.className = [\r\n 'niid-login-button',\r\n `niid-login-button-${config.variant || 'primary'}`,\r\n config.className || ''\r\n ].filter(Boolean).join(' ');\r\n button.setAttribute('aria-label', 'Sign in with NIID');\r\n\r\n const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n icon.setAttribute('class', 'niid-login-button-icon');\r\n icon.setAttribute('width', '16');\r\n icon.setAttribute('height', '16');\r\n icon.setAttribute('viewBox', '0 0 24 24');\r\n icon.setAttribute('fill', 'none');\r\n icon.setAttribute('stroke', 'currentColor');\r\n icon.setAttribute('stroke-width', '2');\r\n icon.setAttribute('stroke-linecap', 'round');\r\n icon.setAttribute('stroke-linejoin', 'round');\r\n \r\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r\n path.setAttribute('d', 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z');\r\n path.setAttribute('fill', 'currentColor');\r\n icon.appendChild(path);\r\n\r\n const text = document.createElement('span');\r\n text.className = 'niid-login-button-text';\r\n text.textContent = config.text || 'Sign in with NIID';\r\n\r\n button.appendChild(icon);\r\n button.appendChild(text);\r\n\r\n button.addEventListener('click', handleClick);\r\n\r\n container.appendChild(button);\r\n buttonElement = button;\r\n\r\n handleCallback();\r\n };\r\n\r\n const handleClick = async () => {\r\n if (!client || isLoading) return;\r\n\r\n isLoading = true;\r\n updateButtonState(true);\r\n\r\n try {\r\n client.login(currentConfig.redirectUri, currentConfig.scope);\r\n } catch (error: any) {\r\n isLoading = false;\r\n updateButtonState(false);\r\n if (currentConfig.onError) {\r\n currentConfig.onError(error);\r\n }\r\n }\r\n };\r\n\r\n const handleCallback = async () => {\r\n if (!client) return;\r\n\r\n const urlParams = new URLSearchParams(window.location.search);\r\n if (urlParams.get('code')) {\r\n isLoading = true;\r\n updateButtonState(true);\r\n\r\n try {\r\n const user = await client.handleCallback();\r\n if (user && currentConfig.onSuccess) {\r\n currentConfig.onSuccess(user);\r\n }\r\n } catch (error: any) {\r\n if (currentConfig.onError) {\r\n currentConfig.onError(error);\r\n }\r\n } finally {\r\n isLoading = false;\r\n updateButtonState(false);\r\n }\r\n }\r\n };\r\n\r\n const updateButtonState = (loading: boolean) => {\r\n if (!buttonElement) return;\r\n\r\n if (loading) {\r\n buttonElement.classList.add('niid-login-button-loading');\r\n buttonElement.disabled = true;\r\n \r\n const spinner = document.createElement('span');\r\n spinner.className = 'niid-login-button-spinner';\r\n \r\n const text = document.createElement('span');\r\n text.className = 'niid-login-button-text';\r\n text.textContent = 'Loading...';\r\n\r\n buttonElement.innerHTML = '';\r\n buttonElement.appendChild(spinner);\r\n buttonElement.appendChild(text);\r\n } else {\r\n buttonElement.classList.remove('niid-login-button-loading');\r\n buttonElement.disabled = false;\r\n\r\n const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n icon.setAttribute('class', 'niid-login-button-icon');\r\n icon.setAttribute('width', '16');\r\n icon.setAttribute('height', '16');\r\n icon.setAttribute('viewBox', '0 0 24 24');\r\n icon.setAttribute('fill', 'none');\r\n icon.setAttribute('stroke', 'currentColor');\r\n icon.setAttribute('stroke-width', '2');\r\n icon.setAttribute('stroke-linecap', 'round');\r\n icon.setAttribute('stroke-linejoin', 'round');\r\n \r\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r\n path.setAttribute('d', 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z');\r\n path.setAttribute('fill', 'currentColor');\r\n icon.appendChild(path);\r\n\r\n const text = document.createElement('span');\r\n text.className = 'niid-login-button-text';\r\n text.textContent = currentConfig.text || 'Sign in with NIID';\r\n\r\n buttonElement.innerHTML = '';\r\n buttonElement.appendChild(icon);\r\n buttonElement.appendChild(text);\r\n }\r\n };\r\n\r\n const destroy = () => {\r\n if (buttonElement) {\r\n buttonElement.removeEventListener('click', handleClick);\r\n buttonElement.remove();\r\n buttonElement = null;\r\n }\r\n client = null;\r\n };\r\n\r\n const update = (newConfig: Partial<LoginButtonConfig>) => {\r\n currentConfig = { ...currentConfig, ...newConfig };\r\n \r\n if (newConfig.text && buttonElement) {\r\n const textElement = buttonElement.querySelector('.niid-login-button-text');\r\n if (textElement) {\r\n textElement.textContent = newConfig.text;\r\n }\r\n }\r\n\r\n if (newConfig.variant && buttonElement) {\r\n buttonElement.className = buttonElement.className\r\n .replace(/niid-login-button-(primary|secondary)/g, '')\r\n .trim();\r\n buttonElement.classList.add(`niid-login-button-${newConfig.variant}`);\r\n }\r\n\r\n if (newConfig.clientId || newConfig.clientSecret || newConfig.apiUrl || newConfig.ssoUrl) {\r\n client = new NIIDClient({\r\n clientId: currentConfig.clientId,\r\n clientSecret: currentConfig.clientSecret,\r\n apiUrl: currentConfig.apiUrl,\r\n ssoUrl: currentConfig.ssoUrl,\r\n redirectUri: currentConfig.redirectUri,\r\n scope: currentConfig.scope\r\n });\r\n }\r\n };\r\n\r\n init();\r\n\r\n return {\r\n destroy,\r\n update\r\n };\r\n}\r\n\r\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@niid/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "NIID Web SDK for OAuth 2.0 integration - React and Vanilla JavaScript support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./react": {
|
|
15
|
+
"import": "./dist/react.js",
|
|
16
|
+
"types": "./dist/react.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./vanilla": {
|
|
19
|
+
"import": "./dist/vanilla.js",
|
|
20
|
+
"types": "./dist/vanilla.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./styles": "./dist/styles/button.css",
|
|
23
|
+
"./styles/button.css": "./dist/styles/button.css"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc && vite build",
|
|
31
|
+
"dev": "vite build --watch",
|
|
32
|
+
"prepublishOnly": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"oauth",
|
|
36
|
+
"oauth2",
|
|
37
|
+
"sso",
|
|
38
|
+
"single-sign-on",
|
|
39
|
+
"authentication",
|
|
40
|
+
"niid",
|
|
41
|
+
"react",
|
|
42
|
+
"typescript"
|
|
43
|
+
],
|
|
44
|
+
"author": "NIID Team",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/your-org/niid.git",
|
|
49
|
+
"directory": "packages/niid-sdk"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://docs.id.nicorp.tech",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/your-org/niid/issues"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"axios": "^1.6.2",
|
|
57
|
+
"jwt-decode": "^4.0.0",
|
|
58
|
+
"lucide-react": "^0.562.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": "^18.0.0",
|
|
62
|
+
"react-dom": "^18.0.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/react": "^18.2.43",
|
|
66
|
+
"@types/react-dom": "^18.2.17",
|
|
67
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
68
|
+
"typescript": "^5.2.2",
|
|
69
|
+
"vite": "^5.0.8",
|
|
70
|
+
"vite-plugin-dts": "^3.6.4"
|
|
71
|
+
}
|
|
72
|
+
}
|