-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.ts
139 lines (126 loc) · 4.61 KB
/
index.ts
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
130
131
132
133
134
135
136
137
138
139
// #!/usr/bin/env babel-node
// -*- coding: utf-8 -*-
/** @module index */
'use strict'
// region import
import {CLOSE_EVENT_NAMES, Mapping, represent} from 'clientnode'
import {
createServer as createHttp2Server,
Http2Server as HttpServer,
Http2ServerResponse as HTTPServerResponse,
Http2ServerRequest as HTTPServerRequest
} from 'http2'
import {createServer} from 'http'
import polyfillLibrary from 'polyfill-library'
import url from 'url'
// endregion
// region types
const Flags = ['always', 'gated'] as const
type Flag = typeof Flags[number]
const UnknownTechnologyConfigurations = ['ignore', 'polyfill'] as const
type UnknownTechnologyConfiguration =
typeof UnknownTechnologyConfigurations[number]
// endregion
export const requestHandler = async (
request: HTTPServerRequest, response: HTTPServerResponse
): Promise<void> => {
try {
console.info('Got request url', request.url)
if (request.url.startsWith('/polyfill.')) {
// region parse query parameter
const queryParameter = url.parse(request.url, true).query
let excludes: Array<string> = []
for (const parameter of ([] as Array<string>).concat(
queryParameter.excludes || []
))
excludes = excludes.concat(parameter.split(','))
let features: Array<string> = []
for (const parameter of ([] as Array<string>).concat(
queryParameter.features || []
))
features = features.concat(parameter.split(','))
let flags: Array<Flag> = []
for (const parameter of ([] as Array<string>).concat(
queryParameter.flags || []
))
flags = flags.concat(
parameter
.split(',')
.filter((flagCandidate: string): boolean =>
Flags.includes(flagCandidate as Flag)
) as Array<Flag>
)
const givenUnknown: Array<string> =
([] as Array<string>).concat(queryParameter.unknown || [])
const unknown: UnknownTechnologyConfiguration =
givenUnknown.length &&
UnknownTechnologyConfigurations.includes(
givenUnknown[0] as UnknownTechnologyConfiguration
) ?
givenUnknown[0] as UnknownTechnologyConfiguration :
'polyfill'
// endregion
// region build feature options
const featureOptions: Mapping<{ flags: Array<Flag> }> = {}
for (const feature of features) {
const configuration =
feature.split('|') as [string, ...Array<Flag>]
const option = configuration[0]
featureOptions[option] = {
flags: configuration.length > 1 ?
configuration[1] as unknown as Array<Flag> :
flags
}
}
// endregion
// region build configuration and log
const configuration = {
excludes,
features: featureOptions,
minify: request.url.includes('.min.js?'),
uaString: request.headers['user-agent'],
unknown
}
console.info(
'Apply polyfill configuration: "' +
`${represent(configuration)}"`
)
// endregion
// region write response
response.statusCode = 200
response.setHeader(
'Content-Type', 'text/javascript; charset=utf-8'
)
response.write(
await polyfillLibrary.getPolyfillString(configuration) as
string
)
// endregion
} else
response.statusCode = 404
} catch (error) {
console.warn('Error occurred:', error)
response.statusCode = 500
} finally {
response.end()
}
}
const instance:HttpServer = (
createServer as unknown as typeof createHttp2Server
)((...parameters) => {
void requestHandler(...parameters)
})
const port =
parseInt(process.argv[2] ?? (process.env.PORT ? process.env.PORT : 8080))
instance.listen(
port, () => {
console.info(`Listen on port ${String(port)} for incoming requests.`)
}
)
for (const name of CLOSE_EVENT_NAMES)
process.on(name, () => {
console.info(`\nGot "${name}" signal: stopping server.`)
instance.close(() => {
console.info('Server stopped.')
})
})