@rpcbase/auth 0.44.0 → 0.45.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 (38) hide show
  1. package/dist/api/me/handler.d.ts +5 -0
  2. package/dist/api/me/handler.d.ts.map +1 -0
  3. package/dist/api/me/index.d.ts +16 -0
  4. package/dist/api/me/index.d.ts.map +1 -0
  5. package/dist/api/sign-in/handler.d.ts +2 -1
  6. package/dist/api/sign-in/handler.d.ts.map +1 -1
  7. package/dist/api/sign-in/index.d.ts +4 -0
  8. package/dist/api/sign-in/index.d.ts.map +1 -1
  9. package/dist/api/sign-out/handler.d.ts.map +1 -1
  10. package/dist/api/sign-up/handler.d.ts +2 -1
  11. package/dist/api/sign-up/handler.d.ts.map +1 -1
  12. package/dist/api/sign-up/index.d.ts +4 -0
  13. package/dist/api/sign-up/index.d.ts.map +1 -1
  14. package/dist/components/PasswordInput/index.d.ts +10 -0
  15. package/dist/components/PasswordInput/index.d.ts.map +1 -0
  16. package/dist/components/SignInForm/index.d.ts.map +1 -1
  17. package/dist/components/SignUpForm/index.d.ts.map +1 -1
  18. package/dist/components/index.d.ts +1 -0
  19. package/dist/components/index.d.ts.map +1 -1
  20. package/dist/handler-BSoyBLZM.js +50 -0
  21. package/dist/handler-Ba3pgtfZ.js +57 -0
  22. package/dist/{handler-42q87FS8.js → handler-CNHucHrj.js} +4 -1
  23. package/dist/handler-rZR_dx7n.js +71 -0
  24. package/dist/{index-Nc4R1TKZ.js → index-Cq04nmsE.js} +7 -3
  25. package/dist/{index-oIC-DH2m.js → index-r56vqjph.js} +6 -2
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +87 -6
  29. package/dist/middleware-BiMXO6Dq.js +21 -0
  30. package/dist/middleware.d.ts +6 -0
  31. package/dist/middleware.d.ts.map +1 -0
  32. package/dist/routes.js +1 -1
  33. package/dist/{schemas-7XFc7XYG.js → schemas-KL7REOdt.js} +1 -0
  34. package/dist/types.d.ts +7 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/package.json +1 -1
  37. package/dist/handler-BD2C82Z3.js +0 -17
  38. package/dist/handler-C7htSfmB.js +0 -32
@@ -0,0 +1,5 @@
1
+ import { Api } from '../../../../api/src';
2
+ import { AuthSessionUser } from '../../types';
3
+ declare const _default: (api: Api<AuthSessionUser>) => void;
4
+ export default _default;
5
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/me/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAA8B,MAAM,cAAc,CAAA;AAE9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;yBAkDlC,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAGC"}
@@ -0,0 +1,16 @@
1
+ import { z } from '../../../../vite/node_modules/zod';
2
+ export declare const Route = "/api/rb/auth/me";
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
+ id: z.ZodOptional<z.ZodString>;
7
+ email: z.ZodOptional<z.ZodString>;
8
+ phone: z.ZodOptional<z.ZodString>;
9
+ name: z.ZodOptional<z.ZodString>;
10
+ tenants: z.ZodDefault<z.ZodArray<z.ZodString>>;
11
+ current_tenant_id: z.ZodOptional<z.ZodString>;
12
+ signed_in_tenants: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
13
+ error: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strip>;
15
+ export type ResponsePayload = z.infer<typeof responseSchema>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/me/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,KAAK,oBAAoB,CAAA;AAEtC,eAAO,MAAM,aAAa,gCAAe,CAAA;AACzC,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAE1D,eAAO,MAAM,cAAc;;;;;;;;;iBASzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { Api } from '../../../../api/src';
2
- declare const _default: (api: Api) => void;
2
+ import { AuthSessionUser } from '../../types';
3
+ declare const _default: (api: Api<AuthSessionUser>) => void;
3
4
  export default _default;
4
5
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-in/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAiC,MAAM,cAAc,CAAA;yBA+ChD,KAAK,GAAG;AAAxB,wBAEC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-in/handler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAA8B,MAAM,cAAc,CAAA;AAG9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;yBAgElC,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
@@ -2,11 +2,15 @@ import { z } from '../../../../vite/node_modules/zod';
2
2
  export declare const Route = "/api/rb/auth/sign-in";
