@ministerjs/auth 2.0.1 → 3.0.1

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/nestjs.mjs CHANGED
@@ -13,6 +13,165 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
13
13
  // src/nestjs/token.ts
14
14
  var AUTH_DRIVER = Symbol("AUTH_DRIVER");
15
15
 
16
+ // src/nestjs/stores.ts
17
+ var InMemoryLockoutStore = class {
18
+ constructor(windowMs) {
19
+ this.windowMs = windowMs;
20
+ }
21
+ entries = /* @__PURE__ */ new Map();
22
+ async recordFailure(key) {
23
+ const now = Date.now();
24
+ const entry = this.entries.get(key);
25
+ if (!entry || now - entry.firstFailure > this.windowMs) {
26
+ this.entries.set(key, { count: 1, firstFailure: now });
27
+ } else {
28
+ entry.count++;
29
+ }
30
+ }
31
+ async getFailures(key) {
32
+ const entry = this.entries.get(key);
33
+ if (!entry) return 0;
34
+ if (Date.now() - entry.firstFailure > this.windowMs) {
35
+ this.entries.delete(key);
36
+ return 0;
37
+ }
38
+ return entry.count;
39
+ }
40
+ async reset(key) {
41
+ this.entries.delete(key);
42
+ }
43
+ };
44
+ var InMemoryRefreshTokenStore = class {
45
+ tokens = /* @__PURE__ */ new Map();
46
+ userJtis = /* @__PURE__ */ new Map();
47
+ async save(jti, userId, expiresAt) {
48
+ this.tokens.set(jti, { userId, expiresAt });
49
+ let jtis = this.userJtis.get(userId);
50
+ if (!jtis) {
51
+ jtis = /* @__PURE__ */ new Set();
52
+ this.userJtis.set(userId, jtis);
53
+ }
54
+ jtis.add(jti);
55
+ }
56
+ async find(jti) {
57
+ const entry = this.tokens.get(jti);
58
+ if (!entry) return null;
59
+ if (entry.expiresAt.getTime() < Date.now()) {
60
+ this.tokens.delete(jti);
61
+ return null;
62
+ }
63
+ return entry;
64
+ }
65
+ async revoke(jti) {
66
+ const entry = this.tokens.get(jti);
67
+ if (entry) {
68
+ this.userJtis.get(entry.userId)?.delete(jti);
69
+ }
70
+ this.tokens.delete(jti);
71
+ }
72
+ async revokeAll(userId) {
73
+ const jtis = this.userJtis.get(userId);
74
+ if (jtis) {
75
+ for (const jti of jtis) {
76
+ this.tokens.delete(jti);
77
+ }
78
+ this.userJtis.delete(userId);
79
+ }
80
+ }
81
+ };
82
+
83
+ // src/nestjs/rbac.ts
84
+ import { SetMetadata } from "@nestjs/common";
85
+ var ROLES_KEY = "ministerjs:roles";
86
+ var Roles = (...roles) => SetMetadata(ROLES_KEY, roles);
87
+
88
+ // src/nestjs/guards/JwtAuthGuard.ts
89
+ import {
90
+ Injectable,
91
+ UnauthorizedException
92
+ } from "@nestjs/common";
93
+ import { verify } from "jsonwebtoken";
94
+ var JwtAuthGuard = class {
95
+ jwtSecret;
96
+ cookieName;
97
+ csrfEnabled;
98
+ constructor(options) {
99
+ this.jwtSecret = options.jwtSecret;
100
+ this.cookieName = options.cookieName ?? "auth_token";
101
+ this.csrfEnabled = options.csrfEnabled ?? false;
102
+ }
103
+ canActivate(context) {
104
+ const request = context.switchToHttp().getRequest();
105
+ const token = this.extractToken(request);
106
+ if (!token) {
107
+ throw new UnauthorizedException("No token provided");
108
+ }
109
+ let payload;
110
+ try {
111
+ payload = verify(token, this.jwtSecret, {
112
+ algorithms: ["HS256"]
113
+ });
114
+ } catch {
115
+ throw new UnauthorizedException("Invalid token");
116
+ }
117
+ if (this.csrfEnabled) {
118
+ this.validateCsrf(request);
119
+ }
120
+ request.user = {
121
+ id: payload.sub,
122
+ roles: payload.roles ?? []
123
+ };
124
+ return true;
125
+ }
126
+ extractToken(request) {
127
+ const fromCookie = request.cookies?.[this.cookieName];
128
+ if (fromCookie) return fromCookie;
129
+ const authHeader = request.headers.authorization;
130
+ if (authHeader?.startsWith("Bearer ")) return authHeader.slice(7);
131
+ return void 0;
132
+ }
133
+ validateCsrf(request) {
134
+ const headerToken = request.headers["x-csrf-token"];
135
+ const cookieToken = request.cookies?.["csrf_token"];
136
+ if (!headerToken || headerToken !== cookieToken) {
137
+ throw new UnauthorizedException("CSRF token mismatch");
138
+ }
139
+ }
140
+ };
141
+ JwtAuthGuard = __decorateClass([
142
+ Injectable()
143
+ ], JwtAuthGuard);
144
+
145
+ // src/nestjs/guards/RolesGuard.ts
146
+ import {
147
+ ForbiddenException,
148
+ Injectable as Injectable2
149
+ } from "@nestjs/common";
150
+ var RolesGuard = class {
151
+ constructor(reflector) {
152
+ this.reflector = reflector;
153
+ }
154
+ canActivate(context) {
155
+ const required = this.reflector.getAllAndOverride(ROLES_KEY, [
156
+ context.getHandler(),
157
+ context.getClass()
158
+ ]);
159
+ if (!required?.length) return true;
160
+ const request = context.switchToHttp().getRequest();
161
+ if (!request.user) {
162
+ throw new ForbiddenException("Not authenticated");
163
+ }
164
+ const hasRole = required.some((r) => request.user.roles.includes(r));
165
+ if (!hasRole) {
166
+ throw new ForbiddenException("Insufficient permissions");
167
+ }
168
+ return true;
169
+ }
170
+ };
171
+ RolesGuard = __decorateClass([
172
+ Injectable2()
173
+ ], RolesGuard);
174
+
16
175
  // src/nestjs/AuthController.ts
