@work-shape/catalyst-api-client 0.8.0-rc.10 → 0.8.0-rc.11
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.d.ts +49 -1
- package/dist/index.js +70 -3
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -25,13 +25,61 @@ interface AuthResult {
|
|
|
25
25
|
/** The sign-in library's code for a refusal, such as `INVALID_EMAIL_OR_PASSWORD`. */
|
|
26
26
|
code?: string;
|
|
27
27
|
message?: string;
|
|
28
|
+
/** The HTTP status of a refusal; 429 is the instance's limit on attempts. */
|
|
29
|
+
status?: number;
|
|
30
|
+
}
|
|
31
|
+
/** The second factor of a sign-in: a code from the authenticator app, or a backup code. */
|
|
32
|
+
type SecondFactorKind = "app" | "backup";
|
|
33
|
+
/** A sign-in: refused, signed in, or waiting for the second factor (TWO-FACTOR-1). */
|
|
34
|
+
interface SignInResult extends AuthResult {
|
|
35
|
+
/** The password was right and the account asks for a code before there is a session. */
|
|
36
|
+
secondFactor?: true;
|
|
37
|
+
}
|
|
38
|
+
/** What an authenticator app reads, and the ten backup codes, shown once. */
|
|
39
|
+
interface TwoFactorSetup {
|
|
40
|
+
totpUri: string;
|
|
41
|
+
backupCodes: string[];
|
|
28
42
|
}
|
|
29
43
|
declare function getAuthSession(apiBaseUrl: string): Promise<AuthSession | null>;
|
|
30
44
|
declare function signInWithEmail(input: {
|
|
31
45
|
apiBaseUrl: string;
|
|
32
46
|
email: string;
|
|
33
47
|
password: string;
|
|
48
|
+
}): Promise<SignInResult>;
|
|
49
|
+
/**
|
|
50
|
+
* The second sign-in step: a code from the authenticator app, or a backup code, which signs in
|
|
51
|
+
* once. `trustBrowser` skips the code in this browser for 30 days from now.
|
|
52
|
+
*/
|
|
53
|
+
declare function verifySecondFactor(input: {
|
|
54
|
+
apiBaseUrl: string;
|
|
55
|
+
code: string;
|
|
56
|
+
kind: SecondFactorKind;
|
|
57
|
+
trustBrowser?: boolean;
|
|
58
|
+
}): Promise<AuthResult>;
|
|
59
|
+
/**
|
|
60
|
+
* Starts the setup of two-factor sign-in with the password. The factor is on only after the
|
|
61
|
+
* first code from the app is confirmed with `verifySecondFactor`.
|
|
62
|
+
*/
|
|
63
|
+
declare function startTwoFactorSetup(input: {
|
|
64
|
+
apiBaseUrl: string;
|
|
65
|
+
password: string;
|
|
66
|
+
}): Promise<AuthResult & {
|
|
67
|
+
setup?: TwoFactorSetup;
|
|
68
|
+
}>;
|
|
69
|
+
/** Turns two-factor sign-in off with the password; every trusted browser is forgotten. */
|
|
70
|
+
declare function turnOffTwoFactor(input: {
|
|
71
|
+
apiBaseUrl: string;
|
|
72
|
+
password: string;
|
|
34
73
|
}): Promise<AuthResult>;
|
|
74
|
+
/** Replaces all ten backup codes with the password. The new ones are shown once. */
|
|
75
|
+
declare function regenerateBackupCodes(input: {
|
|
76
|
+
apiBaseUrl: string;
|
|
77
|
+
password: string;
|
|
78
|
+
}): Promise<AuthResult & {
|
|
79
|
+
backupCodes?: string[];
|
|
80
|
+
}>;
|
|
81
|
+
/** Every browser of the person asks for the code again at its next sign-in. */
|
|
82
|
+
declare function forgetTrustedBrowsers(apiBaseUrl: string): Promise<AuthResult>;
|
|
35
83
|
/**
|
|
36
84
|
* For a tool outside a browser, which keeps no cookies: signs in and returns a fetch that
|
|
37
85
|
* carries the session cookie and the origin the instance trusts on every request.
|
|
@@ -248,4 +296,4 @@ declare function listAll<Item>(readPage: (paging: {
|
|
|
248
296
|
nextCursor?: string;
|
|
249
297
|
}>): Promise<Item[]>;
|
|
250
298
|
|
|
251
|
-
export { AUTH_MOUNT_PATH, type ApiClient, type ApiClientFor, type ApiClientOptions, ApiError, type ApiOperationMethods, ApiResponseShapeError, type AuthResult, type AuthSession, type OperationInput, type OperationOutcome, completedOutput, createApiClient, createApiClientFor, getAuthSession, listAll, refusalError, signInForSessionFetch, signInWithEmail, signOut, transportError, unreadableResponseError };
|
|
299
|
+
export { AUTH_MOUNT_PATH, type ApiClient, type ApiClientFor, type ApiClientOptions, ApiError, type ApiOperationMethods, ApiResponseShapeError, type AuthResult, type AuthSession, type OperationInput, type OperationOutcome, type SecondFactorKind, type SignInResult, type TwoFactorSetup, completedOutput, createApiClient, createApiClientFor, forgetTrustedBrowsers, getAuthSession, listAll, refusalError, regenerateBackupCodes, signInForSessionFetch, signInWithEmail, signOut, startTwoFactorSetup, transportError, turnOffTwoFactor, unreadableResponseError, verifySecondFactor };
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,11 @@ var authFailureSchema = z.object({
|
|
|
10
10
|
message: z.string().optional(),
|
|
11
11
|
error: z.object({ message: z.string().optional() }).optional()
|
|
12
12
|
});
|
|
13
|
+
var signInAnswerSchema = z.object({ twoFactorRedirect: z.boolean().optional() });
|
|
14
|
+
var twoFactorSetupSchema = z.object({
|
|
15
|
+
totpURI: z.string(),
|
|
16
|
+
backupCodes: z.array(z.string())
|
|
17
|
+
});
|
|
13
18
|
async function getAuthSession(apiBaseUrl) {
|
|
14
19
|
const response = await fetch(authUrl(apiBaseUrl, "/get-session"), {
|
|
15
20
|
credentials: "include"
|
|
@@ -33,13 +38,64 @@ async function signInWithEmail(input) {
|
|
|
33
38
|
})
|
|
34
39
|
});
|
|
35
40
|
if (response.ok) {
|
|
36
|
-
|
|
41
|
+
const answer = signInAnswerSchema.safeParse(await response.json().catch(() => void 0));
|
|
42
|
+
return answer.data?.twoFactorRedirect === true ? { ok: true, secondFactor: true } : { ok: true };
|
|
37
43
|
}
|
|
44
|
+
return failureOf(response, "Sign in failed");
|
|
45
|
+
}
|
|
46
|
+
async function verifySecondFactor(input) {
|
|
47
|
+
const path = input.kind === "app" ? "/two-factor/verify-totp" : "/two-factor/verify-backup-code";
|
|
48
|
+
const response = await postAuth(input.apiBaseUrl, path, {
|
|
49
|
+
code: input.code.replaceAll(/\s/gu, ""),
|
|
50
|
+
trustDevice: input.trustBrowser === true
|
|
51
|
+
});
|
|
52
|
+
return response.ok ? { ok: true } : failureOf(response, "The code was not accepted");
|
|
53
|
+
}
|
|
54
|
+
async function startTwoFactorSetup(input) {
|
|
55
|
+
const response = await postAuth(input.apiBaseUrl, "/two-factor/enable", {
|
|
56
|
+
password: input.password
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
return failureOf(response, "Two-factor sign-in could not be set up");
|
|
60
|
+
}
|
|
61
|
+
const setup = twoFactorSetupSchema.parse(await response.json());
|
|
62
|
+
return { ok: true, setup: { totpUri: setup.totpURI, backupCodes: setup.backupCodes } };
|
|
63
|
+
}
|
|
64
|
+
async function turnOffTwoFactor(input) {
|
|
65
|
+
const response = await postAuth(input.apiBaseUrl, "/two-factor/disable", {
|
|
66
|
+
password: input.password
|
|
67
|
+
});
|
|
68
|
+
return response.ok ? { ok: true } : failureOf(response, "Two-factor sign-in stayed on");
|
|
69
|
+
}
|
|
70
|
+
async function regenerateBackupCodes(input) {
|
|
71
|
+
const response = await postAuth(input.apiBaseUrl, "/two-factor/generate-backup-codes", {
|
|
72
|
+
password: input.password
|
|
73
|
+
});
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
return failureOf(response, "No new backup codes were made");
|
|
76
|
+
}
|
|
77
|
+
const { backupCodes } = twoFactorSetupSchema.pick({ backupCodes: true }).parse(await response.json());
|
|
78
|
+
return { ok: true, backupCodes };
|
|
79
|
+
}
|
|
80
|
+
async function forgetTrustedBrowsers(apiBaseUrl) {
|
|
81
|
+
const response = await postAuth(apiBaseUrl, "/two-factor/forget-trusted-browsers", {});
|
|
82
|
+
return response.ok ? { ok: true } : failureOf(response, "The browsers are still trusted");
|
|
83
|
+
}
|
|
84
|
+
function postAuth(apiBaseUrl, path, body) {
|
|
85
|
+
return fetch(authUrl(apiBaseUrl, path), {
|
|
86
|
+
method: "POST",
|
|
87
|
+
credentials: "include",
|
|
88
|
+
headers: { "content-type": "application/json" },
|
|
89
|
+
body: JSON.stringify(body)
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async function failureOf(response, fallback) {
|
|
38
93
|
const failure = authFailureSchema.safeParse(await response.json().catch(() => void 0));
|
|
39
94
|
return {
|
|
40
95
|
ok: false,
|
|
96
|
+
status: response.status,
|
|
41
97
|
...failure.data?.code === void 0 ? {} : { code: failure.data.code },
|
|
42
|
-
message: failure.data?.message ?? failure.data?.error?.message ??
|
|
98
|
+
message: failure.data?.message ?? failure.data?.error?.message ?? fallback
|
|
43
99
|
};
|
|
44
100
|
}
|
|
45
101
|
async function signInForSessionFetch(input) {
|
|
@@ -52,6 +108,12 @@ async function signInForSessionFetch(input) {
|
|
|
52
108
|
if (!response.ok) {
|
|
53
109
|
throw new Error(`Sign-in as '${input.email}' was refused with status ${response.status}`);
|
|
54
110
|
}
|
|
111
|
+
const answer = signInAnswerSchema.safeParse(
|
|
112
|
+
await response.clone().json().catch(() => void 0)
|
|
113
|
+
);
|
|
114
|
+
if (answer.data?.twoFactorRedirect === true) {
|
|
115
|
+
throw new Error(`'${input.email}' signs in with a second factor; use an API key for this tool`);
|
|
116
|
+
}
|
|
55
117
|
const cookie = response.headers.getSetCookie().map((value) => value.split(";", 1)[0]).join("; ");
|
|
56
118
|
return (resource, init) => {
|
|
57
119
|
const request = new Request(resource, init);
|
|
@@ -433,12 +495,17 @@ export {
|
|
|
433
495
|
completedOutput,
|
|
434
496
|
createApiClient,
|
|
435
497
|
createApiClientFor,
|
|
498
|
+
forgetTrustedBrowsers,
|
|
436
499
|
getAuthSession,
|
|
437
500
|
listAll,
|
|
438
501
|
refusalError,
|
|
502
|
+
regenerateBackupCodes,
|
|
439
503
|
signInForSessionFetch,
|
|
440
504
|
signInWithEmail,
|
|
441
505
|
signOut,
|
|
506
|
+
startTwoFactorSetup,
|
|
442
507
|
transportError,
|
|
443
|
-
|
|
508
|
+
turnOffTwoFactor,
|
|
509
|
+
unreadableResponseError,
|
|
510
|
+
verifySecondFactor
|
|
444
511
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@work-shape/catalyst-api-client",
|
|
3
|
-
"version": "0.8.0-rc.
|
|
3
|
+
"version": "0.8.0-rc.11",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"zod": "4.4.3",
|
|
32
|
-
"@work-shape/catalyst-api-contract": "0.8.0-rc.
|
|
32
|
+
"@work-shape/catalyst-api-contract": "0.8.0-rc.11"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^24.13.1",
|