@megacorp-ai/auth-react 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/dist/index.js ADDED
@@ -0,0 +1,143 @@
1
+ // src/client.ts
2
+ import { createAuthClient as createBetterAuthClient } from "better-auth/react";
3
+ import { adminClient, emailOTPClient } from "better-auth/client/plugins";
4
+ function createAuthClient(opts = {}) {
5
+ return createBetterAuthClient({
6
+ ...opts.baseURL && { baseURL: opts.baseURL },
7
+ basePath: "/api/auth",
8
+ plugins: [emailOTPClient(), adminClient()]
9
+ });
10
+ }
11
+
12
+ // src/hooks.ts
13
+ function useSession(client) {
14
+ const { data, isPending, error, refetch } = client.useSession();
15
+ return {
16
+ data: data ?? null,
17
+ user: data?.user ?? null,
18
+ isPending,
19
+ error,
20
+ refetch,
21
+ signOut: () => client.signOut()
22
+ };
23
+ }
24
+ function parseRoles(role) {
25
+ return (role ?? "").split(",").map((r) => r.trim()).filter((r) => ["megacorp_admin", "customer_admin", "member"].includes(r));
26
+ }
27
+ function useRole(client) {
28
+ const { user, isPending } = useSession(client);
29
+ const roles = parseRoles(user?.role);
30
+ const has = (...allowed) => roles.some((r) => allowed.includes(r));
31
+ return {
32
+ roles,
33
+ isPending,
34
+ hasRole: has,
35
+ isMegacorpAdmin: has("megacorp_admin"),
36
+ isCustomerAdmin: has("customer_admin"),
37
+ canInvite: has("megacorp_admin", "customer_admin")
38
+ };
39
+ }
40
+
41
+ // src/SignIn.tsx
42
+ import { useState } from "react";
43
+ import { jsx, jsxs } from "react/jsx-runtime";
44
+ var defaultLabels = {
45
+ email: "Email address",
46
+ sendCode: "Send sign-in code",
47
+ code: "6-digit code",
48
+ verify: "Sign in",
49
+ resend: "Resend code",
50
+ changeEmail: "Use a different email",
51
+ sent: "We emailed a code to",
52
+ unknownEmail: "That email is not registered. Ask an administrator for an invite."
53
+ };
54
+ function SignIn({ client, initialEmail = "", onSignedIn, classNames: c = {}, labels: l = {} }) {
55
+ const t = { ...defaultLabels, ...l };
56
+ const [email, setEmail] = useState(initialEmail);
57
+ const [otp, setOtp] = useState("");
58
+ const [step, setStep] = useState("email");
59
+ const [busy, setBusy] = useState(false);
60
+ const [error, setError] = useState(null);
61
+ const [notice, setNotice] = useState(null);
62
+ const sendCode = async () => {
63
+ setBusy(true);
64
+ setError(null);
65
+ setNotice(null);
66
+ const { error: error2 } = await client.emailOtp.sendVerificationOtp({ email: email.trim().toLowerCase(), type: "sign-in" });
67
+ setBusy(false);
68
+ if (error2) {
69
+ setError(error2.status === 429 ? "Too many attempts. Please wait a few minutes." : error2.message ?? "Could not send code");
70
+ return;
71
+ }
72
+ setStep("code");
73
+ setOtp("");
74
+ setNotice(`${t.sent} ${email.trim()}`);
75
+ };
76
+ const onEmailSubmit = (e) => {
77
+ e.preventDefault();
78
+ void sendCode();
79
+ };
80
+ const onCodeSubmit = async (e) => {
81
+ e.preventDefault();
82
+ setBusy(true);
83
+ setError(null);
84
+ const { error: error2 } = await client.signIn.emailOtp({ email: email.trim().toLowerCase(), otp: otp.trim() });
85
+ setBusy(false);
86
+ if (error2) {
87
+ const code = error2.code ?? "";
88
+ if (code.includes("USER_NOT_FOUND") || error2.status === 404) setError(t.unknownEmail);
89
+ else if (code.includes("TOO_MANY_ATTEMPTS")) setError("Too many wrong codes. Request a new one.");
90
+ else if (code.includes("EXPIRED")) setError("That code has expired. Request a new one.");
91
+ else setError(error2.message ?? "Invalid code");
92
+ return;
93
+ }
94
+ onSignedIn?.();
95
+ };
96
+ return /* @__PURE__ */ jsxs("div", { className: c.root, children: [
97
+ step === "email" ? /* @__PURE__ */ jsxs("form", { className: c.form, onSubmit: onEmailSubmit, children: [
98
+ /* @__PURE__ */ jsx("label", { className: c.label, htmlFor: "mc-auth-email", children: t.email }),
99
+ /* @__PURE__ */ jsx("input", { id: "mc-auth-email", className: c.input, type: "email", autoComplete: "email", required: true, value: email, onChange: (e) => setEmail(e.target.value), disabled: busy }),
100
+ /* @__PURE__ */ jsx("button", { className: c.button, type: "submit", disabled: busy || !email, children: t.sendCode })
101
+ ] }) : /* @__PURE__ */ jsxs("form", { className: c.form, onSubmit: onCodeSubmit, children: [
102
+ notice && /* @__PURE__ */ jsx("p", { className: c.hint, children: notice }),
103
+ /* @__PURE__ */ jsx("label", { className: c.label, htmlFor: "mc-auth-otp", children: t.code }),
104
+ /* @__PURE__ */ jsx("input", { id: "mc-auth-otp", className: c.input, inputMode: "numeric", autoComplete: "one-time-code", pattern: "[0-9]{6}", maxLength: 6, required: true, value: otp, onChange: (e) => setOtp(e.target.value.replace(/\D/g, "")), disabled: busy, autoFocus: true }),
105
+ /* @__PURE__ */ jsx("button", { className: c.button, type: "submit", disabled: busy || otp.length !== 6, children: t.verify }),
106
+ /* @__PURE__ */ jsx("button", { className: c.secondaryButton, type: "button", onClick: () => void sendCode(), disabled: busy, children: t.resend }),
107
+ /* @__PURE__ */ jsx("button", { className: c.secondaryButton, type: "button", onClick: () => {
108
+ setStep("email");
109
+ setError(null);
110
+ setNotice(null);
111
+ }, disabled: busy, children: t.changeEmail })
112
+ ] }),
113
+ error && /* @__PURE__ */ jsx("p", { className: c.error, role: "alert", children: error })
114
+ ] });
115
+ }
116
+
117
+ // src/ImpersonationBanner.tsx
118
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
119
+ function ImpersonationBanner({ client, className, buttonClassName, onStopped }) {
120
+ const { data, refetch } = useSession(client);
121
+ if (!data?.session.impersonatedBy) return null;
122
+ const stop = async () => {
123
+ await client.admin.stopImpersonating();
124
+ await refetch();
125
+ onStopped?.();
126
+ };
127
+ return /* @__PURE__ */ jsxs2("div", { className, role: "status", children: [
128
+ "You are impersonating ",
129
+ /* @__PURE__ */ jsx2("strong", { children: data.user.email }),
130
+ ".",
131
+ " ",
132
+ /* @__PURE__ */ jsx2("button", { type: "button", className: buttonClassName, onClick: () => void stop(), children: "Stop impersonating" })
133
+ ] });
134
+ }
135
+ export {
136
+ ImpersonationBanner,
137
+ SignIn,
138
+ createAuthClient,
139
+ parseRoles,
140
+ useRole,
141
+ useSession
142
+ };
143
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/hooks.ts","../src/SignIn.tsx","../src/ImpersonationBanner.tsx"],"mappings":";AAAA,SAAS,oBAAoB,8BAA8B;AAC3D,SAAS,aAAa,sBAAsB;AAUrC,SAAS,iBAAiB,OAAgC,CAAC,GAAG;AACnE,SAAO,uBAAuB;AAAA,IAC5B,GAAI,KAAK,WAAW,EAAE,SAAS,KAAK,QAAQ;AAAA,IAC5C,UAAU;AAAA,IACV,SAAS,CAAC,eAAe,GAAG,YAAY,CAAC;AAAA,EAC3C,CAAC;AACH;;;ACAO,SAAS,WAAW,QAAoB;AAC7C,QAAM,EAAE,MAAM,WAAW,OAAO,QAAQ,IAAI,OAAO,WAAW;AAC9D,SAAO;AAAA,IACL,MAAO,QAAQ;AAAA,IACf,MAAO,MAAM,QAAQ;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,MAAM,OAAO,QAAQ;AAAA,EAChC;AACF;AAEO,SAAS,WAAW,MAAyC;AAClE,UAAQ,QAAQ,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,MAAiB,CAAC,kBAAkB,kBAAkB,QAAQ,EAAE,SAAS,CAAC,CAAC;AACzI;AAGO,SAAS,QAAQ,QAAoB;AAC1C,QAAM,EAAE,MAAM,UAAU,IAAI,WAAW,MAAM;AAC7C,QAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,QAAM,MAAM,IAAI,YAAoB,MAAM,KAAK,CAAC,MAAM,QAAQ,SAAS,CAAC,CAAC;AACzE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,iBAAiB,IAAI,gBAAgB;AAAA,IACrC,iBAAiB,IAAI,gBAAgB;AAAA,IACrC,WAAW,IAAI,kBAAkB,gBAAgB;AAAA,EACnD;AACF;;;AC9CA,SAAS,gBAAgC;AAsEjC,SACE,KADF;AAtDR,IAAM,gBAAgB;AAAA,EACpB,OAAO;AAAA,EACP,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,MAAM;AAAA,EACN,cAAc;AAChB;AAGO,SAAS,OAAO,EAAE,QAAQ,eAAe,IAAI,YAAY,YAAY,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,EAAE,GAAgB;AACjH,QAAM,IAAI,EAAE,GAAG,eAAe,GAAG,EAAE;AACnC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,YAAY;AAC/C,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,EAAE;AACjC,QAAM,CAAC,MAAM,OAAO,IAAI,SAA2B,OAAO;AAC1D,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB,IAAI;AAExD,QAAM,WAAW,YAAY;AAC3B,YAAQ,IAAI;AAAG,aAAS,IAAI;AAAG,cAAU,IAAI;AAC7C,UAAM,EAAE,OAAAA,OAAM,IAAI,MAAM,OAAO,SAAS,oBAAoB,EAAE,OAAO,MAAM,KAAK,EAAE,YAAY,GAAG,MAAM,UAAU,CAAC;AAClH,YAAQ,KAAK;AACb,QAAIA,QAAO;AACT,eAASA,OAAM,WAAW,MAAM,kDAAkDA,OAAM,WAAW,qBAAqB;AACxH;AAAA,IACF;AACA,YAAQ,MAAM;AAAG,WAAO,EAAE;AAC1B,cAAU,GAAG,EAAE,IAAI,IAAI,MAAM,KAAK,CAAC,EAAE;AAAA,EACvC;AAEA,QAAM,gBAAgB,CAAC,MAAiB;AAAE,MAAE,eAAe;AAAG,SAAK,SAAS;AAAA,EAAG;AAE/E,QAAM,eAAe,OAAO,MAAiB;AAC3C,MAAE,eAAe;AACjB,YAAQ,IAAI;AAAG,aAAS,IAAI;AAC5B,UAAM,EAAE,OAAAA,OAAM,IAAI,MAAM,OAAO,OAAO,SAAS,EAAE,OAAO,MAAM,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC;AACrG,YAAQ,KAAK;AACb,QAAIA,QAAO;AACT,YAAM,OAAQA,OAA4B,QAAQ;AAClD,UAAI,KAAK,SAAS,gBAAgB,KAAKA,OAAM,WAAW,IAAK,UAAS,EAAE,YAAY;AAAA,eAC3E,KAAK,SAAS,mBAAmB,EAAG,UAAS,0CAA0C;AAAA,eACvF,KAAK,SAAS,SAAS,EAAG,UAAS,2CAA2C;AAAA,UAClF,UAASA,OAAM,WAAW,cAAc;AAC7C;AAAA,IACF;AACA,iBAAa;AAAA,EACf;AAEA,SACE,qBAAC,SAAI,WAAW,EAAE,MACf;AAAA,aAAS,UACR,qBAAC,UAAK,WAAW,EAAE,MAAM,UAAU,eACjC;AAAA,0BAAC,WAAM,WAAW,EAAE,OAAO,SAAQ,iBAAiB,YAAE,OAAM;AAAA,MAC5D,oBAAC,WAAM,IAAG,iBAAgB,WAAW,EAAE,OAAO,MAAK,SAAQ,cAAa,SAAQ,UAAQ,MAAC,OAAO,OAAO,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK,GAAG,UAAU,MAAM;AAAA,MAClK,oBAAC,YAAO,WAAW,EAAE,QAAQ,MAAK,UAAS,UAAU,QAAQ,CAAC,OAAQ,YAAE,UAAS;AAAA,OACnF,IAEA,qBAAC,UAAK,WAAW,EAAE,MAAM,UAAU,cAChC;AAAA,gBAAU,oBAAC,OAAE,WAAW,EAAE,MAAO,kBAAO;AAAA,MACzC,oBAAC,WAAM,WAAW,EAAE,OAAO,SAAQ,eAAe,YAAE,MAAK;AAAA,MACzD,oBAAC,WAAM,IAAG,eAAc,WAAW,EAAE,OAAO,WAAU,WAAU,cAAa,iBAAgB,SAAQ,YAAW,WAAW,GAAG,UAAQ,MAAC,OAAO,KAAK,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,MAAM,QAAQ,OAAO,EAAE,CAAC,GAAG,UAAU,MAAM,WAAS,MAAC;AAAA,MACzO,oBAAC,YAAO,WAAW,EAAE,QAAQ,MAAK,UAAS,UAAU,QAAQ,IAAI,WAAW,GAAI,YAAE,QAAO;AAAA,MACzF,oBAAC,YAAO,WAAW,EAAE,iBAAiB,MAAK,UAAS,SAAS,MAAM,KAAK,SAAS,GAAG,UAAU,MAAO,YAAE,QAAO;AAAA,MAC9G,oBAAC,YAAO,WAAW,EAAE,iBAAiB,MAAK,UAAS,SAAS,MAAM;AAAE,gBAAQ,OAAO;AAAG,iBAAS,IAAI;AAAG,kBAAU,IAAI;AAAA,MAAG,GAAG,UAAU,MAAO,YAAE,aAAY;AAAA,OAC5J;AAAA,IAED,SAAS,oBAAC,OAAE,WAAW,EAAE,OAAO,MAAK,SAAS,iBAAM;AAAA,KACvD;AAEJ;;;ACpEI,SACwB,OAAAC,MADxB,QAAAC,aAAA;AATG,SAAS,oBAAoB,EAAE,QAAQ,WAAW,iBAAiB,UAAU,GAA6B;AAC/G,QAAM,EAAE,MAAM,QAAQ,IAAI,WAAW,MAAM;AAC3C,MAAI,CAAC,MAAM,QAAQ,eAAgB,QAAO;AAC1C,QAAM,OAAO,YAAY;AACvB,UAAM,OAAO,MAAM,kBAAkB;AACrC,UAAM,QAAQ;AACd,gBAAY;AAAA,EACd;AACA,SACE,gBAAAA,MAAC,SAAI,WAAsB,MAAK,UAAS;AAAA;AAAA,IACjB,gBAAAD,KAAC,YAAQ,eAAK,KAAK,OAAM;AAAA,IAAS;AAAA,IAAE;AAAA,IAC1D,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,iBAAiB,SAAS,MAAM,KAAK,KAAK,GAAG,gCAAkB;AAAA,KAClG;AAEJ;","names":["error","jsx","jsxs"]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@megacorp-ai/auth-react",
3
+ "version": "0.1.0",
4
+ "description": "React client for @megacorp-ai/auth: SignIn component, useSession, useRole, ImpersonationBanner",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Megacorp-Logistics/auth.git",
9
+ "directory": "packages/auth-react"
10
+ },
11
+ "type": "module",
12
+ "engines": {
13
+ "node": ">=24"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "sideEffects": false,
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "test": "vitest run --passWithNoTests",
32
+ "typecheck": "tsc --noEmit -p tsconfig.json"
33
+ },
34
+ "dependencies": {
35
+ "better-auth": "^1.7.4"
36
+ },
37
+ "peerDependencies": {
38
+ "react": ">=19",
39
+ "react-dom": ">=19"
40
+ },
41
+ "devDependencies": {
42
+ "@types/react": "19.3.0",
43
+ "@types/react-dom": "19.3.0",
44
+ "react": "19.3.0",
45
+ "react-dom": "19.3.0"
46
+ }
47
+ }