navojit-auth 1.0.0 → 1.0.2

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.d.mts CHANGED
@@ -1,100 +1,55 @@
1
- import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify';
1
+ import { FastifyInstance } from 'fastify';
2
2
 
3
+ /**
4
+ * -----------------------------------------------------------
5
+ * 1. TYPES & INTERFACES
6
+ * -----------------------------------------------------------
7
+ */
3
8
  interface User {
4
9
  id: string;
5
10
  email: string;
6
- passwordHash: string;
7
- orgId: string;
8
- role: string;
11
+ password?: string;
12
+ role?: string;
13
+ orgId?: string;
14
+ [key: string]: any;
9
15
  }
10
16
  interface AuthAdapter {
11
- getUserByEmail(email: string, orgId: string): Promise<User | null>;
12
- createUser(data: Omit<User, "id">): Promise<User>;
17
+ findUserByEmail(email: string): Promise<User | null>;
18
+ createUser(data: Partial<User>): Promise<User>;
13
19
  }
14
- interface AuthProvider {
15
- id: string;
16
- name: string;
17
- handle(body: any): Promise<User | null>;
18
- handleAction?(action: string, body: any): Promise<any>;
19
- getRedirectUrl?(): string;
20
- }
21
- interface NavojitAuthConfig {
20
+ interface AuthConfig {
22
21
  adapter: AuthAdapter;
23
- jwtSecret: string;
24
- providers: AuthProvider[];
25
- }
26
- declare module "@fastify/jwt" {
27
- interface FastifyJWT {
28
- payload: {
29
- sub: string;
30
- role: string;
31
- orgId: string;
32
- };
33
- user: {
34
- sub: string;
35
- role: string;
36
- orgId: string;
37
- };
38
- }
39
- }
40
-
41
- /**
42
- * 1. Credentials Provider
43
- * Standard Email/Password authentication using Argon2 hashing.
44
- */
45
- declare class CredentialsProvider implements AuthProvider {
46
- private adapter;
47
- id: string;
48
- name: string;
49
- constructor(adapter: AuthAdapter);
50
- handle(body: any): Promise<User | null>;
22
+ secret: string;
23
+ sessionExpiry?: string;
24
+ multiTenant?: boolean;
51
25
  }
52
26
  /**
53
- * 2. Google Social Provider
54
- * Handles One-Click login/registration using Google OAuth2.
27
+ * -----------------------------------------------------------
28
+ * 2. DATABASE ADAPTERS (SQL & NoSQL)
29
+ * -----------------------------------------------------------
55
30
  */
56
- declare class GoogleProvider implements AuthProvider {
57
- private adapter;
58
- id: string;
59
- name: string;
60
- private client;
61
- constructor(adapter: AuthAdapter);
62
- handle(body: any): Promise<User | null>;
63
- }
64
- /**
65
- * 3. OTP Provider
66
- * Passwordless login with 6-digit codes sent via Real Email (Resend).
67
- */
68
- declare class OTPProvider implements AuthProvider {
69
- private adapter;
70
- id: string;
71
- name: string;
72
- private otpStore;
73
- constructor(adapter: AuthAdapter);
74
- handleAction(action: string, body: any): Promise<any>;
75
- handle(body: any): Promise<User | null>;
76
- }
77
-
78
31
  declare class DrizzleAdapter implements AuthAdapter {
79
- getUserByEmail(email: string, orgId: string): Promise<User | null>;
80
- createUser(data: Omit<User, "id">): Promise<User>;
32
+ private db;
33
+ private schema;
34
+ constructor(db: any, schema: any);
35
+ findUserByEmail(email: string): Promise<User | null>;
36
+ createUser(data: Partial<User>): Promise<User>;
37
+ }
38
+ declare class MongooseAdapter implements AuthAdapter {
39
+ private userModel;
40
+ constructor(userModel: any);
41
+ findUserByEmail(email: string): Promise<User | null>;
42
+ createUser(data: Partial<User>): Promise<User>;
81
43
  }
82
-
83
- declare const authorize: (allowedRoles: string[]) => (request: FastifyRequest, reply: FastifyReply) => Promise<undefined>;
84
-
85
44
  /**
86
- * NavojitAuth Engine
87
- * Attach this class to your Fastify instance to enable multi-tenant auth.
45
+ * -----------------------------------------------------------
46
+ * 3. THE CORE ENGINE (NavojitAuth)
47
+ * -----------------------------------------------------------
88
48
  */
89
49
  declare class NavojitAuth {
90
50
  private config;
91
- constructor(config: NavojitAuthConfig);
92
- /**
93
- * Automatically registers all auth routes (login, register, refresh, logout, etc.)
94
- * @param server Fastify Instance
95
- * @param prefix URL prefix for auth routes (default: /auth)
96
- */
97
- attach(server: FastifyInstance, prefix?: string): void;
51
+ constructor(config: AuthConfig);
52
+ attach(server: FastifyInstance, prefix?: string): Promise<void>;
98
53
  }
99
54
 
100
- export { type AuthAdapter, type AuthProvider, CredentialsProvider, DrizzleAdapter, GoogleProvider, NavojitAuth, type NavojitAuthConfig, OTPProvider, type User, authorize };
55
+ export { type AuthAdapter, type AuthConfig, DrizzleAdapter, MongooseAdapter, NavojitAuth, type User };
package/dist/index.d.ts CHANGED
@@ -1,100 +1,55 @@
1
- import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify';
1
+ import { FastifyInstance } from 'fastify';
2
2
 
3
+ /**
4
+ * -----------------------------------------------------------
5
+ * 1. TYPES & INTERFACES
6
+ * -----------------------------------------------------------
7
+ */
3
8
  interface User {
4
9
  id: string;
5
10
  email: string;
6
- passwordHash: string;
7
- orgId: string;
8
- role: string;
11
+ password?: string;
12
+ role?: string;
13
+ orgId?: string;
14
+ [key: string]: any;
9
15
  }
10
16
  interface AuthAdapter {
11
- getUserByEmail(email: string, orgId: string): Promise<User | null>;
12
- createUser(data: Omit<User, "id">): Promise<User>;
17
+ findUserByEmail(email: string): Promise<User | null>;
18
+ createUser(data: Partial<User>): Promise<User>;
13
19
  }
14
- interface AuthProvider {
15
- id: string;
16
- name: string;
17
- handle(body: any): Promise<User | null>;
18
- handleAction?(action: string, body: any): Promise<any>;
19
- getRedirectUrl?(): string;
20
- }
21
- interface NavojitAuthConfig {
20
+ interface AuthConfig {
22
21
  adapter: AuthAdapter;
23
- jwtSecret: string;
24
- providers: AuthProvider[];
25
- }
26
- declare module "@fastify/jwt" {
27
- interface FastifyJWT {
28
- payload: {
29
- sub: string;
30
- role: string;
31
- orgId: string;
32
- };
33
- user: {
34
- sub: string;
35
- role: string;
36
- orgId: string;
37
- };
38
- }
39
- }
40
-
41
- /**
42
- * 1. Credentials Provider
43
- * Standard Email/Password authentication using Argon2 hashing.
44
- */
45
- declare class CredentialsProvider implements AuthProvider {
46
- private adapter;
47
- id: string;
48
- name: string;
49
- constructor(adapter: AuthAdapter);
50
- handle(body: any): Promise<User | null>;
22
+ secret: string;
23
+ sessionExpiry?: string;
24
+ multiTenant?: boolean;
51
25
  }
52
26
  /**
53
- * 2. Google Social Provider
54
- * Handles One-Click login/registration using Google OAuth2.
27
+ * -----------------------------------------------------------
28
+ * 2. DATABASE ADAPTERS (SQL & NoSQL)
29
+ * -----------------------------------------------------------
55
30
  */
56
- declare class GoogleProvider implements AuthProvider {
57
- private adapter;
58
- id: string;
59
- name: string;
60
- private client;
61
- constructor(adapter: AuthAdapter);
62
- handle(body: any): Promise<User | null>;
63
- }
64
- /**
65
- * 3. OTP Provider
66
- * Passwordless login with 6-digit codes sent via Real Email (Resend).
67
- */
68
- declare class OTPProvider implements AuthProvider {
69
- private adapter;
70
- id: string;
71
- name: string;
72
- private otpStore;
73
- constructor(adapter: AuthAdapter);
74
- handleAction(action: string, body: any): Promise<any>;
75
- handle(body: any): Promise<User | null>;
76
- }
77
-
78
31
  declare class DrizzleAdapter implements AuthAdapter {
79
- getUserByEmail(email: string, orgId: string): Promise<User | null>;
80
- createUser(data: Omit<User, "id">): Promise<User>;
32
+ private db;
33
+ private schema;
34
+ constructor(db: any, schema: any);
35
+ findUserByEmail(email: string): Promise<User | null>;
36
+ createUser(data: Partial<User>): Promise<User>;
37
+ }
38
+ declare class MongooseAdapter implements AuthAdapter {
39
+ private userModel;
40
+ constructor(userModel: any);
41
+ findUserByEmail(email: string): Promise<User | null>;
42
+ createUser(data: Partial<User>): Promise<User>;
81
43
  }
82
-
83
- declare const authorize: (allowedRoles: string[]) => (request: FastifyRequest, reply: FastifyReply) => Promise<undefined>;
84
-
85
44
  /**
86
- * NavojitAuth Engine
87
- * Attach this class to your Fastify instance to enable multi-tenant auth.
45
+ * -----------------------------------------------------------
46
+ * 3. THE CORE ENGINE (NavojitAuth)
47
+ * -----------------------------------------------------------
88
48
  */
89
49
  declare class NavojitAuth {
90
50
  private config;
91
- constructor(config: NavojitAuthConfig);
92
- /**
93
- * Automatically registers all auth routes (login, register, refresh, logout, etc.)
94
- * @param server Fastify Instance
95
- * @param prefix URL prefix for auth routes (default: /auth)
96
- */
97
- attach(server: FastifyInstance, prefix?: string): void;
51
+ constructor(config: AuthConfig);
52
+ attach(server: FastifyInstance, prefix?: string): Promise<void>;
98
53
  }
99
54
 
100
- export { type AuthAdapter, type AuthProvider, CredentialsProvider, DrizzleAdapter, GoogleProvider, NavojitAuth, type NavojitAuthConfig, OTPProvider, type User, authorize };
55
+ export { type AuthAdapter, type AuthConfig, DrizzleAdapter, MongooseAdapter, NavojitAuth, type User };
package/dist/index.js CHANGED
@@ -30,293 +30,107 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- CredentialsProvider: () => CredentialsProvider,
34
33
  DrizzleAdapter: () => DrizzleAdapter,
35
- GoogleProvider: () => GoogleProvider,
36
- NavojitAuth: () => NavojitAuth,
37
- OTPProvider: () => OTPProvider,
38
- authorize: () => authorize
34
+ MongooseAdapter: () => MongooseAdapter,
35
+ NavojitAuth: () => NavojitAuth
39
36
  });
