mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {AtpSessionData, AtpSessionEvent} from '@atproto/api'
2import {sha256} from 'js-sha256'
3import {Statsig} from 'statsig-react-native-expo'
4
5import {IS_INTERNAL} from '#/lib/app-info'
6import {Schema} from '../persisted'
7import {Action, State} from './reducer'
8import {SessionAccount} from './types'
9
10type Reducer = (state: State, action: Action) => State
11
12type Log =
13 | {
14 type: 'reducer:init'
15 state: State
16 }
17 | {
18 type: 'reducer:call'
19 action: Action
20 prevState: State
21 nextState: State
22 }
23 | {
24 type: 'method:start'
25 method:
26 | 'createAccount'
27 | 'login'
28 | 'logout'
29 | 'resumeSession'
30 | 'removeAccount'
31 account?: SessionAccount
32 }
33 | {
34 type: 'method:end'
35 method:
36 | 'createAccount'
37 | 'login'
38 | 'logout'
39 | 'resumeSession'
40 | 'removeAccount'
41 account?: SessionAccount
42 }
43 | {
44 type: 'persisted:broadcast'
45 data: Schema['session']
46 }
47 | {
48 type: 'persisted:receive'
49 data: Schema['session']
50 }
51 | {
52 type: 'agent:switch'
53 prevAgent: object
54 nextAgent: object
55 }
56 | {
57 type: 'agent:patch'
58 agent: object
59 prevSession: AtpSessionData | undefined
60 nextSession: AtpSessionData | undefined
61 }
62
63export function wrapSessionReducerForLogging(reducer: Reducer): Reducer {
64 return function loggingWrapper(prevState: State, action: Action): State {
65 const nextState = reducer(prevState, action)
66 addSessionDebugLog({type: 'reducer:call', prevState, action, nextState})
67 return nextState
68 }
69}
70
71let nextMessageIndex = 0
72const MAX_SLICE_LENGTH = 1000
73
74// Not gated.
75export function addSessionErrorLog(did: string, event: AtpSessionEvent) {
76 try {
77 if (!Statsig.initializeCalled() || !Statsig.getStableID()) {
78 return
79 }
80 const stack = (new Error().stack ?? '').slice(0, MAX_SLICE_LENGTH)
81 Statsig.logEvent('session:error', null, {
82 did,
83 event,
84 stack,
85 })
86 } catch (e) {
87 console.error(e)
88 }
89}
90
91export function addSessionDebugLog(log: Log) {
92 try {
93 if (!Statsig.initializeCalled() || !Statsig.getStableID()) {
94 // Drop these logs for now.
95 return
96 }
97 // DISABLING THIS GATE DUE TO EME @TODO EME-GATE
98 if (!IS_INTERNAL) {
99 return
100 }
101 // if (!Statsig.checkGate('debug_session')) {
102 // return
103 // }
104 const messageIndex = nextMessageIndex++
105 const {type, ...content} = log
106 let payload = JSON.stringify(content, replacer)
107
108 let nextSliceIndex = 0
109 while (payload.length > 0) {
110 const sliceIndex = nextSliceIndex++
111 const slice = payload.slice(0, MAX_SLICE_LENGTH)
112 payload = payload.slice(MAX_SLICE_LENGTH)
113 Statsig.logEvent('session:debug', null, {
114 realmId,
115 messageIndex: String(messageIndex),
116 messageType: type,
117 sliceIndex: String(sliceIndex),
118 slice,
119 })
120 }
121 } catch (e) {
122 console.error(e)
123 }
124}
125
126let agentIds = new WeakMap<object, string>()
127let realmId = Math.random().toString(36).slice(2)
128let nextAgentId = 1
129
130function getAgentId(agent: object) {
131 let id = agentIds.get(agent)
132 if (id === undefined) {
133 id = realmId + '::' + nextAgentId++
134 agentIds.set(agent, id)
135 }
136 return id
137}
138
139function replacer(key: string, value: unknown) {
140 if (typeof value === 'object' && value != null && 'api' in value) {
141 return getAgentId(value)
142 }
143 if (
144 key === 'service' ||
145 key === 'email' ||
146 key === 'emailConfirmed' ||
147 key === 'emailAuthFactor' ||
148 key === 'pdsUrl'
149 ) {
150 return undefined
151 }
152 if (
153 typeof value === 'string' &&
154 (key === 'refreshJwt' || key === 'accessJwt')
155 ) {
156 return sha256(value)
157 }
158 return value
159}