From 02fe2d0b0c3fda18aae5dcabe94e1326f1973a84 Mon Sep 17 00:00:00 2001 From: Sergey Nikitin Date: Sat, 28 Jan 2023 16:26:14 +0000 Subject: [PATCH 1/6] split account creation during context init --- truthsayer/src/lib/global.tsx | 62 +++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/truthsayer/src/lib/global.tsx b/truthsayer/src/lib/global.tsx index 1ec47cf6..4464892b 100644 --- a/truthsayer/src/lib/global.tsx +++ b/truthsayer/src/lib/global.tsx @@ -110,6 +110,18 @@ export function MzdGlobal(props: React.PropsWithChildren) { ) const [account, setAccount] = React.useState(null) + useAsyncEffect(async () => { + try { + setAccount(await createUserAccount(fetchAccountAbortController.signal)) + } catch (err) { + log.warning( + `Faild to initialise user acc (error = ${errorise( + err + )}), ${kAnonymousAnalyticsWarning}` + ) + } + }, []) + const [storage, setStorage] = React.useState( makeStorageApi(defaultAppSettings) ) @@ -120,37 +132,29 @@ export function MzdGlobal(props: React.PropsWithChildren) { }) useAsyncEffect(async () => { - let acc: AccountInterface | null = null - try { - acc = await createUserAccount(fetchAccountAbortController.signal) - } catch (err) { - log.warning( - `Faild to initialise user acc (error = ${errorise( - err - )}), ${kAnonymousAnalyticsWarning}` - ) + if (account == null || !account.isAuthenticated()) { + return + } + if (state.analytics == null) { return } - setAccount(acc) - - if (state.analytics) { - try { - // TODO[snikitin@outlook.com] In cases when truthsayer is launched - // the user is already logged in user identification should happen - // immediately at the point of product analytics instance creation - // (via 'PostHogConfig.bootstrap' field). Without that, opening - // truthsayer produces a single anonymous '$pageview' event followed - // immediately by an '$identify' event. This makes analytics data - // more difficult to navigate and consumes extra quota. - productanalytics.identifyUser({ - analytics: state.analytics, - nodeEnv: process.env.NODE_ENV, - userUid: acc.getUid(), - }) - } catch (e) { - log.warning(`${errorise(e).message}, ${kAnonymousAnalyticsWarning}`) - } + try { + // TODO[snikitin@outlook.com] In cases when truthsayer is launched + // the user is already logged in user identification should happen + // immediately at the point of product analytics instance creation + // (via 'PostHogConfig.bootstrap' field). Without that, opening + // truthsayer produces a single anonymous '$pageview' event followed + // immediately by an '$identify' event. This makes analytics data + // more difficult to navigate and consumes extra quota. + productanalytics.identifyUser({ + analytics: state.analytics, + nodeEnv: process.env.NODE_ENV, + userUid: account.getUid(), + }) + } catch (e) { + log.warning(`${errorise(e).message}, ${kAnonymousAnalyticsWarning}`) + throw e } return () => { @@ -161,7 +165,7 @@ export function MzdGlobal(props: React.PropsWithChildren) { ) } } - }, []) + }, [account]) useAsyncEffect(async () => { const response = await FromTruthsayer.sendMessage({ From 613a6514b4fcc18efc556bb3d8189c3bc453466b Mon Sep 17 00:00:00 2001 From: Sergey Nikitin Date: Sat, 28 Jan 2023 20:51:38 +0000 Subject: [PATCH 2/6] reorg account init to make usage deterministic --- truthsayer/src/App.tsx | 354 ++++++++++++------------- truthsayer/src/lib/global.tsx | 56 ++-- truthsayer/src/navbar/GlobalNavBar.tsx | 5 - 3 files changed, 188 insertions(+), 227 deletions(-) diff --git a/truthsayer/src/App.tsx b/truthsayer/src/App.tsx index 83015f8d..de9e3a19 100644 --- a/truthsayer/src/App.tsx +++ b/truthsayer/src/App.tsx @@ -17,6 +17,7 @@ import { css } from '@emotion/react' import { Card, Button, Container } from 'react-bootstrap' import { PostHog } from 'posthog-js' +import { useAsyncEffect } from 'use-async-effect' import { Triptych } from './card/Triptych' import { SearchGridView } from './grid/SearchGridView' @@ -33,7 +34,6 @@ import WaitingForApproval from './account/create/WaitingForApproval' import { GoToInboxToConfirmEmail } from './account/create/GoToInboxToConfirmEmail' import UserPreferences from './auth/UserPreferences' import { LandingPage } from './landing-page/LandingPage' -import { PublicPage } from './public-page/PublicPage' import { TruthsayerPath, PasswordRecoverFormUrlParams, @@ -54,26 +54,164 @@ import { } from './public-page/legal/Index' import { log, productanalytics } from 'armoury' import { ApplicationSettings } from './AppSettings' +import { + AccountInterface, + authCookie, + createUserAccount, + UserAccount, +} from 'smuggler-api' +import { KnockerElement } from './auth/Knocker' + +function isAuthenticated(account: AccountInterface): account is UserAccount { + return account.isAuthenticated() +} export function App() { - const analytics = React.useMemo( - () => productanalytics.make('truthsayer', process.env.NODE_ENV), - [] - ) return ( - +
+ - +
) } function AppRouter() { + const analytics = React.useMemo( + () => productanalytics.make('truthsayer', process.env.NODE_ENV), + [] + ) + + const [account, setAccount] = React.useState(null) + useAsyncEffect(async () => { + if (account != null) { + return + } + const acc = await createUserAccount() + if (!isAuthenticated(acc)) { + log.warning( + "Failed to initialise user account, most functionality won't work until the page reloads" + ) + return + } + log.info('Initialised an authenticated user account') + setAccount(acc) + }, []) + + const publicOnlyRoutes = [ + + + , + + + , + + + , + + + , + + + , + + + , + ] + + const publicRoutes = [ + + + , + + + , + + + , + + + , + + + , + + + , + + + , + + + , + + + , + + + , + , + ] + + const privateRoutes = [ + + + , + + + , + + + , + + + , + + + , + + + , + + + , + + + , + + + , + + + , + ] + + const authorisationLikelyComplete = authCookie.veil.check() + return ( - + {analytics != null ? ( + + ) : null} - + {account != null ? : null} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + {publicRoutes} + {authorisationLikelyComplete ? ( + account != null ? ( + + {privateRoutes} + + ) : ( + + ) + ) : ( + publicOnlyRoutes + )} ) } -/** - * Route available only for logged-in users - */ -function PrivateRoute({ - children, - ...rest -}: RouteProps & { path: TruthsayerPath }) { - const location = useLocation() - const ctx = useContext(MzdGlobalContext) - const account = ctx.account - if (account == null) { - return - } - const isAuthenticated = account.isAuthenticated() - if (isAuthenticated) { - return {children} - } else { - return ( - - ) - } -} - -/** - * Route available only for anonymous users - */ -function PublicOnlyRoute({ - children, - ...rest -}: RouteProps & { path: TruthsayerPath }) { - const location = useLocation() - const ctx = useContext(MzdGlobalContext) - const account = ctx.account - if (account == null) { - return - } - const isAuthenticated = account.isAuthenticated() - if (!isAuthenticated) { - return ( - - {children} - - ) - } else { - return ( - - ) - } -} - -/** - * Route available for both anonymous and logged-in users - */ -function PublicRoute({ - children, - ...rest -}: RouteProps & { path: TruthsayerPath }) { - const ctx = useContext(MzdGlobalContext) - const account = ctx.account - if (account == null || !account.isAuthenticated()) { - return ( - - {children} - - ) - } else { - return {children} - } -} - -function MainView() { - const ctx = useContext(MzdGlobalContext) - const account = ctx.account - if (account == null) { - return - } - const isAuthenticated = account.isAuthenticated() - if (isAuthenticated) { - return - } else { - return - } +function TruthsayerRoute(props: RouteProps & { path: TruthsayerPath }) { + return } function HelpInfo() { @@ -340,20 +322,12 @@ function TriptychView() { } // Based on https://www.sheshbabu.com/posts/automatic-pageview-tracking-using-react-router/ -function PageviewEventTracker() { - const ctx = useContext(MzdGlobalContext) +function PageviewEventTracker({ analytics }: { analytics: PostHog }) { const track = useCallback(() => { - if (!ctx.analytics) { - log.warning( - `No product analytics initialised yet, pageview event won't be reported` - ) - return - } - // See https://posthog.com/docs/integrate/client/js#one-page-apps-and-page-views // for more information about pageview events in PostHog - ctx.analytics.capture('$pageview') - }, [ctx]) + analytics.capture('$pageview') + }, []) const history = useHistory() React.useEffect(() => { diff --git a/truthsayer/src/lib/global.tsx b/truthsayer/src/lib/global.tsx index 4464892b..6879e9a5 100644 --- a/truthsayer/src/lib/global.tsx +++ b/truthsayer/src/lib/global.tsx @@ -7,11 +7,11 @@ import { KnockerElement } from '../auth/Knocker' import { jcss } from 'elementary' import { - createUserAccount, AccountInterface, makeAlwaysThrowingStorageApi, makeDatacenterStorageApi, makeMsgProxyStorageApi, + UserAccount, } from 'smuggler-api' import type { StorageApi, @@ -27,8 +27,10 @@ import { useAsyncEffect } from 'use-async-effect' import { defaultSettings, FromTruthsayer, + ToTruthsayer, } from 'truthsayer-archaeologist-communication' import type { AppSettings } from 'truthsayer-archaeologist-communication' +import { Loader } from './loader' type Toaster = { push: (item: React.ReactElement) => void @@ -75,23 +77,19 @@ export const MzdGlobalContext = React.createContext({ type MzdGlobalProps = { analytics: PostHog | null + account: UserAccount } type MzdGlobalState = { toaster: Toaster - account: AccountInterface | null + account: UserAccount | null storage: StorageApi analytics: PostHog | null - appSettings: AppSettings } const kAnonymousAnalyticsWarning = 'future product analytics events will be attached to an anonymous identity' export function MzdGlobal(props: React.PropsWithChildren) { - const [fetchAccountAbortController] = React.useState(new AbortController()) - - const defaultAppSettings = defaultSettings() - const [toasts, setToasts] = React.useState([]) const pushToast = React.useCallback( (item: React.ReactElement) => { @@ -109,32 +107,28 @@ export function MzdGlobal(props: React.PropsWithChildren) { [toasts] ) - const [account, setAccount] = React.useState(null) + const [storage, setStorage] = React.useState(null) useAsyncEffect(async () => { - try { - setAccount(await createUserAccount(fetchAccountAbortController.signal)) - } catch (err) { + const response = await FromTruthsayer.sendMessage({ + type: 'GET_APP_SETTINGS_REQUEST', + }).catch((reason): ToTruthsayer.GetAppSettingsResponse => { + const defaults = defaultSettings() log.warning( - `Faild to initialise user acc (error = ${errorise( - err - )}), ${kAnonymousAnalyticsWarning}` + `Failed to get user's app settings,` + + ` falling back to ${JSON.stringify(defaults)}; ` + + `error - ${errorise(reason).message}` ) - } + return { type: 'GET_APP_SETTINGS_RESPONSE', settings: defaults } + }) + setStorage(makeStorageApi(response.settings)) }, []) - const [storage, setStorage] = React.useState( - makeStorageApi(defaultAppSettings) - ) const [state] = React.useState>({ toaster: { push: pushToast }, analytics: props.analytics, - appSettings: defaultAppSettings, }) useAsyncEffect(async () => { - if (account == null || !account.isAuthenticated()) { - return - } if (state.analytics == null) { return } @@ -150,7 +144,7 @@ export function MzdGlobal(props: React.PropsWithChildren) { productanalytics.identifyUser({ analytics: state.analytics, nodeEnv: process.env.NODE_ENV, - userUid: account.getUid(), + userUid: props.account.getUid(), }) } catch (e) { log.warning(`${errorise(e).message}, ${kAnonymousAnalyticsWarning}`) @@ -165,18 +159,16 @@ export function MzdGlobal(props: React.PropsWithChildren) { ) } } - }, [account]) - - useAsyncEffect(async () => { - const response = await FromTruthsayer.sendMessage({ - type: 'GET_APP_SETTINGS_REQUEST', - }) - setStorage(makeStorageApi(response.settings)) }, []) + if (storage == null) { + return + } + return ( - - +
From 9aa0da7883a12d8595028483d9be5513ae9079a5 Mon Sep 17 00:00:00 2001 From: Sergey Nikitin Date: Mon, 30 Jan 2023 21:51:53 +0000 Subject: [PATCH 3/6] minor cleanup --- smuggler-api/src/auth/account.ts | 2 +- truthsayer/src/App.tsx | 7 +++---- truthsayer/src/auth/Logout.js | 7 +++---- truthsayer/src/lib/global.tsx | 4 +--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/smuggler-api/src/auth/account.ts b/smuggler-api/src/auth/account.ts index 222ebf3f..fd87963d 100644 --- a/smuggler-api/src/auth/account.ts +++ b/smuggler-api/src/auth/account.ts @@ -67,7 +67,7 @@ export class UserAccount extends AnonymousAccount { return this._lc } - isAuthenticated(): boolean { + isAuthenticated(): true { return true } } diff --git a/truthsayer/src/App.tsx b/truthsayer/src/App.tsx index de9e3a19..edd78b23 100644 --- a/truthsayer/src/App.tsx +++ b/truthsayer/src/App.tsx @@ -7,7 +7,6 @@ import { Redirect, Route, Switch, - useLocation, useParams, RouteProps, useHistory, @@ -45,7 +44,7 @@ import { Export } from './export/Export' import { AppsList } from './apps-list/AppsList' import { AppHead } from './AppHead' -import { MzdGlobal, MzdGlobalContext } from './lib/global' +import { MzdGlobal } from './lib/global' import { TermsOfService, CookiePolicy, @@ -68,11 +67,11 @@ function isAuthenticated(account: AccountInterface): account is UserAccount { export function App() { return ( -
+ <> -
+ ) } diff --git a/truthsayer/src/auth/Logout.js b/truthsayer/src/auth/Logout.js index 656c8024..cc4b973c 100644 --- a/truthsayer/src/auth/Logout.js +++ b/truthsayer/src/auth/Logout.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import { withRouter } from 'react-router-dom' import { goto } from '../lib/route' -import { authentication } from 'smuggler-api' +import { authCookie, authentication } from 'smuggler-api' import { MzdGlobalContext } from './../lib/global' @@ -23,9 +23,7 @@ class Logout extends React.Component { } componentDidMount() { - const account = this.context.account - const isAuthenticated = account != null && account.isAuthenticated() - if (isAuthenticated) { + if (this.context.account != null) { authentication.session .delete({ signal: this.fetchAbortController.signal, @@ -33,6 +31,7 @@ class Logout extends React.Component { .catch(this.handleError) .then((res) => { if (res != null) { + authCookie.veil.drop() // for some reason proper redirect with history doesn't work here goto.notice.seeYou({}) } else { diff --git a/truthsayer/src/lib/global.tsx b/truthsayer/src/lib/global.tsx index 6879e9a5..e5ea3947 100644 --- a/truthsayer/src/lib/global.tsx +++ b/truthsayer/src/lib/global.tsx @@ -3,8 +3,6 @@ import React from 'react' import { Button } from 'react-bootstrap' import { PostHog } from 'posthog-js' -import { KnockerElement } from '../auth/Knocker' - import { jcss } from 'elementary' import { AccountInterface, @@ -56,7 +54,7 @@ function makeStorageApi(appSettings: AppSettings): StorageApi { } export type MzdGlobalContextProps = { - account: null | AccountInterface + account: null | UserAccount toaster: Toaster storage: StorageApi analytics: PostHog | null From c161816ae8598df00b41a852fd0f95e9ca01411b Mon Sep 17 00:00:00 2001 From: Sergey Nikitin Date: Mon, 30 Jan 2023 22:56:26 +0000 Subject: [PATCH 4/6] local storage: fix node & edge ownership --- archaeologist/src/background.ts | 20 +++++- archaeologist/src/background/auth.ts | 66 ++++++++++++-------- archaeologist/src/storage_api_browser_ext.ts | 28 ++++----- 3 files changed, 70 insertions(+), 44 deletions(-) diff --git a/archaeologist/src/background.ts b/archaeologist/src/background.ts index cd82e649..78c38460 100644 --- a/archaeologist/src/background.ts +++ b/archaeologist/src/background.ts @@ -40,6 +40,7 @@ import { makeAlwaysThrowingStorageApi, makeDatacenterStorageApi, processMsgFromMsgProxyStorageApi, + UserAccount, } from 'smuggler-api' import { makeBrowserExtStorageApi } from './storage_api_browser_ext' @@ -824,17 +825,30 @@ async function initMazedPartsOfTab( } } -function makeStorageApi(appSettings: AppSettings): StorageApi { +function makeStorageApi( + appSettings: AppSettings, + account: UserAccount +): StorageApi { switch (appSettings.storageType) { case 'datacenter': return makeDatacenterStorageApi() case 'browser_ext': - return makeBrowserExtStorageApi(browser.storage.local) + return makeBrowserExtStorageApi(browser.storage.local, account) } } async function initBackground() { - storage = makeStorageApi(await getAppSettings(browser.storage.local)) + auth.observe({ + onLogin: async (account: UserAccount) => { + storage = makeStorageApi( + await getAppSettings(browser.storage.local), + account + ) + }, + onLogout: () => { + storage = makeAlwaysThrowingStorageApi() + }, + }) browser.runtime.onMessage.addListener( async ( diff --git a/archaeologist/src/background/auth.ts b/archaeologist/src/background/auth.ts index 07d35b34..5334408e 100644 --- a/archaeologist/src/background/auth.ts +++ b/archaeologist/src/background/auth.ts @@ -7,7 +7,8 @@ import { UserAccount, } from 'smuggler-api' import { Knocker, authCookie } from 'smuggler-api' -import { log, isAbortError } from 'armoury' +import { log, isAbortError, errorise } from 'armoury' +import { v4 as uuidv4 } from 'uuid' // Periodically renew auth token using Knocker const _authKnocker = new Knocker( @@ -60,10 +61,35 @@ const _authKnocker = new Knocker( ) let _account: AccountInterface = new AnonymousAccount() -// External listener for login events -let _onLoginListener: ((account: UserAccount) => void) | null = null -// External listener for logout events -let _onLogoutListener: (() => void) | null = null +const _listeners: Map< + string /*listener ID*/, + { + // External listener for login events + onLogin: (account: UserAccount) => void + // External listener for logout events + onLogout: () => void + } +> = new Map() + +function _onLogin(account: UserAccount) { + for (const [_, { onLogin }] of _listeners) { + try { + onLogin(account) + } catch (reason) { + log.error(`onLogin listener failed: ${errorise(reason).message}`) + } + } +} + +function _onLogout() { + for (const [_, { onLogout }] of _listeners) { + try { + onLogout() + } catch (reason) { + log.error(`onLogin listener failed: ${errorise(reason).message}`) + } + } +} function isAuthenticated(account: AccountInterface): account is UserAccount { return account.isAuthenticated() @@ -91,9 +117,7 @@ async function _loginHandler() { if (!_authKnocker.isActive()) { await _authKnocker.start({ onKnockFailure }) } - if (_onLoginListener) { - _onLoginListener(_account) - } + _onLogin(_account) } await badge.setActive(_account.isAuthenticated()) } @@ -103,9 +127,7 @@ async function _logoutHandler() { _account = new AnonymousAccount() await _authKnocker.abort() await badge.setActive(false) - if (_onLogoutListener) { - _onLogoutListener() - } + _onLogout() } // Actions to do on authorisation token renewal failure (knock of Knocker) @@ -155,23 +177,16 @@ export function observe({ onLogin: (account: UserAccount) => void onLogout: () => void }): () => void { - if (_onLoginListener != null || _onLogoutListener != null) { - throw new Error( - 'Background authentication is already being observed, ' + - 'to observe from multiple places the functionality has to be extended' - ) - } - _onLoginListener = onLogin - _onLogoutListener = onLogout + const listenerId = uuidv4() + _listeners.set(uuidv4(), { onLogin, onLogout }) const unregister = () => { - _onLoginListener = null - _onLogoutListener = null + _listeners.delete(listenerId) } try { if (isAuthenticated(_account)) { - _onLoginListener(_account) + onLogin(_account) } } catch (e) { unregister() @@ -202,12 +217,9 @@ export async function register() { browser.cookies.onChanged.removeListener(onChangedCookiesListener) await _logoutHandler() try { - if (_onLogoutListener) { - _onLogoutListener() - } + _onLogout() } finally { - _onLoginListener = null - _onLogoutListener = null + _listeners.clear() } } } diff --git a/archaeologist/src/storage_api_browser_ext.ts b/archaeologist/src/storage_api_browser_ext.ts index cdf4039d..b39fb4ca 100644 --- a/archaeologist/src/storage_api_browser_ext.ts +++ b/archaeologist/src/storage_api_browser_ext.ts @@ -43,6 +43,7 @@ import type { ExternalIngestionAdvanceArgs, ExternalIngestionGetArgs, NodeGetAllNidsArgs, + UserAccount, } from 'smuggler-api' import { INodeIterator, @@ -278,12 +279,12 @@ function generateEid(): Eid { async function createNode( store: YekLavStore, - args: NodeCreateArgs + args: NodeCreateArgs, + account: UserAccount ): Promise { // TODO[snikitin@outlook.com] Below keys must become functional somehow. // const _created_via: NodeCreatedVia | undefined = args.created_via - // TODO[snikitin@outlook.com] This graph structure has to work somehow const from_nid: Nid[] = args.from_nid ?? [] const to_nid: Nid[] = args.to_nid ?? [] @@ -298,6 +299,9 @@ async function createNode( index_text: args.index_text, created_at: createdAt, updated_at: createdAt, + meta: { + uid: account.getUid(), + }, } let records: YekLav[] = [ @@ -326,9 +330,7 @@ async function createNode( crtd: createdAt, upd: createdAt, is_sticky: false, - // TODO[snikitin@outlook.com] Evaluate if ownership support is needed - // and implement if yes - owned_by: 'todo', + owned_by: account.getUid(), } // Step 1: create records that allow to discover connected nodes from the // newly created node @@ -487,12 +489,9 @@ class Iterator implements INodeIterator { async function createEdge( store: YekLavStore, - args: EdgeCreateArgs + args: EdgeCreateArgs, + account: UserAccount ): Promise { - // TODO[snikitin@outlook.com] Evaluate if ownership support is needed - // and implement if yes - const owned_by = 'todo' - const createdAt: number = unixtime.now() const edge: TEdgeJson = { eid: generateEid(), @@ -501,7 +500,7 @@ async function createEdge( crtd: createdAt, upd: createdAt, is_sticky: false, - owned_by, + owned_by: account.getUid(), } const items: YekLav[] = [] @@ -645,7 +644,8 @@ export async function getAllNids( } export function makeBrowserExtStorageApi( - browserStore: browser.Storage.StorageArea + browserStore: browser.Storage.StorageArea, + account: UserAccount ): StorageApi { const store = new YekLavStore(browserStore) @@ -664,7 +664,7 @@ export function makeBrowserExtStorageApi( getByOrigin: (args: NodeGetByOriginArgs) => getNodesByOrigin(store, args), getAllNids: (args: NodeGetAllNidsArgs) => getAllNids(store, args), update: (args: NodeUpdateArgs) => updateNode(store, args), - create: (args: NodeCreateArgs) => createNode(store, args), + create: (args: NodeCreateArgs) => createNode(store, args, account), iterate: () => new Iterator(store), delete: throwUnimplementedError('node.delete'), bulkDelete: throwUnimplementedError('node.bulkdDelete'), @@ -692,7 +692,7 @@ export function makeBrowserExtStorageApi( }, }, edge: { - create: (args: EdgeCreateArgs) => createEdge(store, args), + create: (args: EdgeCreateArgs) => createEdge(store, args, account), get: (args: EdgeGetArgs) => getNodeAllEdges(store, args), sticky: throwUnimplementedError('edge.sticky'), delete: throwUnimplementedError('edge.delete'), From 0e74cefc6228e4bcb1f24cc7e6ace60fef469c28 Mon Sep 17 00:00:00 2001 From: Sergey Nikitin Date: Mon, 30 Jan 2023 22:58:49 +0000 Subject: [PATCH 5/6] typo --- archaeologist/src/background/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archaeologist/src/background/auth.ts b/archaeologist/src/background/auth.ts index 5334408e..547ef41e 100644 --- a/archaeologist/src/background/auth.ts +++ b/archaeologist/src/background/auth.ts @@ -178,7 +178,7 @@ export function observe({ onLogout: () => void }): () => void { const listenerId = uuidv4() - _listeners.set(uuidv4(), { onLogin, onLogout }) + _listeners.set(listenerId, { onLogin, onLogout }) const unregister = () => { _listeners.delete(listenerId) From 72b569b1b952868cf28e1f8e77baaec2e84aa19c Mon Sep 17 00:00:00 2001 From: Sergey Nikitin Date: Tue, 31 Jan 2023 19:41:47 +0000 Subject: [PATCH 6/6] lint --- archaeologist/src/background/auth.ts | 4 ++-- truthsayer/src/App.tsx | 4 ++-- truthsayer/src/lib/global.tsx | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/archaeologist/src/background/auth.ts b/archaeologist/src/background/auth.ts index 547ef41e..5ed97946 100644 --- a/archaeologist/src/background/auth.ts +++ b/archaeologist/src/background/auth.ts @@ -72,7 +72,7 @@ const _listeners: Map< > = new Map() function _onLogin(account: UserAccount) { - for (const [_, { onLogin }] of _listeners) { + for (const { onLogin } of _listeners.values()) { try { onLogin(account) } catch (reason) { @@ -82,7 +82,7 @@ function _onLogin(account: UserAccount) { } function _onLogout() { - for (const [_, { onLogout }] of _listeners) { + for (const { onLogout } of _listeners.values()) { try { onLogout() } catch (reason) { diff --git a/truthsayer/src/App.tsx b/truthsayer/src/App.tsx index edd78b23..59715e50 100644 --- a/truthsayer/src/App.tsx +++ b/truthsayer/src/App.tsx @@ -1,6 +1,6 @@ /** @jsxImportSource @emotion/react */ -import React, { useCallback, useContext } from 'react' +import React, { useCallback } from 'react' import { BrowserRouter as Router, @@ -326,7 +326,7 @@ function PageviewEventTracker({ analytics }: { analytics: PostHog }) { // See https://posthog.com/docs/integrate/client/js#one-page-apps-and-page-views // for more information about pageview events in PostHog analytics.capture('$pageview') - }, []) + }, [analytics]) const history = useHistory() React.useEffect(() => { diff --git a/truthsayer/src/lib/global.tsx b/truthsayer/src/lib/global.tsx index e5ea3947..52ea251e 100644 --- a/truthsayer/src/lib/global.tsx +++ b/truthsayer/src/lib/global.tsx @@ -5,7 +5,6 @@ import { PostHog } from 'posthog-js' import { jcss } from 'elementary' import { - AccountInterface, makeAlwaysThrowingStorageApi, makeDatacenterStorageApi, makeMsgProxyStorageApi,