3
3
  export declare const requestSchema: z.ZodObject<{
4
4
  email_or_phone: z.ZodDefault<z.ZodString>;
5
+ password: z.ZodString;
5
6
  remember_me: z.ZodDefault<z.ZodBoolean>;
6
7
  }, z.core.$strip>;
7
8
  export type RequestPayload = z.infer<typeof requestSchema>;
8
9
  export declare const responseSchema: z.ZodObject<{
9
10
  success: z.ZodBoolean;
11
+ error: z.ZodOptional<z.ZodString>;
12
+ user_id: z.ZodOptional<z.ZodString>;
13
+ tenant_id: z.ZodOptional<z.ZodString>;
10
14
  }, z.core.$strip>;
11
15
  export type ResponsePayload = z.infer<typeof responseSchema>;
12
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../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;;;;iBAexB,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAE1D,eAAO,MAAM,cAAc;;;;;iBAKzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-out/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAmB,MAAM,cAAc,CAAA;yBAcnC,KAAK,GAAG;AAAxB,wBAEC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-out/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAO,MAAM,cAAc,CAAA;yBAkBvB,KAAK,GAAG;AAAxB,wBAEC"}
@@ -1,4 +1,5 @@
1
1
  import { Api } from '../../../../api/src';
2
- declare const _default: (api: Api) => void;
2
+ import { AuthSessionUser } from '../../types';
3
+ declare const _default: (api: Api<AuthSessionUser>) => void;
3
4
  export default _default;
4
5
  //# sourceMappingURL=handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-up/handler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,GAAG,EAA6B,MAAM,cAAc,CAAA;yBA0C5C,KAAK,GAAG;AAAxB,wBAEC"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/sign-up/handler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAA8B,MAAM,cAAc,CAAA;AAG9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;yBAwFlC,KAAK,GAAG,CAAC,eAAe,CAAC;AAAzC,wBAEC"}
@@ -4,10 +4,14 @@ export declare const requestSchema: z.ZodObject<{
4
4
  email_or_phone: z.ZodString;
5
5
  password: z.ZodString;
6
6
  password_confirmation: z.ZodString;
7
+ remember_me: z.ZodDefault<z.ZodBoolean>;
7
8
  }, z.core.$strip>;
8
9
  export type RequestPayload = z.infer<typeof requestSchema>;
9
10
  export declare const responseSchema: z.ZodObject<{
10
11
  success: z.ZodBoolean;
12
+ error: z.ZodOptional<z.ZodString>;
13
+ user_id: z.ZodOptional<z.ZodString>;
14
+ tenant_id: z.ZodOptional<z.ZodString>;
11
15
  }, z.core.$strip>;
12
16
  export type ResponsePayload = z.infer<typeof responseSchema>;
13
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../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;;;;;iBAoBtB,CAAA;AAEJ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAE1D,eAAO,MAAM,cAAc;;;;;iBAKzB,CAAA;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
@@ -0,0 +1,10 @@
1
+ type PasswordInputProps = {
2
+ id: string;
3
+ name?: string;
4
+ className?: string;
5
+ placeholder?: string;
6
+ autoComplete?: string;
7
+ };
8
+ export declare const PasswordInput: ({ id, name, className, placeholder, autoComplete, }: PasswordInputProps) => import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/PasswordInput/index.tsx"],"names":[],"mappings":"AAGA,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,qDAM3B,kBAAkB,4CA0BpB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../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,4CA6CA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SignUpForm/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAsB,MAAM,OAAO,CAAA;AAWpD,eAAO,MAAM,UAAU,GAAI,yBAGxB;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,4CAyEA,CAAA"}
@@ -4,4 +4,5 @@ export * from './EmailOrPhoneInput';
4
4
  export * from './SignInForm';
5
5
  export * from './SignUpForm';
6
6
  export * from './RememberMeCheckbox';
