@finos/legend-application 16.0.105 → 16.0.107
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/lib/components/LegendTokenSync.d.ts +5 -0
- package/lib/components/LegendTokenSync.d.ts.map +1 -1
- package/lib/components/LegendTokenSync.js +30 -5
- package/lib/components/LegendTokenSync.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/package.json +4 -4
- package/src/components/LegendTokenSync.tsx +37 -5
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
/**
|
|
17
17
|
* Must be rendered inside an `<AuthProvider>` and an
|
|
18
18
|
* `<ApplicationStoreProvider>`.
|
|
19
|
+
*
|
|
20
|
+
* Keeps the in-memory token and cookie in sync with the OIDC provider
|
|
21
|
+
* and proactively renews the access token before it expires so that
|
|
22
|
+
* long-running sessions (e.g. Legend marketplace AI chat, query execution) never send
|
|
23
|
+
* stale credentials.
|
|
19
24
|
*/
|
|
20
25
|
export declare const LegendTokenSync: (props: {
|
|
21
26
|
children: React.ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LegendTokenSync.d.ts","sourceRoot":"","sources":["../../src/components/LegendTokenSync.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH
|
|
1
|
+
{"version":3,"file":"LegendTokenSync.d.ts","sourceRoot":"","sources":["../../src/components/LegendTokenSync.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,KAAG,KAAK,CAAC,YA2DT,CAAC"}
|
|
@@ -14,7 +14,7 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import { useEffect } from 'react';
|
|
17
|
+
import { useEffect, useCallback } from 'react';
|
|
18
18
|
import { useAuth } from 'react-oidc-context';
|
|
19
19
|
import { LogEvent } from '@finos/legend-shared';
|
|
20
20
|
import { useApplicationStore } from './ApplicationStoreProvider.js';
|
|
@@ -22,12 +22,26 @@ import { APPLICATION_EVENT } from '../__lib__/LegendApplicationEvent.js';
|
|
|
22
22
|
/**
|
|
23
23
|
* Must be rendered inside an `<AuthProvider>` and an
|
|
24
24
|
* `<ApplicationStoreProvider>`.
|
|
25
|
+
*
|
|
26
|
+
* Keeps the in-memory token and cookie in sync with the OIDC provider
|
|
27
|
+
* and proactively renews the access token before it expires so that
|
|
28
|
+
* long-running sessions (e.g. Legend marketplace AI chat, query execution) never send
|
|
29
|
+
* stale credentials.
|
|
25
30
|
*/
|
|
26
31
|
export const LegendTokenSync = (props) => {
|
|
27
32
|
const auth = useAuth();
|
|
28
33
|
const applicationStore = useApplicationStore();
|
|
29
34
|
const token = auth.user?.access_token;
|
|
30
35
|
const expiresAt = auth.user?.expires_at;
|
|
36
|
+
const attemptSilentRenew = useCallback(async () => {
|
|
37
|
+
try {
|
|
38
|
+
await auth.signinSilent();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
applicationStore.logService.warn(LogEvent.create(APPLICATION_EVENT.TOKEN_EXPIRED), 'OIDC silent renewal failed — clearing token');
|
|
42
|
+
applicationStore.setAccessToken(undefined);
|
|
43
|
+
}
|
|
44
|
+
}, [auth, applicationStore]);
|
|
31
45
|
// Sync token into ApplicationStore whenever it changes (including
|
|
32
46
|
// after a successful automatic silent renewal). When the auth object
|
|
33
47
|
// contains an `expires_at` timestamp we derive `max-age` so the
|
|
@@ -38,15 +52,26 @@ export const LegendTokenSync = (props) => {
|
|
|
38
52
|
: undefined;
|
|
39
53
|
applicationStore.setAccessToken(token ?? undefined, maxAge);
|
|
40
54
|
}, [applicationStore, token, expiresAt]);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const removeExpiring = auth.events.addAccessTokenExpiring(() => {
|
|
57
|
+
applicationStore.logService.info(LogEvent.create(APPLICATION_EVENT.TOKEN_EXPIRED), 'OIDC access token expiring soon — attempting silent renewal');
|
|
58
|
+
attemptSilentRenew().catch(() => {
|
|
59
|
+
/* handled inside attemptSilentRenew */
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
return removeExpiring;
|
|
63
|
+
}, [auth.events, applicationStore, attemptSilentRenew]);
|
|
41
64
|
// If the token fully expires (automatic renewal failed or was never
|
|
42
|
-
// attempted)
|
|
65
|
+
// attempted) make one last renewal attempt before giving up.
|
|
43
66
|
useEffect(() => {
|
|
44
67
|
const removeExpired = auth.events.addAccessTokenExpired(() => {
|
|
45
|
-
applicationStore.logService.warn(LogEvent.create(APPLICATION_EVENT.TOKEN_EXPIRED), 'OIDC access token expired —
|
|
46
|
-
|
|
68
|
+
applicationStore.logService.warn(LogEvent.create(APPLICATION_EVENT.TOKEN_EXPIRED), 'OIDC access token expired — attempting silent renewal');
|
|
69
|
+
attemptSilentRenew().catch(() => {
|
|
70
|
+
/* handled inside attemptSilentRenew */
|
|
71
|
+
});
|
|
47
72
|
});
|
|
48
73
|
return removeExpired;
|
|
49
|
-
}, [auth.events, applicationStore]);
|
|
74
|
+
}, [auth.events, applicationStore, attemptSilentRenew]);
|
|
50
75
|
return _jsx(_Fragment, { children: props.children });
|
|
51
76
|
};
|
|
52
77
|
//# sourceMappingURL=LegendTokenSync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LegendTokenSync.js","sourceRoot":"","sources":["../../src/components/LegendTokenSync.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"LegendTokenSync.js","sourceRoot":"","sources":["../../src/components/LegendTokenSync.tsx"],"names":[],"mappings":"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"}
|
package/lib/index.css
CHANGED
package/lib/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finos/legend-application",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.107",
|
|
4
4
|
"description": "Legend application core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"legend",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"test:watch": "jest --watch"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@finos/legend-art": "7.1.
|
|
49
|
-
"@finos/legend-shared": "11.0.
|
|
50
|
-
"@finos/legend-storage": "3.0.
|
|
48
|
+
"@finos/legend-art": "7.1.148",
|
|
49
|
+
"@finos/legend-shared": "11.0.25",
|
|
50
|
+
"@finos/legend-storage": "3.0.146",
|
|
51
51
|
"@types/react": "19.0.10",
|
|
52
52
|
"@types/react-dom": "19.0.4",
|
|
53
53
|
"@types/react-router-dom": "5.3.3",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { useEffect } from 'react';
|
|
17
|
+
import { useEffect, useCallback } from 'react';
|
|
18
18
|
import { useAuth } from 'react-oidc-context';
|
|
19
19
|
import { LogEvent } from '@finos/legend-shared';
|
|
20
20
|
import { useApplicationStore } from './ApplicationStoreProvider.js';
|
|
@@ -23,6 +23,11 @@ import { APPLICATION_EVENT } from '../__lib__/LegendApplicationEvent.js';
|
|
|
23
23
|
/**
|
|
24
24
|
* Must be rendered inside an `<AuthProvider>` and an
|
|
25
25
|
* `<ApplicationStoreProvider>`.
|
|
26
|
+
*
|
|
27
|
+
* Keeps the in-memory token and cookie in sync with the OIDC provider
|
|
28
|
+
* and proactively renews the access token before it expires so that
|
|
29
|
+
* long-running sessions (e.g. Legend marketplace AI chat, query execution) never send
|
|
30
|
+
* stale credentials.
|
|
26
31
|
*/
|
|
27
32
|
export const LegendTokenSync = (props: {
|
|
28
33
|
children: React.ReactNode;
|
|
@@ -32,6 +37,18 @@ export const LegendTokenSync = (props: {
|
|
|
32
37
|
const token = auth.user?.access_token;
|
|
33
38
|
const expiresAt = auth.user?.expires_at;
|
|
34
39
|
|
|
40
|
+
const attemptSilentRenew = useCallback(async () => {
|
|
41
|
+
try {
|
|
42
|
+
await auth.signinSilent();
|
|
43
|
+
} catch {
|
|
44
|
+
applicationStore.logService.warn(
|
|
45
|
+
LogEvent.create(APPLICATION_EVENT.TOKEN_EXPIRED),
|
|
46
|
+
'OIDC silent renewal failed — clearing token',
|
|
47
|
+
);
|
|
48
|
+
applicationStore.setAccessToken(undefined);
|
|
49
|
+
}
|
|
50
|
+
}, [auth, applicationStore]);
|
|
51
|
+
|
|
35
52
|
// Sync token into ApplicationStore whenever it changes (including
|
|
36
53
|
// after a successful automatic silent renewal). When the auth object
|
|
37
54
|
// contains an `expires_at` timestamp we derive `max-age` so the
|
|
@@ -44,18 +61,33 @@ export const LegendTokenSync = (props: {
|
|
|
44
61
|
applicationStore.setAccessToken(token ?? undefined, maxAge);
|
|
45
62
|
}, [applicationStore, token, expiresAt]);
|
|
46
63
|
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const removeExpiring = auth.events.addAccessTokenExpiring(() => {
|
|
66
|
+
applicationStore.logService.info(
|
|
67
|
+
LogEvent.create(APPLICATION_EVENT.TOKEN_EXPIRED),
|
|
68
|
+
'OIDC access token expiring soon — attempting silent renewal',
|
|
69
|
+
);
|
|
70
|
+
attemptSilentRenew().catch(() => {
|
|
71
|
+
/* handled inside attemptSilentRenew */
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
return removeExpiring;
|
|
75
|
+
}, [auth.events, applicationStore, attemptSilentRenew]);
|
|
76
|
+
|
|
47
77
|
// If the token fully expires (automatic renewal failed or was never
|
|
48
|
-
// attempted)
|
|
78
|
+
// attempted) make one last renewal attempt before giving up.
|
|
49
79
|
useEffect(() => {
|
|
50
80
|
const removeExpired = auth.events.addAccessTokenExpired(() => {
|
|
51
81
|
applicationStore.logService.warn(
|
|
52
82
|
LogEvent.create(APPLICATION_EVENT.TOKEN_EXPIRED),
|
|
53
|
-
'OIDC access token expired —
|
|
83
|
+
'OIDC access token expired — attempting silent renewal',
|
|
54
84
|
);
|
|
55
|
-
|
|
85
|
+
attemptSilentRenew().catch(() => {
|
|
86
|
+
/* handled inside attemptSilentRenew */
|
|
87
|
+
});
|
|
56
88
|
});
|
|
57
89
|
return removeExpired;
|
|
58
|
-
}, [auth.events, applicationStore]);
|
|
90
|
+
}, [auth.events, applicationStore, attemptSilentRenew]);
|
|
59
91
|
|
|
60
92
|
return <>{props.children}</>;
|
|
61
93
|
};
|