@attlaz/client 1.99.0 → 1.100.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.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Why a password was rejected. `null` means it was accepted.
3
+ *
4
+ * Mirrors the server's `PasswordCheckResult` — duplicated here rather than imported, per the client's
5
+ * standing rule that it does not depend on Core.
6
+ */
7
+ export type PasswordCheckCode = 'password_missing' | 'password_not_long_enough' | 'password_too_long' | 'password_repeat_match' | 'password_general_match' | 'password_too_weak';
8
+ export declare class PasswordCheck {
9
+ /** Null when the password is acceptable. */
10
+ code: PasswordCheckCode | null;
11
+ /** Human-readable reason, ready to display. Null when the password is acceptable. */
12
+ error: string | null;
13
+ /**
14
+ * zxcvbn score, 0 (weakest) to 4 (strongest). Null when the password was rejected before it was
15
+ * scored — an empty or out-of-bounds password never reaches the estimator.
16
+ *
17
+ * Treat it as a display hint, not a policy: the server owns the threshold, and a low score with
18
+ * `code === null` still means accepted.
19
+ */
20
+ strength: number | null;
21
+ isAcceptable(): boolean;
22
+ }
@@ -0,0 +1,17 @@
1
+ export class PasswordCheck {
2
+ /** Null when the password is acceptable. */
3
+ code = null;
4
+ /** Human-readable reason, ready to display. Null when the password is acceptable. */
5
+ error = null;
6
+ /**
7
+ * zxcvbn score, 0 (weakest) to 4 (strongest). Null when the password was rejected before it was
8
+ * scored — an empty or out-of-bounds password never reaches the estimator.
9
+ *
10
+ * Treat it as a display hint, not a policy: the server owns the threshold, and a low score with
11
+ * `code === null` still means accepted.
12
+ */
13
+ strength = null;
14
+ isAcceptable() {
15
+ return this.code === null;
16
+ }
17
+ }
@@ -1,6 +1,7 @@
1
1
  import { UserAuthProvider } from '../Model/User/UserAuthProvider.js';
2
2
  import { User } from '../Model/User/User.js';
3
3
  import { UserSummary } from '../Model/User/UserSummary.js';
4
+ import { PasswordCheck } from '../Model/User/PasswordCheck.js';
4
5
  import { CollectionResult } from '../Model/Result/CollectionResult.js';
5
6
  import { Endpoint } from './Endpoint.js';
6
7
  import { UserNotificationSession } from '../Model/User/UserNotificationSession.js';
@@ -23,6 +24,18 @@ export declare class UserEndpoint extends Endpoint {
23
24
  update(user: User): Promise<User>;
24
25
  create(user: User, password: string, invitationCode?: string | null): Promise<User>;
25
26
  requestResetPassword(email: string): Promise<boolean>;
27
+ /**
28
+ * Ask the server whether a password is acceptable, without setting it.
29
+ *
30
+ * Unauthenticated — signup calls this before an account, and therefore a token, exists. Pass the
31
+ * email when it is known so the server can price the password against the user's own details;
32
+ * `stijn2026` for `stijn@echron.com` scores far lower with it than without.
33
+ *
34
+ * Advisory only. The same rules run again when the password is actually set, so a caller must not
35
+ * treat acceptance here as a guarantee.
36
+ */
37
+ checkPassword(password: string, email?: string | null): Promise<PasswordCheck>;
38
+ private static parsePasswordCheck;
26
39
  resetPassword(code: string, password: string): Promise<boolean>;
27
40
  createWebPush(session: UserNotificationSession): Promise<boolean>;
28
41
  getSessions(pagination: CursorPagination): Promise<CollectionResult<UserNotificationSession>>;
@@ -2,6 +2,7 @@ import { path } from '../Http/Data/Path.js';
2
2
  import { UserAuthProvider } from '../Model/User/UserAuthProvider.js';
3
3
  import { User } from '../Model/User/User.js';
4
4
  import { UserSummary } from '../Model/User/UserSummary.js';
5
+ import { PasswordCheck } from '../Model/User/PasswordCheck.js';
5
6
  import { Endpoint } from './Endpoint.js';
6
7
  import { UserNotificationSession } from '../Model/User/UserNotificationSession.js';
7
8
  import { QueryString } from '../Http/Data/QueryString.js';
@@ -115,6 +116,42 @@ export class UserEndpoint extends Endpoint {
115
116
  throw e;
116
117
  }
117
118
  }