40
37
  module.exports = __toCommonJS(index_exports);
41
-
42
- // src/db/index.ts
43
- var import_postgres_js = require("drizzle-orm/postgres-js");
44
- var import_postgres = __toESM(require("postgres"));
45
-
46
- // src/db/schema.ts
47
- var schema_exports = {};
48
- __export(schema_exports, {
49
- organizations: () => organizations,
50
- refreshTokens: () => refreshTokens,
51
- roleEnum: () => roleEnum,
52
- users: () => users
53
- });
54
- var import_pg_core = require("drizzle-orm/pg-core");
55
- var roleEnum = (0, import_pg_core.pgEnum)("role", ["owner", "admin", "member", "guest"]);
56
- var organizations = (0, import_pg_core.pgTable)("organizations", {
57
- id: (0, import_pg_core.uuid)("id").primaryKey().defaultRandom(),
58
- name: (0, import_pg_core.varchar)("name", { length: 255 }).notNull(),
59
- slug: (0, import_pg_core.varchar)("slug", { length: 255 }).unique().notNull(),
60
- createdAt: (0, import_pg_core.timestamp)("created_at").defaultNow().notNull()
61
- });
62
- var users = (0, import_pg_core.pgTable)("users", {
63
- id: (0, import_pg_core.uuid)("id").primaryKey().defaultRandom(),
64
- orgId: (0, import_pg_core.uuid)("org_id").references(() => organizations.id).notNull(),
65
- email: (0, import_pg_core.varchar)("email", { length: 255 }).unique().notNull(),
66
- passwordHash: (0, import_pg_core.varchar)("password_hash", { length: 255 }).notNull(),
67
- role: roleEnum("role").default("member").notNull(),
68
- createdAt: (0, import_pg_core.timestamp)("created_at").defaultNow().notNull()
69
- });
70
- var refreshTokens = (0, import_pg_core.pgTable)("refresh_tokens", {
71
- id: (0, import_pg_core.uuid)("id").primaryKey().defaultRandom(),
72
- userId: (0, import_pg_core.uuid)("user_id").references(() => users.id).notNull(),
73
- token: (0, import_pg_core.varchar)("token", { length: 500 }).unique().notNull(),
74
- revoked: (0, import_pg_core.boolean)("revoked").default(false).notNull(),
75
- expiresAt: (0, import_pg_core.timestamp)("expires_at").notNull()
76
- });
77
-
78
- // src/db/index.ts
79
- var dotenv = __toESM(require("dotenv"));
80
- dotenv.config();
81
- var client = (0, import_postgres.default)(process.env.DATABASE_URL, { max: 1 });
82
- var db = (0, import_postgres_js.drizzle)(client, { schema: schema_exports });
83
-
84
- // src/routes/auth.ts
85
- var import_drizzle_orm = require("drizzle-orm");
38
+ var import_jwt = __toESM(require("@fastify/jwt"));
86
39
  var import_argon2 = __toESM(require("argon2"));
