@acorex-platform/framework-client 2.0.0-next.0 → 2.0.0-next.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/fesm2022/acorex-platform-framework-client-auth.mjs +113 -45
- package/fesm2022/acorex-platform-framework-client-auth.mjs.map +1 -1
- package/fesm2022/acorex-platform-framework-client-layout-components.mjs +2 -0
- package/fesm2022/acorex-platform-framework-client-layout-components.mjs.map +1 -1
- package/fesm2022/{acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-Drmmu4HQ.mjs → acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-BYPl8uyp.mjs} +222 -11
- package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-BYPl8uyp.mjs.map +1 -0
- package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BiuahYd8.mjs → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-IU_-eHQS.mjs} +2 -2
- package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BiuahYd8.mjs.map → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-IU_-eHQS.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-CU_5b_te.mjs → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-ET8ZuuCj.mjs} +2 -2
- package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-CU_5b_te.mjs.map → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-ET8ZuuCj.mjs.map} +1 -1
- package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs +1 -1
- package/fesm2022/acorex-platform-framework-client-themes-default.mjs +2 -7
- package/fesm2022/acorex-platform-framework-client-themes-default.mjs.map +1 -1
- package/package.json +2 -2
- package/types/acorex-platform-framework-client-auth.d.ts +15 -1
- package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-Drmmu4HQ.mjs.map +0 -1
|
@@ -534,6 +534,18 @@ function collectErrorCodes(error) {
|
|
|
534
534
|
}
|
|
535
535
|
return codes;
|
|
536
536
|
}
|
|
537
|
+
/**
|
|
538
|
+
* True when the API rejected the call because no access cookie / bearer was sent.
|
|
539
|
+
* An expired HttpOnly access cookie is omitted by the browser, so the server says
|
|
540
|
+
* "required" rather than "invalid or expired".
|
|
541
|
+
*/
|
|
542
|
+
function isMissingAccessTokenError(error) {
|
|
543
|
+
const text = collectErrorText(error);
|
|
544
|
+
if (!text.trim()) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
return /bearer access token is required/i.test(text) || /access token is required/i.test(text);
|
|
548
|
+
}
|
|
537
549
|
/**
|
|
538
550
|
* True only when refresh failed because the refresh cookie / session family is dead.
|
|
539
551
|
* Network / 5xx / Redis unavailable / empty transient results → false.
|
|
@@ -1047,59 +1059,31 @@ class AXPSessionService {
|
|
|
1047
1059
|
this.applicationsListCache = null;
|
|
1048
1060
|
}
|
|
1049
1061
|
try {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
throw new Error(`Authentication strategy '${strategyName}' is not supported`);
|
|
1062
|
+
// Refresh outside the UpdateSession lock. The access cookie expires sooner than
|
|
1063
|
+
// the refresh cookie; a stale click must not run UpdateSession while that lock is held,
|
|
1064
|
+
// or the 401 refresh path deadlocks on the same Web Lock.
|
|
1065
|
+
await this.refreshAccessCookieIfStale();
|
|
1066
|
+
try {
|
|
1067
|
+
await this.commitSessionUpdate(params, isApplicationUpdate, isTenantUpdate, startedAt);
|
|
1057
1068
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
if (result?.succeed) {
|
|
1062
|
-
if (params?.['code']) {
|
|
1063
|
-
// OAuth code exchange replaces identity metadata; wipe stale local fields first.
|
|
1064
|
-
this.clearSession();
|
|
1065
|
-
clearOAuthPendingStrategy();
|
|
1066
|
-
}
|
|
1067
|
-
else {
|
|
1068
|
-
this.permissionsSubject.next([]);
|
|
1069
|
-
this.featuresSubject.next([]);
|
|
1070
|
-
this.invalidateAccessPolicyCache();
|
|
1069
|
+
catch (error) {
|
|
1070
|
+
if (!isMissingAccessTokenError(error)) {
|
|
1071
|
+
throw error;
|
|
1071
1072
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
user: result.data.user,
|
|
1075
|
-
tenant: result.data?.tenant ?? null,
|
|
1076
|
-
application: this.resolveApplicationAfterUpdate(result.data?.application ?? null, isApplicationUpdate, isTenantUpdate),
|
|
1077
|
-
expiresIn: result.data?.expiresIn,
|
|
1078
|
-
locked: false,
|
|
1079
|
-
cookieSession: true,
|
|
1080
|
-
});
|
|
1081
|
-
await this.reloadAccessPolicyIfReady('updateToken');
|
|
1082
|
-
await this.syncSessionAuthorization();
|
|
1083
|
-
traceAuthWorkspace('UpdateSession complete', () => ({
|
|
1084
|
-
ms: Date.now() - startedAt,
|
|
1085
|
-
status: this.status.value,
|
|
1086
|
-
tenantId: this.tenant?.id,
|
|
1087
|
-
applicationId: this.application?.id,
|
|
1073
|
+
warnAuthWorkspace('UpdateSession missing access cookie — refreshing', () => ({
|
|
1074
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1088
1075
|
}));
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1076
|
+
const refreshed = await this.refreshToken();
|
|
1077
|
+
if (!refreshed) {
|
|
1078
|
+
throw error;
|
|
1079
|
+
}
|
|
1080
|
+
await this.commitSessionUpdate(params, isApplicationUpdate, isTenantUpdate, startedAt);
|
|
1092
1081
|
}
|
|
1093
1082
|
}
|
|
1094
1083
|
catch (error) {
|
|
1095
1084
|
traceAuthLifecycleError('UpdateSession failed', () => ({
|
|
1096
1085
|
error: error instanceof Error ? error.message : String(error),
|
|
1097
1086
|
}));
|
|
1098
|
-
warnAuthWorkspace('UpdateSession failed — identity session kept', () => ({
|
|
1099
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1100
|
-
tenantId: params?.['tenant']?.id ?? params?.['tenantId'] ?? null,
|
|
1101
|
-
applicationId: params?.['application']?.id ?? params?.['applicationId'] ?? null,
|
|
1102
|
-
}));
|
|
1103
1087
|
if (params?.['code']) {
|
|
1104
1088
|
clearOAuthPendingStrategy();
|
|
1105
1089
|
}
|
|
@@ -1108,6 +1092,11 @@ class AXPSessionService {
|
|
|
1108
1092
|
this.syncContextSubjectsFromStorage();
|
|
1109
1093
|
const stored = this.getSessionData();
|
|
1110
1094
|
if (stored?.user && stored.cookieSession) {
|
|
1095
|
+
warnAuthWorkspace('UpdateSession failed — identity session kept', () => ({
|
|
1096
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1097
|
+
tenantId: params?.['tenant']?.id ?? params?.['tenantId'] ?? null,
|
|
1098
|
+
applicationId: params?.['application']?.id ?? params?.['applicationId'] ?? null,
|
|
1099
|
+
}));
|
|
1111
1100
|
await this.syncSessionAuthorization();
|
|
1112
1101
|
}
|
|
1113
1102
|
throw error;
|
|
@@ -1571,6 +1560,85 @@ class AXPSessionService {
|
|
|
1571
1560
|
invalidateAccessPolicyCache() {
|
|
1572
1561
|
this.accessPolicyCache?.invalidate();
|
|
1573
1562
|
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Access cookie max-age matches the JWT (often 15m) while the refresh cookie lasts days.
|
|
1565
|
+
* After it expires the browser omits it, and UpdateSession is not retried by the HTTP
|
|
1566
|
+
* interceptor (auth commands skip 401 refresh to avoid a lock deadlock).
|
|
1567
|
+
*/
|
|
1568
|
+
isAccessCookieStale() {
|
|
1569
|
+
const expiresIn = this.getSessionData()?.expiresIn;
|
|
1570
|
+
if (!expiresIn) {
|
|
1571
|
+
return false;
|
|
1572
|
+
}
|
|
1573
|
+
const expiresAt = new Date(expiresIn).getTime();
|
|
1574
|
+
if (Number.isNaN(expiresAt)) {
|
|
1575
|
+
return false;
|
|
1576
|
+
}
|
|
1577
|
+
const skewMs = 15_000;
|
|
1578
|
+
return expiresAt <= Date.now() + skewMs;
|
|
1579
|
+
}
|
|
1580
|
+
async refreshAccessCookieIfStale() {
|
|
1581
|
+
if (!this.isAccessCookieStale() || !this.hasSessionCredentials()) {
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
traceAuthWorkspace('Access cookie stale — refreshing before UpdateSession', () => ({
|
|
1585
|
+
expiresIn: this.getSessionData()?.expiresIn ?? null,
|
|
1586
|
+
}));
|
|
1587
|
+
try {
|
|
1588
|
+
await this.refreshToken();
|
|
1589
|
+
}
|
|
1590
|
+
catch (error) {
|
|
1591
|
+
if (isDefinitiveAuthRefreshFailure(error)) {
|
|
1592
|
+
throw error;
|
|
1593
|
+
}
|
|
1594
|
+
warnAuthWorkspace('Stale access refresh failed — continuing UpdateSession', () => ({
|
|
1595
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1596
|
+
}));
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
async commitSessionUpdate(params, isApplicationUpdate, isTenantUpdate, startedAt) {
|
|
1600
|
+
const strategyName = this.resolveStrategyName();
|
|
1601
|
+
if (!strategyName) {
|
|
1602
|
+
throw new Error('Strategy not found');
|
|
1603
|
+
}
|
|
1604
|
+
const strategy = this.authStrategyRegistry.get(strategyName);
|
|
1605
|
+
if (!strategy) {
|
|
1606
|
+
throw new Error(`Authentication strategy '${strategyName}' is not supported`);
|
|
1607
|
+
}
|
|
1608
|
+
// Same lock as cookie refresh — UpdateSession rotates refresh `jti`.
|
|
1609
|
+
// A restore in another tab must not consume the previous cookie concurrently.
|
|
1610
|
+
const result = await withAuthRefreshLock(() => strategy.updateToken(params));
|
|
1611
|
+
if (!result?.succeed) {
|
|
1612
|
+
throw new Error('UpdateSession failed');
|
|
1613
|
+
}
|
|
1614
|
+
if (params?.['code']) {
|
|
1615
|
+
// OAuth code exchange replaces identity metadata; wipe stale local fields first.
|
|
1616
|
+
this.clearSession();
|
|
1617
|
+
clearOAuthPendingStrategy();
|
|
1618
|
+
}
|
|
1619
|
+
else {
|
|
1620
|
+
this.permissionsSubject.next([]);
|
|
1621
|
+
this.featuresSubject.next([]);
|
|
1622
|
+
this.invalidateAccessPolicyCache();
|
|
1623
|
+
}
|
|
1624
|
+
this.setSession({
|
|
1625
|
+
strategy: strategyName,
|
|
1626
|
+
user: result.data.user,
|
|
1627
|
+
tenant: result.data?.tenant ?? null,
|
|
1628
|
+
application: this.resolveApplicationAfterUpdate(result.data?.application ?? null, isApplicationUpdate, isTenantUpdate),
|
|
1629
|
+
expiresIn: result.data?.expiresIn,
|
|
1630
|
+
locked: false,
|
|
1631
|
+
cookieSession: true,
|
|
1632
|
+
});
|
|
1633
|
+
await this.reloadAccessPolicyIfReady('updateToken');
|
|
1634
|
+
await this.syncSessionAuthorization();
|
|
1635
|
+
traceAuthWorkspace('UpdateSession complete', () => ({
|
|
1636
|
+
ms: Date.now() - startedAt,
|
|
1637
|
+
status: this.status.value,
|
|
1638
|
+
tenantId: this.tenant?.id,
|
|
1639
|
+
applicationId: this.application?.id,
|
|
1640
|
+
}));
|
|
1641
|
+
}
|
|
1574
1642
|
isApplicationContextUpdate(params) {
|
|
1575
1643
|
return params?.['application'] != null || params?.['applicationId'] != null;
|
|
1576
1644
|
}
|
|
@@ -2826,5 +2894,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
2826
2894
|
* Generated bundle index. Do not edit.
|
|
2827
2895
|
*/
|
|
2828
2896
|
|
|
2829
|
-
export { AUTH_SESSION_TRACE_NS, AUTH_SESSION_TRACE_TITLE, AXPAuthGuard, AXPAuthModule, AXPAuthStrategy, AXPAuthStrategyRegistryService, AXPFeatureDirective, AXPFeatureEvaluatorScopeProvider, AXPFeatureGuard, AXPLoginChallengeComponentBase, AXPLoginChallengeProvider, AXPPermissionDefinitionBuilder, AXPPermissionDefinitionGroupBuilder, AXPPermissionDefinitionProviderContext, AXPPermissionDefinitionService, AXPPermissionDirective, AXPPermissionEvaluatorScopeProvider, AXPPermissionGuard, AXPPlatformAuthRuntimeService, AXPSessionContext, AXPSessionService, AXPSessionStatus, AXPSignInMethod, AXPSignInMethodRegistry, AXPUnauthenticatedError, AXPUnauthorizedError, AXPUserProfileIdentityService, AXP_ACCESS_POLICY_CACHE_PORT, AXP_APPLICATION_LOADER, AXP_DEFAULT_PLATFORM_OAUTH_CLIENT_ID, AXP_DEFAULT_PLATFORM_OAUTH_SCOPE, AXP_FEATURE_CHECKER, AXP_FEATURE_LOADER, AXP_LOGIN_CHALLENGE_PROVIDER, AXP_OAUTH_PKCE_VERIFIER_KEY, AXP_PERMISSION_CHECKER, AXP_PERMISSION_DEFINITION_PROVIDER, AXP_PERMISSION_LOADER, AXP_PERMISSION_MODULES_RESOLVER, AXP_PLATFORM_OAUTH_CSRF_COOKIE, AXP_TENANT_LOADER, AXP_USER_AVATAR_CACHE_PORT, DEFINITIVE_AUTH_REFRESH_CODES, JwtUtil, MAX_ACTIVE_DEVICE_SESSIONS_CODE, PkceUtil, TimeUtil, asAuthListProvidersResponse, clearOAuthPendingStrategy, clearSessionLimitPendingTenant, commandMessageTextForError, exchangePlatformOAuthAuthorizationCode, fetchPlatformOAuthDiscoveryDocument, findIdentityProvider, getOAuthPendingStrategy, hasLegacyOAuthPkceVerifier, hasOAuthPendingFlow, initPlatformOAuthAuthorization, isDefinitiveAuthRefreshFailure, isMaxActiveDeviceSessionsError, isOAuthRedirectInFlight, platformOAuthSessionUpdateParams, readPlatformOAuthCsrfToken, readSessionLimitPendingTenant, resolvePlatformOAuthAuthorizeEndpoint, resolvePlatformOAuthClientConfig, resolvePlatformOAuthIssuer, resolvePlatformOAuthRedirectUri, resolvePlatformOAuthTokenEndpoint, resolveStatusAfterSoftRestore, setOAuthPendingStrategy, shouldPlatformOAuthBindSession, shouldRetryAccessPolicyAuthorization, storeSessionLimitPendingTenant, toPlatformOAuthSignInResult, traceAuthAccessPolicy, traceAuthCatalog, traceAuthGuard, traceAuthLifecycle, traceAuthLifecycleError, traceAuthRestore, traceAuthWorkspace, warnAuthAccessPolicy, warnAuthLifecycle, warnAuthWorkspace };
|
|
2897
|
+
export { AUTH_SESSION_TRACE_NS, AUTH_SESSION_TRACE_TITLE, AXPAuthGuard, AXPAuthModule, AXPAuthStrategy, AXPAuthStrategyRegistryService, AXPFeatureDirective, AXPFeatureEvaluatorScopeProvider, AXPFeatureGuard, AXPLoginChallengeComponentBase, AXPLoginChallengeProvider, AXPPermissionDefinitionBuilder, AXPPermissionDefinitionGroupBuilder, AXPPermissionDefinitionProviderContext, AXPPermissionDefinitionService, AXPPermissionDirective, AXPPermissionEvaluatorScopeProvider, AXPPermissionGuard, AXPPlatformAuthRuntimeService, AXPSessionContext, AXPSessionService, AXPSessionStatus, AXPSignInMethod, AXPSignInMethodRegistry, AXPUnauthenticatedError, AXPUnauthorizedError, AXPUserProfileIdentityService, AXP_ACCESS_POLICY_CACHE_PORT, AXP_APPLICATION_LOADER, AXP_DEFAULT_PLATFORM_OAUTH_CLIENT_ID, AXP_DEFAULT_PLATFORM_OAUTH_SCOPE, AXP_FEATURE_CHECKER, AXP_FEATURE_LOADER, AXP_LOGIN_CHALLENGE_PROVIDER, AXP_OAUTH_PKCE_VERIFIER_KEY, AXP_PERMISSION_CHECKER, AXP_PERMISSION_DEFINITION_PROVIDER, AXP_PERMISSION_LOADER, AXP_PERMISSION_MODULES_RESOLVER, AXP_PLATFORM_OAUTH_CSRF_COOKIE, AXP_TENANT_LOADER, AXP_USER_AVATAR_CACHE_PORT, DEFINITIVE_AUTH_REFRESH_CODES, JwtUtil, MAX_ACTIVE_DEVICE_SESSIONS_CODE, PkceUtil, TimeUtil, asAuthListProvidersResponse, clearOAuthPendingStrategy, clearSessionLimitPendingTenant, commandMessageTextForError, exchangePlatformOAuthAuthorizationCode, fetchPlatformOAuthDiscoveryDocument, findIdentityProvider, getOAuthPendingStrategy, hasLegacyOAuthPkceVerifier, hasOAuthPendingFlow, initPlatformOAuthAuthorization, isDefinitiveAuthRefreshFailure, isMaxActiveDeviceSessionsError, isMissingAccessTokenError, isOAuthRedirectInFlight, platformOAuthSessionUpdateParams, readPlatformOAuthCsrfToken, readSessionLimitPendingTenant, resolvePlatformOAuthAuthorizeEndpoint, resolvePlatformOAuthClientConfig, resolvePlatformOAuthIssuer, resolvePlatformOAuthRedirectUri, resolvePlatformOAuthTokenEndpoint, resolveStatusAfterSoftRestore, setOAuthPendingStrategy, shouldPlatformOAuthBindSession, shouldRetryAccessPolicyAuthorization, storeSessionLimitPendingTenant, toPlatformOAuthSignInResult, traceAuthAccessPolicy, traceAuthCatalog, traceAuthGuard, traceAuthLifecycle, traceAuthLifecycleError, traceAuthRestore, traceAuthWorkspace, warnAuthAccessPolicy, warnAuthLifecycle, warnAuthWorkspace };
|
|
2830
2898
|
//# sourceMappingURL=acorex-platform-framework-client-auth.mjs.map
|