@rpcbase/auth 0.27.0 → 0.29.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.
Files changed (57) hide show
  1. package/dist/api/sign-in/handler.d.ts +4 -0
  2. package/dist/api/sign-in/handler.d.ts.map +1 -0
  3. package/dist/api/sign-in/handler.js +38 -0
  4. package/dist/api/sign-in/index.d.ts +12 -0
  5. package/dist/api/sign-in/index.d.ts.map +1 -0
  6. package/dist/api/sign-in/index.js +18 -0
  7. package/dist/api/sign-out/handler.d.ts +4 -0
  8. package/dist/api/sign-out/handler.d.ts.map +1 -0
  9. package/dist/api/sign-out/handler.js +11 -0
  10. package/dist/api/sign-out/index.d.ts +9 -0
  11. package/dist/api/sign-out/index.d.ts.map +1 -0
  12. package/dist/api/sign-out/index.js +7 -0
  13. package/dist/api/sign-up/handler.d.ts +4 -0
  14. package/dist/api/sign-up/handler.d.ts.map +1 -0
  15. package/dist/api/sign-up/handler.js +34 -0
  16. package/dist/api/sign-up/index.d.ts +13 -0
  17. package/dist/api/sign-up/index.d.ts.map +1 -0
  18. package/dist/api/sign-up/index.js +23 -0
  19. package/dist/components/AppleSignInButton/index.d.ts +5 -0
  20. package/dist/components/AppleSignInButton/index.d.ts.map +1 -0
  21. package/dist/components/AppleSignInButton/index.js +14 -0
  22. package/dist/components/AuthLayout/index.d.ts +6 -0
  23. package/dist/components/AuthLayout/index.d.ts.map +1 -0
  24. package/dist/components/AuthLayout/index.js +26 -0
  25. package/dist/components/EmailOrPhoneInput/index.d.ts +6 -0
  26. package/dist/components/EmailOrPhoneInput/index.d.ts.map +1 -0
  27. package/dist/components/EmailOrPhoneInput/index.js +15 -0
  28. package/dist/components/RememberMeCheckbox/index.d.ts +6 -0
  29. package/dist/components/RememberMeCheckbox/index.d.ts.map +1 -0
  30. package/dist/components/RememberMeCheckbox/index.js +6 -0
  31. package/dist/components/SignInForm/index.d.ts +6 -0
  32. package/dist/components/SignInForm/index.d.ts.map +1 -0
  33. package/dist/components/SignInForm/index.js +20 -0
  34. package/dist/components/SignUpForm/index.d.ts +6 -0
  35. package/dist/components/SignUpForm/index.d.ts.map +1 -0
  36. package/dist/components/SignUpForm/index.js +21 -0
  37. package/dist/components/index.d.ts +7 -0
  38. package/dist/components/index.d.ts.map +1 -0
  39. package/dist/components/index.js +6 -0
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +1 -0
  43. package/package.json +22 -4
  44. package/src/api/sign-in/handler.ts +0 -51
  45. package/src/api/sign-in/index.ts +0 -29
  46. package/src/api/sign-out/handler.ts +0 -17
  47. package/src/api/sign-out/index.ts +0 -15
  48. package/src/api/sign-up/handler.ts +0 -48
  49. package/src/api/sign-up/index.ts +0 -34
  50. package/src/components/AppleSignInButton/index.tsx +0 -37
  51. package/src/components/AuthLayout/index.tsx +0 -55
  52. package/src/components/EmailOrPhoneInput/index.tsx +0 -33
  53. package/src/components/RememberMeCheckbox/index.tsx +0 -28
  54. package/src/components/SignInForm/index.tsx +0 -42
  55. package/src/components/SignUpForm/index.tsx +0 -43
  56. package/src/components/index.ts +0 -6
  57. package/src/index.ts +0 -1