87
- var import_zod = require("zod");
88
- var RegisterSchema = import_zod.z.object({
89
- email: import_zod.z.string().email(),
90
- password: import_zod.z.string().min(8),
91
- orgName: import_zod.z.string().min(2),
92
- role: import_zod.z.enum(["owner", "admin", "member", "guest"]).optional()
93
- });
94
- function createAuthRoutes(config2) {
95
- return async function authRoutes(server) {
96
- server.post("/register", async (request, reply) => {
97
- const result = RegisterSchema.safeParse(request.body);
98
- if (!result.success)
99
- return reply.code(400).send({ errors: result.error.format() });
100
- const { email, password, orgName, role } = result.data;
101
- try {
102
- let [org] = await db.select().from(organizations).where((0, import_drizzle_orm.eq)(organizations.name, orgName)).limit(1);
103
- if (!org) {
104
- [org] = await db.insert(organizations).values({
105
- name: orgName,
106
- slug: orgName.toLowerCase().replace(/\s/g, "-")
107
- }).returning();
108
- }
109
- const hash = await import_argon2.default.hash(password);
110
- const user = await config2.adapter.createUser({
111
- email,
112
- passwordHash: hash,
113
- orgId: org.id,
114
- role: role || "member"
115
- });
116
- return reply.send({ success: true, userId: user.id, orgId: org.id });
117
- } catch (err) {
118
- return reply.code(500).send({ error: "Registration failed", details: err.message });
119
- }
120
- });
121
- server.post("/login/:providerId", async (request, reply) => {
122
- const { providerId } = request.params;
123
- const provider = config2.providers.find((p) => p.id === providerId);
124
- if (!provider) return reply.code(400).send({ error: "Invalid Provider" });
125
- const user = await provider.handle(request.body);
126
- if (!user) return reply.code(401).send({ error: "Unauthorized" });
127
- const accessToken = server.jwt.sign(
128
- { sub: user.id, role: user.role, orgId: user.orgId },
129
- { expiresIn: "15m" }
130
- );
131
- const refreshToken = server.jwt.sign(
132
- { sub: user.id, role: user.role, orgId: user.orgId },
133
- { expiresIn: "7d" }
134
- );
135
- await db.insert(refreshTokens).values({
136
- userId: user.id,
137
- token: refreshToken,
138
- expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1e3)
139
- });
140
- return reply.send({
141
- success: true,
142
- access_token: accessToken,
143
- refresh_token: refreshToken
144
- });
145
- });
146
- server.post("/logout", async (request, reply) => {
147
- const { refresh_token } = request.body;
148
- if (refresh_token) {
149
- await db.update(refreshTokens).set({ revoked: true }).where((0, import_drizzle_orm.eq)(refreshTokens.token, refresh_token));
150
- }
151
- return reply.send({
152
- success: true,
153
- message: "Logged out from all devices"
154
- });
40
+ var DrizzleAdapter = class {
41
+ constructor(db, schema) {
42
+ this.db = db;
43
+ this.schema = schema;
44
+ }
45
+ db;
46
+ schema;
47
+ async findUserByEmail(email) {
48
+ const result = await this.db.query.users.findFirst({
49
+ where: (u, { eq }) => eq(u.email, email)
155
50
  });
156
- };
157
- }
158
-
159
- // src/core/types.ts
160
- var import_jwt = require("@fastify/jwt");
161
-
162
- // src/core/providers.ts
163
- var import_argon22 = __toESM(require("argon2"));
164
- var import_google_auth_library = require("google-auth-library");
165
- var import_resend = require("resend");
166
- var resend = new import_resend.Resend(process.env.RESEND_API_KEY);
167
- var CredentialsProvider = class {
168
- constructor(adapter) {
169
- this.adapter = adapter;
51
+ return result || null;
170
52
  }
171
- adapter;
172
- id = "credentials";
173
- name = "Email/Password";
174
- async handle(body) {
175
- const { email, password, orgId } = body;
176
- const user = await this.adapter.getUserByEmail(email, orgId);
177
- if (user && await import_argon22.default.verify(user.passwordHash, password)) {
178
- return user;
179
- }
180
- return null;
53
+ async createUser(data) {
54
+ const [user] = await this.db.insert(this.schema).values(data).returning();
55
+ return user;
181
56
  }
182
57
  };
183
- var GoogleProvider = class {
184
- constructor(adapter) {
185
- this.adapter = adapter;
58
+ var MongooseAdapter = class {
59
+ constructor(userModel) {
60
+ this.userModel = userModel;
186
61
  }
187
- adapter;
188
- id = "google";
189
- name = "Google";
190
- client = new import_google_auth_library.OAuth2Client(process.env.GOOGLE_CLIENT_ID);
191
- async handle(body) {
192
- const { idToken, orgId } = body;
193
- try {
194
- const ticket = await this.client.verifyIdToken({
195
- idToken,
196
- audience: process.env.GOOGLE_CLIENT_ID
197
- });
198
- const payload = ticket.getPayload();
199
- if (!payload || !payload.email) return null;
200
- let user = await this.adapter.getUserByEmail(payload.email, orgId);
201
- if (!user) {
202
- user = await this.adapter.createUser({
203
- email: payload.email,
204
- passwordHash: "SOCIAL_AUTH_EXTERNAL",
205
- // Placeholder for social users
206
- orgId,
207
- role: "member"
208
- });
209
- }
210
- return user;
211
- } catch (error) {
212
- console.error("[AUTH] Google Verification Failed:", error);
213
- return null;
214
- }
215
- }
216
- };
217
- var OTPProvider = class {
218
- constructor(adapter) {
219
- this.adapter = adapter;
220
- }
221
- adapter;
222
- id = "otp";
223
- name = "OTP";
224
- otpStore = /* @__PURE__ */ new Map();
225
- async handleAction(action, body) {
226
- if (action === "send") {
227
- const otp = Math.floor(1e5 + Math.random() * 9e5).toString();
228
- this.otpStore.set(body.email, { otp, expires: Date.now() + 3e5 });
229
- if (process.env.RESEND_API_KEY) {
230
- try {
231
- await resend.emails.send({
232
- from: "Navojit Auth <no-reply@navojit.io>",
233
- // Apne verified domain se replace karein
234
- to: body.email,
235
- subject: "Your Security Code",
236
- html: `<div style="font-family: sans-serif; padding: 20px;">
237
- <h2>Verification Code</h2>
238
- <p>Use the following code to sign in to your account:</p>
239
- <h1 style="color: #4F46E5;">${otp}</h1>
240
- <p>This code expires in 5 minutes.</p>
241
- </div>`
242
- });
243
- } catch (error) {
244
- console.error("[AUTH] Email Delivery Failed:", error);
245
- }
246
- }
247
- console.log(`[AUTH] OTP for ${body.email}: ${otp}`);
248
- return { success: true, message: "OTP sent successfully" };
249
- }
250
- return { success: false, message: "Invalid action" };
251
- }
252
- async handle(body) {
253
- const { email, otp, orgId } = body;
254
- const record = this.otpStore.get(email);
255
- if (record && record.otp === otp && record.expires > Date.now()) {
256
- this.otpStore.delete(email);
257
- return await this.adapter.getUserByEmail(email, orgId);
258
- }
259
- return null;
260
- }
261
- };
262
-
263
- // src/adapters/drizzle.ts
264
- var import_drizzle_orm2 = require("drizzle-orm");
265
- var DrizzleAdapter = class {
266
- async getUserByEmail(email, orgId) {
267
- const result = await db.select().from(users).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(users.email, email), (0, import_drizzle_orm2.eq)(users.orgId, orgId))).limit(1);
268
- return result[0] || null;
62
+ userModel;
63
+ async findUserByEmail(email) {
64
+ return await this.userModel.findOne({ email }).lean();
269
65
  }
270
66
  async createUser(data) {
271
- const [newUser] = await db.insert(users).values({
272
- email: data.email,
273
- passwordHash: data.passwordHash,
274
- orgId: data.orgId,
275
- role: data.role
276
- }).returning();
277
- return newUser;
67
+ const user = await this.userModel.create(data);
68
+ return user.toObject();
278
69
  }
279
70
  };
280
-
281
- // src/middleware/rbac.ts
282
- var authorize = (allowedRoles) => {
283
- return async (request, reply) => {
284
- try {
285
- await request.jwtVerify();
286
- const user = request.user;
287
- if (!allowedRoles.includes(user.role)) {
288
- return reply.code(403).send({
289
- error: "Forbidden",
290
- message: `Your role (${user.role}) does not have permission to access this resource.`
291
- });
292
- }
293
- } catch (err) {
294
- return reply.code(401).send({ error: "Unauthorized", message: "Invalid or expired token" });
295
- }
296
- };
297
- };
298
-
299
- // src/index.ts
300
71
  var NavojitAuth = class {
301
- constructor(config2) {
302
- this.config = config2;
303
- }
304
72
  config;
305
- /**
306
- * Automatically registers all auth routes (login, register, refresh, logout, etc.)
307
- * @param server Fastify Instance
308
- * @param prefix URL prefix for auth routes (default: /auth)
309
- */
310
- attach(server, prefix = "/auth") {
311
- server.register(createAuthRoutes(this.config), { prefix });
73
+ constructor(config) {
74
+ this.config = {
75
+ sessionExpiry: "1d",
76
+ multiTenant: false,
77
+ ...config
78
+ };
79
+ }
80
+ async attach(server, prefix = "/auth") {
81
+ if (!server.hasDecorator("jwt")) {
82
+ server.register(import_jwt.default, { secret: this.config.secret });
83
+ }
84
+ server.post(`${prefix}/register`, async (request, reply) => {
85
+ const { email, password, ...extra } = request.body;
86
+ try {
87
+ const existing = await this.config.adapter.findUserByEmail(email);
88
+ if (existing)
89
+ return reply.code(400).send({ error: "User already exists" });
90
+ const hashedPassword = await import_argon2.default.hash(password);
91
+ const user = await this.config.adapter.createUser({
92
+ email,
93
+ password: hashedPassword,
94
+ ...extra
95
+ });
96
+ return {
97
+ success: true,
98
+ userId: user.id,
99
+ message: "Registration successful"
100
+ };
101
+ } catch (err) {
102
+ return reply.code(500).send({ error: err.message });
103
+ }
104
+ });
105
+ server.post(`${prefix}/login`, async (request, reply) => {
106
+ const { email, password } = request.body;
107
+ try {
108
+ const user = await this.config.adapter.findUserByEmail(email);
109
+ if (!user || !user.password) {
110
+ return reply.code(401).send({ error: "Invalid credentials" });
111
+ }
112
+ const isValid = await import_argon2.default.verify(user.password, password);
113
+ if (!isValid)
114
+ return reply.code(401).send({ error: "Invalid credentials" });
115
+ const payload = {
116
+ sub: user.id,
117
+ email: user.email,
118
+ orgId: user.orgId,
119
+ role: user.role
120
+ };
121
+ const token = server.jwt.sign(payload, {
122
+ expiresIn: this.config.sessionExpiry
123
+ });
124
+ return { success: true, token };
125
+ } catch (err) {
126
+ return reply.code(500).send({ error: err.message });
127
+ }
128
+ });
312
129
  }
313
130
  };
314
131
  // Annotate the CommonJS export names for ESM import in node:
315
132
  0 && (module.exports = {
316
- CredentialsProvider,
317
133
  DrizzleAdapter,
318
- GoogleProvider,
319
- NavojitAuth,
320
- OTPProvider,
321
- authorize
134
+ MongooseAdapter,
135
+ NavojitAuth
322
136
  });
package/dist/index.mjs CHANGED
@@ -1,293 +1,99 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/db/index.ts
8
- import { drizzle } from "drizzle-orm/postgres-js";
9
- import postgres from "postgres";
10
-
11
- // src/db/schema.ts
12
- var schema_exports = {};
13
- __export(schema_exports, {
14
- organizations: () => organizations,
15
- refreshTokens: () => refreshTokens,
16
- roleEnum: () => roleEnum,
17
- users: () => users
18
- });
19
- import {
20
- pgTable,
21
- uuid,
22
- varchar,
23
- timestamp,
24
- pgEnum,
25
- boolean
26
- } from "drizzle-orm/pg-core";
27
- var roleEnum = pgEnum("role", ["owner", "admin", "member", "guest"]);
28
- var organizations = pgTable("organizations", {
29
- id: uuid("id").primaryKey().defaultRandom(),
30
- name: varchar("name", { length: 255 }).notNull(),
31
- slug: varchar("slug", { length: 255 }).unique().notNull(),
32
- createdAt: timestamp("created_at").defaultNow().notNull()
33
- });
34
- var users = pgTable("users", {
35
- id: uuid("id").primaryKey().defaultRandom(),
36
- orgId: uuid("org_id").references(() => organizations.id).notNull(),
37
- email: varchar("email", { length: 255 }).unique().notNull(),
38
- passwordHash: varchar("password_hash", { length: 255 }).notNull(),
39
- role: roleEnum("role").default("member").notNull(),
40
- createdAt: timestamp("created_at").defaultNow().notNull()
41
- });
42
- var refreshTokens = pgTable("refresh_tokens", {
43
- id: uuid("id").primaryKey().defaultRandom(),
44
- userId: uuid("user_id").references(() => users.id).notNull(),
45
- token: varchar("token", { length: 500 }).unique().notNull(),
46
- revoked: boolean("revoked").default(false).notNull(),
47
- expiresAt: timestamp("expires_at").notNull()
48
- });
49
-
50
- // src/db/index.ts
51
- import * as dotenv from "dotenv";
52
- dotenv.config();
53
- var client = postgres(process.env.DATABASE_URL, { max: 1 });
54
- var db = drizzle(client, { schema: schema_exports });
55
-
56
- // src/routes/auth.ts
57
- import { eq } from "drizzle-orm";
1
+ // src/index.ts
2
+ import jwt from "@fastify/jwt";
58
3
  import argon2 from "argon2";
59
- import { z } from "zod";
60
- var RegisterSchema = z.object({
61
- email: z.string().email(),
62
- password: z.string().min(8),
63
- orgName: z.string().min(2),
64
- role: z.enum(["owner", "admin", "member", "guest"]).optional()
65
- });
66
- function createAuthRoutes(config2) {
67
- return async function authRoutes(server) {
68
- server.post("/register", async (request, reply) => {
69
- const result = RegisterSchema.safeParse(request.body);
70
- if (!result.success)
71
- return reply.code(400).send({ errors: result.error.format() });
72
- const { email, password, orgName, role } = result.data;
73
- try {
74
- let [org] = await db.select().from(organizations).where(eq(organizations.name, orgName)).limit(1);
75
- if (!org) {
76
- [org] = await db.insert(organizations).values({
77
- name: orgName,
78
- slug: orgName.toLowerCase().replace(/\s/g, "-")
79
- }).returning();
80
- }
81
- const hash = await argon2.hash(password);
82
- const user = await config2.adapter.createUser({
83
- email,
84
- passwordHash: hash,
85
- orgId: org.id,
86
- role: role || "member"
87
- });
88
- return reply.send({ success: true, userId: user.id, orgId: org.id });
89
- } catch (err) {
90
- return reply.code(500).send({ error: "Registration failed", details: err.message });
91
- }
92
- });
93
- server.post("/login/:providerId", async (request, reply) => {
94
- const { providerId } = request.params;
95
- const provider = config2.providers.find((p) => p.id === providerId);
96
- if (!provider) return reply.code(400).send({ error: "Invalid Provider" });
97
- const user = await provider.handle(request.body);
98
- if (!user) return reply.code(401).send({ error: "Unauthorized" });
99
- const accessToken = server.jwt.sign(
100
- { sub: user.id, role: user.role, orgId: user.orgId },
101
- { expiresIn: "15m" }
102
- );
103
- const refreshToken = server.jwt.sign(
104
- { sub: user.id, role: user.role, orgId: user.orgId },
105
- { expiresIn: "7d" }
106
- );
107
- await db.insert(refreshTokens).values({
108
- userId: user.id,
109
- token: refreshToken,
110
- expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1e3)
111
- });
112
- return reply.send({
113
- success: true,
114
- access_token: accessToken,
115
- refresh_token: refreshToken
116
- });
117
- });
118
- server.post("/logout", async (request, reply) => {
119
- const { refresh_token } = request.body;
120
- if (refresh_token) {
121
- await db.update(refreshTokens).set({ revoked: true }).where(eq(refreshTokens.token, refresh_token));
122
- }
123
- return reply.send({
124
- success: true,
125
- message: "Logged out from all devices"
126
- });
127
- });
128
- };
129
- }
130
-
131
- // src/core/types.ts
132
- import "@fastify/jwt";
133
-
134
- // src/core/providers.ts
135
- import argon22 from "argon2";
136
- import { OAuth2Client } from "google-auth-library";
137
- import { Resend } from "resend";
138
- var resend = new Resend(process.env.RESEND_API_KEY);
139
- var CredentialsProvider = class {
140
- constructor(adapter) {
141
- this.adapter = adapter;
142
- }
143
- adapter;
144
- id = "credentials";
145
- name = "Email/Password";
146
- async handle(body) {
147
- const { email, password, orgId } = body;
148
- const user = await this.adapter.getUserByEmail(email, orgId);
149
- if (user && await argon22.verify(user.passwordHash, password)) {
150
- return user;
151
- }
152
- return null;
4
+ var DrizzleAdapter = class {
5
+ constructor(db, schema) {
6
+ this.db = db;
7
+ this.schema = schema;
153
8
  }
154
- };
155
- var GoogleProvider = class {
156
- constructor(adapter) {
157
- this.adapter = adapter;
9
+ db;
10
+ schema;
11
+ async findUserByEmail(email) {
12
+ const result = await this.db.query.users.findFirst({
13
+ where: (u, { eq }) => eq(u.email, email)
14
+ });
15
+ return result || null;
158
16
  }
159
- adapter;
160
- id = "google";
161
- name = "Google";
162
- client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);
163
- async handle(body) {
164
- const { idToken, orgId } = body;
165
- try {
166
- const ticket = await this.client.verifyIdToken({
167
- idToken,
168
- audience: process.env.GOOGLE_CLIENT_ID
169
- });
170
- const payload = ticket.getPayload();
171
- if (!payload || !payload.email) return null;
172
- let user = await this.adapter.getUserByEmail(payload.email, orgId);
173
- if (!user) {
174
- user = await this.adapter.createUser({
175
- email: payload.email,
176
- passwordHash: "SOCIAL_AUTH_EXTERNAL",
177
- // Placeholder for social users
178
- orgId,
179
- role: "member"
180
- });
181
- }
182
- return user;
183
- } catch (error) {
184
- console.error("[AUTH] Google Verification Failed:", error);
185
- return null;
186
- }
17
+ async createUser(data) {
18
+ const [user] = await this.db.insert(this.schema).values(data).returning();
19
+ return user;
187
20
  }
188
21
  };
189
- var OTPProvider = class {
190
- constructor(adapter) {
191
- this.adapter = adapter;
22
+ var MongooseAdapter = class {
23
+ constructor(userModel) {
24
+ this.userModel = userModel;
192
25
  }
193
- adapter;
194
- id = "otp";
195
- name = "OTP";
196
- otpStore = /* @__PURE__ */ new Map();
197
- async handleAction(action, body) {
198
- if (action === "send") {
199
- const otp = Math.floor(1e5 + Math.random() * 9e5).toString();
200
- this.otpStore.set(body.email, { otp, expires: Date.now() + 3e5 });
201
- if (process.env.RESEND_API_KEY) {
202
- try {
203
- await resend.emails.send({
204
- from: "Navojit Auth <no-reply@navojit.io>",
205
- // Apne verified domain se replace karein
206
- to: body.email,
207
- subject: "Your Security Code",
208
- html: `<div style="font-family: sans-serif; padding: 20px;">
209
- <h2>Verification Code</h2>
210
- <p>Use the following code to sign in to your account:</p>
211
- <h1 style="color: #4F46E5;">${otp}</h1>
212
- <p>This code expires in 5 minutes.</p>
213
- </div>`
214
- });
215
- } catch (error) {
216
- console.error("[AUTH] Email Delivery Failed:", error);
217
- }
218
- }
219
- console.log(`[AUTH] OTP for ${body.email}: ${otp}`);
220
- return { success: true, message: "OTP sent successfully" };
221
- }
222
- return { success: false, message: "Invalid action" };
223
- }
224
- async handle(body) {
225
- const { email, otp, orgId } = body;
226
- const record = this.otpStore.get(email);
227
- if (record && record.otp === otp && record.expires > Date.now()) {
228
- this.otpStore.delete(email);
229
- return await this.adapter.getUserByEmail(email, orgId);
230
- }
231
- return null;
232
- }
233
- };
234
-
235
- // src/adapters/drizzle.ts
236
- import { eq as eq2, and } from "drizzle-orm";
237
- var DrizzleAdapter = class {
238
- async getUserByEmail(email, orgId) {
239
- const result = await db.select().from(users).where(and(eq2(users.email, email), eq2(users.orgId, orgId))).limit(1);
240
- return result[0] || null;
26
+ userModel;
27
+ async findUserByEmail(email) {
28
+ return await this.userModel.findOne({ email }).lean();
241
29
  }
242
30
  async createUser(data) {
243
- const [newUser] = await db.insert(users).values({
244
- email: data.email,
245
- passwordHash: data.passwordHash,
246
- orgId: data.orgId,
247
- role: data.role
248
- }).returning();
249
- return newUser;
31
+ const user = await this.userModel.create(data);
32
+ return user.toObject();
250
33
  }
251
34
  };
252
-
253
- // src/middleware/rbac.ts
254
- var authorize = (allowedRoles) => {
255
- return async (request, reply) => {
256
- try {
257
- await request.jwtVerify();
258
- const user = request.user;
259
- if (!allowedRoles.includes(user.role)) {
260
- return reply.code(403).send({
261
- error: "Forbidden",
262
- message: `Your role (${user.role}) does not have permission to access this resource.`
263
- });
264
- }
265
- } catch (err) {
266
- return reply.code(401).send({ error: "Unauthorized", message: "Invalid or expired token" });
267
- }
268
- };
269
- };
270
-
271
- // src/index.ts
272
35
  var NavojitAuth = class {
273
- constructor(config2) {
274
- this.config = config2;
275
- }
276
36
  config;
277
- /**
278
- * Automatically registers all auth routes (login, register, refresh, logout, etc.)
279
- * @param server Fastify Instance
280
- * @param prefix URL prefix for auth routes (default: /auth)
281
- */
282
- attach(server, prefix = "/auth") {
283
- server.register(createAuthRoutes(this.config), { prefix });
37
+ constructor(config) {
38
+ this.config = {
39
+ sessionExpiry: "1d",
40
+ multiTenant: false,
41
+ ...config
42
+ };
43
+ }
44
+ async attach(server, prefix = "/auth") {
45
+ if (!server.hasDecorator("jwt")) {
46
+ server.register(jwt, { secret: this.config.secret });
47
+ }
48
+ server.post(`${prefix}/register`, async (request, reply) => {
49
+ const { email, password, ...extra } = request.body;
50
+ try {
51
+ const existing = await this.config.adapter.findUserByEmail(email);
52
+ if (existing)
53
+ return reply.code(400).send({ error: "User already exists" });
54
+ const hashedPassword = await argon2.hash(password);
55
+ const user = await this.config.adapter.createUser({
56
+ email,
57
+ password: hashedPassword,
58
+ ...extra
59
+ });
60
+ return {
61
+ success: true,
62
+ userId: user.id,
63
+ message: "Registration successful"
64
+ };
65
+ } catch (err) {
66
+ return reply.code(500).send({ error: err.message });
67
+ }
68
+ });
69
+ server.post(`${prefix}/login`, async (request, reply) => {
70
+ const { email, password } = request.body;
71
+ try {
72
+ const user = await this.config.adapter.findUserByEmail(email);
73
+ if (!user || !user.password) {
74
+ return reply.code(401).send({ error: "Invalid credentials" });
75
+ }
76
+ const isValid = await argon2.verify(user.password, password);
77
+ if (!isValid)
78
+ return reply.code(401).send({ error: "Invalid credentials" });
79
+ const payload = {
80
+ sub: user.id,
81
+ email: user.email,
82
+ orgId: user.orgId,
83
+ role: user.role
84
+ };
85
+ const token = server.jwt.sign(payload, {
86
+ expiresIn: this.config.sessionExpiry
87
+ });
88
+ return { success: true, token };
89
+ } catch (err) {
90
+ return reply.code(500).send({ error: err.message });
91
+ }
92
+ });
284
93
  }
285
94
  };
286
95
  export {
287
- CredentialsProvider,
288
96
  DrizzleAdapter,
289
- GoogleProvider,
290
- NavojitAuth,
291
- OTPProvider,
292
- authorize
97
+ MongooseAdapter,
98
+ NavojitAuth
293
99
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "navojit-auth",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Blazing fast, multi-tenant global authentication engine for Fastify & Drizzle ORM.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",