-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
108 lines (92 loc) · 2.55 KB
/
index.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
const conditional = require('koa-conditional-get')
const etag = require('koa-etag')
const kompose = require('koa-compose')
const qs = require('qs')
const { error: errorToResponse } = require('./lib/error')
const { html } = require('./lib/html')
const { json } = require('./lib/json')
const { parseCookies } = require('./lib/parseCookies')
const { redirect } = require('./lib/redirect')
const { send } = require('./lib/send')
const {
applySpec,
compose,
converge,
curry,
dissoc,
either,
merge,
path,
pipe,
prop
} = require('ramda')
// setDefaults :: KoaContext -> KoaContext
const setDefaults = ctx => {
ctx.set('Content-Type', 'application/octet-stream')
return ctx
}
// parseProtocol :: KoaContext -> String
const parseProtocol = pipe(
prop('request'),
either(path(['headers', 'x-forwarded-proto']), prop('protocol'))
)
// parseQuery :: KoaContext -> Object
const parseQuery =
compose(qs.parse, path(['request', 'querystring']))
// contextToRequest :: KoaContext -> PaperplaneRequest
const contextToRequest = applySpec({
body: path(['request', 'body']),
headers: prop('headers'),
method: prop('method'),
params: prop('params'),
pathname: prop('path'),
protocol: parseProtocol,
query: parseQuery,
url: prop('url')
})
// contextToPaperplane :: KoaContext -> PaperplaneRequest
const contextToPaperplane =
converge(merge, [prop('state'), contextToRequest])
// handleError :: KoaContext -> Error -> PaperplaneReponse
const handleError = curry((ctx, err) => {
if (!(err instanceof Error)) return err
const res = errorToResponse(err)
if (res.statusCode >= 500 || err.cry) {
ctx.app.emit('error', err, ctx)
}
if (err.expose === false || (err.expose == null && res.statusCode >= 500)) {
return dissoc('body', res)
}
return res
})
// applyEtag :: (KoaContext, () -> Promise) -> Promise
const applyEtag =
kompose([conditional(), etag()])
// writeResponse :: KoaContext -> PaperplaneResponse -> ()
const writeResponse = curry((ctx, res) => {
const { body = '', headers = {}, statusCode = 200 } = res
ctx.status = statusCode
ctx.set(headers)
ctx.body = body
})
// mount :: (PaperPlaneRequest -> PaperplaneResponse)
// -> (KoaContext, () -> Promise)
// -> Promise
const mount = handler => {
const middle = ctx =>
Promise.resolve(ctx)
.then(setDefaults)
.then(contextToPaperplane)
.then(parseCookies)
.then(handler)
.catch(handleError(ctx))
.then(writeResponse(ctx))
return kompose([applyEtag, middle])
}
module.exports = {
html,
json,
mount,
redirect,
send
}