@gopherium/react-auth 0.1.1 → 0.2.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.
@@ -1,6 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  import { z } from 'zod';
3
3
  import { UnauthorizedError } from '../api.js';
4
+ import { resolveTransport } from '../transport.js';
4
5
  export const usersQueryKey = ['users'];
5
6
  const userSchema = z.object({
6
7
  id: z.string(),
@@ -36,11 +37,11 @@ async function errorMessage(response, fallback) {
36
37
  }
37
38
  }
38
39
  /**
39
- * Returns every user account.
40
+ * Lists the accounts over REST.
40
41
  * @param signal - Aborts the in-flight request.
41
42
  * @returns The parsed list of users.
42
43
  */
43
- export async function fetchUsers(signal) {
44
+ async function restFetchUsers(signal) {
44
45
  const response = await fetch('/api/users', { signal });
45
46
  if (response.status === 401) {
46
47
  throw new UnauthorizedError('session expired');
@@ -51,11 +52,11 @@ export async function fetchUsers(signal) {
51
52
  return z.array(userSchema).parse(await response.json());
52
53
  }
53
54
  /**
54
- * Creates a user account and returns it.
55
+ * Creates an account over REST.
55
56
  * @param input - The email, name, and password of the new account.
56
57
  * @returns The created user.
57
58
  */
58
- export async function createUser(input) {
59
+ async function restCreateUser(input) {
59
60
  const response = await fetch('/api/users', {
60
61
  method: 'POST',
61
62
  headers: { 'Content-Type': 'application/json' },
@@ -76,11 +77,11 @@ export async function createUser(input) {
76
77
  return userSchema.parse(await response.json());
77
78
  }
78
79
  /**
79
- * Sets whether a user may log in.
80
+ * Updates an account's disabled flag over REST.
80
81
  * @param id - The identifier of the user to update.
81
82
  * @param disabled - Whether the account should be disabled.
82
83
  */
83
- export async function setUserDisabled(id, disabled) {
84
+ async function restSetUserDisabled(id, disabled) {
84
85
  const response = await fetch(`/api/users/${id}`, {
85
86
  method: 'PATCH',
86
87
  headers: { 'Content-Type': 'application/json' },
@@ -93,3 +94,27 @@ export async function setUserDisabled(id, disabled) {
93
94
  throw new Error(`updating user failed with status ${response.status}`);
94
95
  }
95
96
  }
97
+ /**
98
+ * Returns every user account.
99
+ * @param signal - Aborts the in-flight request.
100
+ * @returns The parsed list of users.
101
+ */
102
+ export async function fetchUsers(signal) {
103
+ return resolveTransport('fetchUsers', restFetchUsers)(signal);
104
+ }
105
+ /**
106
+ * Creates a user account and returns it.
107
+ * @param input - The email, name, and password of the new account.
108
+ * @returns The created user.
109
+ */
110
+ export async function createUser(input) {
111
+ return resolveTransport('createUser', restCreateUser)(input);
112
+ }
113
+ /**
114
+ * Sets whether a user may log in.
115
+ * @param id - The identifier of the user to update.
116
+ * @param disabled - Whether the account should be disabled.
117
+ */
118
+ export async function setUserDisabled(id, disabled) {
119
+ await resolveTransport('setUserDisabled', restSetUserDisabled)(id, disabled);
120
+ }
package/dist/api.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  import { z } from 'zod';
3
+ import { resolveTransport } from './transport.js';
3
4
  const userSchema = z.object({
4
5
  id: z.string(),
5
6
  email: z.string(),
@@ -23,11 +24,11 @@ export class UnauthorizedError extends Error {
23
24
  export class RateLimitedError extends Error {
24
25
  }
25
26
  /**
26
- * Returns the logged-in user, or null when no session is active.
27
+ * Loads the session over REST.
27
28
  * @param signal - Aborts the in-flight request.
28
29
  * @returns The current user, or null when unauthenticated.
29
30
  */
30
- export async function fetchSession(signal) {
31
+ async function restFetchSession(signal) {
31
32
  const response = await fetch('/api/auth/session', { signal });
32
33
  if (response.status === 401) {
33
34
  return null;
@@ -38,12 +39,12 @@ export async function fetchSession(signal) {
38
39
  return userSchema.parse(await response.json());
39
40
  }
40
41
  /**
41
- * Logs in with the given credentials and returns the user.
42
+ * Logs in over REST.
42
43
  * @param email - The account email address.
43
44
  * @param password - The account password.
44
45
  * @returns The authenticated user.
45
46
  */
46
- export async function login(email, password) {
47
+ async function restLogin(email, password) {
47
48
  const response = await fetch('/api/auth/login', {
48
49
  method: 'POST',
49
50
  headers: { 'Content-Type': 'application/json' },
@@ -61,11 +62,34 @@ export async function login(email, password) {
61
62
  return userSchema.parse(await response.json());
62
63
  }
63
64
  /**
64
- * Ends the current session.
65
+ * Ends the session over REST.
65
66
  */
66
- export async function logout() {
67
+ async function restLogout() {
67
68
  const response = await fetch('/api/auth/logout', { method: 'POST' });
68
69
  if (!response.ok) {
69
70
  throw new Error(`logout failed with status ${response.status}`);
70
71
  }
71
72
  }
73
+ /**
74
+ * Returns the logged-in user, or null when no session is active.
75
+ * @param signal - Aborts the in-flight request.
76
+ * @returns The current user, or null when unauthenticated.
77
+ */
78
+ export async function fetchSession(signal) {
79
+ return resolveTransport('fetchSession', restFetchSession)(signal);
80
+ }
81
+ /**
82
+ * Logs in with the given credentials and returns the user.
83
+ * @param email - The account email address.
84
+ * @param password - The account password.
85
+ * @returns The authenticated user.
86
+ */
87
+ export async function login(email, password) {
88
+ return resolveTransport('login', restLogin)(email, password);
89
+ }
90
+ /**
91
+ * Ends the current session.
92
+ */
93
+ export async function logout() {
94
+ await resolveTransport('logout', restLogout)();
95
+ }
package/dist/index.d.ts CHANGED
@@ -4,3 +4,5 @@ export { AuthGate } from './AuthGate.js';
4
4
  export { isSessionRevoked } from './probe.js';
5
5
  export { createAuthQueryClient } from './queryClient.js';
6
6
  export { sessionQueryKey, useLogout, useSession } from './session.js';
7
+ export { configureAuthTransport, resetAuthTransport } from './transport.js';
8
+ export type { AuthTransport } from './transport.js';
package/dist/index.js CHANGED
@@ -4,3 +4,4 @@ export { AuthGate } from './AuthGate.js';
4
4
  export { isSessionRevoked } from './probe.js';
5
5
  export { createAuthQueryClient } from './queryClient.js';
6
6
  export { sessionQueryKey, useLogout, useSession } from './session.js';
7
+ export { configureAuthTransport, resetAuthTransport } from './transport.js';
package/dist/probe.js CHANGED
@@ -1,15 +1,24 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
+ import { resolveTransport } from './transport.js';
2
3
  /**
3
- * Reports whether the backend considers the session gone, distinguishing
4
- * a revoked login from a transient outage after a stream failure.
4
+ * Probes the session over REST.
5
5
  * @param signal - Aborts the in-flight request.
6
- * @returns True when the session is revoked, false when the backend still
7
- * accepts it.
6
+ * @returns True when the session is revoked.
8
7
  */
9
- export async function isSessionRevoked(signal) {
8
+ async function restIsSessionRevoked(signal) {
10
9
  const response = await fetch('/api/auth/session', {
11
10
  credentials: 'include',
12
11
  signal,
13
12
  });
14
13
  return response.status === 401;
15
14
  }
15
+ /**
16
+ * Reports whether the backend considers the session gone, distinguishing
17
+ * a revoked login from a transient outage after a stream failure.
18
+ * @param signal - Aborts the in-flight request.
19
+ * @returns True when the session is revoked, false when the backend still
20
+ * accepts it.
21
+ */
22
+ export async function isSessionRevoked(signal) {
23
+ return resolveTransport('isSessionRevoked', restIsSessionRevoked)(signal);
24
+ }
@@ -0,0 +1,34 @@
1
+ import type { User as Account, NewUser } from './admin/index.js';
2
+ import type { User } from './api.js';
3
+ /**
4
+ * AuthTransport carries every backend call of the package, so a consumer
5
+ * can replace the REST transport with its own while keeping the screens,
6
+ * hooks, and error contract. Implementations must throw the same error
7
+ * classes the REST transport throws.
8
+ */
9
+ export interface AuthTransport {
10
+ fetchSession(signal?: AbortSignal): Promise<User | null>;
11
+ login(email: string, password: string): Promise<User>;
12
+ logout(): Promise<void>;
13
+ isSessionRevoked(signal?: AbortSignal): Promise<boolean>;
14
+ fetchUsers(signal?: AbortSignal): Promise<Account[]>;
15
+ createUser(input: NewUser): Promise<Account>;
16
+ setUserDisabled(id: string, disabled: boolean): Promise<void>;
17
+ }
18
+ /**
19
+ * Replaces backend calls with the given implementations, keeping the REST
20
+ * transport for every operation not named.
21
+ * @param transport - The operations to override.
22
+ */
23
+ export declare function configureAuthTransport(transport: Partial<AuthTransport>): void;
24
+ /**
25
+ * Restores the REST transport for every operation.
26
+ */
27
+ export declare function resetAuthTransport(): void;
28
+ /**
29
+ * Returns the configured implementation of one operation, or the fallback.
30
+ * @param name - The operation to resolve.
31
+ * @param fallback - The REST implementation used when not overridden.
32
+ * @returns The active implementation.
33
+ */
34
+ export declare function resolveTransport<K extends keyof AuthTransport>(name: K, fallback: AuthTransport[K]): AuthTransport[K];
@@ -0,0 +1,25 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ let overrides = {};
3
+ /**
4
+ * Replaces backend calls with the given implementations, keeping the REST
5
+ * transport for every operation not named.
6
+ * @param transport - The operations to override.
7
+ */
8
+ export function configureAuthTransport(transport) {
9
+ overrides = { ...overrides, ...transport };
10
+ }
11
+ /**
12
+ * Restores the REST transport for every operation.
13
+ */
14
+ export function resetAuthTransport() {
15
+ overrides = {};
16
+ }
17
+ /**
18
+ * Returns the configured implementation of one operation, or the fallback.
19
+ * @param name - The operation to resolve.
20
+ * @param fallback - The REST implementation used when not overridden.
21
+ * @returns The active implementation.
22
+ */
23
+ export function resolveTransport(name, fallback) {
24
+ return overrides[name] ?? fallback;
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gopherium/react-auth",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Session authentication for React apps backed by gouncer's authkit.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -47,7 +47,8 @@
47
47
  "@tanstack/react-query": "^5.101.2",
48
48
  "@testing-library/jest-dom": "^6.9.1",
49
49
  "@testing-library/react": "^16.3.2",
50
- "@wordpress/ui": "^0.17.0",
50
+ "@wordpress/theme": ">=1.0.0 <2.0.0",
51
+ "@wordpress/ui": ">=0.17.0 <1.0.0",
51
52
  "msw": "^2.15.0",
52
53
  "react": "^19.2.7",
53
54
  "vitest": "^4.1.10"
@@ -59,6 +60,9 @@
59
60
  "@testing-library/react": {
60
61
  "optional": true
61
62
  },
63
+ "@wordpress/theme": {
64
+ "optional": true
65
+ },
62
66
  "@wordpress/ui": {
63
67
  "optional": true
64
68
  },
@@ -77,9 +81,11 @@
77
81
  "@types/react": "^19.2.17",
78
82
  "@vitejs/plugin-react": "^6.0.3",
79
83
  "@vitest/coverage-v8": "^4.1.10",
80
- "@wordpress/ui": "^0.17.0",
84
+ "@wordpress/theme": "1.1.0",
85
+ "@wordpress/ui": "0.19.0",
81
86
  "eslint": "^9.39.1",
82
87
  "eslint-plugin-jsdoc": "^63.0.13",
88
+ "eslint-plugin-sonarjs": "^4.2.0",
83
89
  "eslint-plugin-tsdoc": "^0.4.0",
84
90
  "jsdom": "^29.1.1",
85
91
  "msw": "^2.15.0",