7
+ export * from './PasswordInput';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../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;AACpC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,50 @@
1
+ import crypto from "crypto";
2
+ import { i as isEmail } from "./isEmail-IG0hXiQk.js";
3
+ import { loadModel } from "@rpcbase/api";
4
+ import { hashPassword } from "@rpcbase/server";
5
+ import { R as Route, r as requestSchema } from "./index-r56vqjph.js";
6
+ const signIn = async (payload, ctx) => {
7
+ const User = await loadModel("User", ctx);
8
+ const parsed = requestSchema.safeParse(payload);
9
+ if (!parsed.success) {
10
+ ctx.res.status(400);
11
+ return { success: false, error: "invalid_payload" };
12
+ }
13
+ const { email_or_phone, password } = parsed.data;
14
+ const query = isEmail(email_or_phone) ? { email: email_or_phone } : { phone: email_or_phone };
15
+ const user = await User.findOne(query, { password: 1, tenants: 1 });
16
+ if (!user?.password) {
17
+ ctx.res.status(401);
18
+ return { success: false, error: "invalid_credentials" };
19
+ }
20
+ const [salt, hashedPassword] = String(user.password).split(":");
21
+ if (!salt || !hashedPassword) {
22
+ ctx.res.status(500);
23
+ return { success: false, error: "invalid_password_format" };
24
+ }
25
+ const derivedKey = await hashPassword(password, salt);
26
+ const passwordMatches = crypto.timingSafeEqual(Buffer.from(hashedPassword, "hex"), derivedKey);
27
+ if (!passwordMatches) {
28
+ ctx.res.status(401);
29
+ return { success: false, error: "invalid_credentials" };
30
+ }
31
+ const tenantId = user.tenants?.[0]?.toString?.() || "00000000";
32
+ const signedInTenants = (user.tenants || []).map((t) => t.toString?.() || String(t)) || [tenantId];
33
+ if (!ctx.req.session) {
34
+ ctx.res.status(500);
35
+ return { success: false, error: "session_unavailable" };
36
+ }
37
+ ctx.req.session.user = {
38
+ id: user._id.toString(),
39
+ current_tenant_id: tenantId,
40
+ signed_in_tenants: signedInTenants.length ? signedInTenants : [tenantId],
41
+ is_entry_gate_authorized: true
42
+ };
43
+ return { success: true, user_id: user._id.toString(), tenant_id: tenantId };
44
+ };
45
+ const handler = (api) => {
46
+ api.post(Route, signIn);
47
+ };
48
+ export {
49
+ handler as default
50
+ };
@@ -0,0 +1,57 @@
1
+ import { loadModel } from "@rpcbase/api";
2
+ import { r as restrictSessionMiddleware } from "./middleware-BiMXO6Dq.js";
3
+ import { o as object, s as string, a as array } from "./schemas-KL7REOdt.js";
4
+ const Route = "/api/rb/auth/me";
5
+ object({});
6
+ object({
7
+ id: string().optional(),
8
+ email: string().email().optional(),
9
+ phone: string().optional(),
10
+ name: string().optional(),
11
+ tenants: array(string()).default([]),
12
+ current_tenant_id: string().optional(),
13
+ signed_in_tenants: array(string()).default([]).optional(),
14
+ error: string().optional()
15
+ });
16
+ const me = async (_payload, ctx) => {
17
+ const sessionUser = ctx.req.session?.user;
18
+ if (!sessionUser?.id) {
19
+ ctx.res.status(401);
20
+ return {
21
+ id: "",
22
+ current_tenant_id: "",
23
+ signed_in_tenants: [],
24
+ tenants: [],
25
+ error: "not_authenticated"
26
+ };
27
+ }
28
+ const User = await loadModel("User", ctx);
29
+ const user = await User.findById(sessionUser.id);
30
+ if (!user) {
31
+ ctx.res.status(404);
32
+ return {
33
+ id: "",
34
+ current_tenant_id: "",
35
+ signed_in_tenants: [],
36
+ tenants: [],
37
+ error: "user_not_found"
38
+ };
39
+ }
40
+ const tenantId = sessionUser.current_tenant_id || user.tenants?.[0]?.toString?.() || "00000000";
41
+ return {
42
+ id: user._id.toString(),
43
+ email: user.email,
44
+ phone: user.phone,
45
+ name: user.name,
46
+ tenants: (user.tenants || []).map((t) => t.toString?.() || String(t)),
47
+ current_tenant_id: tenantId,
48
+ signed_in_tenants: sessionUser.signed_in_tenants || []
49
+ };
50
+ };
51
+ const handler = (api) => {
52
+ api.use(Route, restrictSessionMiddleware);
53
+ api.get(Route, me);
54
+ };
55
+ export {
56
+ handler as default
57
+ };
@@ -1,10 +1,13 @@
1
- import { o as object, b as boolean } from "./schemas-7XFc7XYG.js";
1
+ import { o as object, b as boolean } from "./schemas-KL7REOdt.js";
2
2
  const Route = "/api/rb/auth/sign-out";
