@djangocfg/api 2.1.546 → 2.1.548
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/README.md +25 -0
- package/dist/auth.cjs +339 -73
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +106 -2
- package/dist/auth.d.ts +106 -2
- package/dist/auth.mjs +339 -73
- package/dist/auth.mjs.map +1 -1
- package/dist/clients.cjs +18 -0
- package/dist/clients.cjs.map +1 -1
- package/dist/clients.d.cts +96 -0
- package/dist/clients.d.ts +96 -0
- package/dist/clients.mjs +18 -0
- package/dist/clients.mjs.map +1 -1
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.cjs +18 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +171 -3
- package/dist/index.d.ts +171 -3
- package/dist/index.mjs +18 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/_api/generated/_cfg_accounts/hooks/index.ts +1 -0
- package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenCreate.ts +64 -0
- package/src/_api/generated/_cfg_accounts/openapi.json +157 -0
- package/src/_api/generated/_cfg_accounts/schemas/PasswordLoginError.ts +13 -0
- package/src/_api/generated/_cfg_accounts/schemas/PasswordLoginRequest.ts +13 -0
- package/src/_api/generated/_cfg_accounts/schemas/PasswordLoginResponse.ts +18 -0
- package/src/_api/generated/_cfg_accounts/schemas/index.ts +3 -0
- package/src/_api/generated/openapi.json +157 -0
- package/src/_api/generated/sdk.gen.ts +20 -1
- package/src/_api/generated/types.gen.ts +149 -0
- package/src/auth/__tests__/guard.test.ts +65 -0
- package/src/auth/__tests__/passwordLogin.test.tsx +239 -0
- package/src/auth/context/AccountsContext.tsx +32 -7
- package/src/auth/context/AuthContext.tsx +104 -1
- package/src/auth/context/types.ts +10 -1
- package/src/auth/hooks/useAuthForm.ts +84 -0
- package/src/auth/hooks/useAuthFormState.ts +3 -0
- package/src/auth/types/form.ts +41 -1
- package/src/auth/types/index.ts +2 -0
- package/src/auth/utils/analytics.ts +1 -0
- package/src/auth/utils/guard.ts +27 -1
- package/src/auth/utils/index.ts +1 -0
package/README.md
CHANGED
|
@@ -77,6 +77,31 @@ import {
|
|
|
77
77
|
} from '@djangocfg/api/auth';
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
### Guard resolvers
|
|
81
|
+
|
|
82
|
+
The "spinner vs redirect vs render" decision is pure and separately testable.
|
|
83
|
+
`useAuthGuard` (and `@djangocfg/layouts`' `PrivateLayout`) just wire React state
|
|
84
|
+
into these:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import {
|
|
88
|
+
resolveGuardIsLoading, // show the preloader?
|
|
89
|
+
shouldRedirectToAuth, // no session → send to the auth form
|
|
90
|
+
isForbidden, // signed in, but lacks the required privilege
|
|
91
|
+
resolveGuardIsAuthenticated,
|
|
92
|
+
type GuardInput,
|
|
93
|
+
} from '@djangocfg/api/auth';
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`GuardInput` takes two optional fields for the role gate: `requireStaff` (the
|
|
97
|
+
route needs staff/admin) and `isAdminUser` (from `useAuth()` — the
|
|
98
|
+
`is_staff || is_superuser` fold, never one flag).
|
|
99
|
+
|
|
100
|
+
`isForbidden` is deliberately **not** a redirect condition: the session is
|
|
101
|
+
valid, so the auth form cannot fix it, and redirecting would loop on the saved
|
|
102
|
+
URL. Render a distinct "not authorised" state instead. `resolveGuardIsLoading`
|
|
103
|
+
returns `false` once forbidden, so the preloader never spins on it.
|
|
104
|
+
|
|
80
105
|
## Token storage & DPoP
|
|
81
106
|
|
|
82
107
|
The token lives in the shared `auth` store (localStorage by default, switchable
|
package/dist/auth.cjs
CHANGED
|
@@ -50,6 +50,7 @@ __export(auth_exports, {
|
|
|
50
50
|
getCachedProfile: () => getCachedProfile,
|
|
51
51
|
hasValidCache: () => hasValidCache,
|
|
52
52
|
isAllowedAuthPath: () => isAllowedAuthPath,
|
|
53
|
+
isForbidden: () => isForbidden,
|
|
53
54
|
logger: () => logger,
|
|
54
55
|
normalizePath: () => normalizePath,
|
|
55
56
|
peekSavedRedirect: () => peekSavedRedirect,
|
|
@@ -1044,6 +1045,7 @@ var formatCountdown = /* @__PURE__ */ __name((s) => {
|
|
|
1044
1045
|
var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "") => {
|
|
1045
1046
|
const [identifier, setIdentifier] = (0, import_react4.useState)(initialIdentifier);
|
|
1046
1047
|
const [otp, setOtp] = (0, import_react4.useState)("");
|
|
1048
|
+
const [password, setPassword] = (0, import_react4.useState)("");
|
|
1047
1049
|
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
1048
1050
|
const [acceptedTerms, setAcceptedTerms] = (0, import_react4.useState)(true);
|
|
1049
1051
|
const [marketingConsent, setMarketingConsent] = (0, import_react4.useState)(null);
|
|
@@ -1079,6 +1081,7 @@ var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "") => {
|
|
|
1079
1081
|
// State
|
|
1080
1082
|
identifier,
|
|
1081
1083
|
otp,
|
|
1084
|
+
password,
|
|
1082
1085
|
isLoading,
|
|
1083
1086
|
acceptedTerms,
|
|
1084
1087
|
marketingConsent,
|
|
@@ -1096,6 +1099,7 @@ var useAuthFormState = /* @__PURE__ */ __name((initialIdentifier = "") => {
|
|
|
1096
1099
|
// Handlers
|
|
1097
1100
|
setIdentifier,
|
|
1098
1101
|
setOtp,
|
|
1102
|
+
setPassword,
|
|
1099
1103
|
setAcceptedTerms,
|
|
1100
1104
|
setMarketingConsent,
|
|
1101
1105
|
setRememberMe,
|
|
@@ -2310,6 +2314,24 @@ var CfgAccountsAuth = class {
|
|
|
2310
2314
|
static {
|
|
2311
2315
|
__name(this, "CfgAccountsAuth");
|
|
2312
2316
|
}
|
|
2317
|
+
/**
|
|
2318
|
+
* Obtain a JWT pair with email + password.
|
|
2319
|
+
*
|
|
2320
|
+
* Returns the same envelope as OTP verify: either ``requires_2fa=True`` with
|
|
2321
|
+
* a session id, or the token pair plus the user object. Failures are uniform
|
|
2322
|
+
* (401 ``invalid_credentials``) whether the email is unknown, the password is
|
|
2323
|
+
* wrong, or the account is inactive/soft-deleted — no enumeration.
|
|
2324
|
+
*/
|
|
2325
|
+
static cfgAccountsTokenCreate(options) {
|
|
2326
|
+
return (options.client ?? client).post({
|
|
2327
|
+
url: "/cfg/accounts/token/",
|
|
2328
|
+
...options,
|
|
2329
|
+
headers: {
|
|
2330
|
+
"Content-Type": "application/json",
|
|
2331
|
+
...options.headers
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2313
2335
|
/**
|
|
2314
2336
|
* Revoke a refresh token (logout).
|
|
2315
2337
|
*
|
|
@@ -2498,6 +2520,7 @@ var AnalyticsEvent = /* @__PURE__ */ ((AnalyticsEvent2) => {
|
|
|
2498
2520
|
AnalyticsEvent2["AUTH_OTP_REQUEST"] = "auth_otp_request";
|
|
2499
2521
|
AnalyticsEvent2["AUTH_LOGIN_SUCCESS"] = "auth_login_success";
|
|
2500
2522
|
AnalyticsEvent2["AUTH_OTP_VERIFY_FAIL"] = "auth_otp_verify_fail";
|
|
2523
|
+
AnalyticsEvent2["AUTH_PASSWORD_LOGIN_FAIL"] = "auth_password_login_fail";
|
|
2501
2524
|
AnalyticsEvent2["AUTH_SESSION_EXPIRED"] = "auth_session_expired";
|
|
2502
2525
|
AnalyticsEvent2["AUTH_TOKEN_REFRESH"] = "auth_token_refresh";
|
|
2503
2526
|
AnalyticsEvent2["AUTH_TOKEN_REFRESH_FAIL"] = "auth_token_refresh_fail";
|
|
@@ -2937,12 +2960,14 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
|
|
|
2937
2960
|
const {
|
|
2938
2961
|
requestOTP,
|
|
2939
2962
|
verifyOTP,
|
|
2963
|
+
login,
|
|
2940
2964
|
getSavedEmail,
|
|
2941
2965
|
saveEmail
|
|
2942
2966
|
} = useAuth();
|
|
2943
2967
|
const {
|
|
2944
2968
|
identifier,
|
|
2945
2969
|
otp,
|
|
2970
|
+
password,
|
|
2946
2971
|
acceptedTerms,
|
|
2947
2972
|
marketingConsent,
|
|
2948
2973
|
rememberMe,
|
|
@@ -3094,6 +3119,78 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
|
|
|
3094
3119
|
e.preventDefault();
|
|
3095
3120
|
await submitOTP(identifier, otp);
|
|
3096
3121
|
}, [identifier, otp, submitOTP]);
|
|
3122
|
+
const submitPassword = (0, import_react9.useCallback)(async (submitIdentifier, submitPassword_) => {
|
|
3123
|
+
if (!submitIdentifier || !validateIdentifier2(submitIdentifier)) {
|
|
3124
|
+
const msg = "Please enter a valid email address";
|
|
3125
|
+
setError(msg);
|
|
3126
|
+
onError?.(msg);
|
|
3127
|
+
return false;
|
|
3128
|
+
}
|
|
3129
|
+
if (!submitPassword_) {
|
|
3130
|
+
const msg = "Please enter your password";
|
|
3131
|
+
setError(msg);
|
|
3132
|
+
onError?.(msg);
|
|
3133
|
+
return false;
|
|
3134
|
+
}
|
|
3135
|
+
setIsLoading(true);
|
|
3136
|
+
clearError();
|
|
3137
|
+
try {
|
|
3138
|
+
const result = await login(submitIdentifier, submitPassword_, {
|
|
3139
|
+
redirectUrl,
|
|
3140
|
+
skipRedirect: true,
|
|
3141
|
+
rememberMe
|
|
3142
|
+
});
|
|
3143
|
+
if (result.requires_2fa && result.session_id) {
|
|
3144
|
+
authLogger.info("2FA required after password login");
|
|
3145
|
+
setTwoFactorSessionId(result.session_id);
|
|
3146
|
+
setShouldPrompt2FA(result.should_prompt_2fa || false);
|
|
3147
|
+
setStep("2fa");
|
|
3148
|
+
saveIdentifierToStorage(submitIdentifier);
|
|
3149
|
+
return true;
|
|
3150
|
+
}
|
|
3151
|
+
if (result.success) {
|
|
3152
|
+
saveIdentifierToStorage(submitIdentifier);
|
|
3153
|
+
authLogger.info("Password login successful, showing success screen");
|
|
3154
|
+
setStep("success");
|
|
3155
|
+
onOTPSuccess?.();
|
|
3156
|
+
return true;
|
|
3157
|
+
}
|
|
3158
|
+
if (result.retryAfter) {
|
|
3159
|
+
startRateLimitCountdown(result.retryAfter);
|
|
3160
|
+
clearError();
|
|
3161
|
+
} else {
|
|
3162
|
+
setError(result.message);
|
|
3163
|
+
onError?.(result.message);
|
|
3164
|
+
}
|
|
3165
|
+
return false;
|
|
3166
|
+
} catch {
|
|
3167
|
+
const msg = "An unexpected error occurred";
|
|
3168
|
+
setError(msg);
|
|
3169
|
+
onError?.(msg);
|
|
3170
|
+
return false;
|
|
3171
|
+
} finally {
|
|
3172
|
+
setIsLoading(false);
|
|
3173
|
+
}
|
|
3174
|
+
}, [
|
|
3175
|
+
login,
|
|
3176
|
+
validateIdentifier2,
|
|
3177
|
+
saveIdentifierToStorage,
|
|
3178
|
+
setError,
|
|
3179
|
+
setIsLoading,
|
|
3180
|
+
clearError,
|
|
3181
|
+
startRateLimitCountdown,
|
|
3182
|
+
onOTPSuccess,
|
|
3183
|
+
onError,
|
|
3184
|
+
redirectUrl,
|
|
3185
|
+
rememberMe,
|
|
3186
|
+
setTwoFactorSessionId,
|
|
3187
|
+
setShouldPrompt2FA,
|
|
3188
|
+
setStep
|
|
3189
|
+
]);
|
|
3190
|
+
const handlePasswordSubmit = (0, import_react9.useCallback)(async (e) => {
|
|
3191
|
+
e.preventDefault();
|
|
3192
|
+
await submitPassword(identifier, password);
|
|
3193
|
+
}, [identifier, password, submitPassword]);
|
|
3097
3194
|
const handleResendOTP = (0, import_react9.useCallback)(async () => {
|
|
3098
3195
|
setIsLoading(true);
|
|
3099
3196
|
clearError();
|
|
@@ -3187,6 +3284,7 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
|
|
|
3187
3284
|
// Submit handlers
|
|
3188
3285
|
handleIdentifierSubmit,
|
|
3189
3286
|
handleOTPSubmit,
|
|
3287
|
+
handlePasswordSubmit,
|
|
3190
3288
|
handleResendOTP,
|
|
3191
3289
|
handleBackToIdentifier,
|
|
3192
3290
|
forceOTPStep,
|
|
@@ -4290,119 +4388,197 @@ __name(useCfgAccountsProfileUpdateUpdate, "useCfgAccountsProfileUpdateUpdate");
|
|
|
4290
4388
|
// src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenBlacklistCreate.ts
|
|
4291
4389
|
var import_mutation15 = __toESM(require("swr/mutation"), 1);
|
|
4292
4390
|
|
|
4293
|
-
// src/_api/generated/_cfg_accounts/hooks/
|
|
4391
|
+
// src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenCreate.ts
|
|
4294
4392
|
var import_mutation16 = __toESM(require("swr/mutation"), 1);
|
|
4295
4393
|
|
|
4296
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4394
|
+
// src/_api/generated/_cfg_accounts/schemas/PasswordLoginResponse.ts
|
|
4297
4395
|
var import_zod20 = require("zod");
|
|
4298
|
-
var
|
|
4299
|
-
|
|
4300
|
-
|
|
4396
|
+
var PasswordLoginResponseSchema = import_zod20.z.object({
|
|
4397
|
+
requires_2fa: import_zod20.z.boolean().default(false).optional(),
|
|
4398
|
+
session_id: import_zod20.z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i).nullable().optional(),
|
|
4399
|
+
refresh: import_zod20.z.string().nullable().optional(),
|
|
4400
|
+
access: import_zod20.z.string().nullable().optional(),
|
|
4401
|
+
user: UserSchema.nullable().optional(),
|
|
4402
|
+
should_prompt_2fa: import_zod20.z.boolean().optional(),
|
|
4403
|
+
persistent_session: import_zod20.z.boolean().optional()
|
|
4301
4404
|
});
|
|
4302
4405
|
|
|
4303
|
-
// src/_api/generated/_cfg_accounts/
|
|
4406
|
+
// src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenCreate.ts
|
|
4407
|
+
function useCfgAccountsTokenCreate(config) {
|
|
4408
|
+
return (0, import_mutation16.default)(
|
|
4409
|
+
["cfg_accounts_token_create"],
|
|
4410
|
+
async (_key, { arg }) => {
|
|
4411
|
+
const res = await CfgAccountsAuth.cfgAccountsTokenCreate({ ...arg, throwOnError: true });
|
|
4412
|
+
const data = res.data;
|
|
4413
|
+
const parsed = PasswordLoginResponseSchema.safeParse(data);
|
|
4414
|
+
if (!parsed.success) {
|
|
4415
|
+
console.warn(
|
|
4416
|
+
"[zod] response did not match schema",
|
|
4417
|
+
{
|
|
4418
|
+
operation: "cfg_accounts_token_create",
|
|
4419
|
+
method: "POST",
|
|
4420
|
+
path: "/cfg/accounts/token/",
|
|
4421
|
+
issues: parsed.error.issues,
|
|
4422
|
+
data
|
|
4423
|
+
}
|
|
4424
|
+
);
|
|
4425
|
+
if (typeof window !== "undefined") {
|
|
4426
|
+
try {
|
|
4427
|
+
window.dispatchEvent(
|
|
4428
|
+
new CustomEvent("zod-validation-error", {
|
|
4429
|
+
detail: {
|
|
4430
|
+
operation: "cfg_accounts_token_create",
|
|
4431
|
+
method: "POST",
|
|
4432
|
+
path: "/cfg/accounts/token/",
|
|
4433
|
+
issues: parsed.error.issues,
|
|
4434
|
+
data,
|
|
4435
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
4436
|
+
},
|
|
4437
|
+
bubbles: true,
|
|
4438
|
+
cancelable: false
|
|
4439
|
+
})
|
|
4440
|
+
);
|
|
4441
|
+
} catch {
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
return data;
|
|
4445
|
+
}
|
|
4446
|
+
return parsed.data;
|
|
4447
|
+
},
|
|
4448
|
+
config
|
|
4449
|
+
);
|
|
4450
|
+
}
|
|
4451
|
+
__name(useCfgAccountsTokenCreate, "useCfgAccountsTokenCreate");
|
|
4452
|
+
|
|
4453
|
+
// src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenRefreshCreate.ts
|
|
4454
|
+
var import_mutation17 = __toESM(require("swr/mutation"), 1);
|
|
4455
|
+
|
|
4456
|
+
// src/_api/generated/_cfg_accounts/schemas/TokenRefresh.ts
|
|
4304
4457
|
var import_zod21 = require("zod");
|
|
4305
|
-
var
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
created_at: import_zod21.z.string().datetime({ offset: true })
|
|
4458
|
+
var TokenRefreshSchema = import_zod21.z.object({
|
|
4459
|
+
access: import_zod21.z.string(),
|
|
4460
|
+
refresh: import_zod21.z.string()
|
|
4309
4461
|
});
|
|
4310
4462
|
|
|
4311
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4463
|
+
// src/_api/generated/_cfg_accounts/schemas/APIKeyRequest.ts
|
|
4312
4464
|
var import_zod22 = require("zod");
|
|
4313
|
-
var
|
|
4314
|
-
key: import_zod22.z.string().min(1)
|
|
4465
|
+
var APIKeyRequestSchema = import_zod22.z.object({
|
|
4466
|
+
key: import_zod22.z.string().min(1),
|
|
4467
|
+
reissued_at: import_zod22.z.string().datetime({ offset: true }).nullable(),
|
|
4468
|
+
created_at: import_zod22.z.string().datetime({ offset: true })
|
|
4315
4469
|
});
|
|
4316
4470
|
|
|
4317
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4471
|
+
// src/_api/generated/_cfg_accounts/schemas/APIKeyTestRequest.ts
|
|
4318
4472
|
var import_zod23 = require("zod");
|
|
4319
|
-
var
|
|
4320
|
-
|
|
4321
|
-
last_name: import_zod23.z.string().max(50).optional(),
|
|
4322
|
-
company: import_zod23.z.string().max(100).optional(),
|
|
4323
|
-
phone: import_zod23.z.string().max(20).optional(),
|
|
4324
|
-
position: import_zod23.z.string().max(100).optional(),
|
|
4325
|
-
language: import_zod23.z.string().max(10).optional(),
|
|
4326
|
-
timezone: import_zod23.z.string().max(64).optional()
|
|
4473
|
+
var APIKeyTestRequestSchema = import_zod23.z.object({
|
|
4474
|
+
key: import_zod23.z.string().min(1)
|
|
4327
4475
|
});
|
|
4328
4476
|
|
|
4329
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4477
|
+
// src/_api/generated/_cfg_accounts/schemas/CfgUserUpdateRequest.ts
|
|
4330
4478
|
var import_zod24 = require("zod");
|
|
4331
|
-
var
|
|
4332
|
-
|
|
4333
|
-
|
|
4479
|
+
var CfgUserUpdateRequestSchema = import_zod24.z.object({
|
|
4480
|
+
first_name: import_zod24.z.string().max(50).optional(),
|
|
4481
|
+
last_name: import_zod24.z.string().max(50).optional(),
|
|
4482
|
+
company: import_zod24.z.string().max(100).optional(),
|
|
4483
|
+
phone: import_zod24.z.string().max(20).optional(),
|
|
4484
|
+
position: import_zod24.z.string().max(100).optional(),
|
|
4485
|
+
language: import_zod24.z.string().max(10).optional(),
|
|
4486
|
+
timezone: import_zod24.z.string().max(64).optional()
|
|
4334
4487
|
});
|
|
4335
4488
|
|
|
4336
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4489
|
+
// src/_api/generated/_cfg_accounts/schemas/OAuthAuthorizeRequestRequest.ts
|
|
4337
4490
|
var import_zod25 = require("zod");
|
|
4338
|
-
var
|
|
4339
|
-
code: import_zod25.z.string().min(10).max(500),
|
|
4340
|
-
state: import_zod25.z.string().min(20).max(100),
|
|
4491
|
+
var OAuthAuthorizeRequestRequestSchema = import_zod25.z.object({
|
|
4341
4492
|
redirect_uri: import_zod25.z.string().optional(),
|
|
4342
|
-
|
|
4493
|
+
source_url: import_zod25.z.string().optional()
|
|
4343
4494
|
});
|
|
4344
4495
|
|
|
4345
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4496
|
+
// src/_api/generated/_cfg_accounts/schemas/OAuthCallbackRequestRequest.ts
|
|
4346
4497
|
var import_zod26 = require("zod");
|
|
4347
|
-
var
|
|
4348
|
-
|
|
4498
|
+
var OAuthCallbackRequestRequestSchema = import_zod26.z.object({
|
|
4499
|
+
code: import_zod26.z.string().min(10).max(500),
|
|
4500
|
+
state: import_zod26.z.string().min(20).max(100),
|
|
4501
|
+
redirect_uri: import_zod26.z.string().optional(),
|
|
4502
|
+
remember_me: import_zod26.z.boolean().default(false).optional()
|
|
4349
4503
|
});
|
|
4350
4504
|
|
|
4351
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4505
|
+
// src/_api/generated/_cfg_accounts/schemas/OAuthDisconnectRequestRequest.ts
|
|
4352
4506
|
var import_zod27 = require("zod");
|
|
4353
|
-
var
|
|
4354
|
-
|
|
4355
|
-
error_description: import_zod27.z.string().optional()
|
|
4507
|
+
var OAuthDisconnectRequestRequestSchema = import_zod27.z.object({
|
|
4508
|
+
provider: OAuthProviderEnumSchema
|
|
4356
4509
|
});
|
|
4357
4510
|
|
|
4358
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4511
|
+
// src/_api/generated/_cfg_accounts/schemas/OAuthError.ts
|
|
4359
4512
|
var import_zod28 = require("zod");
|
|
4360
|
-
var
|
|
4513
|
+
var OAuthErrorSchema = import_zod28.z.object({
|
|
4361
4514
|
error: import_zod28.z.string(),
|
|
4362
|
-
|
|
4363
|
-
retry_after: import_zod28.z.number().int().nullable().optional()
|
|
4515
|
+
error_description: import_zod28.z.string().optional()
|
|
4364
4516
|
});
|
|
4365
4517
|
|
|
4366
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4518
|
+
// src/_api/generated/_cfg_accounts/schemas/OTPErrorResponse.ts
|
|
4367
4519
|
var import_zod29 = require("zod");
|
|
4368
|
-
var
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
consent_disclosure_version: import_zod29.z.string().max(64).optional()
|
|
4520
|
+
var OTPErrorResponseSchema = import_zod29.z.object({
|
|
4521
|
+
error: import_zod29.z.string(),
|
|
4522
|
+
error_code: import_zod29.z.string().nullable().optional(),
|
|
4523
|
+
retry_after: import_zod29.z.number().int().nullable().optional()
|
|
4373
4524
|
});
|
|
4374
4525
|
|
|
4375
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4526
|
+
// src/_api/generated/_cfg_accounts/schemas/OTPRequestRequest.ts
|
|
4376
4527
|
var import_zod30 = require("zod");
|
|
4377
|
-
var
|
|
4528
|
+
var OTPRequestRequestSchema = import_zod30.z.object({
|
|
4378
4529
|
identifier: import_zod30.z.string().min(1),
|
|
4379
|
-
otp: import_zod30.z.string().min(4).max(4),
|
|
4380
4530
|
source_url: import_zod30.z.string().optional(),
|
|
4381
|
-
|
|
4531
|
+
marketing_consent: import_zod30.z.boolean().nullable().optional(),
|
|
4532
|
+
consent_disclosure_version: import_zod30.z.string().max(64).optional()
|
|
4382
4533
|
});
|
|
4383
4534
|
|
|
4384
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4535
|
+
// src/_api/generated/_cfg_accounts/schemas/OTPVerifyRequest.ts
|
|
4385
4536
|
var import_zod31 = require("zod");
|
|
4386
|
-
var
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
position: import_zod31.z.string().max(100).optional(),
|
|
4392
|
-
language: import_zod31.z.string().max(10).optional(),
|
|
4393
|
-
timezone: import_zod31.z.string().max(64).optional()
|
|
4537
|
+
var OTPVerifyRequestSchema = import_zod31.z.object({
|
|
4538
|
+
identifier: import_zod31.z.string().min(1),
|
|
4539
|
+
otp: import_zod31.z.string().min(4).max(4),
|
|
4540
|
+
source_url: import_zod31.z.string().optional(),
|
|
4541
|
+
remember_me: import_zod31.z.boolean().default(false).optional()
|
|
4394
4542
|
});
|
|
4395
4543
|
|
|
4396
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4544
|
+
// src/_api/generated/_cfg_accounts/schemas/PasswordLoginError.ts
|
|
4397
4545
|
var import_zod32 = require("zod");
|
|
4398
|
-
var
|
|
4399
|
-
|
|
4546
|
+
var PasswordLoginErrorSchema = import_zod32.z.object({
|
|
4547
|
+
error: import_zod32.z.string(),
|
|
4548
|
+
error_code: import_zod32.z.string(),
|
|
4549
|
+
retry_after: import_zod32.z.number().int().nullable().optional()
|
|
4400
4550
|
});
|
|
4401
4551
|
|
|
4402
|
-
// src/_api/generated/_cfg_accounts/schemas/
|
|
4552
|
+
// src/_api/generated/_cfg_accounts/schemas/PasswordLoginRequest.ts
|
|
4403
4553
|
var import_zod33 = require("zod");
|
|
4404
|
-
var
|
|
4405
|
-
|
|
4554
|
+
var PasswordLoginRequestSchema = import_zod33.z.object({
|
|
4555
|
+
remember_me: import_zod33.z.boolean().default(false).optional(),
|
|
4556
|
+
email: import_zod33.z.email(),
|
|
4557
|
+
password: import_zod33.z.string()
|
|
4558
|
+
});
|
|
4559
|
+
|
|
4560
|
+
// src/_api/generated/_cfg_accounts/schemas/PatchedCfgUserUpdateRequest.ts
|
|
4561
|
+
var import_zod34 = require("zod");
|
|
4562
|
+
var PatchedCfgUserUpdateRequestSchema = import_zod34.z.object({
|
|
4563
|
+
first_name: import_zod34.z.string().max(50).optional(),
|
|
4564
|
+
last_name: import_zod34.z.string().max(50).optional(),
|
|
4565
|
+
company: import_zod34.z.string().max(100).optional(),
|
|
4566
|
+
phone: import_zod34.z.string().max(20).optional(),
|
|
4567
|
+
position: import_zod34.z.string().max(100).optional(),
|
|
4568
|
+
language: import_zod34.z.string().max(10).optional(),
|
|
4569
|
+
timezone: import_zod34.z.string().max(64).optional()
|
|
4570
|
+
});
|
|
4571
|
+
|
|
4572
|
+
// src/_api/generated/_cfg_accounts/schemas/TokenBlacklistRequest.ts
|
|
4573
|
+
var import_zod35 = require("zod");
|
|
4574
|
+
var TokenBlacklistRequestSchema = import_zod35.z.object({
|
|
4575
|
+
refresh: import_zod35.z.string().min(1)
|
|
4576
|
+
});
|
|
4577
|
+
|
|
4578
|
+
// src/_api/generated/_cfg_accounts/schemas/TokenRefreshRequest.ts
|
|
4579
|
+
var import_zod36 = require("zod");
|
|
4580
|
+
var TokenRefreshRequestSchema = import_zod36.z.object({
|
|
4581
|
+
refresh: import_zod36.z.string().min(1)
|
|
4406
4582
|
});
|
|
4407
4583
|
|
|
4408
4584
|
// src/auth/context/AccountsContext.tsx
|
|
@@ -4439,6 +4615,7 @@ function AccountsProvider({ children }) {
|
|
|
4439
4615
|
const { trigger: triggerAvatar } = useCfgAccountsProfileAvatarCreate();
|
|
4440
4616
|
const { trigger: triggerOtpRequest } = useCfgAccountsOtpRequestCreate();
|
|
4441
4617
|
const { trigger: triggerOtpVerify } = useCfgAccountsOtpVerifyCreate();
|
|
4618
|
+
const { trigger: triggerPasswordLogin } = useCfgAccountsTokenCreate();
|
|
4442
4619
|
const refreshProfile = (0, import_react15.useCallback)(async (options) => {
|
|
4443
4620
|
const { callerId, force } = options || {};
|
|
4444
4621
|
if (!hasApiOrigin()) {
|
|
@@ -4488,22 +4665,30 @@ function AccountsProvider({ children }) {
|
|
|
4488
4665
|
const result = await triggerOtpRequest({ body: data });
|
|
4489
4666
|
return result;
|
|
4490
4667
|
}, [triggerOtpRequest]);
|
|
4491
|
-
const
|
|
4492
|
-
const result = await triggerOtpVerify({ body: data });
|
|
4668
|
+
const settleLoginEnvelope = (0, import_react15.useCallback)(async (result, callerId) => {
|
|
4493
4669
|
if (result.requires_2fa && result.session_id) {
|
|
4494
4670
|
authLogger.info("2FA required, session:", result.session_id);
|
|
4495
|
-
return
|
|
4671
|
+
return;
|
|
4496
4672
|
}
|
|
4497
4673
|
if (result.access && result.refresh) {
|
|
4498
4674
|
auth.setSession({ access: result.access, refresh: result.refresh });
|
|
4499
4675
|
try {
|
|
4500
|
-
await refreshProfile({ callerId
|
|
4676
|
+
await refreshProfile({ callerId, force: true });
|
|
4501
4677
|
} catch (profileError2) {
|
|
4502
|
-
authLogger.warn(
|
|
4678
|
+
authLogger.warn(`Profile refresh failed after ${callerId} (tokens are saved):`, profileError2);
|
|
4503
4679
|
}
|
|
4504
4680
|
}
|
|
4681
|
+
}, [refreshProfile]);
|
|
4682
|
+
const verifyOTP = (0, import_react15.useCallback)(async (data) => {
|
|
4683
|
+
const result = await triggerOtpVerify({ body: data });
|
|
4684
|
+
await settleLoginEnvelope(result, "verifyOTP");
|
|
4505
4685
|
return result;
|
|
4506
|
-
}, [triggerOtpVerify,
|
|
4686
|
+
}, [triggerOtpVerify, settleLoginEnvelope]);
|
|
4687
|
+
const loginWithPassword = (0, import_react15.useCallback)(async (data) => {
|
|
4688
|
+
const result = await triggerPasswordLogin({ body: data });
|
|
4689
|
+
await settleLoginEnvelope(result, "loginWithPassword");
|
|
4690
|
+
return result;
|
|
4691
|
+
}, [triggerPasswordLogin, settleLoginEnvelope]);
|
|
4507
4692
|
const logout = (0, import_react15.useCallback)(() => {
|
|
4508
4693
|
const refresh = auth.getRefreshToken();
|
|
4509
4694
|
if (refresh) {
|
|
@@ -4526,6 +4711,7 @@ function AccountsProvider({ children }) {
|
|
|
4526
4711
|
refreshProfile,
|
|
4527
4712
|
requestOTP,
|
|
4528
4713
|
verifyOTP,
|
|
4714
|
+
loginWithPassword,
|
|
4529
4715
|
logout
|
|
4530
4716
|
}), [
|
|
4531
4717
|
profile,
|
|
@@ -4537,6 +4723,7 @@ function AccountsProvider({ children }) {
|
|
|
4537
4723
|
refreshProfile,
|
|
4538
4724
|
requestOTP,
|
|
4539
4725
|
verifyOTP,
|
|
4726
|
+
loginWithPassword,
|
|
4540
4727
|
logout
|
|
4541
4728
|
]);
|
|
4542
4729
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccountsContext.Provider, { value, children });
|
|
@@ -4773,6 +4960,72 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
|
|
|
4773
4960
|
},
|
|
4774
4961
|
[setStoredEmail, redirectManager, router]
|
|
4775
4962
|
);
|
|
4963
|
+
const login = (0, import_react16.useCallback)(
|
|
4964
|
+
async (email, password, options) => {
|
|
4965
|
+
const { redirectUrl, skipRedirect, rememberMe = false } = options || {};
|
|
4966
|
+
try {
|
|
4967
|
+
pendingManualNavRef.current = Boolean(skipRedirect);
|
|
4968
|
+
const result = await accountsRef.current.loginWithPassword({
|
|
4969
|
+
email,
|
|
4970
|
+
password,
|
|
4971
|
+
remember_me: rememberMe
|
|
4972
|
+
});
|
|
4973
|
+
if (result.requires_2fa && result.session_id) {
|
|
4974
|
+
authLogger.info("2FA required, session:", result.session_id);
|
|
4975
|
+
return {
|
|
4976
|
+
success: true,
|
|
4977
|
+
message: "Password verified, 2FA required",
|
|
4978
|
+
requires_2fa: true,
|
|
4979
|
+
session_id: result.session_id,
|
|
4980
|
+
should_prompt_2fa: result.should_prompt_2fa
|
|
4981
|
+
};
|
|
4982
|
+
}
|
|
4983
|
+
if (!result.access || !result.refresh) {
|
|
4984
|
+
authLogger.error("Password login returned invalid response:", result);
|
|
4985
|
+
return { success: false, message: "Invalid login response" };
|
|
4986
|
+
}
|
|
4987
|
+
setStoredEmail(email);
|
|
4988
|
+
Analytics.event("auth_login_success" /* AUTH_LOGIN_SUCCESS */, {
|
|
4989
|
+
category: "auth" /* AUTH */,
|
|
4990
|
+
label: "password"
|
|
4991
|
+
});
|
|
4992
|
+
if (result.user?.id) {
|
|
4993
|
+
Analytics.setUser(String(result.user.id));
|
|
4994
|
+
}
|
|
4995
|
+
if (!skipRedirect) {
|
|
4996
|
+
const saved = redirectManager.hasRedirect() ? redirectManager.getRedirect() : null;
|
|
4997
|
+
if (saved) redirectManager.clearRedirect();
|
|
4998
|
+
const finalRedirectUrl = saved || redirectUrl || routesRef.current.defaultCallback;
|
|
4999
|
+
authLogger.info("Redirecting after auth to:", finalRedirectUrl);
|
|
5000
|
+
router.hardPush(finalRedirectUrl);
|
|
5001
|
+
}
|
|
5002
|
+
return {
|
|
5003
|
+
success: true,
|
|
5004
|
+
message: "Login successful",
|
|
5005
|
+
user: result.user,
|
|
5006
|
+
should_prompt_2fa: result.should_prompt_2fa
|
|
5007
|
+
};
|
|
5008
|
+
} catch (error) {
|
|
5009
|
+
authLogger.error("Password login error:", error);
|
|
5010
|
+
Analytics.event("auth_password_login_fail" /* AUTH_PASSWORD_LOGIN_FAIL */, {
|
|
5011
|
+
category: "auth" /* AUTH */,
|
|
5012
|
+
label: "password"
|
|
5013
|
+
});
|
|
5014
|
+
if (error instanceof APIError) {
|
|
5015
|
+
const body = error.response;
|
|
5016
|
+
return {
|
|
5017
|
+
success: false,
|
|
5018
|
+
statusCode: error.statusCode,
|
|
5019
|
+
message: apiErrorMessage(error),
|
|
5020
|
+
errorCode: body?.error_code,
|
|
5021
|
+
retryAfter: typeof body?.retry_after === "number" ? body.retry_after : void 0
|
|
5022
|
+
};
|
|
5023
|
+
}
|
|
5024
|
+
return { success: false, message: "Failed to sign in" };
|
|
5025
|
+
}
|
|
5026
|
+
},
|
|
5027
|
+
[setStoredEmail, redirectManager, router]
|
|
5028
|
+
);
|
|
4776
5029
|
const refreshToken = (0, import_react16.useCallback)(async () => {
|
|
4777
5030
|
const access = await auth.refreshNow();
|
|
4778
5031
|
if (access) {
|
|
@@ -4827,6 +5080,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
|
|
|
4827
5080
|
clearSavedEmail: clearStoredEmail,
|
|
4828
5081
|
requestOTP,
|
|
4829
5082
|
verifyOTP,
|
|
5083
|
+
login,
|
|
4830
5084
|
refreshToken,
|
|
4831
5085
|
logout,
|
|
4832
5086
|
saveRedirectUrl: redirectManager.setRedirect,
|
|
@@ -4849,6 +5103,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
|
|
|
4849
5103
|
clearStoredEmail,
|
|
4850
5104
|
requestOTP,
|
|
4851
5105
|
verifyOTP,
|
|
5106
|
+
login,
|
|
4852
5107
|
refreshToken,
|
|
4853
5108
|
logout,
|
|
4854
5109
|
redirectManager,
|
|
@@ -4892,6 +5147,10 @@ var defaultAuthState = {
|
|
|
4892
5147
|
authLogger.warn("useAuth: verifyOTP called outside AuthProvider");
|
|
4893
5148
|
return { success: false, message: "AuthProvider not available" };
|
|
4894
5149
|
}, "verifyOTP"),
|
|
5150
|
+
login: /* @__PURE__ */ __name(async () => {
|
|
5151
|
+
authLogger.warn("useAuth: login called outside AuthProvider");
|
|
5152
|
+
return { success: false, message: "AuthProvider not available" };
|
|
5153
|
+
}, "login"),
|
|
4895
5154
|
refreshToken: /* @__PURE__ */ __name(async () => {
|
|
4896
5155
|
authLogger.warn("useAuth: refreshToken called outside AuthProvider");
|
|
4897
5156
|
return { success: false, message: "AuthProvider not available" };
|
|
@@ -4952,9 +5211,16 @@ var formatAuthError = /* @__PURE__ */ __name((error) => {
|
|
|
4952
5211
|
}, "formatAuthError");
|
|
4953
5212
|
|
|
4954
5213
|
// src/auth/utils/guard.ts
|
|
5214
|
+
function isForbidden(s) {
|
|
5215
|
+
return Boolean(
|
|
5216
|
+
s.mounted && s.requireAuth && s.requireStaff && !s.authLoading && s.isAuthenticated && !s.isAdminUser
|
|
5217
|
+
);
|
|
5218
|
+
}
|
|
5219
|
+
__name(isForbidden, "isForbidden");
|
|
4955
5220
|
function resolveGuardIsLoading(s) {
|
|
4956
5221
|
if (!s.mounted) return true;
|
|
4957
5222
|
if (!s.requireAuth) return false;
|
|
5223
|
+
if (isForbidden(s)) return false;
|
|
4958
5224
|
return s.authLoading || s.isRedirecting || !s.isAuthenticated;
|
|
4959
5225
|
}
|
|
4960
5226
|
__name(resolveGuardIsLoading, "resolveGuardIsLoading");
|