@gopherium/react-auth 0.1.2 → 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.
- package/dist/admin/index.js +31 -6
- package/dist/api.js +30 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/probe.js +14 -5
- package/dist/transport.d.ts +34 -0
- package/dist/transport.js +25 -0
- package/package.json +2 -1
package/dist/admin/index.js
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
65
|
+
* Ends the session over REST.
|
|
65
66
|
*/
|
|
66
|
-
|
|
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
|
-
*
|
|
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
|
|
7
|
-
* accepts it.
|
|
6
|
+
* @returns True when the session is revoked.
|
|
8
7
|
*/
|
|
9
|
-
|
|
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.
|
|
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",
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"@wordpress/ui": "0.19.0",
|
|
86
86
|
"eslint": "^9.39.1",
|
|
87
87
|
"eslint-plugin-jsdoc": "^63.0.13",
|
|
88
|
+
"eslint-plugin-sonarjs": "^4.2.0",
|
|
88
89
|
"eslint-plugin-tsdoc": "^0.4.0",
|
|
89
90
|
"jsdom": "^29.1.1",
|
|
90
91
|
"msw": "^2.15.0",
|