`);
const statePromises = {
navInfo: navInfoPromise,
+ deviceID: null,
currentUserInfo: ((currentUserInfoPromise: any): Promise
),
sessionID: sessionIDPromise,
entryStore: entryStorePromise,
threadStore: threadStorePromise,
userStore: userStorePromise,
messageStore: messageStorePromise,
updatesCurrentAsOf: initialTime,
loadingStatuses: {},
calendarFilters: defaultCalendarFilters,
// We can use paths local to the on web
urlPrefix: '',
windowDimensions: { width: 0, height: 0 },
baseHref,
connection: {
...defaultConnectionInfo('web', viewer.timeZone),
actualizedCalendarQuery: calendarQuery,
},
watchedThreadIDs: [],
lifecycleState: 'active',
enabledApps: defaultWebEnabledApps,
reportStore: {
enabledReports: defaultEnabledReports,
queuedReports: [],
},
nextLocalID: 0,
timeZone: viewer.timeZone,
userAgent: viewer.userAgent,
cookie: undefined,
deviceToken: undefined,
dataLoaded: viewer.loggedIn,
windowActive: true,
_persist: null,
};
const [stateResult, App] = await Promise.all([
promiseAll(statePromises),
appPromise,
]);
const state: AppState = { ...stateResult };
const store: Store = createStore(reducer, state);
const routerContext = {};
const clientPath = clientPathFromRouterPath(req.url, appURLFacts);
const reactStream = renderToNodeStream(
,
);
if (routerContext.url) {
throw new ServerError('URL modified during server render!');
}
reactStream.pipe(res, { end: false });
await waitForStream(reactStream);
res.write(html`
`);
}
export { websiteResponder };
diff --git a/web/redux/action-types.js b/web/redux/action-types.js
index 61caaa45d..1b67c2d6d 100644
--- a/web/redux/action-types.js
+++ b/web/redux/action-types.js
@@ -1,3 +1,4 @@
// @flow
export const updateWindowActiveActionType = 'UPDATE_WINDOW_ACTIVE';
+export const setDeviceIDActionType = 'SET_DEVICE_ID';
diff --git a/web/redux/device-id-reducer.js b/web/redux/device-id-reducer.js
new file mode 100644
index 000000000..d0bbd40fb
--- /dev/null
+++ b/web/redux/device-id-reducer.js
@@ -0,0 +1,19 @@
+// @flow
+
+import type { Action } from '../redux/redux-setup';
+import { deviceIDCharLength } from '../utils//device-id';
+import { setDeviceIDActionType } from './action-types';
+
+const deviceIDRegex = new RegExp(
+ `^(ks|mobile|web):[a-zA-Z0-9]{${deviceIDCharLength.toString()}}$`,
+);
+
+export function reduceDeviceID(state: ?string, action: Action): ?string {
+ if (action.type === setDeviceIDActionType) {
+ if (action.payload?.match(deviceIDRegex)) {
+ return action.payload;
+ }
+ return null;
+ }
+ return state;
+}
diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js
index e2350407b..f02f93e61 100644
--- a/web/redux/redux-setup.js
+++ b/web/redux/redux-setup.js
@@ -1,234 +1,247 @@
// @flow
import invariant from 'invariant';
import type { PersistState } from 'redux-persist/src/types';
import {
logOutActionTypes,
deleteAccountActionTypes,
} from 'lib/actions/user-actions';
import baseReducer from 'lib/reducers/master-reducer';
import { mostRecentlyReadThreadSelector } from 'lib/selectors/thread-selectors';
import { isLoggedIn } from 'lib/selectors/user-selectors';
import { invalidSessionDowngrade } from 'lib/shared/account-utils';
import type { Shape } from 'lib/types/core';
import type { EnabledApps } from 'lib/types/enabled-apps';
import type { EntryStore } from 'lib/types/entry-types';
import type { CalendarFilter } from 'lib/types/filter-types';
import type { LifecycleState } from 'lib/types/lifecycle-state-types';
import type { LoadingStatus } from 'lib/types/loading-types';
import type { MessageStore } from 'lib/types/message-types';
import type { BaseAction } from 'lib/types/redux-types';
import type { ReportStore } from 'lib/types/report-types';
import type { ConnectionInfo } from 'lib/types/socket-types';
import type { ThreadStore } from 'lib/types/thread-types';
import type { CurrentUserInfo, UserStore } from 'lib/types/user-types';
import { setNewSessionActionType } from 'lib/utils/action-utils';
import { activeThreadSelector } from '../selectors/nav-selectors';
import { type NavInfo, updateNavInfoActionType } from '../types/nav-types';
-import { updateWindowActiveActionType } from './action-types';
+import {
+ updateWindowActiveActionType,
+ setDeviceIDActionType,
+} from './action-types';
+import { reduceDeviceID } from './device-id-reducer';
import reduceNavInfo from './nav-reducer';
import { getVisibility } from './visibility';
export type WindowDimensions = { width: number, height: number };
export type AppState = {
navInfo: NavInfo,
+ deviceID: ?string,
currentUserInfo: ?CurrentUserInfo,
sessionID: ?string,
entryStore: EntryStore,
threadStore: ThreadStore,
userStore: UserStore,
messageStore: MessageStore,
updatesCurrentAsOf: number,
loadingStatuses: { [key: string]: { [idx: number]: LoadingStatus } },
calendarFilters: $ReadOnlyArray