17
176
  import {
18
177
  Body,
@@ -22,7 +181,7 @@ import {
22
181
  Post,
23
182
  Req,
24
183
  Res,
25
- UnauthorizedException
184
+ UnauthorizedException as UnauthorizedException2
26
185
  } from "@nestjs/common";
27
186
  var AuthController = class {
28
187
  constructor(driver) {
@@ -35,7 +194,17 @@ var AuthController = class {
35
194
  async checkIn(request, response) {
36
195
  const user = await this.driver.checkIn(request, response);
37
196
  if (!user) {
38
- throw new UnauthorizedException("Not authenticated");
197
+ throw new UnauthorizedException2("Not authenticated");
198
+ }
199
+ return { message: "ok", data: user };
200
+ }
201
+ async refresh(request, response) {
202
+ if (!this.driver.refresh) {
203
+ throw new UnauthorizedException2("Refresh not supported");
204
+ }
205
+ const user = await this.driver.refresh(request, response);
206
+ if (!user) {
207
+ throw new UnauthorizedException2("Invalid refresh token");
39
208
  }
40
209
  return { message: "ok", data: user };
41
210
  }
@@ -57,6 +226,12 @@ __decorateClass([
57
226
  __decorateParam(0, Req()),
58
227
  __decorateParam(1, Res({ passthrough: true }))
59
228
  ], AuthController.prototype, "checkIn", 1);
229
+ __decorateClass([
230
+ Post("/refresh"),
231
+ HttpCode(200),
232
+ __decorateParam(0, Req()),
233
+ __decorateParam(1, Res({ passthrough: true }))
234
+ ], AuthController.prototype, "refresh", 1);
60
235
  __decorateClass([
61
236
  Post("/logout"),
62
237
  HttpCode(200),
@@ -94,6 +269,9 @@ var AuthModule = class {
94
269
  exports: [driverProvider]
95
270
  };
96
271
  }
272
+ static createGuard(options) {
273
+ return new JwtAuthGuard(options);
274
+ }
97
275
  static normalizeDriverProvider(driver) {
98
276
  if (typeof driver === "function") {
99
277
  return { provide: AUTH_DRIVER, useClass: driver };
@@ -119,12 +297,26 @@ AuthModule = __decorateClass([
119
297
  ], AuthModule);
120
298
 
121
299
  // src/nestjs/JwtPrismaCookieAuthDriver.ts
122
- import { UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
123
- import { sign, verify } from "jsonwebtoken";
300
+ import { randomBytes, randomUUID } from "crypto";
301
+ import { UnauthorizedException as UnauthorizedException3 } from "@nestjs/common";
302
+ import { sign, verify as verify2 } from "jsonwebtoken";
303
+ var DURATION_UNITS = {
304
+ s: 1e3,
305
+ m: 6e4,
306
+ h: 36e5,
307
+ d: 864e5
308
+ };
309
+ function parseDuration(value) {
310
+ const match = value.match(/^(\d+)\s*([smhd])$/);
311
+ if (!match) return 7 * 864e5;
312
+ return parseInt(match[1], 10) * DURATION_UNITS[match[2]];
313
+ }
314
+ var isProduction = process.env.NODE_ENV === "production";
124
315
  var defaultCookieOptions = {
125
316
  httpOnly: true,
126
317
  sameSite: "lax",
127
- path: "/"
318
+ path: "/",
319
+ secure: isProduction
128
320
  };
129
321
  var JwtPrismaCookieAuthDriver = class {
130
322
  prismaModel;
@@ -137,13 +329,23 @@ var JwtPrismaCookieAuthDriver = class {
137
329
  cookieOptions;
138
330
  comparePassword;
139
331
  transformUser;
332
+ csrf;
333
+ onAudit;
334
+ onRateLimitCheck;
335
+ lockoutStore;
336
+ lockoutMaxAttempts;
337
+ refreshTokenEnabled;
338
+ refreshTokenCookieName;
339
+ refreshTokenExpiresIn;
340
+ refreshTokenStore;
140
341
  constructor(options) {
141
- this.prismaModel = options.prisma[options.modelName];
142
- if (!this.prismaModel) {
342
+ const model = options.prisma[options.modelName];
343
+ if (!model) {
143
344
  throw new Error(
144
345
  `Model "${options.modelName}" n\xE3o encontrado no PrismaClient.`
145
346
  );
146
347
  }
348
+ this.prismaModel = model;
147
349
  this.identifierField = options.identifierField ?? "email";
148
350
  this.passwordField = options.passwordField ?? "password";
149
351
  this.idField = options.idField ?? "id";
@@ -154,34 +356,107 @@ var JwtPrismaCookieAuthDriver = class {
154
356
  ...defaultCookieOptions,
155
357
  ...options.cookieOptions ?? {}
156
358
  };
157
- this.comparePassword = options.comparePassword ?? ((provided, stored) => String(stored) === provided);
359
+ this.comparePassword = options.comparePassword;
158
360
  this.transformUser = options.transformUser ?? ((user) => {
159
361
  const clone = { ...user };
160
362
  delete clone[this.passwordField];
161
363
  return clone;
162
364
  });
365
+ this.csrf = options.csrf ?? false;
366
+ this.onAudit = options.onAudit;
367
+ this.onRateLimitCheck = options.onRateLimitCheck;
368
+ if (options.lockout) {
369
+ const windowMs = options.lockout.windowMs ?? 15 * 60 * 1e3;
370
+ this.lockoutMaxAttempts = options.lockout.maxAttempts ?? 5;
371
+ this.lockoutStore = options.lockout.store ?? new InMemoryLockoutStore(windowMs);
372
+ } else {
373
+ this.lockoutMaxAttempts = 0;
374
+ }
375
+ if (options.refreshToken?.enabled) {
376
+ this.refreshTokenEnabled = true;
377
+ this.refreshTokenCookieName = options.refreshToken.cookieName ?? "refresh_token";
378
+ this.refreshTokenExpiresIn = options.refreshToken.expiresIn ?? "30d";
379
+ this.refreshTokenStore = options.refreshToken.store ?? new InMemoryRefreshTokenStore();
380
+ } else {
381
+ this.refreshTokenEnabled = false;
382
+ this.refreshTokenCookieName = "refresh_token";
383
+ this.refreshTokenExpiresIn = "30d";
384
+ }
163
385
  }
164
- async login(payload, _req, res) {
386
+ async login(payload, req, res) {
165
387
  const identifier = payload[this.identifierField];
388
+ const ip = req.ip ?? req.socket?.remoteAddress ?? "unknown";
389
+ if (this.onRateLimitCheck) {
390
+ const allowed = await this.onRateLimitCheck(ip, identifier);
391
+ if (!allowed) {
392
+ await this.emitAudit({
393
+ action: "login",
394
+ ip,
395
+ success: false,
396
+ metadata: { reason: "rate_limited" }
397
+ });
398
+ throw new UnauthorizedException3("Too many requests");
399
+ }
400
+ }
401
+ if (this.lockoutStore) {
402
+ const failures = await this.lockoutStore.getFailures(identifier);
403
+ if (failures >= this.lockoutMaxAttempts) {
404
+ await this.emitAudit({
405
+ action: "lockout",
406
+ ip,
407
+ success: false,
408
+ metadata: { identifier }
409
+ });
410
+ throw new UnauthorizedException3("Invalid credentials");
411
+ }
412
+ }
166
413
  const user = await this.prismaModel.findUnique({
167
414
  where: { [this.identifierField]: identifier }
168
415
  });
169
416
  if (!user) {
170
- throw new UnauthorizedException2("Invalid credentials");
417
+ await this.lockoutStore?.recordFailure(identifier);
418
+ await this.emitAudit({ action: "login", ip, success: false });
419
+ throw new UnauthorizedException3("Invalid credentials");
171
420
  }
172
421
  const ok = await this.comparePassword(
173
422
  payload[this.passwordField],
174
423
  user[this.passwordField]
175
424
  );
176
425
  if (!ok) {
177
- throw new UnauthorizedException2("Invalid credentials");
426
+ await this.lockoutStore?.recordFailure(identifier);
427
+ await this.emitAudit({
428
+ action: "login",
429
+ userId: String(user[this.idField]),
430
+ ip,
431
+ success: false
432
+ });
433
+ throw new UnauthorizedException3("Invalid credentials");
178
434
  }
435
+ await this.lockoutStore?.reset(identifier);
179
436
  const token = sign(
180
437
  { sub: user[this.idField] },
181
438
  this.jwtSecret,
182
- { expiresIn: this.jwtExpiresIn }
439
+ { expiresIn: this.jwtExpiresIn, algorithm: "HS256" }
183
440
  );
184
441
  res.cookie(this.cookieName, token, this.cookieOptions);
442
+ if (this.refreshTokenEnabled && this.refreshTokenStore) {
443
+ await this.issueRefreshToken(String(user[this.idField]), res);
444
+ }
445
+ if (this.csrf) {
446
+ const csrfToken = randomBytes(32).toString("hex");
447
+ res.cookie("csrf_token", csrfToken, {
448
+ httpOnly: false,
449
+ sameSite: this.cookieOptions.sameSite,
450
+ path: "/",
451
+ secure: this.cookieOptions.secure
452
+ });
453
+ }
454
+ await this.emitAudit({
455
+ action: "login",
456
+ userId: String(user[this.idField]),
457
+ ip,
458
+ success: true
459
+ });
185
460
  return this.transformUser(user);
186
461
  }
187
462
  async checkIn(req, res) {
@@ -191,7 +466,9 @@ var JwtPrismaCookieAuthDriver = class {
191
466
  }
192
467
  let payload;
193
468
  try {
194
- payload = verify(token, this.jwtSecret);
469
+ payload = verify2(token, this.jwtSecret, {
470
+ algorithms: ["HS256"]
471
+ });
195
472
  } catch {
196
473
  return null;
197
474
  }
@@ -201,19 +478,136 @@ var JwtPrismaCookieAuthDriver = class {
201
478
  if (!user) {
202
479
  return null;
203
480
  }
204
- res.cookie(this.cookieName, token, this.cookieOptions);
481
+ const newToken = sign(
482
+ { sub: payload.sub },
483
+ this.jwtSecret,
484
+ { expiresIn: this.jwtExpiresIn, algorithm: "HS256" }
485
+ );
486
+ res.cookie(this.cookieName, newToken, this.cookieOptions);
487
+ await this.emitAudit({
488
+ action: "checkin",
489
+ userId: String(payload.sub),
490
+ ip: req.ip ?? req.socket?.remoteAddress,
491
+ success: true
492
+ });
205
493
  return this.transformUser(user);
206
494
  }
207
- async logout(_req, res) {
495
+ async logout(req, res) {
208
496
  res.clearCookie(this.cookieName, {
209
497
  ...this.cookieOptions,
210
498
  maxAge: 0
211
499
  });
500
+ if (this.refreshTokenEnabled) {
501
+ const refreshCookie = req.cookies?.[this.refreshTokenCookieName];
502
+ if (refreshCookie && this.refreshTokenStore) {
503
+ try {
504
+ const payload = verify2(refreshCookie, this.jwtSecret, {
505
+ algorithms: ["HS256"]
506
+ });
507
+ if (payload.jti) {
508
+ await this.refreshTokenStore.revokeAll(String(payload.sub));
509
+ }
510
+ } catch {
511
+ }
512
+ }
513
+ res.clearCookie(this.refreshTokenCookieName, {
514
+ ...this.cookieOptions,
515
+ maxAge: 0
516
+ });
517
+ }
518
+ if (this.csrf) {
519
+ res.clearCookie("csrf_token", { path: "/", maxAge: 0 });
520
+ }
521
+ await this.emitAudit({
522
+ action: "logout",
523
+ ip: req.ip ?? req.socket?.remoteAddress,
524
+ success: true
525
+ });
526
+ }
527
+ async refresh(req, res) {
528
+ if (!this.refreshTokenEnabled || !this.refreshTokenStore) {
529
+ return null;
530
+ }
531
+ const refreshCookie = req.cookies?.[this.refreshTokenCookieName];
532
+ if (!refreshCookie) {
533
+ return null;
534
+ }
535
+ let payload;
536
+ try {
537
+ payload = verify2(refreshCookie, this.jwtSecret, {
538
+ algorithms: ["HS256"]
539
+ });
540
+ } catch {
541
+ return null;
542
+ }
543
+ if (!payload.jti) {
544
+ return null;
545
+ }
546
+ const stored = await this.refreshTokenStore.find(payload.jti);
547
+ if (!stored) {
548
+ return null;
549
+ }
550
+ await this.refreshTokenStore.revoke(payload.jti);
551
+ const userId = String(payload.sub);
552
+ const user = await this.prismaModel.findUnique({
553
+ where: { [this.idField]: userId }
554
+ });
555
+ if (!user) {
556
+ return null;
557
+ }
558
+ const accessToken = sign(
559
+ { sub: userId },
560
+ this.jwtSecret,
561
+ { expiresIn: this.jwtExpiresIn, algorithm: "HS256" }
562
+ );
563
+ res.cookie(this.cookieName, accessToken, this.cookieOptions);
564
+ await this.issueRefreshToken(userId, res);
565
+ if (this.csrf) {
566
+ const csrfToken = randomBytes(32).toString("hex");
567
+ res.cookie("csrf_token", csrfToken, {
568
+ httpOnly: false,
569
+ sameSite: this.cookieOptions.sameSite,
570
+ path: "/",
571
+ secure: this.cookieOptions.secure
572
+ });
573
+ }
574
+ await this.emitAudit({
575
+ action: "refresh",
576
+ userId,
577
+ ip: req.ip ?? req.socket?.remoteAddress,
578
+ success: true
579
+ });
580
+ return this.transformUser(user);
581
+ }
582
+ async issueRefreshToken(userId, res) {
583
+ const jti = randomUUID();
584
+ const expiresInMs = typeof this.refreshTokenExpiresIn === "number" ? this.refreshTokenExpiresIn * 1e3 : parseDuration(this.refreshTokenExpiresIn);
585
+ const expiresAt = new Date(Date.now() + expiresInMs);
586
+ const refreshToken = sign(
587
+ { sub: userId, jti },
588
+ this.jwtSecret,
589
+ { expiresIn: this.refreshTokenExpiresIn, algorithm: "HS256" }
590
+ );
591
+ await this.refreshTokenStore.save(jti, userId, expiresAt);
592
+ res.cookie(this.refreshTokenCookieName, refreshToken, {
593
+ ...this.cookieOptions,
594
+ path: "/"
595
+ });
596
+ }
597
+ async emitAudit(partial) {
598
+ if (!this.onAudit) return;
599
+ await this.onAudit({ ...partial, timestamp: /* @__PURE__ */ new Date() });
212
600
  }
213
601
  };
214
602
  export {
215
603
  AUTH_DRIVER,
216
604
  AuthController,
217
605
  AuthModule,
218
- JwtPrismaCookieAuthDriver
606
+ InMemoryLockoutStore,
607
+ InMemoryRefreshTokenStore,
608
+ JwtAuthGuard,
609
+ JwtPrismaCookieAuthDriver,
610
+ ROLES_KEY,
611
+ Roles,
612
+ RolesGuard
219
613
  };
package/dist/vue.d.mts CHANGED
@@ -19,12 +19,14 @@ declare class Auth<User extends Record<string, any>> {
19
19
  on: Ref<boolean, boolean>;
20
20
  loading: Ref<boolean, boolean>;
21
21
  checkedIn: Ref<boolean, boolean>;
22
+ roles: Ref<string[]>;
22
23
  private fetch;
23
24
  private mapUser;
24
25
  private afterLogout;
25
26
  private afterCheckIn;
26
27
  private routes;
27
28
  constructor({ fetch, mapUser, routes, afterLogout, afterCheckIn, }: Options<User>);
29
+ signUp(payload: Record<string, any>): Promise<void>;
28
30
  login(payload: Record<string, any>): Promise<void>;
29
31
  checkIn(): Promise<void>;
30
32
  logout(): Promise<void>;
package/dist/vue.d.ts CHANGED
@@ -19,12 +19,14 @@ declare class Auth<User extends Record<string, any>> {
19
19
  on: Ref<boolean, boolean>;
20
20
  loading: Ref<boolean, boolean>;
21
21
  checkedIn: Ref<boolean, boolean>;
22
+ roles: Ref<string[]>;
22
23
  private fetch;
23
24
  private mapUser;
24
25
  private afterLogout;
25
26
  private afterCheckIn;
26
27
  private routes;
27
28
  constructor({ fetch, mapUser, routes, afterLogout, afterCheckIn, }: Options<User>);
29
+ signUp(payload: Record<string, any>): Promise<void>;
28
30
  login(payload: Record<string, any>): Promise<void>;
29
31
  checkIn(): Promise<void>;
30
32
  logout(): Promise<void>;
package/dist/vue.js CHANGED
@@ -31,11 +31,13 @@ var Auth = class {
31
31
  on = (0, import_vue.ref)(false);
32
32
  loading = (0, import_vue.ref)(false);
33
33
  checkedIn = (0, import_vue.ref)(false);
34
+ roles = (0, import_vue.ref)([]);
34
35
  fetch;
35
36
  mapUser;
36
37
  afterLogout;
37
38
  afterCheckIn;
38
39
  routes = {
40
+ signUp: "/api/signup",
39
41
  login: "/api/login",
40
42
  checkIn: "/api/checkin",
41
43
  logout: "/api/logout"
@@ -57,6 +59,20 @@ var Auth = class {
57
59
  Object.assign(this.routes, routes);
58
60
  }
59
61
  }
62
+ async signUp(payload) {
63
+ this.loading.value = true;
64
+ try {
65
+ const response = await this.fetch(this.routes.signUp, {
66
+ method: "POST",
67
+ body: JSON.stringify(payload)
68
+ });
69
+ this.on.value = true;
70
+ const { data } = await response.json();
71
+ this.setUser(data);
72
+ } finally {
73
+ this.loading.value = false;
74
+ }
75
+ }
60
76
  async login(payload) {
61
77
  this.loading.value = true;
62
78
  try {
@@ -104,6 +120,7 @@ var Auth = class {
104
120
  setUser = (data) => {
105
121
  if (data === null || data === void 0) {
106
122
  this.user.value = null;
123
+ this.roles.value = [];
107
124
  return;
108
125
  }
109
126
  const parsedData = this.mapUser(data);
@@ -113,6 +130,9 @@ var Auth = class {
113
130
  for (const key in parsedData) {
114
131
  this.user.value[key] = parsedData[key];
115
132
  }
133
+ if (Array.isArray(parsedData.roles)) {
134
+ this.roles.value = parsedData.roles;
135
+ }
116
136
  };
117
137
  };
118
138
  // Annotate the CommonJS export names for ESM import in node:
package/dist/vue.mjs CHANGED
@@ -5,11 +5,13 @@ var Auth = class {
5
5
  on = ref(false);
6
6
  loading = ref(false);
7
7
  checkedIn = ref(false);
8
+ roles = ref([]);
8
9
  fetch;
9
10
  mapUser;
10
11
  afterLogout;
11
12
  afterCheckIn;
12
13
  routes = {
14
+ signUp: "/api/signup",
13
15
  login: "/api/login",
14
16
  checkIn: "/api/checkin",
15
17
  logout: "/api/logout"
@@ -31,6 +33,20 @@ var Auth = class {
31
33
  Object.assign(this.routes, routes);
32
34
  }
33
35
  }
36
+ async signUp(payload) {
37
+ this.loading.value = true;
38
+ try {
39
+ const response = await this.fetch(this.routes.signUp, {
40
+ method: "POST",
41
+ body: JSON.stringify(payload)
42
+ });
43
+ this.on.value = true;
44
+ const { data } = await response.json();
45
+ this.setUser(data);
46
+ } finally {
47
+ this.loading.value = false;
48
+ }
49
+ }
34
50
  async login(payload) {
35
51
  this.loading.value = true;
36
52
  try {
@@ -78,6 +94,7 @@ var Auth = class {
78
94
  setUser = (data) => {
79
95
  if (data === null || data === void 0) {
80
96
  this.user.value = null;
97
+ this.roles.value = [];
81
98
  return;
82
99
  }
83
100
  const parsedData = this.mapUser(data);
@@ -87,6 +104,9 @@ var Auth = class {
87
104
  for (const key in parsedData) {
88
105
  this.user.value[key] = parsedData[key];
89
106
  }
107
+ if (Array.isArray(parsedData.roles)) {
108
+ this.roles.value = parsedData.roles;
109
+ }
90
110
  };
91
111
  };
92
112
  export {