@nu-art/user-account-frontend 0.400.5

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.
Files changed (48) hide show
  1. package/_ats/account-editor/ATS_AccountEditor.d.ts +15 -0
  2. package/_ats/account-editor/ATS_AccountEditor.js +45 -0
  3. package/_ats/account-editor/ATS_AccountEditor.scss +127 -0
  4. package/_ats_session-data/ATS_SessionData.d.ts +18 -0
  5. package/_ats_session-data/ATS_SessionData.js +40 -0
  6. package/_entity/account/ModuleFE_Account.d.ts +47 -0
  7. package/_entity/account/ModuleFE_Account.js +153 -0
  8. package/_entity/account/consts.d.ts +8 -0
  9. package/_entity/account/consts.js +7 -0
  10. package/_entity/account/index.d.ts +3 -0
  11. package/_entity/account/index.js +3 -0
  12. package/_entity/account/module-pack.d.ts +2 -0
  13. package/_entity/account/module-pack.js +3 -0
  14. package/_entity/session/ModuleFE_Session.d.ts +33 -0
  15. package/_entity/session/ModuleFE_Session.js +95 -0
  16. package/_entity.d.ts +3 -0
  17. package/_entity.js +3 -0
  18. package/account-editor/Component_AccountEditor.d.ts +38 -0
  19. package/account-editor/Component_AccountEditor.js +134 -0
  20. package/account-editor/Component_AccountEditor.scss +139 -0
  21. package/consts.d.ts +1 -0
  22. package/consts.js +1 -0
  23. package/index.d.ts +9 -0
  24. package/index.js +26 -0
  25. package/module-pack.d.ts +2 -0
  26. package/module-pack.js +21 -0
  27. package/package.json +81 -0
  28. package/ui/Component_AccountThumbnail/Component_AccountThumbnail.d.ts +14 -0
  29. package/ui/Component_AccountThumbnail/Component_AccountThumbnail.js +59 -0
  30. package/ui/Component_AccountThumbnail/Component_AccountThumbnail.scss +66 -0
  31. package/ui/Component_ChangePassword/Component_ChangePassword.d.ts +17 -0
  32. package/ui/Component_ChangePassword/Component_ChangePassword.js +52 -0
  33. package/ui/Component_GoogleSAMLLogin/Component_GoogleSAMLLogin.d.ts +6 -0
  34. package/ui/Component_GoogleSAMLLogin/Component_GoogleSAMLLogin.js +16 -0
  35. package/ui/Component_GoogleSAMLLogin/Component_GoogleSAMLLogin.scss +20 -0
  36. package/ui/Component_Login/Component_Login.d.ts +23 -0
  37. package/ui/Component_Login/Component_Login.js +124 -0
  38. package/ui/Component_Login/Component_Login.scss +66 -0
  39. package/ui/Component_Login/index.d.ts +1 -0
  40. package/ui/Component_Login/index.js +18 -0
  41. package/ui/Component_LoginBlocked/Component_LoginBlocked.d.ts +19 -0
  42. package/ui/Component_LoginBlocked/Component_LoginBlocked.js +35 -0
  43. package/ui/Component_LoginBlocked/Component_LoginBlocked.scss +3 -0
  44. package/ui/Component_Register.d.ts +26 -0
  45. package/ui/Component_Register.js +152 -0
  46. package/ui/PopUp_AccountMenu/PopUp_AccountMenu.d.ts +62 -0
  47. package/ui/PopUp_AccountMenu/PopUp_AccountMenu.js +130 -0
  48. package/ui/PopUp_AccountMenu/PopUp_AccountMenu.scss +167 -0