@@ -0,0 +1,4 @@
1
+ import { Api } from "@rpcbase/api";
2
+ declare const _default: (api: Api) => void;
3
+ export default _default;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/api/sign-in/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAiC,MAAM,cAAc,CAAA;yBA+ChD,KAAK,GAAG;AAAxB,wBAEC"}
@@ -0,0 +1,38 @@
1
+ import isEmail from "validator/lib/isEmail";
2
+ // import { hashPassword } from "@rpcbase/server"
3
+ import * as SignIn from "./index";
4
+ const signIn = async (payload, ctx) => {
5
+ // const User = await loadModel("User", ctx)
6
+ const { email_or_phone } = SignIn.requestSchema.parse(payload);
7
+ if (isEmail(email_or_phone)) {
8
+ console.log("is valid email");
9
+ }
10
+ else {
11
+ console.log("is not valid email");
12
+ }
13
+ return { success: true };
14
+ // console.log("will lookup user", email)
15
+ // const user = await User.findOne({email})
16
+ // if (!user) {
17
+ // console.log("user not found", email)
18
+ // return { success: false }
19
+ // }
20
+ // console.log("found user", user._id.toString())
21
+ // console.time("checkPassword")
22
+ // const [salt, hashedPassword] = user.password.split(":")
23
+ // const derivedKey = await hashPassword(password, salt)
24
+ // const passwordMatches = crypto.timingSafeEqual(Buffer.from(hashedPassword, "hex"), derivedKey)
25
+ // console.timeEnd("checkPassword")
26
+ // ctx.req.session.user = {
27
+ // id: user._id.toString(),
28
+ // current_tenant_id: user.tenants[0],
29
+ // // TODO: handle multiple tenants
30
+ // signed_in_tenants: [user.tenants[0]],
31
+ // }
32
+ // return {
33
+ // success: passwordMatches
34
+ // }
35
+ };
36
+ export default (api) => {
37
+ api.post(SignIn.Route, signIn);
38
+ };
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ export declare const Route = "/api/rb/auth/sign-in";
3
+ export declare const requestSchema: z.ZodObject<{
4
+ email_or_phone: z.ZodDefault<z.ZodString>;
5
+ remember_me: z.ZodDefault<z.ZodBoolean>;
6
+ }, z.core.$strip>;
7
+ export type RequestPayload = z.infer<typeof requestSchema>;
8
+ export declare const responseSchema: z.ZodObject<{
9
+ success: z.ZodBoolean;
10
+ }, z.core.$strip>;
11
+ export type ResponsePayload = z.infer<typeof responseSchema>;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/api/sign-in/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,KAAK,yBAAyB,CAAA;AAE3C,eAAO,MAAM,aAAa;;;iBAcxB,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAE1D,eAAO,MAAM,cAAc;;iBAEzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import { isValidNumber } from "libphonenumber-js";
3
+ export const Route = "/api/rb/auth/sign-in";
4
+ export const requestSchema = z.object({
5
+ email_or_phone: z
6
+ .string()
7
+ .nonempty("Email or phone number is required")
8
+ .default("")
9
+ .refine((value) => {
10
+ const isEmail = z.string().email().safeParse(value).success;
11
+ const isPhone = isValidNumber(value);
12
+ return isEmail || isPhone;
13
+ }, "Please enter a valid email address or phone number"),
14
+ remember_me: z.boolean().default(true),
15
+ });
16
+ export const responseSchema = z.object({
17
+ success: z.boolean(),
18
+ });
@@ -0,0 +1,4 @@
1
+ import { Api } from "@rpcbase/api";
2
+ declare const _default: (api: Api) => void;
3
+ export default _default;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/api/sign-out/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAmB,MAAM,cAAc,CAAA;yBAcnC,KAAK,GAAG;AAAxB,wBAEC"}
@@ -0,0 +1,11 @@
1
+ import * as SignOut from "./index";
2
+ const handleSignOut = async (_, ctx) => {
3
+ // Destroy the session
4
+ await new Promise((resolve) => ctx.req.session.destroy(() => resolve()));
5
+ return {
6
+ success: true
7
+ };
8
+ };
9
+ export default (api) => {
10
+ api.post(SignOut.Route, handleSignOut);
11
+ };
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export declare const Route = "/api/rb/auth/sign-out";
3
+ export declare const requestSchema: z.ZodObject<{}, z.core.$strip>;
4
+ export type RequestPayload = z.infer<typeof requestSchema>;
5
+ export declare const responseSchema: z.ZodObject<{
6
+ success: z.ZodBoolean;
7
+ }, z.core.$strip>;
8
+ export type ResponsePayload = z.infer<typeof responseSchema>;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/api/sign-out/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,KAAK,0BAA0B,CAAA;AAG5C,eAAO,MAAM,aAAa,gCAAe,CAAA;AAEzC,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D,eAAO,MAAM,cAAc;;iBAEzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ export const Route = "/api/rb/auth/sign-out";
3
+ // No request payload needed for signout
4
+ export const requestSchema = z.object({});
5
+ export const responseSchema = z.object({
6
+ success: z.boolean()
7
+ });
@@ -0,0 +1,4 @@
1
+ import { Api } from "@rpcbase/api";
2
+ declare const _default: (api: Api) => void;
3
+ export default _default;
4
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/api/sign-up/handler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,GAAG,EAA6B,MAAM,cAAc,CAAA;yBA0C5C,KAAK,GAAG;AAAxB,wBAEC"}
@@ -0,0 +1,34 @@
1
+ import crypto from "crypto";
2
+ import isEmail from "validator/lib/isEmail";
3
+ import { loadModel } from "@rpcbase/api";
4
+ import { hashPassword } from "@rpcbase/server";
5
+ import * as SignUp from "./index";
6
+ const signUp = async (payload, ctx) => {
7
+ const User = await loadModel("User", ctx);
8
+ const { email_or_phone, password } = SignUp.requestSchema.parse(payload);
9
+ const is_email = isEmail(email_or_phone);
10
+ const query = is_email ? { email: email_or_phone } : { phone: email_or_phone };
11
+ const existingUser = await User.findOne(query);
12
+ if (existingUser) {
13
+ console.log("user with email or phone already exists", email_or_phone);
14
+ // For security, we don't want to reveal if an email/phone is registered.
15
+ // But for this implementation, we'll make it simple.
16
+ return { success: false };
17
+ }
18
+ const salt = crypto.randomBytes(16).toString("hex");
19
+ const derivedKey = await hashPassword(password, salt);
20
+ const hashedPassword = `${salt}:${derivedKey.toString("hex")}`;
21
+ const user = new User({
22
+ ...query,
23
+ password: hashedPassword,
24
+ });
25
+ await user.save();
26
+ console.log("created new user", user._id.toString());
27
+ // Note: This implementation does not automatically sign the user in.
28
+ // A full implementation would likely create a session for the new user,
29
+ // but tenant assignment logic for new users is not clear at this point.
30
+ return { success: true };
31
+ };
32
+ export default (api) => {
33
+ api.post(SignUp.Route, signUp);
34
+ };
@@ -0,0 +1,13 @@
1
+ import { z } from "zod";
2
+ export declare const Route = "/api/rb/auth/sign-up";
3
+ export declare const requestSchema: z.ZodObject<{
4
+ email_or_phone: z.ZodString;
5
+ password: z.ZodString;
6
+ password_confirmation: z.ZodString;
7
+ }, z.core.$strip>;
8
+ export type RequestPayload = z.infer<typeof requestSchema>;
9
+ export declare const responseSchema: z.ZodObject<{
10
+ success: z.ZodBoolean;
11
+ }, z.core.$strip>;
12
+ export type ResponsePayload = z.infer<typeof responseSchema>;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/api/sign-up/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,KAAK,yBAAyB,CAAA;AAE3C,eAAO,MAAM,aAAa;;;;iBAmBtB,CAAA;AAEJ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAE1D,eAAO,MAAM,cAAc;;iBAEzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import { isValidNumber } from "libphonenumber-js";
3
+ export const Route = "/api/rb/auth/sign-up";
4
+ export const requestSchema = z
5
+ .object({
6
+ email_or_phone: z
7
+ .string()
8
+ .nonempty("Email or phone number is required")
9
+ .refine((value) => {
10
+ const isEmail = z.string().email().safeParse(value).success;
11
+ const isPhone = isValidNumber(value);
12
+ return isEmail || isPhone;
13
+ }, "Please enter a valid email address or phone number"),
14
+ password: z.string().min(8, { message: "Password must be at least 8 characters long." }),
15
+ password_confirmation: z.string().nonempty({ message: "Please confirm your password." }),
16
+ })
17
+ .refine((data) => data.password === data.password_confirmation, {
18
+ message: "Passwords do not match.",
19
+ path: ["password_confirmation"],
20
+ });
21
+ export const responseSchema = z.object({
22
+ success: z.boolean(),
23
+ });
@@ -0,0 +1,5 @@
1
+ export declare const AppleSignInButton: ({ onPress, className, }: {
2
+ onPress: () => void;
3
+ className?: string;
4
+ }) => import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/components/AppleSignInButton/index.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,GAAI,yBAG/B;IACD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,4CA2BA,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import clsx from "clsx";
3
+ export const AppleSignInButton = ({ onPress, className, }) => {
4
+ return (_jsxs("button", { onClick: onPress, className: clsx(`
5
+ w-full
6
+ bg-black text-white hover:bg-gray-800
7
+ flex items-center justify-center
8
+ px-6 py-2
9
+ rounded-lg
10
+ font-medium
11
+ transition duration-150 ease-in-out
12
+ focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black
13
+ `, className), children: [_jsx("svg", { className: "w-5 h-5 mr-3", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "white", children: _jsx("path", { d: "M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.539 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701" }) }), _jsx("span", { children: "Continue with Apple" })] }));
14
+ };
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ export declare const AuthLayout: ({ sidePanel, children, }: {
3
+ sidePanel: React.ReactElement | null;
4
+ children: React.ReactNode;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/components/AuthLayout/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAyB9B,eAAO,MAAM,UAAU,GAAI,0BAGxB;IACD,SAAS,EAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAA;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,4CAuBA,CAAA"}
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Link, useLocation } from "@rpcbase/router";
3
+ const LINKS_REDIRECTION_MAP = {
4
+ "/auth/sign-in": {
5
+ "title": "Sign Up",
6
+ "location": "/auth/sign-up"
7
+ },
8
+ "/auth/sign-up": {
9
+ "title": "Sign In",
10
+ "location": "/auth/sign-in"
11
+ },
12
+ "/auth/forgot-password": {
13
+ "title": "Sign In",
14
+ "location": "/auth/sign-in"
15
+ },
16
+ "/auth/logout-success": {
17
+ "title": "Sign In",
18
+ "location": "/auth/sign-in"
19
+ }
20
+ };
21
+ export const AuthLayout = ({ sidePanel = null, children, }) => {
22
+ const location = useLocation();
23
+ const linkTitle = LINKS_REDIRECTION_MAP[location.pathname]?.title;
24
+ const linkLocation = LINKS_REDIRECTION_MAP[location.pathname]?.location;
25
+ return (_jsxs("div", { className: "container relative hidden h-dvh flex-col items-center justify-center md:grid md:w-full lg:max-w-none lg:grid-cols-2 lg:px-0", children: [_jsx(Link, { className: "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground h-9 px-4 py-2 absolute right-4 top-4 md:right-8 md:top-8", to: linkLocation, children: linkTitle }), _jsx("div", { className: "relative hidden h-full flex-col bg-muted p-10 text-white dark:border-r lg:flex", children: sidePanel }), _jsx("div", { className: "mx-auto flex w-full flex-col justify-center gap-6 /*sm:w-[350px]*/", children: children })] }));
26
+ };
@@ -0,0 +1,6 @@
1
+ export declare const EmailOrPhoneInput: ({ id, className, placeholder, }: {
2
+ id: string;
3
+ className?: string;
4
+ placeholder?: string;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/components/EmailOrPhoneInput/index.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,GAAI,iCAI/B;IACD,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,4CA6BA,CAAA"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useFormContext } from "@rpcbase/form";
3
+ export const EmailOrPhoneInput = ({ id, className, placeholder, }) => {
4
+ const { register, formState } = useFormContext();
5
+ const error = formState.errors.email_or_phone;
6
+ let errorMessage;
7
+ if (typeof error === "string") {
8
+ errorMessage = error;
9
+ }
10
+ else if (error && typeof error.message === "string") {
11
+ errorMessage = error.message;
12
+ }
13
+ // console.log("ERRR", errors)
14
+ return (_jsxs(_Fragment, { children: [_jsx("input", { id: id, type: "text", required: true, autoComplete: "on", className: className, placeholder: placeholder, ...register("email_or_phone") }), errorMessage ? (_jsx("p", { className: "mt-1 -mb-2 text-sm/6 text-red-500", children: errorMessage })) : null] }));
15
+ };
@@ -0,0 +1,6 @@
1
+ import { ComponentType } from "react";
2
+ export declare const RememberMeCheckbox: ({ label, as: Component }: {
3
+ label: string;
4
+ as?: ComponentType<any> | string;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/components/RememberMeCheckbox/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,OAAO,CAAA;AAInC,eAAO,MAAM,kBAAkB,GAAI,0BAGhC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,MAAM,CAAA;CACjC,4CAiBA,CAAA"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useFormContext } from "@rpcbase/form";
3
+ export const RememberMeCheckbox = ({ label, as: Component = "input" }) => {
4
+ const { register } = useFormContext();
5
+ return (_jsxs(_Fragment, { children: [_jsx(Component, { id: "remember_me", ...register("remember_me") }), _jsx("label", { htmlFor: "remember_me", className: "pl-2 block text-sm/6 text-gray-900", children: label })] }));
6
+ };
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from "react";
2
+ export declare const SignInForm: ({ children, className }: {
3
+ children: ReactNode;
4
+ className?: string;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/components/SignInForm/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAY,MAAM,OAAO,CAAA;AAW1C,eAAO,MAAM,UAAU,GAAI,yBAGxB;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,4CAyBA,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { useForm, FormProvider, zodResolver } from "@rpcbase/form";
4
+ import { requestSchema } from "../../api/sign-in";
5
+ export const SignInForm = ({ children, className }) => {
6
+ const methods = useForm({
7
+ defaultValues: {
8
+ email_or_phone: "",
9
+ remember_me: true,
10
+ },
11
+ resolver: zodResolver(requestSchema)
12
+ });
13
+ const onSubmit = async (data) => {
14
+ console.log("SUBMIT SIGNIN", data);
15
+ };
16
+ useEffect(() => {
17
+ console.log(methods.formState.errors);
18
+ }, [methods.formState.errors]);
19
+ return (_jsx(FormProvider, { ...methods, children: _jsx("form", { method: "post", noValidate: true, className: className, onSubmit: methods.handleSubmit(onSubmit), children: children }) }));
20
+ };
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from "react";
2
+ export declare const SignUpForm: ({ children, className }: {
3
+ children: ReactNode;
4
+ className?: string;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../pkg/auth/src/components/SignUpForm/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAY,MAAM,OAAO,CAAA;AAW1C,eAAO,MAAM,UAAU,GAAI,yBAGxB;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,4CA0BA,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { useForm, FormProvider, zodResolver } from "@rpcbase/form";
4
+ import { requestSchema } from "../../api/sign-up";
5
+ export const SignUpForm = ({ children, className }) => {
6
+ const methods = useForm({
7
+ defaultValues: {
8
+ email_or_phone: "",
9
+ password: "",
10
+ password_confirmation: "",
11
+ },
12
+ resolver: zodResolver(requestSchema)
13
+ });
14
+ const onSubmit = async (data) => {
15
+ console.log("SUBMIT SIGNUp", data);
16
+ };
17
+ useEffect(() => {
18
+ console.log(methods.formState.errors);
19
+ }, [methods.formState.errors]);
20
+ return (_jsx(FormProvider, { ...methods, children: _jsx("form", { method: "post", noValidate: true, className: className, onSubmit: methods.handleSubmit(onSubmit), children: children }) }));
21
+ };
@@ -0,0 +1,7 @@
1
+ export * from "./AuthLayout";
2
+ export * from "./AppleSignInButton";
3
+ export * from "./EmailOrPhoneInput";
4
+ export * from "./SignInForm";
5
+ export * from "./SignUpForm";
6
+ export * from "./RememberMeCheckbox";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../pkg/auth/src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA"}
@@ -0,0 +1,6 @@
1
+ export * from "./AuthLayout";
2
+ export * from "./AppleSignInButton";
3
+ export * from "./EmailOrPhoneInput";
4
+ export * from "./SignInForm";
5
+ export * from "./SignUpForm";
6
+ export * from "./RememberMeCheckbox";
@@ -0,0 +1,2 @@
1
+ export * from "./components";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../pkg/auth/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./components";
package/package.json CHANGED
@@ -1,16 +1,34 @@
1
1
  {
2
2
  "name": "@rpcbase/auth",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "type": "module",
5
- "main": "./src/index.ts",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
6
10
  "scripts": {
7
- "build": "tsc --watch",
11
+ "build": "wireit",
8
12
  "release": "wireit"
9
13
  },
10
14
  "wireit": {
15
+ "build": {
16
+ "command": "node ../../scripts/build-package.js auth",
17
+ "files": [
18
+ "src/**/*",
19
+ "../../tsconfig.json",
20
+ "../../tsconfig.base.json",
21
+ "../../scripts/build-package.js"
22
+ ],
23
+ "output": [
24
+ "dist/"
25
+ ]
26
+ },
11
27
  "release": {
12
28
  "command": "../../scripts/publish.js",
13
- "dependencies": [],
29
+ "dependencies": [
30
+ "build"
31
+ ],
14
32
  "files": [
15
33
  "package.json",
16
34
  "src/**/*"
@@ -1,51 +0,0 @@
1
- import isEmail from "validator/lib/isEmail"
2
- import {Api, /*loadModel,*/ Ctx, ApiHandler} from "@rpcbase/api"
3
- // import { hashPassword } from "@rpcbase/server"
4
-
5
- import * as SignIn from "./index"
6
-
7
-
8
- const signIn = async(payload: SignIn.RequestPayload, ctx: Ctx): Promise<SignIn.ResponsePayload> => {
9
- // const User = await loadModel("User", ctx)
10
-
11
- const {email_or_phone} = SignIn.requestSchema.parse(payload)
12
-
13
- if (isEmail(email_or_phone)) {
14
- console.log("is valid email")
15
- } else {
16
- console.log("is not valid email")
17
- }
18
-
19
- return {success: true}
20
-
21
- // console.log("will lookup user", email)
22
- // const user = await User.findOne({email})
23
-
24
- // if (!user) {
25
- // console.log("user not found", email)
26
- // return { success: false }
27
- // }
28
-
29
- // console.log("found user", user._id.toString())
30
-
31
- // console.time("checkPassword")
32
- // const [salt, hashedPassword] = user.password.split(":")
33
- // const derivedKey = await hashPassword(password, salt)
34
- // const passwordMatches = crypto.timingSafeEqual(Buffer.from(hashedPassword, "hex"), derivedKey)
35
- // console.timeEnd("checkPassword")
36
-
37
- // ctx.req.session.user = {
38
- // id: user._id.toString(),
39
- // current_tenant_id: user.tenants[0],
40
- // // TODO: handle multiple tenants
41
- // signed_in_tenants: [user.tenants[0]],
42
- // }
43
-
44
- // return {
45
- // success: passwordMatches
46
- // }
47
- }
48
-
49
- export default (api: Api) => {
50
- api.post(SignIn.Route, signIn as ApiHandler)
51
- }
@@ -1,29 +0,0 @@
1
- import { z } from "zod"
2
- import { isValidNumber } from "libphonenumber-js"
3
-
4
-
5
- export const Route = "/api/rb/auth/sign-in"
6
-
7
- export const requestSchema = z.object({
8
- email_or_phone: z
9
- .string()
10
- .nonempty("Email or phone number is required")
11
- .default("")
12
- .refine(
13
- (value) => {
14
- const isEmail = z.string().email().safeParse(value).success
15
- const isPhone = isValidNumber(value)
16
- return isEmail || isPhone
17
- },
18
- "Please enter a valid email address or phone number"
19
- ),
20
- remember_me: z.boolean().default(true),
21
- })
22
-
23
- export type RequestPayload = z.infer<typeof requestSchema>
24
-
25
- export const responseSchema = z.object({
26
- success: z.boolean(),
27
- })
28
-
29
- export type ResponsePayload = z.infer<typeof responseSchema>
@@ -1,17 +0,0 @@
1
- import { Api, Ctx, ApiHandler } from "@rpcbase/api"
2
-
3
- import * as SignOut from "./index"
4
-
5
-
6
- const handleSignOut = async(_: SignOut.RequestPayload, ctx: Ctx): Promise<SignOut.ResponsePayload> => {
7
- // Destroy the session
8
- await new Promise<void>((resolve) => ctx.req.session.destroy(() => resolve()))
9
-
10
- return {
11
- success: true
12
- }
13
- }
14
-
15
- export default (api: Api) => {
16
- api.post(SignOut.Route, handleSignOut as ApiHandler)
17
- }
@@ -1,15 +0,0 @@
1
- import { z } from "zod"
2
-
3
-
4
- export const Route = "/api/rb/auth/sign-out"
5
-
6
- // No request payload needed for signout
7
- export const requestSchema = z.object({})
8
-
9
- export type RequestPayload = z.infer<typeof requestSchema>;
10
-
11
- export const responseSchema = z.object({
12
- success: z.boolean()
13
- })
14
-
15
- export type ResponsePayload = z.infer<typeof responseSchema>;
@@ -1,48 +0,0 @@
1
- import crypto from "crypto"
2
-
3
- import isEmail from "validator/lib/isEmail"
4
- import {Api, loadModel, Ctx, ApiHandler} from "@rpcbase/api"
5
- import { hashPassword } from "@rpcbase/server"
6
-
7
- import * as SignUp from "./index"
8
-
9
-
10
- const signUp = async(payload: SignUp.RequestPayload, ctx: Ctx): Promise<SignUp.ResponsePayload> => {
11
- const User = await loadModel("User", ctx)
12
-
13
- const {email_or_phone, password} = SignUp.requestSchema.parse(payload)
14
-
15
- const is_email = isEmail(email_or_phone)
16
- const query = is_email ? { email: email_or_phone } : { phone: email_or_phone }
17
-
18
- const existingUser = await User.findOne(query)
19
-
20
- if (existingUser) {
21
- console.log("user with email or phone already exists", email_or_phone)
22
- // For security, we don't want to reveal if an email/phone is registered.
23
- // But for this implementation, we'll make it simple.
24
- return { success: false }
25
- }
26
-
27
- const salt = crypto.randomBytes(16).toString("hex")
28
- const derivedKey = await hashPassword(password, salt)
29
- const hashedPassword = `${salt}:${derivedKey.toString("hex")}`
30
-
31
- const user = new User({
32
- ...query,
33
- password: hashedPassword,
34
- })
35
- await user.save()
36
-
37
- console.log("created new user", user._id.toString())
38
-
39
- // Note: This implementation does not automatically sign the user in.
40
- // A full implementation would likely create a session for the new user,
41
- // but tenant assignment logic for new users is not clear at this point.
42
-
43
- return {success: true}
44
- }
45
-
46
- export default (api: Api) => {
47
- api.post(SignUp.Route, signUp as ApiHandler)
48
- }
@@ -1,34 +0,0 @@
1
- import { z } from "zod"
2
- import { isValidNumber } from "libphonenumber-js"
3
-
4
-
5
- export const Route = "/api/rb/auth/sign-up"
6
-
7
- export const requestSchema = z
8
- .object({
9
- email_or_phone: z
10
- .string()
11
- .nonempty("Email or phone number is required")
12
- .refine(
13
- (value) => {
14
- const isEmail = z.string().email().safeParse(value).success
15
- const isPhone = isValidNumber(value)
16
- return isEmail || isPhone
17
- },
18
- "Please enter a valid email address or phone number"
19
- ),
20
- password: z.string().min(8, { message: "Password must be at least 8 characters long." }),
21
- password_confirmation: z.string().nonempty({ message: "Please confirm your password." }),
22
- })
23
- .refine((data) => data.password === data.password_confirmation, {
24
- message: "Passwords do not match.",
25
- path: ["password_confirmation"],
26
- })
27
-
28
- export type RequestPayload = z.infer<typeof requestSchema>
29
-
30
- export const responseSchema = z.object({
31
- success: z.boolean(),
32
- })
33
-
34
- export type ResponsePayload = z.infer<typeof responseSchema>
@@ -1,37 +0,0 @@
1
- import clsx from "clsx"
2
-
3
-
4
- export const AppleSignInButton = ({
5
- onPress,
6
- className,
7
- }: {
8
- onPress: () => void;
9
- className?: string;
10
- }) => {
11
-
12
- return (
13
- <button
14
- onClick={onPress}
15
- className={clsx(`
16
- w-full
17
- bg-black text-white hover:bg-gray-800
18
- flex items-center justify-center
19
- px-6 py-2
20
- rounded-lg
21
- font-medium
22
- transition duration-150 ease-in-out
23
- focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black
24
- `, className)}
25
- >
26
- <svg
27
- className="w-5 h-5 mr-3"
28
- xmlns="http://www.w3.org/2000/svg"
29
- viewBox="0 0 24 24"
30
- fill="white"
31
- >
32
- <path d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.539 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701" />
33
- </svg>
34
- <span>Continue with Apple</span>
35
- </button>
36
- )
37
- }
@@ -1,55 +0,0 @@
1
- import * as React from "react"
2
- import {Link, useLocation } from "@rpcbase/router"
3
-
4
-
5
- const LINKS_REDIRECTION_MAP = {
6
- "/auth/sign-in": {
7
- "title": "Sign Up",
8
- "location": "/auth/sign-up"
9
- },
10
- "/auth/sign-up": {
11
- "title": "Sign In",
12
- "location": "/auth/sign-in"
13
- },
14
- "/auth/forgot-password": {
15
- "title": "Sign In",
16
- "location": "/auth/sign-in"
17
- },
18
- "/auth/logout-success": {
19
- "title": "Sign In",
20
- "location": "/auth/sign-in"
21
- }
22
- }
23
-
24
- type Pathname = keyof typeof LINKS_REDIRECTION_MAP
25
-
26
- export const AuthLayout = ({
27
- sidePanel = null,
28
- children,
29
- }: {
30
- sidePanel: React.ReactElement | null
31
- children: React.ReactNode
32
- }) => {
33
- const location = useLocation()
34
-
35
- const linkTitle = LINKS_REDIRECTION_MAP[location.pathname as Pathname]?.title
36
- const linkLocation = LINKS_REDIRECTION_MAP[location.pathname as Pathname]?.location
37
-
38
- return (
39
- <div className="container relative hidden h-dvh flex-col items-center justify-center md:grid md:w-full lg:max-w-none lg:grid-cols-2 lg:px-0">
40
- {/* Top-right redirection link */}
41
- <Link
42
- className="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground h-9 px-4 py-2 absolute right-4 top-4 md:right-8 md:top-8"
43
- to={linkLocation}
44
- >
45
- {linkTitle}
46
- </Link>
47
- <div className="relative hidden h-full flex-col bg-muted p-10 text-white dark:border-r lg:flex">
48
- {sidePanel}
49
- </div>
50
- <div className="mx-auto flex w-full flex-col justify-center gap-6 /*sm:w-[350px]*/">
51
- {children}
52
- </div>
53
- </div>
54
- )
55
- }
@@ -1,33 +0,0 @@
1
- import {useFormContext} from "@rpcbase/form"
2
-
3
-
4
- export const EmailOrPhoneInput = ({
5
- id,
6
- className,
7
- placeholder,
8
- }: {
9
- id: string
10
- className?: string
11
- placeholder?: string
12
- }) => {
13
- const {register, formState} = useFormContext()
14
-
15
- const error = formState.errors.email_or_phone
16
-
17
- // console.log("ERRR", errors)
18
-
19
- return (
20
- <>
21
- <input
22
- id={id}
23
- type="text"
24
- required
25
- autoComplete="on"
26
- className={className}
27
- placeholder={placeholder}
28
- {...register("email_or_phone")}
29
- />
30
- {error && <p className="mt-1 -mb-2 text-sm/6 text-red-500">{error.message}</p>}
31
- </>
32
- )
33
- }
@@ -1,28 +0,0 @@
1
- import {ComponentType} from "react"
2
- import {useFormContext} from "@rpcbase/form"
3
-
4
-
5
- export const RememberMeCheckbox = ({
6
- label,
7
- as: Component = "input"
8
- }: {
9
- label: string,
10
- as?: ComponentType<any> | string
11
- }) => {
12
- const {register} = useFormContext()
13
-
14
- return (
15
- <>
16
- <Component
17
- id="remember_me"
18
- {...register("remember_me")}
19
- />
20
- <label
21
- htmlFor={"remember_me"}
22
- className="pl-2 block text-sm/6 text-gray-900"
23
- >
24
- {label}
25
- </label>
26
- </>
27
- )
28
- }
@@ -1,42 +0,0 @@
1
- import {ReactNode, useEffect} from "react"
2
- import { useForm, FormProvider, zodResolver } from "@rpcbase/form"
3
-
4
- import {requestSchema, RequestPayload} from "../../api/sign-in"
5
-
6
-
7
- export const SignInForm = ({
8
- children,
9
- className
10
- }: {
11
- children: ReactNode,
12
- className?: string
13
- }) => {
14
-
15
- const methods = useForm<RequestPayload>({
16
- defaultValues: {
17
- email_or_phone: "",
18
- remember_me: true,
19
- },
20
- resolver: zodResolver(requestSchema)
21
- })
22
-
23
- const onSubmit = async(data: RequestPayload, event) => {
24
- console.log("SUBMIT SIGNIN", data)
25
- }
26
-
27
- useEffect(() => {
28
- console.log(methods.formState.errors)
29
- }, [methods.formState.errors])
30
-
31
- useEffect(() => {
32
- // console.log("FOR5M", methods.formState.values)
33
- }, [methods.formState.values])
34
-
35
- return (
36
- <FormProvider {...methods}>
37
- <form method="post" noValidate className={className} onSubmit={methods.handleSubmit(onSubmit)}>
38
- {children}
39
- </form>
40
- </FormProvider>
41
- )
42
- }
@@ -1,43 +0,0 @@
1
- import {ReactNode, useEffect} from "react"
2
- import { useForm, FormProvider, zodResolver } from "@rpcbase/form"
3
-
4
- import {requestSchema, RequestPayload} from "../../api/sign-up"
5
-
6
-
7
- export const SignUpForm = ({
8
- children,
9
- className
10
- }: {
11
- children: ReactNode,
12
- className?: string
13
- }) => {
14
-
15
- const methods = useForm<RequestPayload>({
16
- defaultValues: {
17
- email_or_phone: "",
18
- password: "",
19
- password_confirmation: "",
20
- },
21
- resolver: zodResolver(requestSchema)
22
- })
23
-
24
- const onSubmit = async(data: RequestPayload, event) => {
25
- console.log("SUBMIT SIGNUp", data)
26
- }
27
-
28
- useEffect(() => {
29
- console.log(methods.formState.errors)
30
- }, [methods.formState.errors])
31
-
32
- useEffect(() => {
33
- // console.log("FOR5M", methods.formState.values)
34
- }, [methods.formState.values])
35
-
36
- return (
37
- <FormProvider {...methods}>
38
- <form method="post" noValidate className={className} onSubmit={methods.handleSubmit(onSubmit)}>
39
- {children}
40
- </form>
41
- </FormProvider>
42
- )
43
- }
@@ -1,6 +0,0 @@
1
- export * from "./AuthLayout"
2
- export * from "./AppleSignInButton"
3
- export * from "./EmailOrPhoneInput"
4
- export * from "./SignInForm"
5
- export * from "./SignUpForm"
6
- export * from "./RememberMeCheckbox"
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./components"