@aooth/user 0.1.23 → 0.1.25

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.cjs CHANGED
@@ -420,11 +420,7 @@ var UserService = class {
420
420
  if (!user.account.active) throw new require_federated_identity_store.UserAuthError("INACTIVE");
421
421
  await this.ensureNotLockedOrThrow(user.id, user.account);
422
422
  if (await this.hasher.verify(password, user.password.hash)) {
423
- const now = this.config.clock();
424
- await this.store.update(user.id, { set: { account: {
425
- lastLogin: now,
426
- failedLoginAttempts: 0
427
- } } });
423
+ const now = await this.recordLogin(user.id);
428
424
  user.account.lastLogin = now;
429
425
  user.account.failedLoginAttempts = 0;
430
426
  return {
@@ -434,6 +430,27 @@ var UserService = class {
434
430
  }
435
431
  return this.incrementAndMaybeLock(user.id, user.account, "INVALID_CREDENTIALS", lockoutOverride);
436
432
  }
433
+ /**
434
+ * Stamp a successful login on the user record: `account.lastLogin = now` and
435
+ * reset `account.failedLoginAttempts = 0`. The single writer of `lastLogin`.
436
+ *
437
+ * Called by {@link login} on a valid password verify, AND by passwordless
438
+ * auto-login terminals (invite-accept / signup) which issue a session without
439
+ * going through `login()`. Stamping there closes out that first login so the
440
+ * derived `isFirstLogin = !lastLogin` check stops re-classifying the user's
441
+ * first *credentialed* sign-in as a first login.
442
+ *
443
+ * Returns the timestamp written, so callers holding an in-memory row can patch
444
+ * it without re-reading the store.
445
+ */
446
+ async recordLogin(id) {
447
+ const now = this.config.clock();
448
+ await this.store.update(id, { set: { account: {
449
+ lastLogin: now,
450
+ failedLoginAttempts: 0
451
+ } } });
452
+ return now;
453
+ }
437
454
  async verifyPassword(id, password) {
438
455
  const user = await this.store.findById(id);
439
456
  if (!user) throw new require_federated_identity_store.UserAuthError("NOT_FOUND");
package/dist/index.d.cts CHANGED
@@ -124,6 +124,20 @@ declare class UserService<T extends object = object> {
124
124
  */
125
125
  findByIdentifier(value: string): Promise<(UserCredentials & T) | null>;
126
126
  login(handle: string, password: string, lockoutOverride?: Partial<LockoutConfig>): Promise<LoginResult<T>>;
127
+ /**
128
+ * Stamp a successful login on the user record: `account.lastLogin = now` and
129
+ * reset `account.failedLoginAttempts = 0`. The single writer of `lastLogin`.
130
+ *
131
+ * Called by {@link login} on a valid password verify, AND by passwordless
132
+ * auto-login terminals (invite-accept / signup) which issue a session without
133
+ * going through `login()`. Stamping there closes out that first login so the
134
+ * derived `isFirstLogin = !lastLogin` check stops re-classifying the user's
135
+ * first *credentialed* sign-in as a first login.
136
+ *
137
+ * Returns the timestamp written, so callers holding an in-memory row can patch
138
+ * it without re-reading the store.
139
+ */
140
+ recordLogin(id: string): Promise<number>;
127
141
  verifyPassword(id: string, password: string): Promise<boolean>;
128
142
  changePassword(id: string, currentPassword: string, newPassword: string, repeatPassword?: string): Promise<void>;
129
143
  setPassword(id: string, newPassword: string): Promise<void>;
package/dist/index.d.mts CHANGED
@@ -124,6 +124,20 @@ declare class UserService<T extends object = object> {
124
124
  */
125
125
  findByIdentifier(value: string): Promise<(UserCredentials & T) | null>;
126
126
  login(handle: string, password: string, lockoutOverride?: Partial<LockoutConfig>): Promise<LoginResult<T>>;
127
+ /**
128
+ * Stamp a successful login on the user record: `account.lastLogin = now` and
129
+ * reset `account.failedLoginAttempts = 0`. The single writer of `lastLogin`.
130
+ *
131
+ * Called by {@link login} on a valid password verify, AND by passwordless
132
+ * auto-login terminals (invite-accept / signup) which issue a session without
133
+ * going through `login()`. Stamping there closes out that first login so the
134
+ * derived `isFirstLogin = !lastLogin` check stops re-classifying the user's
135
+ * first *credentialed* sign-in as a first login.
136
+ *
137
+ * Returns the timestamp written, so callers holding an in-memory row can patch
138
+ * it without re-reading the store.
139
+ */
140
+ recordLogin(id: string): Promise<number>;
127
141
  verifyPassword(id: string, password: string): Promise<boolean>;
128
142
  changePassword(id: string, currentPassword: string, newPassword: string, repeatPassword?: string): Promise<void>;
129
143
  setPassword(id: string, newPassword: string): Promise<void>;
package/dist/index.mjs CHANGED
@@ -419,11 +419,7 @@ var UserService = class {
419
419
  if (!user.account.active) throw new UserAuthError("INACTIVE");
420
420
  await this.ensureNotLockedOrThrow(user.id, user.account);
421
421
  if (await this.hasher.verify(password, user.password.hash)) {
422
- const now = this.config.clock();
423
- await this.store.update(user.id, { set: { account: {
424
- lastLogin: now,
425
- failedLoginAttempts: 0
426
- } } });
422
+ const now = await this.recordLogin(user.id);
427
423
  user.account.lastLogin = now;
428
424
  user.account.failedLoginAttempts = 0;
429
425
  return {
@@ -433,6 +429,27 @@ var UserService = class {
433
429
  }
434
430
  return this.incrementAndMaybeLock(user.id, user.account, "INVALID_CREDENTIALS", lockoutOverride);
435
431
  }
432
+ /**
433
+ * Stamp a successful login on the user record: `account.lastLogin = now` and
434
+ * reset `account.failedLoginAttempts = 0`. The single writer of `lastLogin`.
435
+ *
436
+ * Called by {@link login} on a valid password verify, AND by passwordless
437
+ * auto-login terminals (invite-accept / signup) which issue a session without
438
+ * going through `login()`. Stamping there closes out that first login so the
439
+ * derived `isFirstLogin = !lastLogin` check stops re-classifying the user's
440
+ * first *credentialed* sign-in as a first login.
441
+ *
442
+ * Returns the timestamp written, so callers holding an in-memory row can patch
443
+ * it without re-reading the store.
444
+ */
445
+ async recordLogin(id) {
446
+ const now = this.config.clock();
447
+ await this.store.update(id, { set: { account: {
448
+ lastLogin: now,
449
+ failedLoginAttempts: 0
450
+ } } });
451
+ return now;
452
+ }
436
453
  async verifyPassword(id, password) {
437
454
  const user = await this.store.findById(id);
438
455
  if (!user) throw new UserAuthError("NOT_FOUND");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aooth/user",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "User credential primitives for aoothjs",
5
5
  "keywords": [
6
6
  "aoothjs",
@@ -60,14 +60,14 @@
60
60
  "access": "public"
61
61
  },
62
62
  "devDependencies": {
63
- "@atscript/core": "^0.1.76",
64
- "@atscript/db": "^0.1.106",
65
- "@atscript/db-sql-tools": "^0.1.106",
66
- "@atscript/db-sqlite": "^0.1.106",
67
- "@atscript/typescript": "^0.1.76",
63
+ "@atscript/core": "^0.1.77",
64
+ "@atscript/db": "^0.1.107",
65
+ "@atscript/db-sql-tools": "^0.1.107",
66
+ "@atscript/db-sqlite": "^0.1.107",
67
+ "@atscript/typescript": "^0.1.77",
68
68
  "@types/better-sqlite3": "^7.6.13",
69
69
  "better-sqlite3": "^12.6.2",
70
- "unplugin-atscript": "^0.1.76"
70
+ "unplugin-atscript": "^0.1.77"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "@atscript/db": ">=0.1.79"