3
3
  object({});
4
4
  object({
5
5
  success: boolean()
6
6
  });
7
7
  const handleSignOut = async (_, ctx) => {
8
+ if (!ctx.req.session) {
9
+ return { success: true };
10
+ }
8
11
  await new Promise((resolve) => ctx.req.session.destroy(() => resolve()));
9
12
  return {
10
13
  success: true
@@ -0,0 +1,71 @@
1
+ import crypto from "crypto";
2
+ import { i as isEmail } from "./isEmail-IG0hXiQk.js";
3
+ import { loadModel } from "@rpcbase/api";
4
+ import { hashPassword, sendEmail } from "@rpcbase/server";
5
+ import { R as Route, r as requestSchema } from "./index-Cq04nmsE.js";
6
+ const signUp = async (payload, ctx) => {
7
+ const User = await loadModel("User", ctx);
8
+ const Tenant = await loadModel("Tenant", ctx);
9
+ const parsed = requestSchema.safeParse(payload);
10
+ if (!parsed.success) {
11
+ ctx.res.status(400);
12
+ return { success: false, error: "invalid_payload" };
13
+ }
14
+ const { email_or_phone, password, remember_me: _remember_me } = parsed.data;
15
+ const is_email = isEmail(email_or_phone);
16
+ const query = is_email ? { email: email_or_phone } : { phone: email_or_phone };
17
+ const existingUser = await User.findOne(query);
18
+ if (existingUser) {
19
+ console.log("user with email or phone already exists", email_or_phone);
20
+ ctx.res.status(409);
21
+ return { success: false, error: "user_exists" };
22
+ }
23
+ const salt = crypto.randomBytes(16).toString("hex");
24
+ const derivedKey = await hashPassword(password, salt);
25
+ const hashedPassword = `${salt}:${derivedKey.toString("hex")}`;
26
+ const tenantId = crypto.randomUUID();
27
+ const user = new User({
28
+ ...query,
29
+ password: hashedPassword,
30
+ tenants: [tenantId]
31
+ });
32
+ await user.save();
33
+ if (is_email) {
34
+ try {
35
+ await sendEmail({
36
+ to: email_or_phone,
37
+ subject: "Verify your email",
38
+ html: "<p>Welcome to rpcbase!</p><p>We created your account. Use this email to sign in and finish verification.</p>",
39
+ text: "Welcome to rpcbase! We created your account. Use this email to sign in and finish verification."
40
+ });
41
+ } catch (err) {
42
+ console.warn("failed to send sign-up email", err);
43
+ }
44
+ }
45
+ try {
46
+ await Tenant.create({
47
+ tenant_id: tenantId,
48
+ name: query.email || query.phone
49
+ });
50
+ } catch (err) {
51
+ console.warn("failed to create tenant for user", err);
52
+ }
53
+ console.log("created new user", user._id.toString());
54
+ if (!ctx.req.session) {
55
+ ctx.res.status(500);
56
+ return { success: false, error: "session_unavailable" };
57
+ }
58
+ ctx.req.session.user = {
59
+ id: user._id.toString(),
60
+ current_tenant_id: tenantId,
61
+ signed_in_tenants: [tenantId],
62
+ is_entry_gate_authorized: true
63
+ };
64
+ return { success: true, user_id: user._id.toString(), tenant_id: tenantId };
65
+ };
66
+ const handler = (api) => {
67
+ api.post(Route, signUp);
68
+ };
69
+ export {
70
+ handler as default
71
+ };
@@ -1,5 +1,5 @@
1
1
  import { i as isValidNumber } from "./isValidNumber-6pMDGLRn.js";
2
- import { o as object, s as string, b as boolean } from "./schemas-7XFc7XYG.js";
2
+ import { o as object, b as boolean, s as string } from "./schemas-KL7REOdt.js";
3
3
  const Route = "/api/rb/auth/sign-up";
4
4
  const requestSchema = object({
5
5
  email_or_phone: string().nonempty("Email or phone number is required").refine(
@@ -11,13 +11,17 @@ const requestSchema = object({
11
11
  "Please enter a valid email address or phone number"
12
12
  ),
13
13
  password: string().min(8, { message: "Password must be at least 8 characters long." }),
14
- password_confirmation: string().nonempty({ message: "Please confirm your password." })
14
+ password_confirmation: string().nonempty({ message: "Please confirm your password." }),
15
+ remember_me: boolean().default(true)
15
16
  }).refine((data) => data.password === data.password_confirmation, {
16
17
  message: "Passwords do not match.",
17
18
  path: ["password_confirmation"]
18
19
  });
19
20
  object({
20
- success: boolean()
21
+ success: boolean(),
22
+ error: string().optional(),
23
+ user_id: string().optional(),
24
+ tenant_id: string().optional()
21
25
  });
22
26
  export {
23
27
  Route as R,
@@ -1,5 +1,5 @@
1
1
  import { i as isValidNumber } from "./isValidNumber-6pMDGLRn.js";
2
- import { o as object, b as boolean, s as string } from "./schemas-7XFc7XYG.js";
2
+ import { o as object, b as boolean, s as string } from "./schemas-KL7REOdt.js";
3
3
  const Route = "/api/rb/auth/sign-in";
4
4
  const requestSchema = object({
5
5
  email_or_phone: string().nonempty("Email or phone number is required").default("").refine(
@@ -10,10 +10,14 @@ const requestSchema = object({
10
10
  },
11
11
  "Please enter a valid email address or phone number"
12
12
  ),
13
+ password: string().min(1, { message: "Password is required" }),
13
14
  remember_me: boolean().default(true)
14
15
  });
15
16
  object({
16
- success: boolean()
17
+ success: boolean(),
18
+ error: string().optional(),
19
+ user_id: string().optional(),
20
+ tenant_id: string().optional()
17
21
  });
18
22
  export {
19
23
  Route as R,
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from './components';
2
+ export * from './middleware';
3
+ export * from './types';
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -2,9 +2,10 @@ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { useLocation, Link } from "@rpcbase/router";
3
3
  import clsx from "clsx";
4
4
  import { useFormContext, useForm, zodResolver, FormProvider } from "@rpcbase/form";
5
- import { useEffect } from "react";
6
- import { r as requestSchema } from "./index-oIC-DH2m.js";
7
- import { r as requestSchema$1 } from "./index-Nc4R1TKZ.js";
5
+ import { useEffect, useState } from "react";
6
+ import { r as requestSchema } from "./index-r56vqjph.js";
7
+ import { r as requestSchema$1 } from "./index-Cq04nmsE.js";
8
+ import { b, a, r } from "./middleware-BiMXO6Dq.js";
8
9
  const LINKS_REDIRECTION_MAP = {
9
10
  "/auth/sign-in": {
10
11
  "title": "Sign Up",
@@ -113,12 +114,29 @@ const SignInForm = ({
113
114
  const methods = useForm({
114
115
  defaultValues: {
115
116
  email_or_phone: "",
117
+ password: "",
116
118
  remember_me: true
117
119
  },
118
120
  resolver: zodResolver(requestSchema)
119
121
  });
120
122
  const onSubmit = async (data) => {
121
123
  console.log("SUBMIT SIGNIN", data);
124
+ try {
125
+ const res = await fetch("/api/rb/auth/sign-in", {
126
+ method: "POST",
127
+ headers: {
128
+ "Content-Type": "application/json"
129
+ },
130
+ body: JSON.stringify(data)
131
+ });
132
+ const json = await res.json();
133
+ console.log("SIGN IN RESPONSE", json);
134
+ if (!res.ok) {
135
+ console.error("Sign-in failed", json);
136
+ }
137
+ } catch (err) {
138
+ console.error("Sign-in request error", err);
139
+ }
122
140
  };
123
141
  useEffect(() => {
124
142
  console.log(methods.formState.errors);
@@ -129,21 +147,55 @@ const SignUpForm = ({
129
147
  children,
130
148
  className
131
149
  }) => {
150
+ const [serverMessage, setServerMessage] = useState(null);
132
151
  const methods = useForm({
133
152
  defaultValues: {
134
153
  email_or_phone: "",
135
154
  password: "",
136
- password_confirmation: ""
155
+ password_confirmation: "",
156
+ remember_me: true
137
157
  },
138
158
  resolver: zodResolver(requestSchema$1)
139
159
  });
140
160
  const onSubmit = async (data) => {
161
+ setServerMessage(null);
162
+ methods.clearErrors("root");
141
163
  console.log("SUBMIT SIGNUp", data);
164
+ try {
165
+ const res = await fetch("/api/rb/auth/sign-up", {
166
+ method: "POST",
167
+ headers: {
168
+ "Content-Type": "application/json"
169
+ },
170
+ body: JSON.stringify(data)
171
+ });
172
+ const json = await res.json();
173
+ console.log("SIGN UP RESPONSE", json);
174
+ if (!res.ok) {
175
+ console.error("Sign-up failed", json);
176
+ const message = json.error === "user_exists" ? "An account already exists with this email or phone." : "Sign-up failed. Please try again.";
177
+ methods.setError("root", { type: "server", message });
178
+ return;
179
+ }
180
+ if (!json.success) {
181
+ methods.setError("root", { type: "server", message: "Sign-up failed. Please try again." });
182
+ return;
183
+ }
184
+ setServerMessage("Account created. Check your inbox to verify your email.");
185
+ methods.reset();
186
+ } catch (err) {
187
+ console.error("Sign-up request error", err);
188
+ methods.setError("root", { type: "server", message: "Network error. Please try again." });
189
+ }
142
190
  };
143
191
  useEffect(() => {
144
192
  console.log(methods.formState.errors);
145
193
  }, [methods.formState.errors]);
146
- return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsx("form", { method: "post", noValidate: true, className, onSubmit: methods.handleSubmit(onSubmit), children }) });
194
+ return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsxs("form", { method: "post", noValidate: true, className, onSubmit: methods.handleSubmit(onSubmit), children: [
195
+ children,
196
+ methods.formState.errors.root?.message && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-red-600", role: "alert", children: methods.formState.errors.root.message }),
197
+ serverMessage && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-green-700", role: "status", children: serverMessage })
198
+ ] }) });
147
199
  };
148
200
  const RememberMeCheckbox = ({
149
201
  label,
@@ -168,11 +220,40 @@ const RememberMeCheckbox = ({
168
220
  )
169
221
  ] });
170
222
  };
223
+ const PasswordInput = ({
224
+ id,
225
+ name = "password",
226
+ className,
227
+ placeholder,
228
+ autoComplete = "current-password"
229
+ }) => {
230
+ const { register, formState } = useFormContext();
231
+ const fieldError = formState.errors[name];
232
+ const errorMessage = typeof fieldError === "string" ? fieldError : typeof fieldError?.message === "string" ? fieldError.message : void 0;
233
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
234
+ /* @__PURE__ */ jsx(
235
+ "input",
236
+ {
237
+ id,
238
+ type: "password",
239
+ autoComplete,
240
+ className,
241
+ placeholder,
242
+ ...register(name)
243
+ }
244
+ ),
245
+ errorMessage ? /* @__PURE__ */ jsx("p", { className: "mt-1 -mb-2 text-sm/6 text-red-500", children: errorMessage }) : null
246
+ ] });
247
+ };
171
248
  export {
172
249
  AppleSignInButton,
173
250
  AuthLayout,
174
251
  EmailOrPhoneInput,
252
+ PasswordInput,
175
253
  RememberMeCheckbox,
176
254
  SignInForm,
177
- SignUpForm
255
+ SignUpForm,
256
+ b as redirectAuthMiddleware,
257
+ a as requireSession,
258
+ r as restrictSessionMiddleware
178
259
  };
@@ -0,0 +1,21 @@
1
+ const isAuthenticated = (req) => {
2
+ return Boolean(req.session?.user?.id);
3
+ };
4
+ const restrictSessionMiddleware = (req, res, next) => {
5
+ if (isAuthenticated(req)) {
6
+ return next();
7
+ }
8
+ res.status(401).json({ error: "unauthorized" });
9
+ };
10
+ const requireSession = restrictSessionMiddleware;
11
+ const redirectAuthMiddleware = (req, res, next) => {
12
+ if (req.path.startsWith("/app") && !isAuthenticated(req)) {
13
+ return res.redirect("/auth/sign-in");
14
+ }
15
+ next();
16
+ };
17
+ export {
18
+ requireSession as a,
19
+ redirectAuthMiddleware as b,
20
+ restrictSessionMiddleware as r
21
+ };
@@ -0,0 +1,6 @@
1
+ import { Middleware } from '../../api/src';
2
+ import { AuthSessionUser } from './types';
3
+ export declare const restrictSessionMiddleware: Middleware<AuthSessionUser>;
4
+ export declare const requireSession: Middleware<AuthSessionUser>;
5
+ export declare const redirectAuthMiddleware: Middleware<AuthSessionUser>;
6
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAO9C,eAAO,MAAM,yBAAyB,EAAE,UAAU,CAAC,eAAe,CAMjE,CAAA;AAED,eAAO,MAAM,cAAc,6BAA4B,CAAA;AAEvD,eAAO,MAAM,sBAAsB,EAAE,UAAU,CAAC,eAAe,CAM9D,CAAA"}
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const routes = Object.entries({
2
- .../* @__PURE__ */ Object.assign({ "./api/sign-in/handler.ts": () => import("./handler-BD2C82Z3.js"), "./api/sign-out/handler.ts": () => import("./handler-42q87FS8.js"), "./api/sign-up/handler.ts": () => import("./handler-C7htSfmB.js") })
2
+ .../* @__PURE__ */ Object.assign({ "./api/me/handler.ts": () => import("./handler-Ba3pgtfZ.js"), "./api/sign-in/handler.ts": () => import("./handler-BSoyBLZM.js"), "./api/sign-out/handler.ts": () => import("./handler-CNHucHrj.js"), "./api/sign-up/handler.ts": () => import("./handler-rZR_dx7n.js") })
3
3
  }).reduce((acc, [path, mod]) => {
4
4
  acc[path.replace("./api/", "@rpcbase/auth/api/")] = mod;
5
5
  return acc;
@@ -2975,6 +2975,7 @@ function superRefine(fn) {
2975
2975
  return _superRefine(fn);
2976
2976
  }
2977
2977
  export {
2978
+ array as a,
2978
2979
  boolean as b,
2979
2980
  object as o,
2980
2981
  string as s
@@ -0,0 +1,7 @@
1
+ export type AuthSessionUser = {
2
+ id: string;
3
+ current_tenant_id: string;
4
+ signed_in_tenants: string[];
5
+ is_entry_gate_authorized: boolean;
6
+ };
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,iBAAiB,EAAE,MAAM,CAAA;IACzB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,wBAAwB,EAAE,OAAO,CAAA;CAClC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/auth",
3
- "version": "0.44.0",
3
+ "version": "0.45.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -1,17 +0,0 @@
1
- import { i as isEmail } from "./isEmail-IG0hXiQk.js";
2
- import { R as Route, r as requestSchema } from "./index-oIC-DH2m.js";
3
- const signIn = async (payload, ctx) => {
4
- const { email_or_phone } = requestSchema.parse(payload);
5
- if (isEmail(email_or_phone)) {
6
- console.log("is valid email");
7
- } else {
8
- console.log("is not valid email");
9
- }
10
- return { success: true };
11
- };
12
- const handler = (api) => {
13
- api.post(Route, signIn);
14
- };
15
- export {
16
- handler as default
17
- };
@@ -1,32 +0,0 @@
1
- import crypto from "crypto";
2
- import { i as isEmail } from "./isEmail-IG0hXiQk.js";
3
- import { loadModel } from "@rpcbase/api";
4
- import { hashPassword } from "@rpcbase/server";
5
- import { R as Route, r as requestSchema } from "./index-Nc4R1TKZ.js";
6
- const signUp = async (payload, ctx) => {
7
- const User = await loadModel("User", ctx);
8
- const { email_or_phone, password } = 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
- return { success: false };
15
- }
16
- const salt = crypto.randomBytes(16).toString("hex");
17
- const derivedKey = await hashPassword(password, salt);
18
- const hashedPassword = `${salt}:${derivedKey.toString("hex")}`;
19
- const user = new User({
20
- ...query,
21
- password: hashedPassword
22
- });
23
- await user.save();
24
- console.log("created new user", user._id.toString());
25
- return { success: true };
26
- };
27
- const handler = (api) => {
28
- api.post(Route, signUp);
29
- };
30
- export {
31
- handler as default
32
- };