119
+ /**
120
+ * Ask the server whether a password is acceptable, without setting it.
121
+ *
122
+ * Unauthenticated — signup calls this before an account, and therefore a token, exists. Pass the
123
+ * email when it is known so the server can price the password against the user's own details;
124
+ * `stijn2026` for `stijn@echron.com` scores far lower with it than without.
125
+ *
126
+ * Advisory only. The same rules run again when the password is actually set, so a caller must not
127
+ * treat acceptance here as a guarantee.
128
+ */
129
+ async checkPassword(password, email = null) {
130
+ try {
131
+ const url = '/users/check-password';
132
+ const parameters = email === null ? { password } : { password, email };
133
+ const result = await this.requestObject(url, parameters, UserEndpoint.parsePasswordCheck, 'POST', false);
134
+ const check = result.getData();
135
+ if (check === null) {
136
+ throw new Error('Unable to check password: wrong response from API');
137
+ }
138
+ return check;
139
+ }
140
+ catch (e) {
141
+ if (this.httpClient.isDebugEnabled()) {
142
+ // Never log the password itself.
143
+ console.error('Failed to check password: ', e);
144
+ }
145
+ throw e;
146
+ }
147
+ }
148
+ static parsePasswordCheck(raw) {
149
+ const check = new PasswordCheck();
150
+ check.code = (raw.code ?? null);
151
+ check.error = (raw.error ?? null);
152
+ check.strength = (raw.strength ?? null);
153
+ return check;
154
+ }
118
155
  async resetPassword(code, password) {
119
156
  try {
120
157
  const url = path('/users/resetpassword/:code', { code });
package/dist/index.d.ts CHANGED
@@ -209,6 +209,8 @@ export { UserAction } from './Model/User/UserAction.js';
209
209
  export type { UserActionFilter } from './Model/User/UserActionFilter.js';
210
210
  export { UserSummary } from './Model/User/UserSummary.js';
211
211
  export type { UserSummaryType } from './Model/User/UserSummary.js';
212
+ export { PasswordCheck } from './Model/User/PasswordCheck.js';
213
+ export type { PasswordCheckCode } from './Model/User/PasswordCheck.js';
212
214
  export { RunnerImage } from './Model/Runner/RunnerImage.js';
213
215
  export { Component } from './Model/Component/Component.js';
214
216
  export { ComponentKind } from './Model/Component/ComponentKind.js';
package/dist/index.js CHANGED
@@ -172,6 +172,7 @@ export { User } from './Model/User/User.js';
172
172
  export { UserAuthProvider } from './Model/User/UserAuthProvider.js';
173
173
  export { UserAction } from './Model/User/UserAction.js';
174
174
  export { UserSummary } from './Model/User/UserSummary.js';
175
+ export { PasswordCheck } from './Model/User/PasswordCheck.js';
175
176
  export { RunnerImage } from './Model/Runner/RunnerImage.js';
176
177
  export { Component } from './Model/Component/Component.js';
177
178
  export { ComponentKind } from './Model/Component/ComponentKind.js';
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "1.98.0";
1
+ export declare const VERSION = "1.99.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "1.98.0";
1
+ export const VERSION = "1.99.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@attlaz/client",
3
- "version": "1.99.0",
3
+ "version": "1.100.0",
4
4
  "description": "Javascript Client to access Attlaz API",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",
@@ -53,7 +53,7 @@
53
53
  "registry": "https://registry.npmjs.org"
54
54
  },
55
55
  "devDependencies": {
56
- "@types/node": "^26.1.2",
56
+ "@types/node": "^26.2.0",
57
57
  "@typescript-eslint/eslint-plugin": "^8.59.3",
58
58
  "@typescript-eslint/parser": "^8.59.3",
59
59
  "eslint": "^9.39.5",