@@ -0,0 +1,15 @@
1
+ import './ATS_AccountEditor.scss';
2
+ import { AppToolsScreen, ComponentSync } from '@nu-art/thunderstorm-frontend/index';
3
+ import { DB_Account } from '@nu-art/user-account-shared';
4
+ type Props = {};
5
+ type State = {
6
+ selectedUser?: DB_Account;
7
+ isPreview?: boolean;
8
+ };
9
+ export declare class ATS_AccountEditor extends ComponentSync<Props, State> {
10
+ static screen: AppToolsScreen;
11
+ protected deriveStateFromProps(nextProps: {}, state: State): State;
12
+ private setSelectedAccount;
13
+ render(): import("react/jsx-runtime").JSX.Element;
14
+ }
15
+ export {};
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import './ATS_AccountEditor.scss';
3
+ import { _className, Button, ComponentSync, LL_H_C, LL_V_L, TS_PropRenderer } from '@nu-art/thunderstorm-frontend/index';
4
+ import { Component_AccountEditor } from '../../account-editor/Component_AccountEditor.js';
5
+ import { generateUUID } from '@nu-art/ts-common';
6
+ import { ModuleFE_Account } from '../../_entity/account/index.js';
7
+ export class ATS_AccountEditor extends ComponentSync {
8
+ static screen = {
9
+ name: 'Accounts Editor',
10
+ key: 'user-account',
11
+ renderer: this,
12
+ group: 'Permissions',
13
+ modulesToAwait: [ModuleFE_Account]
14
+ };
15
+ // ######################### Life Cycle #########################
16
+ deriveStateFromProps(nextProps, state) {
17
+ state = this.state ? { ...this.state } : {};
18
+ return state;
19
+ }
20
+ // ######################### Logic #########################
21
+ setSelectedAccount = (account) => {
22
+ if (!account)
23
+ this.setState({ isPreview: false, selectedUser: undefined });
24
+ else
25
+ this.setState({ isPreview: true, selectedUser: account });
26
+ };
27
+ render() {
28
+ return _jsxs(LL_H_C, { className: 'account-editor-form', children: [_jsx(Component_AccountList, { user: this.state.selectedUser, setSelectedAccount: this.setSelectedAccount }), _jsx(Component_AccountEditor, { isPreview: this.state.isPreview, user: this.state.selectedUser })] });
29
+ }
30
+ }
31
+ class Component_AccountList extends ComponentSync {
32
+ __onAccountsUpdated(...params) {
33
+ this.reDeriveState();
34
+ }
35
+ deriveStateFromProps(nextProps, state) {
36
+ state.list = ModuleFE_Account.cache.allMutable();
37
+ return state;
38
+ }
39
+ render() {
40
+ return _jsxs(LL_V_L, { className: 'form-container account-list', children: [_jsx(LL_H_C, { className: 'match_width', children: _jsx(TS_PropRenderer.Horizontal, { className: 'match_width', label: 'Accounts List', children: _jsx(Button, { variant: 'primary', onClick: async () => this.props.setSelectedAccount(), children: "Create Account" }) }) }), _jsx(LL_V_L, { className: 'match_width users-list', children: this.state.list.map(account => {
41
+ const className = _className('match_width', 'row', this.props.user?._id === account._id && 'selected');
42
+ return _jsx(TS_PropRenderer.Horizontal, { onClick: () => this.props.setSelectedAccount(account), className: className, label: account.email }, generateUUID());
43
+ }) })] });
44
+ }
45
+ }
@@ -0,0 +1,127 @@
1
+ @use '@nu-art/ts-styles' as styles;
2
+
3
+ .account-editor-form {
4
+ width: 100%;
5
+ height: 100%;
6
+ padding: 15px 35px 35px 35px;
7
+ align-items: flex-start;
8
+ gap: 5%;
9
+
10
+
11
+ .form-container {
12
+ padding: 14px;
13
+ width: 650px;
14
+ background: white;
15
+ border-radius: 4px;
16
+ gap: 15px;
17
+
18
+ &.account-list {
19
+ width: 300px;
20
+ max-height: 100%;
21
+ overflow: auto;
22
+
23
+ .users-list {
24
+ cursor: pointer;
25
+ padding: 10px;
26
+
27
+ .row {
28
+ &.selected {
29
+ background: styles.dark-blue(7);
30
+ }
31
+
32
+ &:not(:last-child) {
33
+ border-bottom: 1px solid styles.gray(6);
34
+ }
35
+ }
36
+ }
37
+ }
38
+
39
+ .user-utils {
40
+ .icon--wrapper {
41
+ cursor: pointer;
42
+
43
+ @include styles.color-svg(var(--prop-renderer__label-color));
44
+ }
45
+ }
46
+
47
+ .ts-prop-renderer {
48
+ &.horizontal {
49
+ justify-content: space-between;
50
+ }
51
+ }
52
+
53
+ .inputs-row {
54
+ justify-content: space-between;
55
+ width: 100%;
56
+ }
57
+
58
+ .ts-input {
59
+ padding: 2px 10px 2px 10px;
60
+ border-radius: 4px;
61
+ background: none;
62
+ border: 1px solid #e3e9f2;
63
+
64
+ &::placeholder {
65
+ font-style: normal;
66
+ }
67
+ }
68
+
69
+ .ts-dropdown {
70
+ max-width: 300px;
71
+
72
+ .ts-dropdown__items-container {
73
+ margin: 0;
74
+ }
75
+
76
+ .ts-dropdown__header {
77
+ background: none;
78
+ border-radius: 4px;
79
+ border: 1px solid #e3e9f2;
80
+ padding: 2px 10px 2px 10px;
81
+ text-align: center;
82
+
83
+ .ts-dropdown__placeholder {
84
+ font-style: normal;
85
+ padding: 0;
86
+ }
87
+ }
88
+
89
+ .ts-dropdown__items-container {
90
+ border: none;
91
+ }
92
+
93
+
94
+ .ts-tree {
95
+ .ts-tree__children-container {
96
+ .ts-tree__node {
97
+ background: none;
98
+ padding: 4px;
99
+ cursor: pointer;
100
+ border: 1px solid #e3e9f2;
101
+
102
+ &:hover {
103
+ background: rgb(210, 219, 234);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ .ts-busy-button {
111
+ background: white;
112
+ font-size: 12px;
113
+ border-radius: 5px;
114
+ color: inherit;
115
+ padding: 2px 10px 2px 10px;
116
+ height: 40px;
117
+ font-weight: 400;
118
+ border: 1px #e3e9f2 solid;
119
+ margin-inline: 0;
120
+
121
+ &:hover {
122
+ background: #6C87B0FF;
123
+ color: white;
124
+ }
125
+ }
126
+ }
127
+ }
@@ -0,0 +1,18 @@
1
+ import { AppToolsScreen, ComponentSync, OnStorageKeyChangedListener } from '@nu-art/thunderstorm-frontend/index';
2
+ type ATS_SessionData_Props = {};
3
+ type ATS_SessionData_State = {
4
+ sessionId?: string;
5
+ };
6
+ export declare class ATS_SessionData extends ComponentSync<ATS_SessionData_Props, ATS_SessionData_State> implements OnStorageKeyChangedListener {
7
+ static screen: AppToolsScreen;
8
+ static defaultProps: {
9
+ modules: never[];
10
+ pageTitle: () => string;
11
+ };
12
+ protected deriveStateFromProps(nextProps: ATS_SessionData_Props, state: ATS_SessionData_State): ATS_SessionData_State;
13
+ constructor(p: ATS_SessionData_Props);
14
+ __onStorageKeyEvent(event: StorageEvent): Promise<void>;
15
+ private getDecodedSessionId;
16
+ render(): import("react/jsx-runtime").JSX.Element;
17
+ }
18
+ export {};
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { __stringify } from '@nu-art/ts-common';
3
+ import { ModuleFE_Account } from '../_entity/account/index.js';
4
+ import { ComponentSync, LL_V_L, TS_Input, TS_TextArea } from '@nu-art/thunderstorm-frontend/index';
5
+ export class ATS_SessionData extends ComponentSync {
6
+ static screen = { name: `SessionData`, renderer: this, group: 'Permissions' };
7
+ static defaultProps = {
8
+ modules: [],
9
+ pageTitle: () => this.screen.name
10
+ };
11
+ deriveStateFromProps(nextProps, state) {
12
+ state = this.state ?? {};
13
+ return state;
14
+ }
15
+ constructor(p) {
16
+ super(p);
17
+ }
18
+ async __onStorageKeyEvent(event) {
19
+ this.forceUpdate();
20
+ }
21
+ getDecodedSessionId() {
22
+ try {
23
+ if (this.state.sessionId && this.state.sessionId.length) { // @ts-ignore
24
+ return __stringify(ModuleFE_Account.decode(this.state.sessionId), true);
25
+ }
26
+ // @ts-ignore
27
+ return __stringify(ModuleFE_Account.sessionData, true);
28
+ }
29
+ catch (e) {
30
+ // @ts-ignore
31
+ return __stringify(ModuleFE_Account.sessionData, true);
32
+ }
33
+ }
34
+ render() {
35
+ const sessionDataAsJson = this.getDecodedSessionId();
36
+ return _jsxs(LL_V_L, { className: 'match_parent', children: [_jsx(TS_Input, { type: 'text', onBlur: (value) => {
37
+ this.setState({ sessionId: value });
38
+ } }), _jsx(TS_TextArea, { style: { fontFamily: 'monospace', fontSize: 15 }, type: "text", value: sessionDataAsJson, disabled: true })] });
39
+ }
40
+ }
@@ -0,0 +1,47 @@
1
+ import * as React from 'react';
2
+ import { ModuleFE_BaseApi, ThunderDispatcher } from '@nu-art/thunderstorm-frontend/index';
3
+ import { ApiDefCaller } from '@nu-art/thunderstorm-shared';
4
+ import { ApiStruct_Account, ApiStruct_SAML, DB_Account, DBProto_Account, PasswordAssertionConfig, UI_Account } from '@nu-art/user-account-shared';
5
+ import { ApiCallerEventType } from '@nu-art/thunderstorm-frontend/core/db-api-gen/types';
6
+ import { OnSessionUpdated } from '../session/ModuleFE_Session.js';
7
+ export interface OnLoginStatusUpdated {
8
+ __onLoginStatusUpdated: () => void;
9
+ }
10
+ export interface OnAccountsUpdated {
11
+ __onAccountsUpdated: (...params: ApiCallerEventType<DBProto_Account>) => void;
12
+ }
13
+ export declare enum LoggedStatus {
14
+ VALIDATING = 0,
15
+ LOGGED_OUT = 1,
16
+ SESSION_TIMEOUT = 2,
17
+ LOGGED_IN = 3
18
+ }
19
+ export declare const dispatch_onLoginStatusChanged: ThunderDispatcher<OnLoginStatusUpdated, "__onLoginStatusUpdated", [], void>;
20
+ export declare const dispatch_onAccountsUpdated: ThunderDispatcher<OnAccountsUpdated, "__onAccountsUpdated", ApiCallerEventType<DBProto_Account>, void>;
21
+ type ApiDefCaller_Account = ApiDefCaller<{
22
+ _v1: ApiStruct_Account['_v1'] & ApiStruct_SAML['_v1'];
23
+ }>;
24
+ declare class ModuleFE_Account_Class extends ModuleFE_BaseApi<DBProto_Account> implements ApiDefCaller_Account, OnLoginStatusUpdated, OnSessionUpdated {
25
+ readonly _v1: ApiDefCaller_Account['_v1'];
26
+ private status;
27
+ __onLoginStatusUpdated(): void;
28
+ constructor();
29
+ protected init(): void;
30
+ getAccounts(): UI_Account[];
31
+ getLoggedStatus: () => LoggedStatus;
32
+ isStatus: (status: LoggedStatus | LoggedStatus[]) => boolean;
33
+ __onSessionUpdated(): void;
34
+ protected setLoggedStatus: (newStatus: LoggedStatus) => void;
35
+ composeSAMLUrl: () => string;
36
+ logout: (url?: string) => Promise<string | undefined>;
37
+ uploadAccountThumbnail: (e: React.MouseEvent, account: DB_Account) => void;
38
+ private encodeFile;
39
+ getPasswordAssertionConfig: () => PasswordAssertionConfig | undefined;
40
+ getCurrentlyLoggedAccount: () => import("@nu-art/user-account-shared").UI_SessionAccount;
41
+ private onAccountCreated;
42
+ private onThumbnailChanged;
43
+ private onLoginCompletedSAML;
44
+ private onPasswordAssertionConfig;
45
+ }
46
+ export declare const ModuleFE_Account: ModuleFE_Account_Class;
47
+ export {};
@@ -0,0 +1,153 @@
1
+ import { apiWithBody, apiWithQuery, ModuleFE_BaseApi, ModuleFE_XHR, readFileContent, StorageKey, ThunderDispatcher } from '@nu-art/thunderstorm-frontend/index';
2
+ import { HeaderKey_DeviceId, HeaderKey_TabId } from '@nu-art/thunderstorm-shared';
3
+ import { dispatcher_onAuthRequired } from '@nu-art/thunderstorm-shared/no-auth-listener';
4
+ import { ApiDef_Account, ApiDef_SAML, DBDef_Accounts, QueryParam_SessionId } from '@nu-art/user-account-shared';
5
+ import { SessionKeyFE_Account, StorageKey_DeviceId, StorageKey_TabId } from './consts.js';
6
+ import { asArray, cloneObj, composeUrl, Exception, generateHex, KB } from '@nu-art/ts-common';
7
+ import { ModuleFE_Session } from '../session/ModuleFE_Session.js';
8
+ export var LoggedStatus;
9
+ (function (LoggedStatus) {
10
+ LoggedStatus[LoggedStatus["VALIDATING"] = 0] = "VALIDATING";
11
+ LoggedStatus[LoggedStatus["LOGGED_OUT"] = 1] = "LOGGED_OUT";
12
+ LoggedStatus[LoggedStatus["SESSION_TIMEOUT"] = 2] = "SESSION_TIMEOUT";
13
+ LoggedStatus[LoggedStatus["LOGGED_IN"] = 3] = "LOGGED_IN";
14
+ })(LoggedStatus || (LoggedStatus = {}));
15
+ export const dispatch_onLoginStatusChanged = new ThunderDispatcher('__onLoginStatusUpdated');
16
+ export const dispatch_onAccountsUpdated = new ThunderDispatcher('__onAccountsUpdated');
17
+ const StorageKey_PasswordAssertionConfig = new StorageKey('account__password-assertion-config', false);
18
+ class ModuleFE_Account_Class extends ModuleFE_BaseApi {
19
+ _v1;
20
+ status = LoggedStatus.LOGGED_OUT;
21
+ __onLoginStatusUpdated() {
22
+ //Get the password assertion config if needed
23
+ if ([LoggedStatus.LOGGED_OUT, LoggedStatus.SESSION_TIMEOUT].includes(this.status))
24
+ this._v1.getPasswordAssertionConfig({}).executeSync();
25
+ }
26
+ constructor() {
27
+ super(DBDef_Accounts, dispatch_onAccountsUpdated);
28
+ // const login = apiWithBody(ApiDef_Account._v1.login, this.setLoginInfo);
29
+ this._v1 = {
30
+ refreshSession: apiWithQuery(ApiDef_Account._v1.refreshSession),
31
+ registerAccount: apiWithBody(ApiDef_Account._v1.registerAccount),
32
+ createAccount: apiWithBody(ApiDef_Account._v1.createAccount, this.onAccountCreated),
33
+ changePassword: apiWithBody(ApiDef_Account._v1.changePassword),
34
+ login: apiWithBody(ApiDef_Account._v1.login),
35
+ // login: (account: Account_Login['request']) => {
36
+ //
37
+ // toUpsert = this.cleanUp(toUpsert);
38
+ // this.validateInternal(toUpsert);
39
+ // return this.updatePending(toUpsert as DB_BaseObject, upsert(toUpsert), 'upsert');
40
+ // },
41
+ logout: apiWithQuery(ApiDef_Account._v1.logout),
42
+ createToken: apiWithBody(ApiDef_Account._v1.createToken),
43
+ setPassword: apiWithBody(ApiDef_Account._v1.setPassword),
44
+ getSessions: apiWithQuery(ApiDef_Account._v1.getSessions),
45
+ changeThumbnail: apiWithBody(ApiDef_Account._v1.changeThumbnail, this.onThumbnailChanged),
46
+ loginSaml: apiWithQuery(ApiDef_SAML._v1.loginSaml, this.onLoginCompletedSAML),
47
+ assertSAML: apiWithBody(ApiDef_SAML._v1.assertSAML),
48
+ getPasswordAssertionConfig: apiWithQuery(ApiDef_Account._v1.getPasswordAssertionConfig, this.onPasswordAssertionConfig)
49
+ };
50
+ }
51
+ init() {
52
+ super.init();
53
+ let defaultTabId = StorageKey_TabId.get();
54
+ let defaultDeviceId = StorageKey_DeviceId.get();
55
+ if (!defaultDeviceId) {
56
+ defaultDeviceId = generateHex(32);
57
+ console.log(`Defining new device Id: ${defaultDeviceId}`);
58
+ StorageKey_DeviceId.set(defaultDeviceId);
59
+ }
60
+ if (!defaultTabId) {
61
+ defaultTabId = generateHex(32);
62
+ console.log(`Defining new tab Id: ${defaultTabId}`);
63
+ StorageKey_TabId.set(defaultTabId);
64
+ }
65
+ ModuleFE_XHR.addDefaultHeader(HeaderKey_DeviceId, () => defaultDeviceId);
66
+ ModuleFE_XHR.addDefaultHeader(HeaderKey_TabId, defaultTabId);
67
+ }
68
+ // ######################## Logic ########################
69
+ getAccounts() {
70
+ return this.cache.all().map(i => cloneObj(i));
71
+ }
72
+ getLoggedStatus = () => this.status;
73
+ isStatus = (status) => asArray(status).includes(this.status);
74
+ __onSessionUpdated() {
75
+ if (!ModuleFE_Session.hasSession())
76
+ return this.setLoggedStatus(LoggedStatus.LOGGED_OUT);
77
+ if (!ModuleFE_Session.isSessionValid())
78
+ return this.setLoggedStatus(LoggedStatus.SESSION_TIMEOUT);
79
+ return this.setLoggedStatus(LoggedStatus.LOGGED_IN);
80
+ }
81
+ setLoggedStatus = (newStatus) => {
82
+ if (this.status === newStatus)
83
+ return;
84
+ const pervStatus = this.status;
85
+ this.status = newStatus;
86
+ this.logInfo(`Login status changes: ${LoggedStatus[pervStatus]} => ${LoggedStatus[newStatus]}`);
87
+ dispatch_onLoginStatusChanged.dispatchUI();
88
+ dispatch_onLoginStatusChanged.dispatchModule();
89
+ };
90
+ composeSAMLUrl = () => {
91
+ const params = new URLSearchParams(window.location.search);
92
+ const paramsObj = {};
93
+ for (const [key, value] of params) {
94
+ paramsObj[key] = value;
95
+ }
96
+ return composeUrl(window.location.origin + window.location.pathname, {
97
+ ...paramsObj,
98
+ [QueryParam_SessionId]: QueryParam_SessionId.toUpperCase(),
99
+ });
100
+ };
101
+ logout = async (url) => {
102
+ await this._v1.logout({}).executeSync();
103
+ dispatcher_onAuthRequired.dispatchModule(undefined);
104
+ if (url)
105
+ return window.location.href = url;
106
+ };
107
+ uploadAccountThumbnail = (e, account) => {
108
+ const input = document.createElement('input');
109
+ input.type = 'file';
110
+ // input.accept = '.jpg,.jpeg,.png';
111
+ input.style.display = 'none';
112
+ input.addEventListener('change', async (e) => {
113
+ const file = input.files[0];
114
+ if (!file)
115
+ return;
116
+ try {
117
+ const hash = await this.encodeFile(file);
118
+ await this._v1.changeThumbnail({ accountId: account._id, hash }).executeSync();
119
+ }
120
+ catch (err) {
121
+ this.logError(err.message, err);
122
+ }
123
+ });
124
+ input.click();
125
+ };
126
+ encodeFile = async (file) => {
127
+ const arrayBuffer = await readFileContent(file);
128
+ if (arrayBuffer.byteLength > 200 * KB)
129
+ throw new Exception('File size exceeds 200KB');
130
+ const buffer = new Uint8Array(arrayBuffer);
131
+ return window.btoa(buffer.reduce((acc, byte) => acc + String.fromCharCode(byte), ''));
132
+ };
133
+ getPasswordAssertionConfig = () => StorageKey_PasswordAssertionConfig.get();
134
+ getCurrentlyLoggedAccount = () => {
135
+ return SessionKeyFE_Account.get();
136
+ };
137
+ // ######################## API Callbacks ########################
138
+ onAccountCreated = async (response) => {
139
+ await this.onEntriesUpdated([response]);
140
+ };
141
+ onThumbnailChanged = async (response) => {
142
+ await this.onEntryUpdated(response.account, response.account);
143
+ };
144
+ onLoginCompletedSAML = async (response) => {
145
+ if (!response.loginUrl)
146
+ return;
147
+ window.location.href = response.loginUrl;
148
+ };
149
+ onPasswordAssertionConfig = async (response) => {
150
+ StorageKey_PasswordAssertionConfig.set(response.config);
151
+ };
152
+ }
153
+ export const ModuleFE_Account = new ModuleFE_Account_Class();
@@ -0,0 +1,8 @@
1
+ import { StorageKey } from '@nu-art/thunderstorm-frontend/index';
2
+ import { _SessionKey_Account, DB_Account } from '@nu-art/user-account-shared';
3
+ import { SessionKey_FE } from '../session/ModuleFE_Session.js';
4
+ import { TypedKeyValue } from '@nu-art/ts-common';
5
+ export declare const SessionKeyFE_Account: SessionKey_FE<_SessionKey_Account>;
6
+ export declare const StorageKey_DeviceId: StorageKey<string>;
7
+ export declare const StorageKey_TabId: StorageKey<string>;
8
+ export declare const SessionKey_Account: SessionKey_FE<TypedKeyValue<"account", DB_Account>>;
@@ -0,0 +1,7 @@
1
+ import { StorageKey } from '@nu-art/thunderstorm-frontend/index';
2
+ import { HeaderKey_DeviceId, HeaderKey_TabId } from '@nu-art/thunderstorm-shared/headers';
3
+ import { SessionKey_FE } from '../session/ModuleFE_Session.js';
4
+ export const SessionKeyFE_Account = new SessionKey_FE('account');
5
+ export const StorageKey_DeviceId = new StorageKey(`storage--${HeaderKey_DeviceId}`).withstandDeletion();
6
+ export const StorageKey_TabId = new StorageKey(`storage--${HeaderKey_TabId}`, false).withstandDeletion();
7
+ export const SessionKey_Account = new SessionKey_FE('account');
@@ -0,0 +1,3 @@
1
+ export * from './ModuleFE_Account.js';
2
+ export * from './module-pack.js';
3
+ export * from './consts.js';
@@ -0,0 +1,3 @@
1
+ export * from './ModuleFE_Account.js';
2
+ export * from './module-pack.js';
3
+ export * from './consts.js';
@@ -0,0 +1,2 @@
1
+ import { Module } from '@nu-art/ts-common';
2
+ export declare const ModulePackFE_AccountDB: Module[];
@@ -0,0 +1,3 @@
1
+ import { ModuleFE_Account } from './ModuleFE_Account.js';
2
+ import { ModuleFE_Session } from '../session/ModuleFE_Session.js';
3
+ export const ModulePackFE_AccountDB = [ModuleFE_Account, ModuleFE_Session];
@@ -0,0 +1,33 @@
1
+ import { OnStorageKeyChangedListener, StorageKey, ThunderDispatcher } from '@nu-art/thunderstorm-frontend/index';
2
+ import { Module, ResolvableContent, TS_Object, TypedKeyValue } from '@nu-art/ts-common';
3
+ import { BaseHttpRequest } from '@nu-art/thunderstorm-shared';
4
+ import { OnAuthRequiredListener } from '@nu-art/thunderstorm-shared/no-auth-listener';
5
+ export interface OnSessionUpdated {
6
+ __onSessionUpdated: VoidFunction;
7
+ }
8
+ export declare const dispatch_onSessionUpdated: ThunderDispatcher<OnSessionUpdated, "__onSessionUpdated", [], void>;
9
+ export declare const StorageKey_SessionTimeoutTimestamp: StorageKey<number>;
10
+ export declare class SessionKey_FE<Binder extends TypedKeyValue<string | number | 'account', any>> {
11
+ private readonly key;
12
+ constructor(key: Binder['key']);
13
+ get(): Binder['value'];
14
+ get(defaultValue: Binder['value']): Binder['value'];
15
+ }
16
+ type SessionDecoder = (sessionAsString: string) => Promise<TS_Object>;
17
+ export declare const sessionContentJWT: SessionDecoder;
18
+ declare class ModuleFE_Session_Class extends Module implements OnStorageKeyChangedListener, OnAuthRequiredListener {
19
+ private sessionData;
20
+ sessionDecoder: SessionDecoder;
21
+ private sessionKey;
22
+ private StorageKey_SessionId;
23
+ init(): void;
24
+ setSessionKey(sessionKey: ResolvableContent<string>): void;
25
+ __onStorageKeyEvent(event: StorageEvent): Promise<void>;
26
+ __onAuthRequiredListener(request: BaseHttpRequest<any>): void;
27
+ private onSessionUpdated;
28
+ hasSession(): boolean;
29
+ isSessionValid(): Promise<boolean>;
30
+ getJWT: () => string | undefined;
31
+ }
32
+ export declare const ModuleFE_Session: ModuleFE_Session_Class;
33
+ export {};
@@ -0,0 +1,95 @@
1
+ import { getQueryParameter, ModuleFE_BrowserHistory, ModuleFE_XHR, StorageKey, ThunderDispatcher } from '@nu-art/thunderstorm-frontend/index';
2
+ import { BadImplementationException, currentTimeMillis, exists, JwtTools, Module, resolveContent } from '@nu-art/ts-common';
3
+ import { HeaderKey_Authorization, ResponseHeaderKey_JWTToken } from '@nu-art/thunderstorm-shared';
4
+ import { QueryParam_SessionId } from '@nu-art/user-account-shared';
5
+ export const dispatch_onSessionUpdated = new ThunderDispatcher('__onSessionUpdated');
6
+ export const StorageKey_SessionTimeoutTimestamp = new StorageKey(`storage-accounts__session-timeout`);
7
+ export class SessionKey_FE {
8
+ key;
9
+ constructor(key) {
10
+ this.key = key;
11
+ }
12
+ get(defaultValue) {
13
+ // @ts-ignore
14
+ const sessionData = ModuleFE_Session.sessionData;
15
+ // means that we don't have a session yet
16
+ if (!sessionData)
17
+ return;
18
+ if (!(this.key in sessionData) && !exists(defaultValue))
19
+ throw new BadImplementationException(`Couldn't find key "${this.key}" in session data`);
20
+ return sessionData[this.key] ?? defaultValue;
21
+ }
22
+ }
23
+ export const sessionContentJWT = async (sessionAsString) => {
24
+ return JwtTools.decode(sessionAsString);
25
+ };
26
+ class ModuleFE_Session_Class extends Module {
27
+ // @ts-ignore
28
+ sessionData;
29
+ sessionDecoder = sessionContentJWT;
30
+ sessionKey = 'session-jwt';
31
+ StorageKey_SessionId;
32
+ init() {
33
+ this.StorageKey_SessionId = new StorageKey(resolveContent(this.sessionKey));
34
+ this.StorageKey_SessionId.onChange(async (sessionAsString) => {
35
+ await this.onSessionUpdated(sessionAsString);
36
+ });
37
+ ModuleFE_XHR.addDefaultHeader(HeaderKey_Authorization, () => {
38
+ const sessionJWT = this.StorageKey_SessionId.get();
39
+ if (!sessionJWT)
40
+ return '';
41
+ return `Bearer ${sessionJWT}`;
42
+ });
43
+ ModuleFE_XHR.setDefaultOnComplete(async (__, _, request) => {
44
+ if (!request.getUrl().startsWith(ModuleFE_XHR.getOrigin()))
45
+ return;
46
+ const responseHeader = request.getResponseHeader(ResponseHeaderKey_JWTToken);
47
+ if (!responseHeader)
48
+ return;
49
+ const sessionId = typeof responseHeader === 'string' ? responseHeader : responseHeader[0];
50
+ this.StorageKey_SessionId.set(sessionId);
51
+ });
52
+ let sessionId = getQueryParameter(QueryParam_SessionId);
53
+ if (sessionId)
54
+ ModuleFE_BrowserHistory.removeQueryParam(QueryParam_SessionId);
55
+ else
56
+ sessionId = this.StorageKey_SessionId.get();
57
+ if (sessionId)
58
+ this.StorageKey_SessionId.set(sessionId);
59
+ }
60
+ setSessionKey(sessionKey) {
61
+ this.sessionKey = sessionKey;
62
+ }
63
+ async __onStorageKeyEvent(event) {
64
+ if (event.key !== this.StorageKey_SessionId.key)
65
+ return;
66
+ await this.onSessionUpdated(this.StorageKey_SessionId.get());
67
+ }
68
+ __onAuthRequiredListener(request) {
69
+ this.StorageKey_SessionId.delete();
70
+ StorageKey_SessionTimeoutTimestamp.set(currentTimeMillis());
71
+ }
72
+ async onSessionUpdated(sessionAsString) {
73
+ if (sessionAsString)
74
+ try {
75
+ this.sessionData = await this.sessionDecoder(sessionAsString);
76
+ }
77
+ catch (e) {
78
+ this.logError('Error decoding session data', e);
79
+ }
80
+ else
81
+ this.sessionData = {};
82
+ dispatch_onSessionUpdated.dispatchAll();
83
+ }
84
+ hasSession() {
85
+ return !!this.StorageKey_SessionId.get();
86
+ }
87
+ async isSessionValid() {
88
+ const sessionToken = this.StorageKey_SessionId.get();
89
+ if (!sessionToken)
90
+ return false;
91
+ return JwtTools.isJwtActive(sessionToken);
92
+ }
93
+ getJWT = () => this.StorageKey_SessionId.get();
94
+ }
95
+ export const ModuleFE_Session = new ModuleFE_Session_Class();
package/_entity.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './_entity/session/ModuleFE_Session.js';
2
+ export * from './_entity/account/index.js';
3
+ export * from './_entity/account/index.js';
package/_entity.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './_entity/session/ModuleFE_Session.js';
2
+ export * from './_entity/account/index.js';
3
+ export * from './_entity/account/index.js';
@@ -0,0 +1,38 @@
1
+ import { Account_CreateAccount, DB_Account } from '@nu-art/user-account-shared';
2
+ import { ComponentSync } from '@nu-art/thunderstorm-frontend/index';
3
+ import { UniqueId } from '@nu-art/ts-common';
4
+ import './Component_AccountEditor.scss';
5
+ type Props = {
6
+ isPreview?: boolean;
7
+ user?: DB_Account;
8
+ onComplete?: (_id: UniqueId) => void;
9
+ };
10
+ type SessionJWT = {
11
+ sessionData: string;
12
+ exp: number;
13
+ iat: number;
14
+ _id: string;
15
+ label?: string;
16
+ deviceId: string;
17
+ sessionIdJwt: string;
18
+ };
19
+ type State = Partial<Account_CreateAccount['request']> & {
20
+ isPreview: boolean;
21
+ tokenTTL: number;
22
+ tokenLabel: string;
23
+ user?: DB_Account;
24
+ sessions: SessionJWT[];
25
+ };
26
+ export declare class Component_AccountEditor extends ComponentSync<Props, State> {
27
+ protected deriveStateFromProps(nextProps: Props, state: State): State;
28
+ private addAccount;
29
+ private canCreate;
30
+ private renderDropdown;
31
+ private renderInputs;
32
+ private renderSubmitButton;
33
+ private renderGenToken;
34
+ private renderSessionGrid;
35
+ private renderDescription;
36
+ render(): import("react/jsx-runtime").JSX.Element;
37
+ }
38
+ export {};