@shipfox/client-auth 4.0.0 → 6.0.1
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +56 -0
- package/dist/components/auth-guard.d.ts.map +1 -1
- package/dist/components/auth-guard.js +4 -4
- package/dist/components/auth-guard.js.map +1 -1
- package/dist/components/email-code-verification.d.ts.map +1 -1
- package/dist/components/email-code-verification.js +1 -1
- package/dist/components/email-code-verification.js.map +1 -1
- package/dist/components/redirect-target.d.ts +7 -0
- package/dist/components/redirect-target.d.ts.map +1 -1
- package/dist/components/redirect-target.js +35 -4
- package/dist/components/redirect-target.js.map +1 -1
- package/dist/components/workspace-switcher.stories.d.ts +1 -1
- package/dist/continuation.d.ts +1 -1
- package/dist/continuation.d.ts.map +1 -1
- package/dist/continuation.js +1 -1
- package/dist/continuation.js.map +1 -1
- package/dist/core/auth.d.ts +57 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +3 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/hooks/api/auth-mapper.d.ts +6 -0
- package/dist/hooks/api/auth-mapper.d.ts.map +1 -0
- package/dist/hooks/api/auth-mapper.js +25 -0
- package/dist/hooks/api/auth-mapper.js.map +1 -0
- package/dist/hooks/api/login-auth.d.ts +3 -28
- package/dist/hooks/api/login-auth.d.ts.map +1 -1
- package/dist/hooks/api/login-auth.js +7 -4
- package/dist/hooks/api/login-auth.js.map +1 -1
- package/dist/hooks/api/logout-auth.js +2 -2
- package/dist/hooks/api/logout-auth.js.map +1 -1
- package/dist/hooks/api/password-reset-auth.d.ts +5 -32
- package/dist/hooks/api/password-reset-auth.d.ts.map +1 -1
- package/dist/hooks/api/password-reset-auth.js +13 -7
- package/dist/hooks/api/password-reset-auth.js.map +1 -1
- package/dist/hooks/api/refresh-auth.d.ts +1 -1
- package/dist/hooks/api/refresh-auth.d.ts.map +1 -1
- package/dist/hooks/api/refresh-auth.js +1 -1
- package/dist/hooks/api/refresh-auth.js.map +1 -1
- package/dist/hooks/api/signup-auth.d.ts +2 -30
- package/dist/hooks/api/signup-auth.d.ts.map +1 -1
- package/dist/hooks/api/signup-auth.js +14 -4
- package/dist/hooks/api/signup-auth.js.map +1 -1
- package/dist/hooks/api/verify-email-auth.d.ts +4 -21
- package/dist/hooks/api/verify-email-auth.d.ts.map +1 -1
- package/dist/hooks/api/verify-email-auth.js +20 -7
- package/dist/hooks/api/verify-email-auth.js.map +1 -1
- package/dist/hooks/api/workspace-auth.d.ts +5 -21
- package/dist/hooks/api/workspace-auth.d.ts.map +1 -1
- package/dist/hooks/api/workspace-auth.js +11 -6
- package/dist/hooks/api/workspace-auth.js.map +1 -1
- package/dist/hooks/api/workspace-mapper.d.ts +4 -0
- package/dist/hooks/api/workspace-mapper.d.ts.map +1 -0
- package/dist/hooks/api/workspace-mapper.js +9 -0
- package/dist/hooks/api/workspace-mapper.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/pages/invitation-context.d.ts +9 -14
- package/dist/pages/invitation-context.d.ts.map +1 -1
- package/dist/pages/invitation-context.js +4 -27
- package/dist/pages/invitation-context.js.map +1 -1
- package/dist/pages/login-page.d.ts.map +1 -1
- package/dist/pages/login-page.js +5 -6
- package/dist/pages/login-page.js.map +1 -1
- package/dist/pages/logout-page.d.ts.map +1 -1
- package/dist/pages/logout-page.js +8 -18
- package/dist/pages/logout-page.js.map +1 -1
- package/dist/pages/password-reset-page.d.ts.map +1 -1
- package/dist/pages/password-reset-page.js +8 -10
- package/dist/pages/password-reset-page.js.map +1 -1
- package/dist/pages/signup-page.d.ts.map +1 -1
- package/dist/pages/signup-page.js +24 -18
- package/dist/pages/signup-page.js.map +1 -1
- package/dist/pages/workspace-onboarding-page.js +2 -2
- package/dist/pages/workspace-onboarding-page.js.map +1 -1
- package/dist/routes/inputs.d.ts +9 -0
- package/dist/routes/inputs.d.ts.map +1 -0
- package/dist/routes/inputs.js +17 -0
- package/dist/routes/inputs.js.map +1 -0
- package/dist/routes/login.d.ts +2 -0
- package/dist/routes/login.d.ts.map +1 -1
- package/dist/routes/login.js +2 -0
- package/dist/routes/login.js.map +1 -1
- package/dist/routes/logout.d.ts +2 -0
- package/dist/routes/logout.d.ts.map +1 -1
- package/dist/routes/logout.js +2 -0
- package/dist/routes/logout.js.map +1 -1
- package/dist/routes/reset.d.ts +2 -0
- package/dist/routes/reset.d.ts.map +1 -1
- package/dist/routes/reset.js +2 -0
- package/dist/routes/reset.js.map +1 -1
- package/dist/routes/signup.d.ts +2 -0
- package/dist/routes/signup.d.ts.map +1 -1
- package/dist/routes/signup.js +2 -0
- package/dist/routes/signup.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/src/components/auth-guard.tsx +4 -2
- package/src/components/email-code-verification.tsx +1 -1
- package/src/components/redirect-target.test.ts +32 -1
- package/src/components/redirect-target.ts +41 -4
- package/src/continuation.ts +1 -1
- package/src/core/auth.ts +55 -0
- package/src/hooks/api/auth-mapper.test.ts +77 -0
- package/src/hooks/api/auth-mapper.ts +29 -0
- package/src/hooks/api/login-auth.test.ts +1 -1
- package/src/hooks/api/login-auth.ts +10 -4
- package/src/hooks/api/logout-auth.ts +2 -2
- package/src/hooks/api/password-reset-auth.test.ts +3 -3
- package/src/hooks/api/password-reset-auth.ts +19 -13
- package/src/hooks/api/refresh-auth.ts +1 -0
- package/src/hooks/api/signup-auth.ts +15 -4
- package/src/hooks/api/verify-email-auth.ts +32 -16
- package/src/hooks/api/workspace-auth.ts +16 -6
- package/src/hooks/api/workspace-mapper.test.ts +21 -0
- package/src/hooks/api/workspace-mapper.ts +6 -0
- package/src/index.ts +0 -1
- package/src/pages/invitation-context.ts +8 -31
- package/src/pages/login-page.test.tsx +1 -1
- package/src/pages/login-page.tsx +5 -4
- package/src/pages/logout-page.test.tsx +75 -0
- package/src/pages/logout-page.tsx +9 -13
- package/src/pages/password-reset-page.tsx +5 -8
- package/src/pages/signup-page.test.tsx +1 -1
- package/src/pages/signup-page.tsx +22 -16
- package/src/pages/workspace-onboarding-page.tsx +2 -2
- package/src/routes/inputs.test.ts +17 -0
- package/src/routes/inputs.ts +21 -0
- package/src/routes/login.tsx +2 -0
- package/src/routes/logout.tsx +2 -1
- package/src/routes/reset.tsx +2 -0
- package/src/routes/signup.tsx +2 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/vercel.json +5 -0
- package/dist/components/auth-shell.d.ts +0 -13
- package/dist/components/auth-shell.d.ts.map +0 -1
- package/dist/components/auth-shell.js +0 -68
- package/dist/components/auth-shell.js.map +0 -1
- package/src/components/auth-shell.tsx +0 -68
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/password-reset-auth.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/password-reset-auth.ts"],"sourcesContent":["import {passwordResetConfirmResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {PasswordResetConfirmCommand, PasswordResetRequestCommand} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nexport async function requestPasswordReset(command: PasswordResetRequestCommand) {\n await checkedApiRequest(emptyResponseSchema, '/auth/password-reset', {\n method: 'POST',\n body: command,\n });\n}\n\nexport async function confirmPasswordReset(command: PasswordResetConfirmCommand) {\n const response = await checkedApiRequest(\n passwordResetConfirmResponseSchema,\n '/auth/password-reset/confirm',\n {\n method: 'POST',\n body: {token: command.token, new_password: command.newPassword},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nexport function useRequestPasswordResetAuth() {\n return useMutation({mutationFn: requestPasswordReset});\n}\n\nexport function useConfirmPasswordResetAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: confirmPasswordReset,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["passwordResetConfirmResponseSchema","checkedApiRequest","emptyResponseSchema","useMutation","useAuthTransition","toAuthenticatedSession","requestPasswordReset","command","method","body","confirmPasswordReset","response","token","new_password","newPassword","useRequestPasswordResetAuth","mutationFn","useConfirmPasswordResetAuth","enterAuthenticated","onSuccess"],"mappings":"AAAA,SAAQA,kCAAkC,QAAO,wBAAwB;AACzE,SAAQC,iBAAiB,EAAEC,mBAAmB,QAAO,sBAAsB;AAC3E,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,OAAO,eAAeC,qBAAqBC,OAAoC;IAC7E,MAAMN,kBAAkBC,qBAAqB,wBAAwB;QACnEM,QAAQ;QACRC,MAAMF;IACR;AACF;AAEA,OAAO,eAAeG,qBAAqBH,OAAoC;IAC7E,MAAMI,WAAW,MAAMV,kBACrBD,oCACA,gCACA;QACEQ,QAAQ;QACRC,MAAM;YAACG,OAAOL,QAAQK,KAAK;YAAEC,cAAcN,QAAQO,WAAW;QAAA;IAChE;IAEF,OAAOT,uBAAuBM;AAChC;AAEA,OAAO,SAASI;IACd,OAAOZ,YAAY;QAACa,YAAYV;IAAoB;AACtD;AAEA,OAAO,SAASW;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGd;IAE7B,OAAOD,YAAY;QACjBa,YAAYN;QACZS,WAAWD;IACb;AACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { authRefreshQueryKey, getAuthRefreshDelayMs, useRefreshAuth, } from '@shipfox/client-shell/runtime';
|
|
1
|
+
export { authRefreshQueryKey, authRefreshQueryOptions, getAuthRefreshDelayMs, useRefreshAuth, } from '@shipfox/client-shell/runtime';
|
|
2
2
|
//# sourceMappingURL=refresh-auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/refresh-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"refresh-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/refresh-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,GACf,MAAM,+BAA+B,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { authRefreshQueryKey, getAuthRefreshDelayMs, useRefreshAuth } from '@shipfox/client-shell/runtime';
|
|
1
|
+
export { authRefreshQueryKey, authRefreshQueryOptions, getAuthRefreshDelayMs, useRefreshAuth } from '@shipfox/client-shell/runtime';
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=refresh-auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/refresh-auth.ts"],"sourcesContent":["export {\n authRefreshQueryKey,\n getAuthRefreshDelayMs,\n useRefreshAuth,\n} from '@shipfox/client-shell/runtime';\n"],"names":["authRefreshQueryKey","getAuthRefreshDelayMs","useRefreshAuth"],"mappings":"AAAA,SACEA,mBAAmB,EACnBC,qBAAqB,EACrBC,cAAc,QACT,gCAAgC"}
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/refresh-auth.ts"],"sourcesContent":["export {\n authRefreshQueryKey,\n authRefreshQueryOptions,\n getAuthRefreshDelayMs,\n useRefreshAuth,\n} from '@shipfox/client-shell/runtime';\n"],"names":["authRefreshQueryKey","authRefreshQueryOptions","getAuthRefreshDelayMs","useRefreshAuth"],"mappings":"AAAA,SACEA,mBAAmB,EACnBC,uBAAuB,EACvBC,qBAAqB,EACrBC,cAAc,QACT,gCAAgC"}
|
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
id: string;
|
|
4
|
-
email: string;
|
|
5
|
-
name: string | null;
|
|
6
|
-
email_verified_at: string | null;
|
|
7
|
-
status: "active" | "suspended" | "deleted";
|
|
8
|
-
created_at: string;
|
|
9
|
-
updated_at: string;
|
|
10
|
-
};
|
|
11
|
-
email_challenge?: {
|
|
12
|
-
id: string;
|
|
13
|
-
next_resend_available_at: string;
|
|
14
|
-
} | undefined;
|
|
15
|
-
token?: string | undefined;
|
|
16
|
-
membership?: {
|
|
17
|
-
id: string;
|
|
18
|
-
user_id: string;
|
|
19
|
-
workspace_id: string;
|
|
20
|
-
} | null | undefined;
|
|
21
|
-
accept_error?: {
|
|
22
|
-
code: string;
|
|
23
|
-
message: string;
|
|
24
|
-
} | undefined;
|
|
25
|
-
}, Error, {
|
|
26
|
-
email: string;
|
|
27
|
-
password: string;
|
|
28
|
-
name: string;
|
|
29
|
-
invitation_token?: string | undefined;
|
|
30
|
-
}, unknown>;
|
|
1
|
+
import type { SignupCommand } from '#core/auth.js';
|
|
2
|
+
export declare function useSignupAuth(): import("@tanstack/react-query").UseMutationResult<import("#core/auth.js").SignupResult, Error, SignupCommand, unknown>;
|
|
31
3
|
//# sourceMappingURL=signup-auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signup-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/signup-auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signup-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/signup-auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,eAAe,CAAC;AAgBjD,wBAAgB,aAAa,2HAE5B"}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { signupResponseSchema } from '@shipfox/api-auth-dto';
|
|
2
|
+
import { checkedApiRequest } from '@shipfox/client-api';
|
|
2
3
|
import { useMutation } from '@tanstack/react-query';
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
import { toSignupResult } from './auth-mapper.js';
|
|
5
|
+
async function signupAuth(command) {
|
|
6
|
+
const response = await checkedApiRequest(signupResponseSchema, '/auth/signup', {
|
|
5
7
|
method: 'POST',
|
|
6
|
-
body
|
|
8
|
+
body: {
|
|
9
|
+
email: command.email,
|
|
10
|
+
password: command.password,
|
|
11
|
+
name: command.name,
|
|
12
|
+
...command.invitationToken ? {
|
|
13
|
+
invitation_token: command.invitationToken
|
|
14
|
+
} : {}
|
|
15
|
+
}
|
|
7
16
|
});
|
|
17
|
+
return toSignupResult(response);
|
|
8
18
|
}
|
|
9
19
|
export function useSignupAuth() {
|
|
10
20
|
return useMutation({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/signup-auth.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/signup-auth.ts"],"sourcesContent":["import {signupResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {SignupCommand} from '#core/auth.js';\nimport {toSignupResult} from './auth-mapper.js';\n\nasync function signupAuth(command: SignupCommand) {\n const response = await checkedApiRequest(signupResponseSchema, '/auth/signup', {\n method: 'POST',\n body: {\n email: command.email,\n password: command.password,\n name: command.name,\n ...(command.invitationToken ? {invitation_token: command.invitationToken} : {}),\n },\n });\n return toSignupResult(response);\n}\n\nexport function useSignupAuth() {\n return useMutation({mutationFn: signupAuth});\n}\n"],"names":["signupResponseSchema","checkedApiRequest","useMutation","toSignupResult","signupAuth","command","response","method","body","email","password","name","invitationToken","invitation_token","useSignupAuth","mutationFn"],"mappings":"AAAA,SAAQA,oBAAoB,QAAO,wBAAwB;AAC3D,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,cAAc,QAAO,mBAAmB;AAEhD,eAAeC,WAAWC,OAAsB;IAC9C,MAAMC,WAAW,MAAML,kBAAkBD,sBAAsB,gBAAgB;QAC7EO,QAAQ;QACRC,MAAM;YACJC,OAAOJ,QAAQI,KAAK;YACpBC,UAAUL,QAAQK,QAAQ;YAC1BC,MAAMN,QAAQM,IAAI;YAClB,GAAIN,QAAQO,eAAe,GAAG;gBAACC,kBAAkBR,QAAQO,eAAe;YAAA,IAAI,CAAC,CAAC;QAChF;IACF;IACA,OAAOT,eAAeG;AACxB;AAEA,OAAO,SAASQ;IACd,OAAOZ,YAAY;QAACa,YAAYX;IAAU;AAC5C"}
|
|
@@ -1,23 +1,6 @@
|
|
|
1
|
+
import type { ResendEmailVerificationCommand, VerifyEmailCommand } from '#core/auth.js';
|
|
1
2
|
export declare function useResendEmailVerificationAuth(): import("@tanstack/react-query").UseMutationResult<{
|
|
2
|
-
|
|
3
|
-
}, Error,
|
|
4
|
-
|
|
5
|
-
challenge_id: string;
|
|
6
|
-
}, unknown>;
|
|
7
|
-
export declare function useVerifyEmailAuth(): import("@tanstack/react-query").UseMutationResult<{
|
|
8
|
-
token: string;
|
|
9
|
-
user: {
|
|
10
|
-
id: string;
|
|
11
|
-
email: string;
|
|
12
|
-
name: string | null;
|
|
13
|
-
email_verified_at: string | null;
|
|
14
|
-
status: "active" | "suspended" | "deleted";
|
|
15
|
-
created_at: string;
|
|
16
|
-
updated_at: string;
|
|
17
|
-
};
|
|
18
|
-
}, Error, {
|
|
19
|
-
email: string;
|
|
20
|
-
challenge_id: string;
|
|
21
|
-
code: string;
|
|
22
|
-
}, unknown>;
|
|
3
|
+
nextResendAvailableAt: string;
|
|
4
|
+
}, Error, ResendEmailVerificationCommand, unknown>;
|
|
5
|
+
export declare function useVerifyEmailAuth(): import("@tanstack/react-query").UseMutationResult<import("@shipfox/client-shell/runtime").AuthenticatedSession, Error, VerifyEmailCommand, unknown>;
|
|
23
6
|
//# sourceMappingURL=verify-email-auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify-email-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/verify-email-auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verify-email-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/verify-email-auth.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,8BAA8B,EAC9B,kBAAkB,EACnB,MAAM,eAAe,CAAC;AA8BvB,wBAAgB,8BAA8B;;mDAE7C;AAED,wBAAgB,kBAAkB,wJAOjC"}
|
|
@@ -1,17 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { verifyEmailConfirmResponseSchema, verifyEmailResendResponseSchema } from '@shipfox/api-auth-dto';
|
|
2
|
+
import { checkedApiRequest } from '@shipfox/client-api';
|
|
2
3
|
import { useMutation } from '@tanstack/react-query';
|
|
3
4
|
import { useAuthTransition } from '#state/auth.js';
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import { toAuthenticatedSession } from './auth-mapper.js';
|
|
6
|
+
async function verifyEmailAuth(command) {
|
|
7
|
+
const response = await checkedApiRequest(verifyEmailConfirmResponseSchema, '/auth/verify-email/confirm', {
|
|
6
8
|
method: 'POST',
|
|
7
|
-
body
|
|
9
|
+
body: {
|
|
10
|
+
email: command.email,
|
|
11
|
+
challenge_id: command.challengeId,
|
|
12
|
+
code: command.code
|
|
13
|
+
}
|
|
8
14
|
});
|
|
15
|
+
return toAuthenticatedSession(response);
|
|
9
16
|
}
|
|
10
|
-
async function resendEmailVerificationAuth(
|
|
11
|
-
|
|
17
|
+
async function resendEmailVerificationAuth(command) {
|
|
18
|
+
const response = await checkedApiRequest(verifyEmailResendResponseSchema, '/auth/verify-email/resend', {
|
|
12
19
|
method: 'POST',
|
|
13
|
-
body
|
|
20
|
+
body: {
|
|
21
|
+
email: command.email,
|
|
22
|
+
challenge_id: command.challengeId
|
|
23
|
+
}
|
|
14
24
|
});
|
|
25
|
+
return {
|
|
26
|
+
nextResendAvailableAt: response.next_resend_available_at
|
|
27
|
+
};
|
|
15
28
|
}
|
|
16
29
|
export function useResendEmailVerificationAuth() {
|
|
17
30
|
return useMutation({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/verify-email-auth.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/verify-email-auth.ts"],"sourcesContent":["import {\n verifyEmailConfirmResponseSchema,\n verifyEmailResendResponseSchema,\n} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {\n EmailVerificationResendResult,\n ResendEmailVerificationCommand,\n VerifyEmailCommand,\n} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nasync function verifyEmailAuth(command: VerifyEmailCommand) {\n const response = await checkedApiRequest(\n verifyEmailConfirmResponseSchema,\n '/auth/verify-email/confirm',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId, code: command.code},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nasync function resendEmailVerificationAuth(command: ResendEmailVerificationCommand) {\n const response = await checkedApiRequest(\n verifyEmailResendResponseSchema,\n '/auth/verify-email/resend',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId},\n },\n );\n return {\n nextResendAvailableAt: response.next_resend_available_at,\n } satisfies EmailVerificationResendResult;\n}\n\nexport function useResendEmailVerificationAuth() {\n return useMutation({mutationFn: resendEmailVerificationAuth});\n}\n\nexport function useVerifyEmailAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: verifyEmailAuth,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["verifyEmailConfirmResponseSchema","verifyEmailResendResponseSchema","checkedApiRequest","useMutation","useAuthTransition","toAuthenticatedSession","verifyEmailAuth","command","response","method","body","email","challenge_id","challengeId","code","resendEmailVerificationAuth","nextResendAvailableAt","next_resend_available_at","useResendEmailVerificationAuth","mutationFn","useVerifyEmailAuth","enterAuthenticated","onSuccess"],"mappings":"AAAA,SACEA,gCAAgC,EAChCC,+BAA+B,QAC1B,wBAAwB;AAC/B,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAMlD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,eAAeC,gBAAgBC,OAA2B;IACxD,MAAMC,WAAW,MAAMN,kBACrBF,kCACA,8BACA;QACES,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;YAAEC,MAAMP,QAAQO,IAAI;QAAA;IACpF;IAEF,OAAOT,uBAAuBG;AAChC;AAEA,eAAeO,4BAA4BR,OAAuC;IAChF,MAAMC,WAAW,MAAMN,kBACrBD,iCACA,6BACA;QACEQ,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;QAAA;IAChE;IAEF,OAAO;QACLG,uBAAuBR,SAASS,wBAAwB;IAC1D;AACF;AAEA,OAAO,SAASC;IACd,OAAOf,YAAY;QAACgB,YAAYJ;IAA2B;AAC7D;AAEA,OAAO,SAASK;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGjB;IAE7B,OAAOD,YAAY;QACjBgB,YAAYb;QACZgB,WAAWD;IACb;AACF"}
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
export declare function createWorkspace(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
status: "active" | "suspended" | "deleted";
|
|
7
|
-
settings: Record<string, unknown>;
|
|
8
|
-
created_at: string;
|
|
9
|
-
updated_at: string;
|
|
10
|
-
}>;
|
|
11
|
-
export { listUserWorkspaces, userWorkspacesQueryKey };
|
|
12
|
-
export declare function useCreateWorkspaceAuth(): import("@tanstack/react-query").UseMutationResult<{
|
|
13
|
-
id: string;
|
|
14
|
-
name: string;
|
|
15
|
-
status: "active" | "suspended" | "deleted";
|
|
16
|
-
settings: Record<string, unknown>;
|
|
17
|
-
created_at: string;
|
|
18
|
-
updated_at: string;
|
|
19
|
-
}, Error, {
|
|
20
|
-
name: string;
|
|
21
|
-
}, unknown>;
|
|
1
|
+
import { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions } from '@shipfox/client-shell/runtime';
|
|
2
|
+
import type { WorkspaceCreateCommand } from '#core/auth.js';
|
|
3
|
+
export declare function createWorkspace(command: WorkspaceCreateCommand): Promise<import("#core/auth.js").Workspace>;
|
|
4
|
+
export { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions };
|
|
5
|
+
export declare function useCreateWorkspaceAuth(): import("@tanstack/react-query").UseMutationResult<import("#core/auth.js").Workspace, Error, WorkspaceCreateCommand, unknown>;
|
|
22
6
|
//# sourceMappingURL=workspace-auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workspace-auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workspace-auth.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,eAAe,CAAC;AAI1D,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,8CAMpE;AAED,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAE,0BAA0B,EAAC,CAAC;AAEhF,wBAAgB,sBAAsB,iIAYrC"}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { workspaceResponseSchema } from '@shipfox/api-workspaces-dto';
|
|
2
|
+
import { checkedApiRequest } from '@shipfox/client-api';
|
|
3
|
+
import { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions } from '@shipfox/client-shell/runtime';
|
|
3
4
|
import { useMutation } from '@tanstack/react-query';
|
|
4
5
|
import { useRefreshAuth } from './refresh-auth.js';
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
import { toWorkspace } from './workspace-mapper.js';
|
|
7
|
+
export async function createWorkspace(command) {
|
|
8
|
+
const response = await checkedApiRequest(workspaceResponseSchema, '/workspaces', {
|
|
7
9
|
method: 'POST',
|
|
8
|
-
body
|
|
10
|
+
body: {
|
|
11
|
+
name: command.name
|
|
12
|
+
}
|
|
9
13
|
});
|
|
14
|
+
return toWorkspace(response);
|
|
10
15
|
}
|
|
11
|
-
export { listUserWorkspaces, userWorkspacesQueryKey };
|
|
16
|
+
export { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions };
|
|
12
17
|
export function useCreateWorkspaceAuth() {
|
|
13
18
|
const refreshAuth = useRefreshAuth();
|
|
14
19
|
return useMutation({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/workspace-auth.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/workspace-auth.ts"],"sourcesContent":["import {workspaceResponseSchema} from '@shipfox/api-workspaces-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {\n listUserWorkspaces,\n userWorkspacesQueryKey,\n userWorkspacesQueryOptions,\n} from '@shipfox/client-shell/runtime';\nimport {useMutation} from '@tanstack/react-query';\nimport type {WorkspaceCreateCommand} from '#core/auth.js';\nimport {useRefreshAuth} from './refresh-auth.js';\nimport {toWorkspace} from './workspace-mapper.js';\n\nexport async function createWorkspace(command: WorkspaceCreateCommand) {\n const response = await checkedApiRequest(workspaceResponseSchema, '/workspaces', {\n method: 'POST',\n body: {name: command.name},\n });\n return toWorkspace(response);\n}\n\nexport {listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions};\n\nexport function useCreateWorkspaceAuth() {\n const refreshAuth = useRefreshAuth();\n\n return useMutation({\n mutationFn: createWorkspace,\n onSuccess: async () => {\n // The new workspace introduces a membership the existing access token\n // doesn't carry. Refresh so the next request includes it in the JWT\n // claim and passes the in-memory canAccess() check on the server.\n await refreshAuth();\n },\n });\n}\n"],"names":["workspaceResponseSchema","checkedApiRequest","listUserWorkspaces","userWorkspacesQueryKey","userWorkspacesQueryOptions","useMutation","useRefreshAuth","toWorkspace","createWorkspace","command","response","method","body","name","useCreateWorkspaceAuth","refreshAuth","mutationFn","onSuccess"],"mappings":"AAAA,SAAQA,uBAAuB,QAAO,8BAA8B;AACpE,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SACEC,kBAAkB,EAClBC,sBAAsB,EACtBC,0BAA0B,QACrB,gCAAgC;AACvC,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,cAAc,QAAO,oBAAoB;AACjD,SAAQC,WAAW,QAAO,wBAAwB;AAElD,OAAO,eAAeC,gBAAgBC,OAA+B;IACnE,MAAMC,WAAW,MAAMT,kBAAkBD,yBAAyB,eAAe;QAC/EW,QAAQ;QACRC,MAAM;YAACC,MAAMJ,QAAQI,IAAI;QAAA;IAC3B;IACA,OAAON,YAAYG;AACrB;AAEA,SAAQR,kBAAkB,EAAEC,sBAAsB,EAAEC,0BAA0B,GAAE;AAEhF,OAAO,SAASU;IACd,MAAMC,cAAcT;IAEpB,OAAOD,YAAY;QACjBW,YAAYR;QACZS,WAAW;YACT,sEAAsE;YACtE,oEAAoE;YACpE,kEAAkE;YAClE,MAAMF;QACR;IACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workspace-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAE7C,wBAAgB,WAAW,CAAC,GAAG,EAAE,oBAAoB,GAAG,SAAS,CAEhE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/workspace-mapper.ts"],"sourcesContent":["import type {WorkspaceResponseDto} from '@shipfox/api-workspaces-dto';\nimport type {Workspace} from '#core/auth.js';\n\nexport function toWorkspace(dto: WorkspaceResponseDto): Workspace {\n return {id: dto.id, name: dto.name, status: dto.status};\n}\n"],"names":["toWorkspace","dto","id","name","status"],"mappings":"AAGA,OAAO,SAASA,YAAYC,GAAyB;IACnD,OAAO;QAACC,IAAID,IAAIC,EAAE;QAAEC,MAAMF,IAAIE,IAAI;QAAEC,QAAQH,IAAIG,MAAM;IAAA;AACxD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './components/auth-guard.js';
|
|
2
2
|
export * from './components/auth-provider.js';
|
|
3
|
-
export * from './components/auth-shell.js';
|
|
4
3
|
export { WorkspaceCrumb, type WorkspaceCrumbProps } from './components/workspace-crumb.js';
|
|
5
4
|
export { WorkspaceSwitcher, type WorkspaceSwitcherProps } from './components/workspace-switcher.js';
|
|
6
5
|
export * from './hooks/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,OAAO,EAAC,cAAc,EAAE,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAC,iBAAiB,EAAE,KAAK,sBAAsB,EAAC,MAAM,oCAAoC,CAAC;AAClG,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,2BAA2B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './components/auth-guard.js';
|
|
2
2
|
export * from './components/auth-provider.js';
|
|
3
|
-
export * from './components/auth-shell.js';
|
|
4
3
|
export { WorkspaceCrumb } from './components/workspace-crumb.js';
|
|
5
4
|
export { WorkspaceSwitcher } from './components/workspace-switcher.js';
|
|
6
5
|
export * from './hooks/index.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './components/auth-guard.js';\nexport * from './components/auth-provider.js';\nexport
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './components/auth-guard.js';\nexport * from './components/auth-provider.js';\nexport {WorkspaceCrumb, type WorkspaceCrumbProps} from './components/workspace-crumb.js';\nexport {WorkspaceSwitcher, type WorkspaceSwitcherProps} from './components/workspace-switcher.js';\nexport * from './hooks/index.js';\nexport * from './pages/login-page.js';\nexport * from './pages/logout-page.js';\nexport * from './pages/password-reset-page.js';\nexport * from './pages/signup-page.js';\nexport * from './pages/workspace-onboarding-page.js';\nexport * from './state/auth.js';\nexport {\n getLastWorkspaceId,\n lastWorkspaceIdAtom,\n rememberLastWorkspaceId,\n} from './state/last-workspace.js';\n"],"names":["WorkspaceCrumb","WorkspaceSwitcher","getLastWorkspaceId","lastWorkspaceIdAtom","rememberLastWorkspaceId"],"mappings":"AAAA,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AAC9C,SAAQA,cAAc,QAAiC,kCAAkC;AACzF,SAAQC,iBAAiB,QAAoC,qCAAqC;AAClG,cAAc,mBAAmB;AACjC,cAAc,wBAAwB;AACtC,cAAc,yBAAyB;AACvC,cAAc,iCAAiC;AAC/C,cAAc,yBAAyB;AACvC,cAAc,uCAAuC;AACrD,cAAc,kBAAkB;AAChC,SACEC,kBAAkB,EAClBC,mBAAmB,EACnBC,uBAAuB,QAClB,4BAA4B"}
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type InvitationPreview, pendingInvitation } from '@shipfox/client-invitations';
|
|
2
2
|
export declare function extractInvitationToken(redirect: unknown): string | undefined;
|
|
3
|
-
export declare function pendingInvitation(data: PreviewInvitationResponseDto | undefined): PreviewInvitationPendingDto | undefined;
|
|
4
|
-
/**
|
|
5
|
-
* Mirrors the hook in `@shipfox/client-invitations` but lives in `client-auth`
|
|
6
|
-
* to avoid a circular dependency. Signup/login pages call this to lock the
|
|
7
|
-
* email field when arriving from an invitation link.
|
|
8
|
-
*/
|
|
9
3
|
export declare function useInvitationContext(token: string | undefined): import("@tanstack/react-query").UseQueryResult<NoInfer<{
|
|
10
4
|
status: "pending";
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
workspaceId: string;
|
|
6
|
+
workspaceName: string;
|
|
13
7
|
email: string;
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
invitedByDisplay?: string;
|
|
9
|
+
expiresAt: string;
|
|
16
10
|
} | {
|
|
17
11
|
status: "expired";
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
workspaceName: string;
|
|
13
|
+
expiresAt: string;
|
|
20
14
|
} | {
|
|
21
15
|
status: "already_used";
|
|
22
|
-
|
|
16
|
+
workspaceName: string;
|
|
23
17
|
} | {
|
|
24
18
|
status: "invalid";
|
|
25
19
|
}>, Error>;
|
|
20
|
+
export { type InvitationPreview, pendingInvitation };
|
|
26
21
|
//# sourceMappingURL=invitation-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invitation-context.d.ts","sourceRoot":"","sources":["../../src/pages/invitation-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"invitation-context.d.ts","sourceRoot":"","sources":["../../src/pages/invitation-context.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,iBAAiB,EAElB,MAAM,6BAA6B,CAAC;AAGrC,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE5E;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;WAE7D;AAED,OAAO,EAAC,KAAK,iBAAiB,EAAE,iBAAiB,EAAC,CAAC"}
|
|
@@ -1,34 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useQuery } from '@tanstack/react-query';
|
|
1
|
+
import { pendingInvitation, usePreviewInvitation } from '@shipfox/client-invitations';
|
|
3
2
|
import { parseRedirectContext } from '#/components/redirect-context.js';
|
|
4
3
|
export function extractInvitationToken(redirect) {
|
|
5
4
|
return parseRedirectContext(redirect).invitationToken;
|
|
6
5
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
token
|
|
10
|
-
});
|
|
11
|
-
return await apiRequest(`/invitations/preview?${params.toString()}`);
|
|
12
|
-
}
|
|
13
|
-
export function pendingInvitation(data) {
|
|
14
|
-
return data?.status === 'pending' ? data : undefined;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Mirrors the hook in `@shipfox/client-invitations` but lives in `client-auth`
|
|
18
|
-
* to avoid a circular dependency. Signup/login pages call this to lock the
|
|
19
|
-
* email field when arriving from an invitation link.
|
|
20
|
-
*/ export function useInvitationContext(token) {
|
|
21
|
-
return useQuery({
|
|
22
|
-
queryKey: [
|
|
23
|
-
'invitations',
|
|
24
|
-
'preview',
|
|
25
|
-
token ?? ''
|
|
26
|
-
],
|
|
27
|
-
queryFn: ()=>fetchPreview(token),
|
|
28
|
-
enabled: Boolean(token),
|
|
29
|
-
retry: false,
|
|
30
|
-
staleTime: 30_000
|
|
31
|
-
});
|
|
6
|
+
export function useInvitationContext(token) {
|
|
7
|
+
return usePreviewInvitation(token);
|
|
32
8
|
}
|
|
9
|
+
export { pendingInvitation };
|
|
33
10
|
|
|
34
11
|
//# sourceMappingURL=invitation-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/invitation-context.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../src/pages/invitation-context.ts"],"sourcesContent":["import {\n type InvitationPreview,\n pendingInvitation,\n usePreviewInvitation,\n} from '@shipfox/client-invitations';\nimport {parseRedirectContext} from '#/components/redirect-context.js';\n\nexport function extractInvitationToken(redirect: unknown): string | undefined {\n return parseRedirectContext(redirect).invitationToken;\n}\n\nexport function useInvitationContext(token: string | undefined) {\n return usePreviewInvitation(token);\n}\n\nexport {type InvitationPreview, pendingInvitation};\n"],"names":["pendingInvitation","usePreviewInvitation","parseRedirectContext","extractInvitationToken","redirect","invitationToken","useInvitationContext","token"],"mappings":"AAAA,SAEEA,iBAAiB,EACjBC,oBAAoB,QACf,8BAA8B;AACrC,SAAQC,oBAAoB,QAAO,mCAAmC;AAEtE,OAAO,SAASC,uBAAuBC,QAAiB;IACtD,OAAOF,qBAAqBE,UAAUC,eAAe;AACvD;AAEA,OAAO,SAASC,qBAAqBC,KAAyB;IAC5D,OAAON,qBAAqBM;AAC9B;AAEA,SAAgCP,iBAAiB,GAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-page.d.ts","sourceRoot":"","sources":["../../src/pages/login-page.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login-page.d.ts","sourceRoot":"","sources":["../../src/pages/login-page.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,SAAS,gCAmKxB"}
|
package/dist/pages/login-page.js
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { loginBodySchema } from '@shipfox/api-auth-dto';
|
|
3
|
+
import { AuthShell, useRouteSearch } from '@shipfox/client-shell/runtime';
|
|
3
4
|
import { Button, ButtonLink } from '@shipfox/react-ui/button';
|
|
4
5
|
import { Callout } from '@shipfox/react-ui/callout';
|
|
5
6
|
import { FormField, FormFieldInput, fieldError } from '@shipfox/react-ui/form-field';
|
|
6
7
|
import { Icon } from '@shipfox/react-ui/icon';
|
|
7
8
|
import { Text } from '@shipfox/react-ui/typography';
|
|
8
9
|
import { useForm } from '@tanstack/react-form';
|
|
9
|
-
import { Link
|
|
10
|
+
import { Link } from '@tanstack/react-router';
|
|
10
11
|
import { useAtom } from 'jotai';
|
|
11
12
|
import { useEffect, useRef, useState } from 'react';
|
|
12
|
-
import { AuthShell } from '#/components/auth-shell.js';
|
|
13
13
|
import { useLoginAuth } from '#hooks/api/login-auth.js';
|
|
14
14
|
import { authFormDraftAtom, initialAuthFormDraft } from '#state/auth.js';
|
|
15
|
+
import { validateRedirectSearch } from '../routes/inputs.js';
|
|
15
16
|
import { loginErrorToFormError } from './form-errors.js';
|
|
16
17
|
import { extractInvitationToken, pendingInvitation, useInvitationContext } from './invitation-context.js';
|
|
17
18
|
export function LoginPage() {
|
|
18
19
|
const login = useLoginAuth();
|
|
19
|
-
const search =
|
|
20
|
-
strict: false
|
|
21
|
-
});
|
|
20
|
+
const search = useRouteSearch(validateRedirectSearch);
|
|
22
21
|
const invitationToken = extractInvitationToken(search.redirect);
|
|
23
22
|
const invitationPreview = useInvitationContext(invitationToken);
|
|
24
23
|
const invitationPending = pendingInvitation(invitationPreview.data);
|
|
@@ -91,7 +90,7 @@ export function LoginPage() {
|
|
|
91
90
|
]);
|
|
92
91
|
const isInvitationEmailLocked = Boolean(invitationPending);
|
|
93
92
|
const invitationRedirect = invitationToken ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}` : undefined;
|
|
94
|
-
const headerTitle = invitationPending ? `Join ${invitationPending.
|
|
93
|
+
const headerTitle = invitationPending ? `Join ${invitationPending.workspaceName}` : 'Connect to Shipfox';
|
|
95
94
|
const headerDescription = invitationPending ? 'Log in to accept your invitation.' : 'Log in to access Shipfox.';
|
|
96
95
|
function persistDraft() {
|
|
97
96
|
const { email, password } = form.state.values;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/login-page.tsx"],"sourcesContent":["import {loginBodySchema} from '@shipfox/api-auth-dto';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {Link, useSearch} from '@tanstack/react-router';\nimport {useAtom} from 'jotai';\nimport {useEffect, useRef, useState} from 'react';\nimport {AuthShell} from '#/components/auth-shell.js';\nimport {useLoginAuth} from '#hooks/api/login-auth.js';\nimport {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';\nimport {loginErrorToFormError} from './form-errors.js';\nimport {\n extractInvitationToken,\n pendingInvitation,\n useInvitationContext,\n} from './invitation-context.js';\n\nexport function LoginPage() {\n const login = useLoginAuth();\n const search = useSearch({strict: false}) as {redirect?: unknown};\n const invitationToken = extractInvitationToken(search.redirect);\n const invitationPreview = useInvitationContext(invitationToken);\n const invitationPending = pendingInvitation(invitationPreview.data);\n const [authFormDraft, setAuthFormDraft] = useAtom(authFormDraftAtom);\n const [formError, setFormError] = useState<string | undefined>();\n const draftRef = useRef(authFormDraft);\n draftRef.current = authFormDraft;\n // Set just before clearing the draft on success so the unmount cleanup\n // below does not repersist the just-submitted credentials.\n const skipDraftPersistRef = useRef(false);\n\n const form = useForm({\n defaultValues: {email: authFormDraft.email, password: authFormDraft.password},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await login.mutateAsync(value);\n skipDraftPersistRef.current = true;\n setAuthFormDraft(initialAuthFormDraft);\n } catch (error) {\n const mapped = loginErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n // Lock the email field when arriving from an invitation link so the user\n // can't log in as a different account than the one the invitation targets.\n useEffect(() => {\n if (invitationPending && form.state.values.email !== invitationPending.email) {\n form.setFieldValue('email', invitationPending.email);\n setAuthFormDraft((current) => ({...current, email: invitationPending.email}));\n }\n }, [invitationPending, form, setAuthFormDraft]);\n\n // Sync TanStack Form values back into the Jotai draft on unmount so a\n // navigation to /signup or /reset preserves what the user typed. Skipped\n // after a successful login because we just intentionally cleared the draft.\n useEffect(() => {\n return () => {\n if (skipDraftPersistRef.current) return;\n const {email, password} = form.state.values;\n if (email !== draftRef.current.email || password !== draftRef.current.password) {\n setAuthFormDraft({email, password});\n }\n };\n }, [form, setAuthFormDraft]);\n\n const isInvitationEmailLocked = Boolean(invitationPending);\n const invitationRedirect = invitationToken\n ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}`\n : undefined;\n const headerTitle = invitationPending\n ? `Join ${invitationPending.workspace_name}`\n : 'Connect to Shipfox';\n const headerDescription = invitationPending\n ? 'Log in to accept your invitation.'\n : 'Log in to access Shipfox.';\n\n function persistDraft() {\n const {email, password} = form.state.values;\n setAuthFormDraft({email, password});\n }\n\n return (\n <AuthShell title={headerTitle} description={headerDescription}>\n <form\n className=\"flex flex-col gap-18\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"email\"\n validators={{onBlur: loginBodySchema.shape.email, onSubmit: loginBodySchema.shape.email}}\n >\n {(field) => (\n <FormField label=\"Email\" id=\"email\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"email\"\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n readOnly={isInvitationEmailLocked}\n iconRight={\n isInvitationEmailLocked ? (\n <Icon\n aria-hidden=\"true\"\n className=\"size-16 text-foreground-neutral-disabled\"\n name=\"lockLine\"\n />\n ) : undefined\n }\n />\n </FormField>\n )}\n </form.Field>\n <form.Field\n name=\"password\"\n validators={{\n onBlur: loginBodySchema.shape.password,\n onSubmit: loginBodySchema.shape.password,\n }}\n >\n {(field) => (\n <FormField label=\"Password\" id=\"password\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"current-password\"\n name=\"password\"\n type=\"password\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n />\n </FormField>\n )}\n </form.Field>\n <ButtonLink asChild variant=\"subtle\" className=\"-mt-8 self-end\">\n <Link to=\"/auth/reset\">Forgot password?</Link>\n </ButtonLink>\n <Button className=\"w-full\" isLoading={login.isPending} type=\"submit\">\n {login.isPending ? 'Logging in...' : 'Log in'}\n </Button>\n </form>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n New to Shipfox?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link\n to=\"/auth/signup\"\n search={invitationRedirect ? {redirect: invitationRedirect} : undefined}\n >\n Create an account\n </Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n}\n"],"names":["loginBodySchema","Button","ButtonLink","Callout","FormField","FormFieldInput","fieldError","Icon","Text","useForm","Link","useSearch","useAtom","useEffect","useRef","useState","AuthShell","useLoginAuth","authFormDraftAtom","initialAuthFormDraft","loginErrorToFormError","extractInvitationToken","pendingInvitation","useInvitationContext","LoginPage","login","search","strict","invitationToken","redirect","invitationPreview","invitationPending","data","authFormDraft","setAuthFormDraft","formError","setFormError","draftRef","current","skipDraftPersistRef","form","defaultValues","email","password","onSubmit","value","undefined","mutateAsync","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","state","values","setFieldValue","isInvitationEmailLocked","Boolean","invitationRedirect","encodeURIComponent","headerTitle","workspace_name","headerDescription","persistDraft","title","description","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","role","type","Field","name","validators","onBlur","shape","label","id","autoComplete","onChange","handleChange","target","handleBlur","readOnly","iconRight","aria-hidden","asChild","variant","to","isLoading","isPending","size","underline"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/pages/login-page.tsx"],"sourcesContent":["import {loginBodySchema} from '@shipfox/api-auth-dto';\nimport {AuthShell, useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {Link} from '@tanstack/react-router';\nimport {useAtom} from 'jotai';\nimport {useEffect, useRef, useState} from 'react';\nimport {useLoginAuth} from '#hooks/api/login-auth.js';\nimport {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';\nimport {validateRedirectSearch} from '../routes/inputs.js';\nimport {loginErrorToFormError} from './form-errors.js';\nimport {\n extractInvitationToken,\n pendingInvitation,\n useInvitationContext,\n} from './invitation-context.js';\n\nexport function LoginPage() {\n const login = useLoginAuth();\n const search = useRouteSearch(validateRedirectSearch);\n const invitationToken = extractInvitationToken(search.redirect);\n const invitationPreview = useInvitationContext(invitationToken);\n const invitationPending = pendingInvitation(invitationPreview.data);\n const [authFormDraft, setAuthFormDraft] = useAtom(authFormDraftAtom);\n const [formError, setFormError] = useState<string | undefined>();\n const draftRef = useRef(authFormDraft);\n draftRef.current = authFormDraft;\n // Set just before clearing the draft on success so the unmount cleanup\n // below does not repersist the just-submitted credentials.\n const skipDraftPersistRef = useRef(false);\n\n const form = useForm({\n defaultValues: {email: authFormDraft.email, password: authFormDraft.password},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await login.mutateAsync(value);\n skipDraftPersistRef.current = true;\n setAuthFormDraft(initialAuthFormDraft);\n } catch (error) {\n const mapped = loginErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n // Lock the email field when arriving from an invitation link so the user\n // can't log in as a different account than the one the invitation targets.\n useEffect(() => {\n if (invitationPending && form.state.values.email !== invitationPending.email) {\n form.setFieldValue('email', invitationPending.email);\n setAuthFormDraft((current) => ({...current, email: invitationPending.email}));\n }\n }, [invitationPending, form, setAuthFormDraft]);\n\n // Sync TanStack Form values back into the Jotai draft on unmount so a\n // navigation to /signup or /reset preserves what the user typed. Skipped\n // after a successful login because we just intentionally cleared the draft.\n useEffect(() => {\n return () => {\n if (skipDraftPersistRef.current) return;\n const {email, password} = form.state.values;\n if (email !== draftRef.current.email || password !== draftRef.current.password) {\n setAuthFormDraft({email, password});\n }\n };\n }, [form, setAuthFormDraft]);\n\n const isInvitationEmailLocked = Boolean(invitationPending);\n const invitationRedirect = invitationToken\n ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}`\n : undefined;\n const headerTitle = invitationPending\n ? `Join ${invitationPending.workspaceName}`\n : 'Connect to Shipfox';\n const headerDescription = invitationPending\n ? 'Log in to accept your invitation.'\n : 'Log in to access Shipfox.';\n\n function persistDraft() {\n const {email, password} = form.state.values;\n setAuthFormDraft({email, password});\n }\n\n return (\n <AuthShell title={headerTitle} description={headerDescription}>\n <form\n className=\"flex flex-col gap-18\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"email\"\n validators={{onBlur: loginBodySchema.shape.email, onSubmit: loginBodySchema.shape.email}}\n >\n {(field) => (\n <FormField label=\"Email\" id=\"email\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"email\"\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n readOnly={isInvitationEmailLocked}\n iconRight={\n isInvitationEmailLocked ? (\n <Icon\n aria-hidden=\"true\"\n className=\"size-16 text-foreground-neutral-disabled\"\n name=\"lockLine\"\n />\n ) : undefined\n }\n />\n </FormField>\n )}\n </form.Field>\n <form.Field\n name=\"password\"\n validators={{\n onBlur: loginBodySchema.shape.password,\n onSubmit: loginBodySchema.shape.password,\n }}\n >\n {(field) => (\n <FormField label=\"Password\" id=\"password\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"current-password\"\n name=\"password\"\n type=\"password\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n />\n </FormField>\n )}\n </form.Field>\n <ButtonLink asChild variant=\"subtle\" className=\"-mt-8 self-end\">\n <Link to=\"/auth/reset\">Forgot password?</Link>\n </ButtonLink>\n <Button className=\"w-full\" isLoading={login.isPending} type=\"submit\">\n {login.isPending ? 'Logging in...' : 'Log in'}\n </Button>\n </form>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n New to Shipfox?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link\n to=\"/auth/signup\"\n search={invitationRedirect ? {redirect: invitationRedirect} : undefined}\n >\n Create an account\n </Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n}\n"],"names":["loginBodySchema","AuthShell","useRouteSearch","Button","ButtonLink","Callout","FormField","FormFieldInput","fieldError","Icon","Text","useForm","Link","useAtom","useEffect","useRef","useState","useLoginAuth","authFormDraftAtom","initialAuthFormDraft","validateRedirectSearch","loginErrorToFormError","extractInvitationToken","pendingInvitation","useInvitationContext","LoginPage","login","search","invitationToken","redirect","invitationPreview","invitationPending","data","authFormDraft","setAuthFormDraft","formError","setFormError","draftRef","current","skipDraftPersistRef","form","defaultValues","email","password","onSubmit","value","undefined","mutateAsync","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","state","values","setFieldValue","isInvitationEmailLocked","Boolean","invitationRedirect","encodeURIComponent","headerTitle","workspaceName","headerDescription","persistDraft","title","description","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","role","type","Field","name","validators","onBlur","shape","label","id","autoComplete","onChange","handleChange","target","handleBlur","readOnly","iconRight","aria-hidden","asChild","variant","to","isLoading","isPending","size","underline"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout-page.d.ts","sourceRoot":"","sources":["../../src/pages/logout-page.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logout-page.d.ts","sourceRoot":"","sources":["../../src/pages/logout-page.tsx"],"names":[],"mappings":"AAQA,wBAAgB,UAAU,gCAoBzB"}
|
|
@@ -1,33 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { AuthShell, useRouteSearch } from '@shipfox/client-shell/runtime';
|
|
2
3
|
import { Text } from '@shipfox/react-ui/typography';
|
|
3
|
-
import {
|
|
4
|
+
import { useRouter } from '@tanstack/react-router';
|
|
4
5
|
import { useEffect } from 'react';
|
|
5
|
-
import {
|
|
6
|
-
import { sanitizeRedirectPath } from '#/components/redirect-target.js';
|
|
6
|
+
import { sanitizeLogoutRedirectPath } from '#/components/redirect-target.js';
|
|
7
7
|
import { useLogoutAuth } from '#hooks/api/logout-auth.js';
|
|
8
|
+
import { validateRedirectSearch } from '../routes/inputs.js';
|
|
8
9
|
export function LogoutPage() {
|
|
9
10
|
const logout = useLogoutAuth();
|
|
10
|
-
const navigate = useNavigate();
|
|
11
11
|
const router = useRouter();
|
|
12
|
-
const search =
|
|
13
|
-
|
|
14
|
-
});
|
|
15
|
-
const target = sanitizeRedirectPath(search.redirect);
|
|
12
|
+
const search = useRouteSearch(validateRedirectSearch);
|
|
13
|
+
const target = sanitizeLogoutRedirectPath(search.redirect);
|
|
16
14
|
useEffect(()=>{
|
|
17
15
|
logout.mutateAsync().finally(()=>{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
router.history.replace(target);
|
|
21
|
-
} else {
|
|
22
|
-
navigate({
|
|
23
|
-
to: '/auth/login',
|
|
24
|
-
replace: true
|
|
25
|
-
});
|
|
26
|
-
}
|
|
16
|
+
// Same-origin runtime path; let history drive route resolution.
|
|
17
|
+
router.history.replace(target);
|
|
27
18
|
});
|
|
28
19
|
}, [
|
|
29
20
|
logout.mutateAsync,
|
|
30
|
-
navigate,
|
|
31
21
|
router,
|
|
32
22
|
target
|
|
33
23
|
]);
|