-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathepic.js
129 lines (116 loc) · 4.68 KB
/
epic.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const { combineEpics } = require('redux-observable')
const Rx = require('rxjs')
const createCid = require('incremental-id')
const { push } = require('react-router-redux')
const { actions: agents } = require('../agents')
const { actions: credentials } = require('../credentials')
const { actions: profiles } = require('../profiles')
const {
signIn, signInStart, signInSuccess, signInError,
logOut, logOutStart, logOutSuccess, logOutError,
register, registerStart, registerSuccess, registerError
} = require('./actions')
module.exports = combineEpics(initEpic, signInEpic, logOutEpic, registerEpic)
exports.initEpic = initEpic
function initEpic () {
return Rx.Observable.of(signIn(createCid()))
.delay(0) // apparently needs delay otherwise action lost
}
exports.signInEpic = signInEpic
function signInEpic (action$, store, { feathers }) {
return action$.ofType(signIn.type)
.switchMap(({ payload, meta: { cid } }) => Rx.Observable.concat(
Rx.Observable.of(signInStart(cid)),
Rx.Observable.fromPromise(
feathers.authenticate(payload)
.then(({ accessToken }) => {
return feathers.passport.verifyJWT(accessToken)
.then(({ credentialId }) => {
return { accessToken, credentialId }
})
})
)
.mergeMap(({ accessToken, credentialId }) => {
return Rx.Observable.concat(
Rx.Observable.of(signInSuccess(cid, { accessToken, credentialId })),
fetchAgentByCredential(action$, cid, credentialId)
)
})
//.mergeMap(actions => Rx.Observable.of(...actions))
// can't swallow error as part of promise chain
// because we want to not emit an action, rather than undefined.
.catch((err) => {
// if init signIn() fails, it's not an error
if (err.message === 'Could not find stored JWT and no authentication strategy was given') return Rx.Observable.empty()
return Rx.Observable.of(signInError(cid, err))
})
))
}
exports.logOutEpic = logOutEpic
function logOutEpic (action$, store, { feathers }) {
return action$.ofType(logOut.type)
.switchMap(({ meta: { cid } }) => Rx.Observable.concat(
Rx.Observable.of(logOutStart(cid)),
Rx.Observable.fromPromise(
feathers.logout()
.then(() => logOutSuccess(cid))
)
.concat(Rx.Observable.of(push('/'))) // TODO this should be configurable
.catch((err) => Rx.Observable.of(logOutError(cid, err)))
))
}
exports.registerEpic = registerEpic
function registerEpic (action$, store, deps) {
return action$.ofType(register.type)
.switchMap(action => {
const { payload } = action
const { email, password, name } = payload
const { cid } = action.meta
const createdSuccess$ = action$.ofType(credentials.complete.type).filter(onlyCid).take(1)
const createdError$ = action$.ofType(credentials.error.type).filter(onlyCid).take(1)
// get only the last set item, since it should be the latest
const createdSet$ = action$.ofType(credentials.set.type).filter(onlyCid)
const signInSuccess$ = action$.ofType(signInSuccess.type).filter(onlyCid).take(1)
// TODO create initial profile with name
return Rx.Observable.merge(
Rx.Observable.of(
registerStart(cid),
credentials.create(cid, { email, password, name })
),
createdSuccess$
.withLatestFrom(createdSet$, (success, set) => set.payload.data)
.mergeMap(created => {
return Rx.Observable.of(
registerSuccess(cid, created),
signIn(cid, { strategy: 'local', email, password })
)
}),
createdError$.map(action => registerError(cid, action.payload)),
signInSuccess$.mapTo(push('/')) // TODO this should be configurable
)
function onlyCid (action) {
return action.meta.cid === cid
}
})
}
function fetchAgentByCredential (action$, cid, credentialId) {
const agentSet$ = action$.ofType(agents.set.type).filter(onlyCid)
const credentialSet$ = action$.ofType(credentials.set.type).filter(onlyCid)
const profileSet$ = action$.ofType(profiles.set.type).filter(onlyCid)
return Rx.Observable.merge(
Rx.Observable.of(credentials.get(cid, credentialId)),
credentialSet$.mergeMap(action => {
const { agentId } = action.payload.data
return Rx.Observable.of(
credentials.complete(cid),
agents.get(cid, agentId),
profiles.find(cid, { query: { agentId } })
)
}),
profileSet$.map(() => profiles.complete(cid)),
agentSet$.map(() => agents.complete(cid))
)
function onlyCid (action) {
return action.meta.cid === cid
}
}